diff --git a/README.OpenSource b/README.OpenSource index d4a280412afb807d480593229aaad01414232aca..ae9ecf874e252edacf6214e7f6f78e9d6850b07c 100644 --- a/README.OpenSource +++ b/README.OpenSource @@ -3,18 +3,18 @@ "Name": "WPA Supplicant", "License": "BSD 3-Clause License", "License File": "wpa_supplicant-2.9_standard/COPYING", - "Version Number": "2.10", + "Version Number": "2.11", "Owner": "maoyufeng3@huawei.com", - "Upstream URL": "https://w1.fi/releases/wpa_supplicant-2.10.tar.gz", + "Upstream URL": "https://w1.fi/releases/wpa_supplicant-2.11.tar.gz", "Description": "wpa_supplicant is a WPA Supplicant for Linux, BSD, Mac OS X, and Windows with support for WPA and WPA2 (IEEE 802.11i / RSN). It is suitable for both desktop/laptop computers and embedded systems. Supplicant is the IEEE 802.1X/WPA component that is used in the client stations. It implements key negotiation with a WPA Authenticator and it controls the roaming and IEEE 802.11 authentication/association of the wlan driver." }, { "Name": "hostapd", "License": "BSD 3-Clause License", "License File": "wpa_supplicant-2.9_standard/COPYING", - "Version Number": "2.10", + "Version Number": "2.11", "Owner": "maoyufeng3@huawei.com", - "Upstream URL": "http://w1.fi/releases/hostapd-2.10.tar.gz", + "Upstream URL": "https://w1.fi/releases/hostapd-2.11.tar.gz", "Description": "hostapd is a user space daemon for access point and authentication servers. It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators, RADIUS client, EAP server, and RADIUS authentication server." } ] diff --git a/wpa_supplicant-2.9_standard/.gitignore b/wpa_supplicant-2.9_standard/.gitignore index f3a028005ae1620a34a614d27c348e1ef86dd7e7..221e32f876f483b8a76e18c4e10a38ec993338b9 100644 --- a/wpa_supplicant-2.9_standard/.gitignore +++ b/wpa_supplicant-2.9_standard/.gitignore @@ -1,7 +1,7 @@ -*.o -*.d -*.a -*.so -hostapd/hostapd_cli -wpa_supplicant/wpa_cli -wpa_supplicant/wpa_passphrase +*.o +*.d +*.a +*.so +hostapd/hostapd_cli +wpa_supplicant/wpa_cli +wpa_supplicant/wpa_passphrase diff --git a/wpa_supplicant-2.9_standard/BUILD.gn b/wpa_supplicant-2.9_standard/BUILD.gn index 4d60277df67522d495536495b0ec48698be19a94..28efdf3a30a0f00dd4dd816375bf148ad8e40994 100644 --- a/wpa_supplicant-2.9_standard/BUILD.gn +++ b/wpa_supplicant-2.9_standard/BUILD.gn @@ -146,7 +146,6 @@ wpa_client_base_cflags = [ "-DCONFIG_NO_RADIUS", "-DCONFIG_NO_RANDOM_POOL", "-DCONFIG_SHA256", - "-DCONFIG_CRYPTO_INTERNAL", "-DCONFIG_INTERNAL_LIBTOMMATH", "-DCONFIG_INTERNAL_SHA384", "-DCONFIG_INTERNAL_SHA512", @@ -305,6 +304,7 @@ wpa_base_sources = [ "$WPA_ROOT_DIR/src/ap/authsrv.c", "$WPA_ROOT_DIR/src/ap/beacon.c", "$WPA_ROOT_DIR/src/ap/bss_load.c", + "$WPA_ROOT_DIR/src/ap/comeback_token.c", "$WPA_ROOT_DIR/src/ap/ctrl_iface_ap.c", "$WPA_ROOT_DIR/src/ap/dfs.c", "$WPA_ROOT_DIR/src/ap/drv_callbacks.c", @@ -313,6 +313,7 @@ wpa_base_sources = [ "$WPA_ROOT_DIR/src/ap/hw_features.c", "$WPA_ROOT_DIR/src/ap/ieee802_11.c", "$WPA_ROOT_DIR/src/ap/ieee802_11_auth.c", + "$WPA_ROOT_DIR/src/ap/ieee802_11_eht.c", "$WPA_ROOT_DIR/src/ap/ieee802_11_ht.c", "$WPA_ROOT_DIR/src/ap/ieee802_11_shared.c", "$WPA_ROOT_DIR/src/ap/ieee802_1x.c", @@ -329,6 +330,7 @@ wpa_base_sources = [ "$WPA_ROOT_DIR/src/common/ctrl_iface_common.c", "$WPA_ROOT_DIR/src/common/hw_features_common.c", "$WPA_ROOT_DIR/src/common/ieee802_11_common.c", + "$WPA_ROOT_DIR/src/common/ptksa_cache.c", "$WPA_ROOT_DIR/src/common/wpa_common.c", "$WPA_ROOT_DIR/src/crypto/aes-internal.c", "$WPA_ROOT_DIR/src/crypto/aes-omac1.c", @@ -345,6 +347,8 @@ wpa_base_sources = [ "$WPA_ROOT_DIR/src/eapol_auth/eapol_auth_sm.c", "$WPA_ROOT_DIR/src/eapol_supp/eapol_supp_sm.c", "$WPA_ROOT_DIR/src/l2_packet/l2_packet_${CONFIG_L2_PACKET}.c", + "$WPA_ROOT_DIR/src/pasn/pasn_common.c", + "$WPA_ROOT_DIR/src/pasn/pasn_responder.c", "$WPA_ROOT_DIR/src/rsn_supp/pmksa_cache.c", "$WPA_ROOT_DIR/src/rsn_supp/preauth.c", "$WPA_ROOT_DIR/src/rsn_supp/wpa.c", @@ -465,6 +469,7 @@ wpa_base_include_dirs = [ "$WPA_ROOT_DIR/src/common", "$WPA_ROOT_DIR/src/utils", "$WPA_ROOT_DIR/src/drivers", + "$WPA_ROOT_DIR/src/pasn", "$WPA_ROOT_DIR/wpa_supplicant", "$WPA_ROOT_DIR/build/include", "$WPA_ROOT_DIR/wpa_supplicant_lib", @@ -500,7 +505,6 @@ ohos_shared_library("wpa_sys") { "-DCONFIG_NO_RADIUS", "-DCONFIG_NO_RANDOM_POOL", "-DCONFIG_SHA256", - "-DCONFIG_CRYPTO_INTERNAL", "-DCONFIG_INTERNAL_LIBTOMMATH", "-DCONFIG_INTERNAL_SHA384", "-DCONFIG_INTERNAL_SHA512", @@ -603,6 +607,7 @@ ohos_shared_library("wpa_sys") { "-DCONFIG_DEBUG_FILE", "-DCONFIG_IEEE80211AC", "-DCONFIG_IEEE80211AX", + "-DCONFIG_IEEE80211BE", ] external_deps += [ "libnl:libnl_share" ] } else { @@ -669,7 +674,6 @@ ohos_shared_library("wpa_sys_updater") { "-DCONFIG_NO_RADIUS", "-DCONFIG_NO_RANDOM_POOL", "-DCONFIG_SHA256", - "-DCONFIG_CRYPTO_INTERNAL", "-DCONFIG_INTERNAL_LIBTOMMATH", "-DCONFIG_INTERNAL_SHA384", "-DCONFIG_INTERNAL_SHA512", @@ -756,6 +760,7 @@ ohos_shared_library("wpa_sys_updater") { "-DCONFIG_DEBUG_FILE", "-DCONFIG_IEEE80211AC", "-DCONFIG_IEEE80211AX", + "-DCONFIG_IEEE80211BE", ] external_deps += [ "libnl:libnl_share" ] } else { @@ -818,7 +823,6 @@ ohos_shared_library("wpa") { "-DCONFIG_NO_RADIUS", "-DCONFIG_NO_RANDOM_POOL", "-DCONFIG_SHA256", - "-DCONFIG_CRYPTO_INTERNAL", "-DCONFIG_INTERNAL_LIBTOMMATH", "-DCONFIG_INTERNAL_SHA384", "-DCONFIG_INTERNAL_SHA512", @@ -927,6 +931,7 @@ ohos_shared_library("wpa") { "-DCONFIG_DEBUG_FILE", "-DCONFIG_IEEE80211AC", "-DCONFIG_IEEE80211AX", + "-DCONFIG_IEEE80211BE", ] external_deps += [ "libnl:libnl_share" ] } else { @@ -995,7 +1000,6 @@ ohos_shared_library("wpa_updater") { "-DCONFIG_NO_RADIUS", "-DCONFIG_NO_RANDOM_POOL", "-DCONFIG_SHA256", - "-DCONFIG_CRYPTO_INTERNAL", "-DCONFIG_INTERNAL_LIBTOMMATH", "-DCONFIG_INTERNAL_SHA384", "-DCONFIG_INTERNAL_SHA512", @@ -1083,6 +1087,7 @@ ohos_shared_library("wpa_updater") { "-DCONFIG_DEBUG_FILE", "-DCONFIG_IEEE80211AC", "-DCONFIG_IEEE80211AX", + "-DCONFIG_IEEE80211BE", ] external_deps += [ "libnl:libnl_share" ] } else { @@ -1137,7 +1142,6 @@ ohos_executable("wpa_cli") { "-DCONFIG_NO_RADIUS", "-DCONFIG_NO_RANDOM_POOL", "-DCONFIG_SHA256", - "-DCONFIG_CRYPTO_INTERNAL", "-DCONFIG_INTERNAL_LIBTOMMATH", "-DCONFIG_INTERNAL_SHA384", "-DCONFIG_INTERNAL_SHA512", @@ -1228,7 +1232,6 @@ ohos_executable("hostapd_cli") { "-DCONFIG_NO_RADIUS", "-DCONFIG_NO_RANDOM_POOL", "-DCONFIG_SHA256", - "-DCONFIG_CRYPTO_INTERNAL", "-DCONFIG_INTERNAL_LIBTOMMATH", "-DCONFIG_INTERNAL_SHA384", "-DCONFIG_INTERNAL_SHA512", diff --git a/wpa_supplicant-2.9_standard/CMakeLists.txt b/wpa_supplicant-2.9_standard/CMakeLists.txt index 7f89f5a7ef927a984afb857ce3cfcbb188e9506e..c00a4ef6f0c4eb9bb4209be832498d2c9176e147 100644 --- a/wpa_supplicant-2.9_standard/CMakeLists.txt +++ b/wpa_supplicant-2.9_standard/CMakeLists.txt @@ -1,1016 +1,1016 @@ -cmake_minimum_required(VERSION 3.22) -project(wpa_supplicant_2_9_standard) - -set(CMAKE_CXX_STANDARD 14) - -include_directories(build/include) -include_directories(hostapd) -include_directories(hs20/client) -include_directories(src/ap) -include_directories(src/common) -include_directories(src/crypto) -include_directories(src/drivers) -include_directories(src/eap_common) -include_directories(src/eap_peer) -include_directories(src/eap_server) -include_directories(src/eapol_auth) -include_directories(src/eapol_supp) -include_directories(src/fst) -include_directories(src/l2_packet) -include_directories(src/p2p) -include_directories(src/pae) -include_directories(src/radius) -include_directories(src/rsn_supp) -include_directories(src/tls) -include_directories(src/utils) -include_directories(src/wps) -include_directories(wpa_supplicant) -include_directories(wpa_supplicant/binder) -include_directories(wpa_supplicant/dbus) -include_directories(wpa_supplicant/wpa_gui-qt4) -include_directories(wpa_supplicant_lib) -include_directories(wpa_test) -include_directories(../../../drivers/peripheral/wlan/client) -include_directories(../../libnl/include) - -add_executable(wpa_supplicant_2_9_standard - build/include/libwpa.h - build/Makefile - hostapd/logwatch/hostapd - hostapd/logwatch/hostapd.conf - hostapd/logwatch/README - hostapd/.config - hostapd/android.config - hostapd/Android.mk - hostapd/ap_config_file.c - hostapd/ap_ctrl_iface.c - hostapd/ap_eap_register.c - hostapd/ap_main.c - hostapd/ChangeLog - hostapd/config_file.h - hostapd/ctrl_iface.h - hostapd/defconfig - hostapd/eap_register.h - hostapd/eap_testing.txt - hostapd/hapd_module_tests.c - hostapd/hlr_auc_gw.c - hostapd/hlr_auc_gw.milenage_db - hostapd/hlr_auc_gw.txt - hostapd/hostapd.8 - hostapd/hostapd.accept - hostapd/hostapd.android.rc - hostapd/hostapd.conf - hostapd/hostapd.deny - hostapd/hostapd.eap_user - hostapd/hostapd.eap_user_sqlite - hostapd/hostapd.radius_clients - hostapd/hostapd.sim_db - hostapd/hostapd.vlan - hostapd/hostapd.wpa_psk - hostapd/hostapd_cli.1 - hostapd/hostapd_cli.c - hostapd/Makefile - hostapd/nt_password_hash.c - hostapd/README - hostapd/README-MULTI-AP - hostapd/README-WPS - hostapd/README.OpenSource - hostapd/sae_pk_gen.c - hostapd/wired.conf - hostapd/wps-ap-nfc.py - hostapd_test/hostapd_sample.c - hs20/client/.gitignore - hs20/client/Android.mk - hs20/client/devdetail.xml - hs20/client/devinfo.xml - hs20/client/est.c - hs20/client/Makefile - hs20/client/oma_dm_client.c - hs20/client/osu_client.c - hs20/client/osu_client.h - hs20/client/spp_client.c - src/ap/accounting.c - src/ap/accounting.h - src/ap/acs.c - src/ap/acs.h - src/ap/airtime_policy.c - src/ap/airtime_policy.h - src/ap/ap_config.c - src/ap/ap_config.h - src/ap/ap_drv_ops.c - src/ap/ap_drv_ops.h - src/ap/ap_list.c - src/ap/ap_list.h - src/ap/ap_mlme.c - src/ap/ap_mlme.h - src/ap/ap_rrm.c - src/ap/authsrv.c - src/ap/authsrv.h - src/ap/beacon.c - src/ap/beacon.h - src/ap/bss_load.c - src/ap/bss_load.h - src/ap/ctrl_iface_ap.c - src/ap/ctrl_iface_ap.h - src/ap/dfs.c - src/ap/dfs.h - src/ap/dhcp_snoop.c - src/ap/dhcp_snoop.h - src/ap/dpp_hostapd.c - src/ap/dpp_hostapd.h - src/ap/drv_callbacks.c - src/ap/eap_user_db.c - src/ap/eth_p_oui.c - src/ap/eth_p_oui.h - src/ap/fils_hlp.c - src/ap/fils_hlp.h - src/ap/gas_query_ap.c - src/ap/gas_query_ap.h - src/ap/gas_serv.c - src/ap/gas_serv.h - src/ap/hostapd.c - src/ap/hostapd.h - src/ap/hs20.c - src/ap/hs20.h - src/ap/hw_features.c - src/ap/hw_features.h - src/ap/ieee802_11.c - src/ap/ieee802_11.h - src/ap/ieee802_11_auth.c - src/ap/ieee802_11_auth.h - src/ap/ieee802_11_he.c - src/ap/ieee802_11_ht.c - src/ap/ieee802_11_shared.c - src/ap/ieee802_11_vht.c - src/ap/ieee802_1x.c - src/ap/ieee802_1x.h - src/ap/Makefile - src/ap/mbo_ap.c - src/ap/mbo_ap.h - src/ap/ndisc_snoop.c - src/ap/ndisc_snoop.h - src/ap/neighbor_db.c - src/ap/neighbor_db.h - src/ap/p2p_hostapd.c - src/ap/p2p_hostapd.h - src/ap/pmksa_cache_auth.c - src/ap/pmksa_cache_auth.h - src/ap/preauth_auth.c - src/ap/preauth_auth.h - src/ap/rrm.c - src/ap/rrm.h - src/ap/sta_info.c - src/ap/sta_info.h - src/ap/taxonomy.c - src/ap/taxonomy.h - src/ap/tkip_countermeasures.c - src/ap/tkip_countermeasures.h - src/ap/utils.c - src/ap/vlan.c - src/ap/vlan.h - src/ap/vlan_full.c - src/ap/vlan_ifconfig.c - src/ap/vlan_init.c - src/ap/vlan_init.h - src/ap/vlan_ioctl.c - src/ap/vlan_util.c - src/ap/vlan_util.h - src/ap/wmm.c - src/ap/wmm.h - src/ap/wnm_ap.c - src/ap/wnm_ap.h - src/ap/wpa_auth.c - src/ap/wpa_auth.h - src/ap/wpa_auth_ft.c - src/ap/wpa_auth_glue.c - src/ap/wpa_auth_glue.h - src/ap/wpa_auth_i.h - src/ap/wpa_auth_ie.c - src/ap/wpa_auth_ie.h - src/ap/wpa_auth_kay.c - src/ap/wpa_auth_kay.h - src/ap/wps_hostapd.c - src/ap/wps_hostapd.h - src/ap/x_snoop.c - src/ap/x_snoop.h - src/common/brcm_vendor.h - src/common/cli.c - src/common/cli.h - src/common/common_module_tests.c - src/common/ctrl_iface_common.c - src/common/ctrl_iface_common.h - src/common/defs.h - src/common/dhcp.h - src/common/dpp.c - src/common/dpp.h - src/common/dpp_auth.c - src/common/dpp_backup.c - src/common/dpp_crypto.c - src/common/dpp_i.h - src/common/dpp_pkex.c - src/common/dpp_reconfig.c - src/common/dpp_tcp.c - src/common/dragonfly.c - src/common/dragonfly.h - src/common/eapol_common.h - src/common/gas.c - src/common/gas.h - src/common/gas_server.c - src/common/gas_server.h - src/common/hw_features_common.c - src/common/hw_features_common.h - src/common/ieee802_11_common.c - src/common/ieee802_11_common.h - src/common/ieee802_11_defs.h - src/common/ieee802_1x_defs.h - src/common/linux_bridge.h - src/common/linux_vlan.h - src/common/Makefile - src/common/ocv.c - src/common/ocv.h - src/common/privsep_commands.h - src/common/ptksa_cache.c - src/common/ptksa_cache.h - src/common/qca-vendor-attr.h - src/common/qca-vendor.h - src/common/sae.c - src/common/sae.h - src/common/sae_pk.c - src/common/tnc.h - src/common/version.h - src/common/wpa_common.c - src/common/wpa_common.h - src/common/wpa_ctrl.c - src/common/wpa_ctrl.h - src/common/wpa_helpers.c - src/common/wpa_helpers.h - src/crypto/aes-cbc.c - src/crypto/aes-ccm.c - src/crypto/aes-ctr.c - src/crypto/aes-eax.c - src/crypto/aes-encblock.c - src/crypto/aes-gcm.c - src/crypto/aes-internal-dec.c - src/crypto/aes-internal-enc.c - src/crypto/aes-internal.c - src/crypto/aes-omac1.c - src/crypto/aes-siv.c - src/crypto/aes-unwrap.c - src/crypto/aes-wrap.c - src/crypto/aes.h - src/crypto/aes_i.h - src/crypto/aes_siv.h - src/crypto/aes_wrap.h - src/crypto/crypto.h - src/crypto/crypto_gnutls.c - src/crypto/crypto_internal-cipher.c - src/crypto/crypto_internal-modexp.c - src/crypto/crypto_internal-rsa.c - src/crypto/crypto_internal.c - src/crypto/crypto_libtomcrypt.c - src/crypto/crypto_linux.c - src/crypto/crypto_module_tests.c - src/crypto/crypto_nettle.c - src/crypto/crypto_none.c - src/crypto/crypto_openssl.c - src/crypto/crypto_wolfssl.c - src/crypto/des-internal.c - src/crypto/des_i.h - src/crypto/dh_group5.c - src/crypto/dh_group5.h - src/crypto/dh_groups.c - src/crypto/dh_groups.h - src/crypto/fips_prf_internal.c - src/crypto/fips_prf_openssl.c - src/crypto/fips_prf_wolfssl.c - src/crypto/Makefile - src/crypto/md4-internal.c - src/crypto/md5-internal.c - src/crypto/md5.c - src/crypto/md5.h - src/crypto/md5_i.h - src/crypto/milenage.c - src/crypto/milenage.h - src/crypto/ms_funcs.c - src/crypto/ms_funcs.h - src/crypto/random.c - src/crypto/random.h - src/crypto/rc4.c - src/crypto/sha1-internal.c - src/crypto/sha1-pbkdf2.c - src/crypto/sha1-prf.c - src/crypto/sha1-tlsprf.c - src/crypto/sha1-tprf.c - src/crypto/sha1.c - src/crypto/sha1.h - src/crypto/sha1_i.h - src/crypto/sha256-internal.c - src/crypto/sha256-kdf.c - src/crypto/sha256-prf.c - src/crypto/sha256-tlsprf.c - src/crypto/sha256.c - src/crypto/sha256.h - src/crypto/sha256_i.h - src/crypto/sha384-internal.c - src/crypto/sha384-kdf.c - src/crypto/sha384-prf.c - src/crypto/sha384-tlsprf.c - src/crypto/sha384.c - src/crypto/sha384.h - src/crypto/sha384_i.h - src/crypto/sha512-internal.c - src/crypto/sha512-kdf.c - src/crypto/sha512-prf.c - src/crypto/sha512.c - src/crypto/sha512.h - src/crypto/sha512_i.h - src/crypto/tls.h - src/crypto/tls_gnutls.c - src/crypto/tls_internal.c - src/crypto/tls_none.c - src/crypto/tls_openssl.c - src/crypto/tls_openssl.h - src/crypto/tls_openssl_ocsp.c - src/crypto/tls_wolfssl.c - src/drivers/android_drv.h - src/drivers/driver.h - src/drivers/driver_atheros.c - src/drivers/driver_bsd.c - src/drivers/driver_common.c - src/drivers/driver_hostap.c - src/drivers/driver_hostap.h - src/drivers/driver_macsec_linux.c - src/drivers/driver_macsec_qca.c - src/drivers/driver_ndis.c - src/drivers/driver_ndis.h - src/drivers/driver_ndis_.c - src/drivers/driver_nl80211.c - src/drivers/driver_nl80211.h - src/drivers/driver_nl80211_android.c - src/drivers/driver_nl80211_capa.c - src/drivers/driver_nl80211_event.c - src/drivers/driver_nl80211_monitor.c - src/drivers/driver_nl80211_scan.c - src/drivers/driver_none.c - src/drivers/driver_openbsd.c - src/drivers/driver_privsep.c - src/drivers/driver_roboswitch.c - src/drivers/driver_wext.c - src/drivers/driver_wext.h - src/drivers/driver_wired.c - src/drivers/driver_wired_common.c - src/drivers/driver_wired_common.h - src/drivers/drivers.c - src/drivers/drivers.mak - src/drivers/drivers.mk - src/drivers/linux_defines.h - src/drivers/linux_ioctl.c - src/drivers/linux_ioctl.h - src/drivers/linux_wext.h - src/drivers/Makefile - src/drivers/ndis_events.c - src/drivers/netlink.c - src/drivers/netlink.h - src/drivers/nl80211_copy.h - src/drivers/priv_netlink.h - src/drivers/rfkill.c - src/drivers/rfkill.h - src/drivers/wpa_hal.c - src/drivers/wpa_hal.h - src/drivers/wpa_hal_event.c - src/eap_common/chap.c - src/eap_common/chap.h - src/eap_common/eap_common.c - src/eap_common/eap_common.h - src/eap_common/eap_defs.h - src/eap_common/eap_eke_common.c - src/eap_common/eap_eke_common.h - src/eap_common/eap_fast_common.c - src/eap_common/eap_fast_common.h - src/eap_common/eap_gpsk_common.c - src/eap_common/eap_gpsk_common.h - src/eap_common/eap_ikev2_common.c - src/eap_common/eap_ikev2_common.h - src/eap_common/eap_pax_common.c - src/eap_common/eap_pax_common.h - src/eap_common/eap_peap_common.c - src/eap_common/eap_peap_common.h - src/eap_common/eap_psk_common.c - src/eap_common/eap_psk_common.h - src/eap_common/eap_pwd_common.c - src/eap_common/eap_pwd_common.h - src/eap_common/eap_sake_common.c - src/eap_common/eap_sake_common.h - src/eap_common/eap_sim_common.c - src/eap_common/eap_sim_common.h - src/eap_common/eap_teap_common.c - src/eap_common/eap_teap_common.h - src/eap_common/eap_tlv_common.h - src/eap_common/eap_ttls.h - src/eap_common/eap_wsc_common.c - src/eap_common/eap_wsc_common.h - src/eap_common/ikev2_common.c - src/eap_common/ikev2_common.h - src/eap_common/Makefile - src/eap_peer/.gitignore - src/eap_peer/eap.c - src/eap_peer/eap.h - src/eap_peer/eap_aka.c - src/eap_peer/eap_config.h - src/eap_peer/eap_eke.c - src/eap_peer/eap_fast.c - src/eap_peer/eap_fast_pac.c - src/eap_peer/eap_fast_pac.h - src/eap_peer/eap_gpsk.c - src/eap_peer/eap_gtc.c - src/eap_peer/eap_i.h - src/eap_peer/eap_ikev2.c - src/eap_peer/eap_leap.c - src/eap_peer/eap_md5.c - src/eap_peer/eap_methods.c - src/eap_peer/eap_methods.h - src/eap_peer/eap_mschapv2.c - src/eap_peer/eap_otp.c - src/eap_peer/eap_pax.c - src/eap_peer/eap_peap.c - src/eap_peer/eap_proxy.h - src/eap_peer/eap_proxy_dummy.c - src/eap_peer/eap_psk.c - src/eap_peer/eap_pwd.c - src/eap_peer/eap_sake.c - src/eap_peer/eap_sim.c - src/eap_peer/eap_teap.c - src/eap_peer/eap_teap_pac.c - src/eap_peer/eap_teap_pac.h - src/eap_peer/eap_tls.c - src/eap_peer/eap_tls_common.c - src/eap_peer/eap_tls_common.h - src/eap_peer/eap_tnc.c - src/eap_peer/eap_ttls.c - src/eap_peer/eap_vendor_test.c - src/eap_peer/eap_wsc.c - src/eap_peer/ikev2.c - src/eap_peer/ikev2.h - src/eap_peer/Makefile - src/eap_peer/mschapv2.c - src/eap_peer/mschapv2.h - src/eap_peer/tncc.c - src/eap_peer/tncc.h - src/eap_server/eap.h - src/eap_server/eap_i.h - src/eap_server/eap_methods.h - src/eap_server/eap_server.c - src/eap_server/eap_server_aka.c - src/eap_server/eap_server_eke.c - src/eap_server/eap_server_fast.c - src/eap_server/eap_server_gpsk.c - src/eap_server/eap_server_gtc.c - src/eap_server/eap_server_identity.c - src/eap_server/eap_server_ikev2.c - src/eap_server/eap_server_md5.c - src/eap_server/eap_server_methods.c - src/eap_server/eap_server_mschapv2.c - src/eap_server/eap_server_pax.c - src/eap_server/eap_server_peap.c - src/eap_server/eap_server_psk.c - src/eap_server/eap_server_pwd.c - src/eap_server/eap_server_sake.c - src/eap_server/eap_server_sim.c - src/eap_server/eap_server_teap.c - src/eap_server/eap_server_tls.c - src/eap_server/eap_server_tls_common.c - src/eap_server/eap_server_tnc.c - src/eap_server/eap_server_ttls.c - src/eap_server/eap_server_vendor_test.c - src/eap_server/eap_server_wsc.c - src/eap_server/eap_sim_db.c - src/eap_server/eap_sim_db.h - src/eap_server/eap_tls_common.h - src/eap_server/ikev2.c - src/eap_server/ikev2.h - src/eap_server/Makefile - src/eap_server/tncs.c - src/eap_server/tncs.h - src/eapol_auth/eapol_auth_dump.c - src/eapol_auth/eapol_auth_sm.c - src/eapol_auth/eapol_auth_sm.h - src/eapol_auth/eapol_auth_sm_i.h - src/eapol_auth/Makefile - src/eapol_supp/eapol_supp_sm.c - src/eapol_supp/eapol_supp_sm.h - src/eapol_supp/Makefile - src/fst/fst.c - src/fst/fst.h - src/fst/fst_ctrl_aux.c - src/fst/fst_ctrl_aux.h - src/fst/fst_ctrl_defs.h - src/fst/fst_ctrl_iface.c - src/fst/fst_ctrl_iface.h - src/fst/fst_defs.h - src/fst/fst_group.c - src/fst/fst_group.h - src/fst/fst_iface.c - src/fst/fst_iface.h - src/fst/fst_internal.h - src/fst/fst_session.c - src/fst/fst_session.h - src/fst/Makefile - src/l2_packet/l2_packet.h - src/l2_packet/l2_packet_freebsd.c - src/l2_packet/l2_packet_linux.c - src/l2_packet/l2_packet_ndis.c - src/l2_packet/l2_packet_none.c - src/l2_packet/l2_packet_pcap.c - src/l2_packet/l2_packet_privsep.c - src/l2_packet/l2_packet_rtos.c - src/l2_packet/l2_packet_winpcap.c - src/l2_packet/Makefile - src/p2p/Makefile - src/p2p/p2p.c - src/p2p/p2p.h - src/p2p/p2p_build.c - src/p2p/p2p_dev_disc.c - src/p2p/p2p_go_neg.c - src/p2p/p2p_group.c - src/p2p/p2p_i.h - src/p2p/p2p_invitation.c - src/p2p/p2p_parse.c - src/p2p/p2p_pd.c - src/p2p/p2p_sd.c - src/p2p/p2p_utils.c - src/pae/ieee802_1x_cp.c - src/pae/ieee802_1x_cp.h - src/pae/ieee802_1x_kay.c - src/pae/ieee802_1x_kay.h - src/pae/ieee802_1x_kay_i.h - src/pae/ieee802_1x_key.c - src/pae/ieee802_1x_key.h - src/pae/ieee802_1x_secy_ops.c - src/pae/ieee802_1x_secy_ops.h - src/pae/Makefile - src/radius/Makefile - src/radius/radius.c - src/radius/radius.h - src/radius/radius_client.c - src/radius/radius_client.h - src/radius/radius_das.c - src/radius/radius_das.h - src/radius/radius_server.c - src/radius/radius_server.h - src/rsn_supp/Makefile - src/rsn_supp/pmksa_cache.c - src/rsn_supp/pmksa_cache.h - src/rsn_supp/preauth.c - src/rsn_supp/preauth.h - src/rsn_supp/tdls.c - src/rsn_supp/wpa.c - src/rsn_supp/wpa.h - src/rsn_supp/wpa_ft.c - src/rsn_supp/wpa_i.h - src/rsn_supp/wpa_ie.c - src/rsn_supp/wpa_ie.h - src/tls/asn1.c - src/tls/asn1.h - src/tls/bignum.c - src/tls/bignum.h - src/tls/libtommath.c - src/tls/Makefile - src/tls/pkcs1.c - src/tls/pkcs1.h - src/tls/pkcs5.c - src/tls/pkcs5.h - src/tls/pkcs8.c - src/tls/pkcs8.h - src/tls/rsa.c - src/tls/rsa.h - src/tls/tlsv1_client.c - src/tls/tlsv1_client.h - src/tls/tlsv1_client_i.h - src/tls/tlsv1_client_ocsp.c - src/tls/tlsv1_client_read.c - src/tls/tlsv1_client_write.c - src/tls/tlsv1_common.c - src/tls/tlsv1_common.h - src/tls/tlsv1_cred.c - src/tls/tlsv1_cred.h - src/tls/tlsv1_record.c - src/tls/tlsv1_record.h - src/tls/tlsv1_server.c - src/tls/tlsv1_server.h - src/tls/tlsv1_server_i.h - src/tls/tlsv1_server_read.c - src/tls/tlsv1_server_write.c - src/tls/x509v3.c - src/tls/x509v3.h - src/utils/base64.c - src/utils/base64.h - src/utils/bitfield.c - src/utils/bitfield.h - src/utils/browser-android.c - src/utils/browser-system.c - src/utils/browser-wpadebug.c - src/utils/browser.c - src/utils/browser.h - src/utils/build_config.h - src/utils/common.c - src/utils/common.h - src/utils/config.c - src/utils/config.h - src/utils/const_time.h - src/utils/crc32.c - src/utils/crc32.h - src/utils/edit.c - src/utils/edit.h - src/utils/edit_readline.c - src/utils/edit_simple.c - src/utils/eloop.c - src/utils/eloop.h - src/utils/eloop_win.c - src/utils/ext_password.c - src/utils/ext_password.h - src/utils/ext_password_file.c - src/utils/ext_password_i.h - src/utils/ext_password_test.c - src/utils/http-utils.h - src/utils/http_curl.c - src/utils/includes.h - src/utils/ip_addr.c - src/utils/ip_addr.h - src/utils/json.c - src/utils/json.h - src/utils/list.h - src/utils/Makefile - src/utils/module_tests.h - src/utils/os.h - src/utils/os_internal.c - src/utils/os_none.c - src/utils/os_unix.c - src/utils/os_win32.c - src/utils/pcsc_funcs.c - src/utils/pcsc_funcs.h - src/utils/platform.h - src/utils/radiotap.c - src/utils/radiotap.h - src/utils/radiotap_iter.h - src/utils/state_machine.h - src/utils/trace.c - src/utils/trace.h - src/utils/utils_module_tests.c - src/utils/uuid.c - src/utils/uuid.h - src/utils/wpa_debug.c - src/utils/wpa_debug.h - src/utils/wpabuf.c - src/utils/wpabuf.h - src/utils/xml-utils.c - src/utils/xml-utils.h - src/utils/xml_libxml2.c - src/wps/http.h - src/wps/http_client.c - src/wps/http_client.h - src/wps/http_server.c - src/wps/http_server.h - src/wps/httpread.c - src/wps/httpread.h - src/wps/Makefile - src/wps/ndef.c - src/wps/upnp_xml.c - src/wps/upnp_xml.h - src/wps/wps.c - src/wps/wps.h - src/wps/wps_attr_build.c - src/wps/wps_attr_parse.c - src/wps/wps_attr_parse.h - src/wps/wps_attr_process.c - src/wps/wps_common.c - src/wps/wps_defs.h - src/wps/wps_dev_attr.c - src/wps/wps_dev_attr.h - src/wps/wps_enrollee.c - src/wps/wps_er.c - src/wps/wps_er.h - src/wps/wps_er_ssdp.c - src/wps/wps_i.h - src/wps/wps_module_tests.c - src/wps/wps_registrar.c - src/wps/wps_upnp.c - src/wps/wps_upnp.h - src/wps/wps_upnp_ap.c - src/wps/wps_upnp_event.c - src/wps/wps_upnp_i.h - src/wps/wps_upnp_ssdp.c - src/wps/wps_upnp_web.c - src/wps/wps_validate.c - src/build.rules - src/lib.rules - src/Makefile - src/objs.mk - wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl - wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl - wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl - wpa_supplicant/binder/.clang-format - wpa_supplicant/binder/binder.cpp - wpa_supplicant/binder/binder.h - wpa_supplicant/binder/binder_constants.cpp - wpa_supplicant/binder/binder_constants.h - wpa_supplicant/binder/binder_i.h - wpa_supplicant/binder/binder_manager.cpp - wpa_supplicant/binder/binder_manager.h - wpa_supplicant/binder/iface.cpp - wpa_supplicant/binder/iface.h - wpa_supplicant/binder/supplicant.cpp - wpa_supplicant/binder/supplicant.h - wpa_supplicant/dbus/.gitignore - wpa_supplicant/dbus/dbus-wpa_supplicant.conf - wpa_supplicant/dbus/dbus_common.c - wpa_supplicant/dbus/dbus_common.h - wpa_supplicant/dbus/dbus_common_i.h - wpa_supplicant/dbus/dbus_dict_helpers.c - wpa_supplicant/dbus/dbus_dict_helpers.h - wpa_supplicant/dbus/dbus_new.c - wpa_supplicant/dbus/dbus_new.h - wpa_supplicant/dbus/dbus_new_handlers.c - wpa_supplicant/dbus/dbus_new_handlers.h - wpa_supplicant/dbus/dbus_new_handlers_p2p.c - wpa_supplicant/dbus/dbus_new_handlers_p2p.h - wpa_supplicant/dbus/dbus_new_handlers_wps.c - wpa_supplicant/dbus/dbus_new_helpers.c - wpa_supplicant/dbus/dbus_new_helpers.h - wpa_supplicant/dbus/dbus_new_introspect.c - wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in - wpa_supplicant/dbus/Makefile - wpa_supplicant/doc/docbook/.gitignore - wpa_supplicant/doc/docbook/eapol_test.8 - wpa_supplicant/doc/docbook/eapol_test.sgml - wpa_supplicant/doc/docbook/Makefile - wpa_supplicant/doc/docbook/manpage.links - wpa_supplicant/doc/docbook/manpage.refs - wpa_supplicant/doc/docbook/wpa_background.8 - wpa_supplicant/doc/docbook/wpa_background.sgml - wpa_supplicant/doc/docbook/wpa_cli.8 - wpa_supplicant/doc/docbook/wpa_cli.sgml - wpa_supplicant/doc/docbook/wpa_gui.8 - wpa_supplicant/doc/docbook/wpa_gui.sgml - wpa_supplicant/doc/docbook/wpa_passphrase.8 - wpa_supplicant/doc/docbook/wpa_passphrase.sgml - wpa_supplicant/doc/docbook/wpa_priv.8 - wpa_supplicant/doc/docbook/wpa_priv.sgml - wpa_supplicant/doc/docbook/wpa_supplicant.8 - wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 - wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml - wpa_supplicant/doc/docbook/wpa_supplicant.sgml - wpa_supplicant/examples/p2p/p2p_connect.py - wpa_supplicant/examples/p2p/p2p_disconnect.py - wpa_supplicant/examples/p2p/p2p_find.py - wpa_supplicant/examples/p2p/p2p_flush.py - wpa_supplicant/examples/p2p/p2p_group_add.py - wpa_supplicant/examples/p2p/p2p_invite.py - wpa_supplicant/examples/p2p/p2p_listen.py - wpa_supplicant/examples/p2p/p2p_stop_find.py - wpa_supplicant/examples/60_wpa_supplicant - wpa_supplicant/examples/dbus-listen-preq.py - wpa_supplicant/examples/dpp-nfc.py - wpa_supplicant/examples/dpp-qrcode.py - wpa_supplicant/examples/ieee8021x.conf - wpa_supplicant/examples/openCryptoki.conf - wpa_supplicant/examples/p2p-action-udhcp.sh - wpa_supplicant/examples/p2p-action.sh - wpa_supplicant/examples/p2p-nfc.py - wpa_supplicant/examples/plaintext.conf - wpa_supplicant/examples/udhcpd-p2p.conf - wpa_supplicant/examples/wep.conf - wpa_supplicant/examples/wpa-psk-tkip.conf - wpa_supplicant/examples/wpa2-eap-ccmp.conf - wpa_supplicant/examples/wpas-dbus-new-getall.py - wpa_supplicant/examples/wpas-dbus-new-signals.py - wpa_supplicant/examples/wpas-dbus-new-wps.py - wpa_supplicant/examples/wpas-dbus-new.py - wpa_supplicant/examples/wps-ap-cli - wpa_supplicant/examples/wps-nfc.py - wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in - wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in - wpa_supplicant/systemd/wpa_supplicant.service.arg.in - wpa_supplicant/systemd/wpa_supplicant.service.in - wpa_supplicant/utils/log2pcap.py - wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj - wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj - wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj - wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj - wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj - wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj - wpa_supplicant/vs2005/wpa_supplicant.sln - wpa_supplicant/wpa_gui-qt4/icons/.gitignore - wpa_supplicant/wpa_gui-qt4/icons/ap.svg - wpa_supplicant/wpa_gui-qt4/icons/group.svg - wpa_supplicant/wpa_gui-qt4/icons/invitation.svg - wpa_supplicant/wpa_gui-qt4/icons/laptop.svg - wpa_supplicant/wpa_gui-qt4/icons/Makefile - wpa_supplicant/wpa_gui-qt4/icons/README - wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg - wpa_supplicant/wpa_gui-qt4/lang/.gitignore - wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts - wpa_supplicant/wpa_gui-qt4/.gitignore - wpa_supplicant/wpa_gui-qt4/addinterface.cpp - wpa_supplicant/wpa_gui-qt4/addinterface.h - wpa_supplicant/wpa_gui-qt4/eventhistory.cpp - wpa_supplicant/wpa_gui-qt4/eventhistory.h - wpa_supplicant/wpa_gui-qt4/eventhistory.ui - wpa_supplicant/wpa_gui-qt4/icons.qrc - wpa_supplicant/wpa_gui-qt4/icons_png.qrc - wpa_supplicant/wpa_gui-qt4/main.cpp - wpa_supplicant/wpa_gui-qt4/networkconfig.cpp - wpa_supplicant/wpa_gui-qt4/networkconfig.h - wpa_supplicant/wpa_gui-qt4/networkconfig.ui - wpa_supplicant/wpa_gui-qt4/peers.cpp - wpa_supplicant/wpa_gui-qt4/peers.h - wpa_supplicant/wpa_gui-qt4/peers.ui - wpa_supplicant/wpa_gui-qt4/scanresults.cpp - wpa_supplicant/wpa_gui-qt4/scanresults.h - wpa_supplicant/wpa_gui-qt4/scanresults.ui - wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp - wpa_supplicant/wpa_gui-qt4/scanresultsitem.h - wpa_supplicant/wpa_gui-qt4/signalbar.cpp - wpa_supplicant/wpa_gui-qt4/signalbar.h - wpa_supplicant/wpa_gui-qt4/stringquery.cpp - wpa_supplicant/wpa_gui-qt4/stringquery.h - wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp - wpa_supplicant/wpa_gui-qt4/userdatarequest.h - wpa_supplicant/wpa_gui-qt4/userdatarequest.ui - wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop - wpa_supplicant/wpa_gui-qt4/wpa_gui.pro - wpa_supplicant/wpa_gui-qt4/wpagui.cpp - wpa_supplicant/wpa_gui-qt4/wpagui.h - wpa_supplicant/wpa_gui-qt4/wpagui.ui - wpa_supplicant/wpa_gui-qt4/wpamsg.h - wpa_supplicant/.config - wpa_supplicant/.gitignore - wpa_supplicant/android.config - wpa_supplicant/Android.mk - wpa_supplicant/ap.c - wpa_supplicant/ap.h - wpa_supplicant/autoscan.c - wpa_supplicant/autoscan.h - wpa_supplicant/autoscan_exponential.c - wpa_supplicant/autoscan_periodic.c - wpa_supplicant/bgscan.c - wpa_supplicant/bgscan.h - wpa_supplicant/bgscan_learn.c - wpa_supplicant/bgscan_simple.c - wpa_supplicant/bss.c - wpa_supplicant/bss.h - wpa_supplicant/bssid_ignore.c - wpa_supplicant/bssid_ignore.h - wpa_supplicant/ChangeLog - wpa_supplicant/config.c - wpa_supplicant/config.h - wpa_supplicant/config_file.c - wpa_supplicant/config_none.c - wpa_supplicant/config_ssid.h - wpa_supplicant/config_winreg.c - wpa_supplicant/ctrl_iface.c - wpa_supplicant/ctrl_iface.h - wpa_supplicant/ctrl_iface_named_pipe.c - wpa_supplicant/ctrl_iface_udp.c - wpa_supplicant/ctrl_iface_unix.c - wpa_supplicant/defconfig - wpa_supplicant/dpp_supplicant.c - wpa_supplicant/dpp_supplicant.h - wpa_supplicant/driver_i.h - wpa_supplicant/eap_proxy_dummy.mak - wpa_supplicant/eap_proxy_dummy.mk - wpa_supplicant/eap_register.c - wpa_supplicant/eap_testing.txt - wpa_supplicant/eapol_test.c - wpa_supplicant/eapol_test.py - wpa_supplicant/events.c - wpa_supplicant/gas_query.c - wpa_supplicant/gas_query.h - wpa_supplicant/hs20_supplicant.c - wpa_supplicant/hs20_supplicant.h - wpa_supplicant/ibss_rsn.c - wpa_supplicant/ibss_rsn.h - wpa_supplicant/interworking.c - wpa_supplicant/interworking.h - wpa_supplicant/libwpa_test.c - wpa_supplicant/main.c - wpa_supplicant/main_none.c - wpa_supplicant/main_winmain.c - wpa_supplicant/main_winsvc.c - wpa_supplicant/Makefile - wpa_supplicant/mbo.c - wpa_supplicant/mesh.c - wpa_supplicant/mesh.h - wpa_supplicant/mesh_mpm.c - wpa_supplicant/mesh_mpm.h - wpa_supplicant/mesh_rsn.c - wpa_supplicant/mesh_rsn.h - wpa_supplicant/nfc_pw_token.c - wpa_supplicant/nmake.mak - wpa_supplicant/notify.c - wpa_supplicant/notify.h - wpa_supplicant/offchannel.c - wpa_supplicant/offchannel.h - wpa_supplicant/op_classes.c - wpa_supplicant/p2p_supplicant.c - wpa_supplicant/p2p_supplicant.h - wpa_supplicant/p2p_supplicant_sd.c - wpa_supplicant/pasn_supplicant.c - wpa_supplicant/preauth_test.c - wpa_supplicant/README - wpa_supplicant/README-DPP - wpa_supplicant/README-HS20 - wpa_supplicant/README-P2P - wpa_supplicant/README-Windows.txt - wpa_supplicant/README-WPS - wpa_supplicant/README.OpenSource - wpa_supplicant/robust_av.c - wpa_supplicant/rrm.c - wpa_supplicant/scan.c - wpa_supplicant/scan.h - wpa_supplicant/sme.c - wpa_supplicant/sme.h - wpa_supplicant/todo.txt - wpa_supplicant/twt.c - wpa_supplicant/wifi_display.c - wpa_supplicant/wifi_display.h - wpa_supplicant/win_example.reg - wpa_supplicant/win_if_list.c - wpa_supplicant/wmm_ac.c - wpa_supplicant/wmm_ac.h - wpa_supplicant/wnm_sta.c - wpa_supplicant/wnm_sta.h - wpa_supplicant/wpa_cli.c - wpa_supplicant/wpa_passphrase.c - wpa_supplicant/wpa_priv.c - wpa_supplicant/wpa_supplicant.c - wpa_supplicant/wpa_supplicant.conf - wpa_supplicant/wpa_supplicant_conf.mk - wpa_supplicant/wpa_supplicant_conf.sh - wpa_supplicant/wpa_supplicant_i.h - wpa_supplicant/wpa_supplicant_template.conf - wpa_supplicant/wpas_glue.c - wpa_supplicant/wpas_glue.h - wpa_supplicant/wpas_kay.c - wpa_supplicant/wpas_kay.h - wpa_supplicant/wpas_module_tests.c - wpa_supplicant/wps_supplicant.c - wpa_supplicant/wps_supplicant.h - wpa_supplicant_lib/driver_nl80211_hisi.c - wpa_supplicant_lib/driver_nl80211_hisi.h - wpa_supplicant_lib/wpa_magiclink.c - wpa_supplicant_lib/wpa_magiclink.h - wpa_test/wpa_sample.c - .gitignore - BUILD.gn - build.sh - CONTRIBUTIONS - COPYING - README) - -ADD_COMPILE_DEFINITIONS(CONFIG_CTRL_IFACE CONFIG_CTRL_IFACE_UDP CONFIG_IEEE80211W CONFIG_NO_VLAN - CONFIG_NO_RADIUS - CONFIG_NO_RANDOM_POOL - CONFIG_SHA256 - CONFIG_CRYPTO_INTERNAL - CONFIG_INTERNAL_LIBTOMMATH - CONFIG_INTERNAL_SHA384 - CONFIG_INTERNAL_SHA512 - CONFIG_CTRL_IFACE - CONFIG_CTRL_IFACE_UDP - CONFIG_IBSS_RSN - IEEE8021X_EAPOL - USERSPACE_CLIENT_SUPPORT - CONFIG_BACKEND_FILE - CONFIG_NO_CONFIG_WRITE - CONFIG_NO_CONFIG_BLOBS - CONFIG_NO_ACCOUNTING - EAP_SERVER_IDENTITY - CONFIG_IEEE80211N - HOSTAPD - NEED_AP_MLME - CONFIG_WPS - CONFIG_AP - CONFIG_P2P - EAP_WSC - EAP_SERVER_WSC - EAP_SERVER - CONFIG_GAS - CONFIG_OFFCHANNEL - CONFIG_MAGICLINK - CONFIG_DEBUG_FILE - CONFIG_DRIVER_NL80211 - CONFIG_LIBNL32 - CONFIG_OPEN_HARMONY_PATCH - CONFIG_OPEN_HARMONY_HUKS_TLS - EAP_MSCHAPV2 - EAP_TLS - EAP_PEAP - EAP_TTLS - EAP_SIM - EAP_PWD - CONFIG_SHA256 - CONFIG_ECC - EAP_AKA - EAP_AKA_PRIME - EAP_TLS_OPENSSL - CONFIG_WEP) +cmake_minimum_required(VERSION 3.22) +project(wpa_supplicant_2_9_standard) + +set(CMAKE_CXX_STANDARD 14) + +include_directories(build/include) +include_directories(hostapd) +include_directories(hs20/client) +include_directories(src/ap) +include_directories(src/common) +include_directories(src/crypto) +include_directories(src/drivers) +include_directories(src/eap_common) +include_directories(src/eap_peer) +include_directories(src/eap_server) +include_directories(src/eapol_auth) +include_directories(src/eapol_supp) +include_directories(src/fst) +include_directories(src/l2_packet) +include_directories(src/p2p) +include_directories(src/pae) +include_directories(src/radius) +include_directories(src/rsn_supp) +include_directories(src/tls) +include_directories(src/utils) +include_directories(src/wps) +include_directories(wpa_supplicant) +include_directories(wpa_supplicant/binder) +include_directories(wpa_supplicant/dbus) +include_directories(wpa_supplicant/wpa_gui-qt4) +include_directories(wpa_supplicant_lib) +include_directories(wpa_test) +include_directories(../../../drivers/peripheral/wlan/client) +include_directories(../../libnl/include) + +add_executable(wpa_supplicant_2_9_standard + build/include/libwpa.h + build/Makefile + hostapd/logwatch/hostapd + hostapd/logwatch/hostapd.conf + hostapd/logwatch/README + hostapd/.config + hostapd/android.config + hostapd/Android.mk + hostapd/ap_config_file.c + hostapd/ap_ctrl_iface.c + hostapd/ap_eap_register.c + hostapd/ap_main.c + hostapd/ChangeLog + hostapd/config_file.h + hostapd/ctrl_iface.h + hostapd/defconfig + hostapd/eap_register.h + hostapd/eap_testing.txt + hostapd/hapd_module_tests.c + hostapd/hlr_auc_gw.c + hostapd/hlr_auc_gw.milenage_db + hostapd/hlr_auc_gw.txt + hostapd/hostapd.8 + hostapd/hostapd.accept + hostapd/hostapd.android.rc + hostapd/hostapd.conf + hostapd/hostapd.deny + hostapd/hostapd.eap_user + hostapd/hostapd.eap_user_sqlite + hostapd/hostapd.radius_clients + hostapd/hostapd.sim_db + hostapd/hostapd.vlan + hostapd/hostapd.wpa_psk + hostapd/hostapd_cli.1 + hostapd/hostapd_cli.c + hostapd/Makefile + hostapd/nt_password_hash.c + hostapd/README + hostapd/README-MULTI-AP + hostapd/README-WPS + hostapd/README.OpenSource + hostapd/sae_pk_gen.c + hostapd/wired.conf + hostapd/wps-ap-nfc.py + hostapd_test/hostapd_sample.c + hs20/client/.gitignore + hs20/client/Android.mk + hs20/client/devdetail.xml + hs20/client/devinfo.xml + hs20/client/est.c + hs20/client/Makefile + hs20/client/oma_dm_client.c + hs20/client/osu_client.c + hs20/client/osu_client.h + hs20/client/spp_client.c + src/ap/accounting.c + src/ap/accounting.h + src/ap/acs.c + src/ap/acs.h + src/ap/airtime_policy.c + src/ap/airtime_policy.h + src/ap/ap_config.c + src/ap/ap_config.h + src/ap/ap_drv_ops.c + src/ap/ap_drv_ops.h + src/ap/ap_list.c + src/ap/ap_list.h + src/ap/ap_mlme.c + src/ap/ap_mlme.h + src/ap/ap_rrm.c + src/ap/authsrv.c + src/ap/authsrv.h + src/ap/beacon.c + src/ap/beacon.h + src/ap/bss_load.c + src/ap/bss_load.h + src/ap/ctrl_iface_ap.c + src/ap/ctrl_iface_ap.h + src/ap/dfs.c + src/ap/dfs.h + src/ap/dhcp_snoop.c + src/ap/dhcp_snoop.h + src/ap/dpp_hostapd.c + src/ap/dpp_hostapd.h + src/ap/drv_callbacks.c + src/ap/eap_user_db.c + src/ap/eth_p_oui.c + src/ap/eth_p_oui.h + src/ap/fils_hlp.c + src/ap/fils_hlp.h + src/ap/gas_query_ap.c + src/ap/gas_query_ap.h + src/ap/gas_serv.c + src/ap/gas_serv.h + src/ap/hostapd.c + src/ap/hostapd.h + src/ap/hs20.c + src/ap/hs20.h + src/ap/hw_features.c + src/ap/hw_features.h + src/ap/ieee802_11.c + src/ap/ieee802_11.h + src/ap/ieee802_11_auth.c + src/ap/ieee802_11_auth.h + src/ap/ieee802_11_he.c + src/ap/ieee802_11_ht.c + src/ap/ieee802_11_shared.c + src/ap/ieee802_11_vht.c + src/ap/ieee802_1x.c + src/ap/ieee802_1x.h + src/ap/Makefile + src/ap/mbo_ap.c + src/ap/mbo_ap.h + src/ap/ndisc_snoop.c + src/ap/ndisc_snoop.h + src/ap/neighbor_db.c + src/ap/neighbor_db.h + src/ap/p2p_hostapd.c + src/ap/p2p_hostapd.h + src/ap/pmksa_cache_auth.c + src/ap/pmksa_cache_auth.h + src/ap/preauth_auth.c + src/ap/preauth_auth.h + src/ap/rrm.c + src/ap/rrm.h + src/ap/sta_info.c + src/ap/sta_info.h + src/ap/taxonomy.c + src/ap/taxonomy.h + src/ap/tkip_countermeasures.c + src/ap/tkip_countermeasures.h + src/ap/utils.c + src/ap/vlan.c + src/ap/vlan.h + src/ap/vlan_full.c + src/ap/vlan_ifconfig.c + src/ap/vlan_init.c + src/ap/vlan_init.h + src/ap/vlan_ioctl.c + src/ap/vlan_util.c + src/ap/vlan_util.h + src/ap/wmm.c + src/ap/wmm.h + src/ap/wnm_ap.c + src/ap/wnm_ap.h + src/ap/wpa_auth.c + src/ap/wpa_auth.h + src/ap/wpa_auth_ft.c + src/ap/wpa_auth_glue.c + src/ap/wpa_auth_glue.h + src/ap/wpa_auth_i.h + src/ap/wpa_auth_ie.c + src/ap/wpa_auth_ie.h + src/ap/wpa_auth_kay.c + src/ap/wpa_auth_kay.h + src/ap/wps_hostapd.c + src/ap/wps_hostapd.h + src/ap/x_snoop.c + src/ap/x_snoop.h + src/common/brcm_vendor.h + src/common/cli.c + src/common/cli.h + src/common/common_module_tests.c + src/common/ctrl_iface_common.c + src/common/ctrl_iface_common.h + src/common/defs.h + src/common/dhcp.h + src/common/dpp.c + src/common/dpp.h + src/common/dpp_auth.c + src/common/dpp_backup.c + src/common/dpp_crypto.c + src/common/dpp_i.h + src/common/dpp_pkex.c + src/common/dpp_reconfig.c + src/common/dpp_tcp.c + src/common/dragonfly.c + src/common/dragonfly.h + src/common/eapol_common.h + src/common/gas.c + src/common/gas.h + src/common/gas_server.c + src/common/gas_server.h + src/common/hw_features_common.c + src/common/hw_features_common.h + src/common/ieee802_11_common.c + src/common/ieee802_11_common.h + src/common/ieee802_11_defs.h + src/common/ieee802_1x_defs.h + src/common/linux_bridge.h + src/common/linux_vlan.h + src/common/Makefile + src/common/ocv.c + src/common/ocv.h + src/common/privsep_commands.h + src/common/ptksa_cache.c + src/common/ptksa_cache.h + src/common/qca-vendor-attr.h + src/common/qca-vendor.h + src/common/sae.c + src/common/sae.h + src/common/sae_pk.c + src/common/tnc.h + src/common/version.h + src/common/wpa_common.c + src/common/wpa_common.h + src/common/wpa_ctrl.c + src/common/wpa_ctrl.h + src/common/wpa_helpers.c + src/common/wpa_helpers.h + src/crypto/aes-cbc.c + src/crypto/aes-ccm.c + src/crypto/aes-ctr.c + src/crypto/aes-eax.c + src/crypto/aes-encblock.c + src/crypto/aes-gcm.c + src/crypto/aes-internal-dec.c + src/crypto/aes-internal-enc.c + src/crypto/aes-internal.c + src/crypto/aes-omac1.c + src/crypto/aes-siv.c + src/crypto/aes-unwrap.c + src/crypto/aes-wrap.c + src/crypto/aes.h + src/crypto/aes_i.h + src/crypto/aes_siv.h + src/crypto/aes_wrap.h + src/crypto/crypto.h + src/crypto/crypto_gnutls.c + src/crypto/crypto_internal-cipher.c + src/crypto/crypto_internal-modexp.c + src/crypto/crypto_internal-rsa.c + src/crypto/crypto_internal.c + src/crypto/crypto_libtomcrypt.c + src/crypto/crypto_linux.c + src/crypto/crypto_module_tests.c + src/crypto/crypto_nettle.c + src/crypto/crypto_none.c + src/crypto/crypto_openssl.c + src/crypto/crypto_wolfssl.c + src/crypto/des-internal.c + src/crypto/des_i.h + src/crypto/dh_group5.c + src/crypto/dh_group5.h + src/crypto/dh_groups.c + src/crypto/dh_groups.h + src/crypto/fips_prf_internal.c + src/crypto/fips_prf_openssl.c + src/crypto/fips_prf_wolfssl.c + src/crypto/Makefile + src/crypto/md4-internal.c + src/crypto/md5-internal.c + src/crypto/md5.c + src/crypto/md5.h + src/crypto/md5_i.h + src/crypto/milenage.c + src/crypto/milenage.h + src/crypto/ms_funcs.c + src/crypto/ms_funcs.h + src/crypto/random.c + src/crypto/random.h + src/crypto/rc4.c + src/crypto/sha1-internal.c + src/crypto/sha1-pbkdf2.c + src/crypto/sha1-prf.c + src/crypto/sha1-tlsprf.c + src/crypto/sha1-tprf.c + src/crypto/sha1.c + src/crypto/sha1.h + src/crypto/sha1_i.h + src/crypto/sha256-internal.c + src/crypto/sha256-kdf.c + src/crypto/sha256-prf.c + src/crypto/sha256-tlsprf.c + src/crypto/sha256.c + src/crypto/sha256.h + src/crypto/sha256_i.h + src/crypto/sha384-internal.c + src/crypto/sha384-kdf.c + src/crypto/sha384-prf.c + src/crypto/sha384-tlsprf.c + src/crypto/sha384.c + src/crypto/sha384.h + src/crypto/sha384_i.h + src/crypto/sha512-internal.c + src/crypto/sha512-kdf.c + src/crypto/sha512-prf.c + src/crypto/sha512.c + src/crypto/sha512.h + src/crypto/sha512_i.h + src/crypto/tls.h + src/crypto/tls_gnutls.c + src/crypto/tls_internal.c + src/crypto/tls_none.c + src/crypto/tls_openssl.c + src/crypto/tls_openssl.h + src/crypto/tls_openssl_ocsp.c + src/crypto/tls_wolfssl.c + src/drivers/android_drv.h + src/drivers/driver.h + src/drivers/driver_atheros.c + src/drivers/driver_bsd.c + src/drivers/driver_common.c + src/drivers/driver_hostap.c + src/drivers/driver_hostap.h + src/drivers/driver_macsec_linux.c + src/drivers/driver_macsec_qca.c + src/drivers/driver_ndis.c + src/drivers/driver_ndis.h + src/drivers/driver_ndis_.c + src/drivers/driver_nl80211.c + src/drivers/driver_nl80211.h + src/drivers/driver_nl80211_android.c + src/drivers/driver_nl80211_capa.c + src/drivers/driver_nl80211_event.c + src/drivers/driver_nl80211_monitor.c + src/drivers/driver_nl80211_scan.c + src/drivers/driver_none.c + src/drivers/driver_openbsd.c + src/drivers/driver_privsep.c + src/drivers/driver_roboswitch.c + src/drivers/driver_wext.c + src/drivers/driver_wext.h + src/drivers/driver_wired.c + src/drivers/driver_wired_common.c + src/drivers/driver_wired_common.h + src/drivers/drivers.c + src/drivers/drivers.mak + src/drivers/drivers.mk + src/drivers/linux_defines.h + src/drivers/linux_ioctl.c + src/drivers/linux_ioctl.h + src/drivers/linux_wext.h + src/drivers/Makefile + src/drivers/ndis_events.c + src/drivers/netlink.c + src/drivers/netlink.h + src/drivers/nl80211_copy.h + src/drivers/priv_netlink.h + src/drivers/rfkill.c + src/drivers/rfkill.h + src/drivers/wpa_hal.c + src/drivers/wpa_hal.h + src/drivers/wpa_hal_event.c + src/eap_common/chap.c + src/eap_common/chap.h + src/eap_common/eap_common.c + src/eap_common/eap_common.h + src/eap_common/eap_defs.h + src/eap_common/eap_eke_common.c + src/eap_common/eap_eke_common.h + src/eap_common/eap_fast_common.c + src/eap_common/eap_fast_common.h + src/eap_common/eap_gpsk_common.c + src/eap_common/eap_gpsk_common.h + src/eap_common/eap_ikev2_common.c + src/eap_common/eap_ikev2_common.h + src/eap_common/eap_pax_common.c + src/eap_common/eap_pax_common.h + src/eap_common/eap_peap_common.c + src/eap_common/eap_peap_common.h + src/eap_common/eap_psk_common.c + src/eap_common/eap_psk_common.h + src/eap_common/eap_pwd_common.c + src/eap_common/eap_pwd_common.h + src/eap_common/eap_sake_common.c + src/eap_common/eap_sake_common.h + src/eap_common/eap_sim_common.c + src/eap_common/eap_sim_common.h + src/eap_common/eap_teap_common.c + src/eap_common/eap_teap_common.h + src/eap_common/eap_tlv_common.h + src/eap_common/eap_ttls.h + src/eap_common/eap_wsc_common.c + src/eap_common/eap_wsc_common.h + src/eap_common/ikev2_common.c + src/eap_common/ikev2_common.h + src/eap_common/Makefile + src/eap_peer/.gitignore + src/eap_peer/eap.c + src/eap_peer/eap.h + src/eap_peer/eap_aka.c + src/eap_peer/eap_config.h + src/eap_peer/eap_eke.c + src/eap_peer/eap_fast.c + src/eap_peer/eap_fast_pac.c + src/eap_peer/eap_fast_pac.h + src/eap_peer/eap_gpsk.c + src/eap_peer/eap_gtc.c + src/eap_peer/eap_i.h + src/eap_peer/eap_ikev2.c + src/eap_peer/eap_leap.c + src/eap_peer/eap_md5.c + src/eap_peer/eap_methods.c + src/eap_peer/eap_methods.h + src/eap_peer/eap_mschapv2.c + src/eap_peer/eap_otp.c + src/eap_peer/eap_pax.c + src/eap_peer/eap_peap.c + src/eap_peer/eap_proxy.h + src/eap_peer/eap_proxy_dummy.c + src/eap_peer/eap_psk.c + src/eap_peer/eap_pwd.c + src/eap_peer/eap_sake.c + src/eap_peer/eap_sim.c + src/eap_peer/eap_teap.c + src/eap_peer/eap_teap_pac.c + src/eap_peer/eap_teap_pac.h + src/eap_peer/eap_tls.c + src/eap_peer/eap_tls_common.c + src/eap_peer/eap_tls_common.h + src/eap_peer/eap_tnc.c + src/eap_peer/eap_ttls.c + src/eap_peer/eap_vendor_test.c + src/eap_peer/eap_wsc.c + src/eap_peer/ikev2.c + src/eap_peer/ikev2.h + src/eap_peer/Makefile + src/eap_peer/mschapv2.c + src/eap_peer/mschapv2.h + src/eap_peer/tncc.c + src/eap_peer/tncc.h + src/eap_server/eap.h + src/eap_server/eap_i.h + src/eap_server/eap_methods.h + src/eap_server/eap_server.c + src/eap_server/eap_server_aka.c + src/eap_server/eap_server_eke.c + src/eap_server/eap_server_fast.c + src/eap_server/eap_server_gpsk.c + src/eap_server/eap_server_gtc.c + src/eap_server/eap_server_identity.c + src/eap_server/eap_server_ikev2.c + src/eap_server/eap_server_md5.c + src/eap_server/eap_server_methods.c + src/eap_server/eap_server_mschapv2.c + src/eap_server/eap_server_pax.c + src/eap_server/eap_server_peap.c + src/eap_server/eap_server_psk.c + src/eap_server/eap_server_pwd.c + src/eap_server/eap_server_sake.c + src/eap_server/eap_server_sim.c + src/eap_server/eap_server_teap.c + src/eap_server/eap_server_tls.c + src/eap_server/eap_server_tls_common.c + src/eap_server/eap_server_tnc.c + src/eap_server/eap_server_ttls.c + src/eap_server/eap_server_vendor_test.c + src/eap_server/eap_server_wsc.c + src/eap_server/eap_sim_db.c + src/eap_server/eap_sim_db.h + src/eap_server/eap_tls_common.h + src/eap_server/ikev2.c + src/eap_server/ikev2.h + src/eap_server/Makefile + src/eap_server/tncs.c + src/eap_server/tncs.h + src/eapol_auth/eapol_auth_dump.c + src/eapol_auth/eapol_auth_sm.c + src/eapol_auth/eapol_auth_sm.h + src/eapol_auth/eapol_auth_sm_i.h + src/eapol_auth/Makefile + src/eapol_supp/eapol_supp_sm.c + src/eapol_supp/eapol_supp_sm.h + src/eapol_supp/Makefile + src/fst/fst.c + src/fst/fst.h + src/fst/fst_ctrl_aux.c + src/fst/fst_ctrl_aux.h + src/fst/fst_ctrl_defs.h + src/fst/fst_ctrl_iface.c + src/fst/fst_ctrl_iface.h + src/fst/fst_defs.h + src/fst/fst_group.c + src/fst/fst_group.h + src/fst/fst_iface.c + src/fst/fst_iface.h + src/fst/fst_internal.h + src/fst/fst_session.c + src/fst/fst_session.h + src/fst/Makefile + src/l2_packet/l2_packet.h + src/l2_packet/l2_packet_freebsd.c + src/l2_packet/l2_packet_linux.c + src/l2_packet/l2_packet_ndis.c + src/l2_packet/l2_packet_none.c + src/l2_packet/l2_packet_pcap.c + src/l2_packet/l2_packet_privsep.c + src/l2_packet/l2_packet_rtos.c + src/l2_packet/l2_packet_winpcap.c + src/l2_packet/Makefile + src/p2p/Makefile + src/p2p/p2p.c + src/p2p/p2p.h + src/p2p/p2p_build.c + src/p2p/p2p_dev_disc.c + src/p2p/p2p_go_neg.c + src/p2p/p2p_group.c + src/p2p/p2p_i.h + src/p2p/p2p_invitation.c + src/p2p/p2p_parse.c + src/p2p/p2p_pd.c + src/p2p/p2p_sd.c + src/p2p/p2p_utils.c + src/pae/ieee802_1x_cp.c + src/pae/ieee802_1x_cp.h + src/pae/ieee802_1x_kay.c + src/pae/ieee802_1x_kay.h + src/pae/ieee802_1x_kay_i.h + src/pae/ieee802_1x_key.c + src/pae/ieee802_1x_key.h + src/pae/ieee802_1x_secy_ops.c + src/pae/ieee802_1x_secy_ops.h + src/pae/Makefile + src/radius/Makefile + src/radius/radius.c + src/radius/radius.h + src/radius/radius_client.c + src/radius/radius_client.h + src/radius/radius_das.c + src/radius/radius_das.h + src/radius/radius_server.c + src/radius/radius_server.h + src/rsn_supp/Makefile + src/rsn_supp/pmksa_cache.c + src/rsn_supp/pmksa_cache.h + src/rsn_supp/preauth.c + src/rsn_supp/preauth.h + src/rsn_supp/tdls.c + src/rsn_supp/wpa.c + src/rsn_supp/wpa.h + src/rsn_supp/wpa_ft.c + src/rsn_supp/wpa_i.h + src/rsn_supp/wpa_ie.c + src/rsn_supp/wpa_ie.h + src/tls/asn1.c + src/tls/asn1.h + src/tls/bignum.c + src/tls/bignum.h + src/tls/libtommath.c + src/tls/Makefile + src/tls/pkcs1.c + src/tls/pkcs1.h + src/tls/pkcs5.c + src/tls/pkcs5.h + src/tls/pkcs8.c + src/tls/pkcs8.h + src/tls/rsa.c + src/tls/rsa.h + src/tls/tlsv1_client.c + src/tls/tlsv1_client.h + src/tls/tlsv1_client_i.h + src/tls/tlsv1_client_ocsp.c + src/tls/tlsv1_client_read.c + src/tls/tlsv1_client_write.c + src/tls/tlsv1_common.c + src/tls/tlsv1_common.h + src/tls/tlsv1_cred.c + src/tls/tlsv1_cred.h + src/tls/tlsv1_record.c + src/tls/tlsv1_record.h + src/tls/tlsv1_server.c + src/tls/tlsv1_server.h + src/tls/tlsv1_server_i.h + src/tls/tlsv1_server_read.c + src/tls/tlsv1_server_write.c + src/tls/x509v3.c + src/tls/x509v3.h + src/utils/base64.c + src/utils/base64.h + src/utils/bitfield.c + src/utils/bitfield.h + src/utils/browser-android.c + src/utils/browser-system.c + src/utils/browser-wpadebug.c + src/utils/browser.c + src/utils/browser.h + src/utils/build_config.h + src/utils/common.c + src/utils/common.h + src/utils/config.c + src/utils/config.h + src/utils/const_time.h + src/utils/crc32.c + src/utils/crc32.h + src/utils/edit.c + src/utils/edit.h + src/utils/edit_readline.c + src/utils/edit_simple.c + src/utils/eloop.c + src/utils/eloop.h + src/utils/eloop_win.c + src/utils/ext_password.c + src/utils/ext_password.h + src/utils/ext_password_file.c + src/utils/ext_password_i.h + src/utils/ext_password_test.c + src/utils/http-utils.h + src/utils/http_curl.c + src/utils/includes.h + src/utils/ip_addr.c + src/utils/ip_addr.h + src/utils/json.c + src/utils/json.h + src/utils/list.h + src/utils/Makefile + src/utils/module_tests.h + src/utils/os.h + src/utils/os_internal.c + src/utils/os_none.c + src/utils/os_unix.c + src/utils/os_win32.c + src/utils/pcsc_funcs.c + src/utils/pcsc_funcs.h + src/utils/platform.h + src/utils/radiotap.c + src/utils/radiotap.h + src/utils/radiotap_iter.h + src/utils/state_machine.h + src/utils/trace.c + src/utils/trace.h + src/utils/utils_module_tests.c + src/utils/uuid.c + src/utils/uuid.h + src/utils/wpa_debug.c + src/utils/wpa_debug.h + src/utils/wpabuf.c + src/utils/wpabuf.h + src/utils/xml-utils.c + src/utils/xml-utils.h + src/utils/xml_libxml2.c + src/wps/http.h + src/wps/http_client.c + src/wps/http_client.h + src/wps/http_server.c + src/wps/http_server.h + src/wps/httpread.c + src/wps/httpread.h + src/wps/Makefile + src/wps/ndef.c + src/wps/upnp_xml.c + src/wps/upnp_xml.h + src/wps/wps.c + src/wps/wps.h + src/wps/wps_attr_build.c + src/wps/wps_attr_parse.c + src/wps/wps_attr_parse.h + src/wps/wps_attr_process.c + src/wps/wps_common.c + src/wps/wps_defs.h + src/wps/wps_dev_attr.c + src/wps/wps_dev_attr.h + src/wps/wps_enrollee.c + src/wps/wps_er.c + src/wps/wps_er.h + src/wps/wps_er_ssdp.c + src/wps/wps_i.h + src/wps/wps_module_tests.c + src/wps/wps_registrar.c + src/wps/wps_upnp.c + src/wps/wps_upnp.h + src/wps/wps_upnp_ap.c + src/wps/wps_upnp_event.c + src/wps/wps_upnp_i.h + src/wps/wps_upnp_ssdp.c + src/wps/wps_upnp_web.c + src/wps/wps_validate.c + src/build.rules + src/lib.rules + src/Makefile + src/objs.mk + wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl + wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl + wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl + wpa_supplicant/binder/.clang-format + wpa_supplicant/binder/binder.cpp + wpa_supplicant/binder/binder.h + wpa_supplicant/binder/binder_constants.cpp + wpa_supplicant/binder/binder_constants.h + wpa_supplicant/binder/binder_i.h + wpa_supplicant/binder/binder_manager.cpp + wpa_supplicant/binder/binder_manager.h + wpa_supplicant/binder/iface.cpp + wpa_supplicant/binder/iface.h + wpa_supplicant/binder/supplicant.cpp + wpa_supplicant/binder/supplicant.h + wpa_supplicant/dbus/.gitignore + wpa_supplicant/dbus/dbus-wpa_supplicant.conf + wpa_supplicant/dbus/dbus_common.c + wpa_supplicant/dbus/dbus_common.h + wpa_supplicant/dbus/dbus_common_i.h + wpa_supplicant/dbus/dbus_dict_helpers.c + wpa_supplicant/dbus/dbus_dict_helpers.h + wpa_supplicant/dbus/dbus_new.c + wpa_supplicant/dbus/dbus_new.h + wpa_supplicant/dbus/dbus_new_handlers.c + wpa_supplicant/dbus/dbus_new_handlers.h + wpa_supplicant/dbus/dbus_new_handlers_p2p.c + wpa_supplicant/dbus/dbus_new_handlers_p2p.h + wpa_supplicant/dbus/dbus_new_handlers_wps.c + wpa_supplicant/dbus/dbus_new_helpers.c + wpa_supplicant/dbus/dbus_new_helpers.h + wpa_supplicant/dbus/dbus_new_introspect.c + wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in + wpa_supplicant/dbus/Makefile + wpa_supplicant/doc/docbook/.gitignore + wpa_supplicant/doc/docbook/eapol_test.8 + wpa_supplicant/doc/docbook/eapol_test.sgml + wpa_supplicant/doc/docbook/Makefile + wpa_supplicant/doc/docbook/manpage.links + wpa_supplicant/doc/docbook/manpage.refs + wpa_supplicant/doc/docbook/wpa_background.8 + wpa_supplicant/doc/docbook/wpa_background.sgml + wpa_supplicant/doc/docbook/wpa_cli.8 + wpa_supplicant/doc/docbook/wpa_cli.sgml + wpa_supplicant/doc/docbook/wpa_gui.8 + wpa_supplicant/doc/docbook/wpa_gui.sgml + wpa_supplicant/doc/docbook/wpa_passphrase.8 + wpa_supplicant/doc/docbook/wpa_passphrase.sgml + wpa_supplicant/doc/docbook/wpa_priv.8 + wpa_supplicant/doc/docbook/wpa_priv.sgml + wpa_supplicant/doc/docbook/wpa_supplicant.8 + wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 + wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml + wpa_supplicant/doc/docbook/wpa_supplicant.sgml + wpa_supplicant/examples/p2p/p2p_connect.py + wpa_supplicant/examples/p2p/p2p_disconnect.py + wpa_supplicant/examples/p2p/p2p_find.py + wpa_supplicant/examples/p2p/p2p_flush.py + wpa_supplicant/examples/p2p/p2p_group_add.py + wpa_supplicant/examples/p2p/p2p_invite.py + wpa_supplicant/examples/p2p/p2p_listen.py + wpa_supplicant/examples/p2p/p2p_stop_find.py + wpa_supplicant/examples/60_wpa_supplicant + wpa_supplicant/examples/dbus-listen-preq.py + wpa_supplicant/examples/dpp-nfc.py + wpa_supplicant/examples/dpp-qrcode.py + wpa_supplicant/examples/ieee8021x.conf + wpa_supplicant/examples/openCryptoki.conf + wpa_supplicant/examples/p2p-action-udhcp.sh + wpa_supplicant/examples/p2p-action.sh + wpa_supplicant/examples/p2p-nfc.py + wpa_supplicant/examples/plaintext.conf + wpa_supplicant/examples/udhcpd-p2p.conf + wpa_supplicant/examples/wep.conf + wpa_supplicant/examples/wpa-psk-tkip.conf + wpa_supplicant/examples/wpa2-eap-ccmp.conf + wpa_supplicant/examples/wpas-dbus-new-getall.py + wpa_supplicant/examples/wpas-dbus-new-signals.py + wpa_supplicant/examples/wpas-dbus-new-wps.py + wpa_supplicant/examples/wpas-dbus-new.py + wpa_supplicant/examples/wps-ap-cli + wpa_supplicant/examples/wps-nfc.py + wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in + wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in + wpa_supplicant/systemd/wpa_supplicant.service.arg.in + wpa_supplicant/systemd/wpa_supplicant.service.in + wpa_supplicant/utils/log2pcap.py + wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj + wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj + wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj + wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj + wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj + wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj + wpa_supplicant/vs2005/wpa_supplicant.sln + wpa_supplicant/wpa_gui-qt4/icons/.gitignore + wpa_supplicant/wpa_gui-qt4/icons/ap.svg + wpa_supplicant/wpa_gui-qt4/icons/group.svg + wpa_supplicant/wpa_gui-qt4/icons/invitation.svg + wpa_supplicant/wpa_gui-qt4/icons/laptop.svg + wpa_supplicant/wpa_gui-qt4/icons/Makefile + wpa_supplicant/wpa_gui-qt4/icons/README + wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg + wpa_supplicant/wpa_gui-qt4/lang/.gitignore + wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts + wpa_supplicant/wpa_gui-qt4/.gitignore + wpa_supplicant/wpa_gui-qt4/addinterface.cpp + wpa_supplicant/wpa_gui-qt4/addinterface.h + wpa_supplicant/wpa_gui-qt4/eventhistory.cpp + wpa_supplicant/wpa_gui-qt4/eventhistory.h + wpa_supplicant/wpa_gui-qt4/eventhistory.ui + wpa_supplicant/wpa_gui-qt4/icons.qrc + wpa_supplicant/wpa_gui-qt4/icons_png.qrc + wpa_supplicant/wpa_gui-qt4/main.cpp + wpa_supplicant/wpa_gui-qt4/networkconfig.cpp + wpa_supplicant/wpa_gui-qt4/networkconfig.h + wpa_supplicant/wpa_gui-qt4/networkconfig.ui + wpa_supplicant/wpa_gui-qt4/peers.cpp + wpa_supplicant/wpa_gui-qt4/peers.h + wpa_supplicant/wpa_gui-qt4/peers.ui + wpa_supplicant/wpa_gui-qt4/scanresults.cpp + wpa_supplicant/wpa_gui-qt4/scanresults.h + wpa_supplicant/wpa_gui-qt4/scanresults.ui + wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp + wpa_supplicant/wpa_gui-qt4/scanresultsitem.h + wpa_supplicant/wpa_gui-qt4/signalbar.cpp + wpa_supplicant/wpa_gui-qt4/signalbar.h + wpa_supplicant/wpa_gui-qt4/stringquery.cpp + wpa_supplicant/wpa_gui-qt4/stringquery.h + wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp + wpa_supplicant/wpa_gui-qt4/userdatarequest.h + wpa_supplicant/wpa_gui-qt4/userdatarequest.ui + wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop + wpa_supplicant/wpa_gui-qt4/wpa_gui.pro + wpa_supplicant/wpa_gui-qt4/wpagui.cpp + wpa_supplicant/wpa_gui-qt4/wpagui.h + wpa_supplicant/wpa_gui-qt4/wpagui.ui + wpa_supplicant/wpa_gui-qt4/wpamsg.h + wpa_supplicant/.config + wpa_supplicant/.gitignore + wpa_supplicant/android.config + wpa_supplicant/Android.mk + wpa_supplicant/ap.c + wpa_supplicant/ap.h + wpa_supplicant/autoscan.c + wpa_supplicant/autoscan.h + wpa_supplicant/autoscan_exponential.c + wpa_supplicant/autoscan_periodic.c + wpa_supplicant/bgscan.c + wpa_supplicant/bgscan.h + wpa_supplicant/bgscan_learn.c + wpa_supplicant/bgscan_simple.c + wpa_supplicant/bss.c + wpa_supplicant/bss.h + wpa_supplicant/bssid_ignore.c + wpa_supplicant/bssid_ignore.h + wpa_supplicant/ChangeLog + wpa_supplicant/config.c + wpa_supplicant/config.h + wpa_supplicant/config_file.c + wpa_supplicant/config_none.c + wpa_supplicant/config_ssid.h + wpa_supplicant/config_winreg.c + wpa_supplicant/ctrl_iface.c + wpa_supplicant/ctrl_iface.h + wpa_supplicant/ctrl_iface_named_pipe.c + wpa_supplicant/ctrl_iface_udp.c + wpa_supplicant/ctrl_iface_unix.c + wpa_supplicant/defconfig + wpa_supplicant/dpp_supplicant.c + wpa_supplicant/dpp_supplicant.h + wpa_supplicant/driver_i.h + wpa_supplicant/eap_proxy_dummy.mak + wpa_supplicant/eap_proxy_dummy.mk + wpa_supplicant/eap_register.c + wpa_supplicant/eap_testing.txt + wpa_supplicant/eapol_test.c + wpa_supplicant/eapol_test.py + wpa_supplicant/events.c + wpa_supplicant/gas_query.c + wpa_supplicant/gas_query.h + wpa_supplicant/hs20_supplicant.c + wpa_supplicant/hs20_supplicant.h + wpa_supplicant/ibss_rsn.c + wpa_supplicant/ibss_rsn.h + wpa_supplicant/interworking.c + wpa_supplicant/interworking.h + wpa_supplicant/libwpa_test.c + wpa_supplicant/main.c + wpa_supplicant/main_none.c + wpa_supplicant/main_winmain.c + wpa_supplicant/main_winsvc.c + wpa_supplicant/Makefile + wpa_supplicant/mbo.c + wpa_supplicant/mesh.c + wpa_supplicant/mesh.h + wpa_supplicant/mesh_mpm.c + wpa_supplicant/mesh_mpm.h + wpa_supplicant/mesh_rsn.c + wpa_supplicant/mesh_rsn.h + wpa_supplicant/nfc_pw_token.c + wpa_supplicant/nmake.mak + wpa_supplicant/notify.c + wpa_supplicant/notify.h + wpa_supplicant/offchannel.c + wpa_supplicant/offchannel.h + wpa_supplicant/op_classes.c + wpa_supplicant/p2p_supplicant.c + wpa_supplicant/p2p_supplicant.h + wpa_supplicant/p2p_supplicant_sd.c + wpa_supplicant/pasn_supplicant.c + wpa_supplicant/preauth_test.c + wpa_supplicant/README + wpa_supplicant/README-DPP + wpa_supplicant/README-HS20 + wpa_supplicant/README-P2P + wpa_supplicant/README-Windows.txt + wpa_supplicant/README-WPS + wpa_supplicant/README.OpenSource + wpa_supplicant/robust_av.c + wpa_supplicant/rrm.c + wpa_supplicant/scan.c + wpa_supplicant/scan.h + wpa_supplicant/sme.c + wpa_supplicant/sme.h + wpa_supplicant/todo.txt + wpa_supplicant/twt.c + wpa_supplicant/wifi_display.c + wpa_supplicant/wifi_display.h + wpa_supplicant/win_example.reg + wpa_supplicant/win_if_list.c + wpa_supplicant/wmm_ac.c + wpa_supplicant/wmm_ac.h + wpa_supplicant/wnm_sta.c + wpa_supplicant/wnm_sta.h + wpa_supplicant/wpa_cli.c + wpa_supplicant/wpa_passphrase.c + wpa_supplicant/wpa_priv.c + wpa_supplicant/wpa_supplicant.c + wpa_supplicant/wpa_supplicant.conf + wpa_supplicant/wpa_supplicant_conf.mk + wpa_supplicant/wpa_supplicant_conf.sh + wpa_supplicant/wpa_supplicant_i.h + wpa_supplicant/wpa_supplicant_template.conf + wpa_supplicant/wpas_glue.c + wpa_supplicant/wpas_glue.h + wpa_supplicant/wpas_kay.c + wpa_supplicant/wpas_kay.h + wpa_supplicant/wpas_module_tests.c + wpa_supplicant/wps_supplicant.c + wpa_supplicant/wps_supplicant.h + wpa_supplicant_lib/driver_nl80211_hisi.c + wpa_supplicant_lib/driver_nl80211_hisi.h + wpa_supplicant_lib/wpa_magiclink.c + wpa_supplicant_lib/wpa_magiclink.h + wpa_test/wpa_sample.c + .gitignore + BUILD.gn + build.sh + CONTRIBUTIONS + COPYING + README) + +ADD_COMPILE_DEFINITIONS(CONFIG_CTRL_IFACE CONFIG_CTRL_IFACE_UDP CONFIG_IEEE80211W CONFIG_NO_VLAN + CONFIG_NO_RADIUS + CONFIG_NO_RANDOM_POOL + CONFIG_SHA256 + CONFIG_CRYPTO_INTERNAL + CONFIG_INTERNAL_LIBTOMMATH + CONFIG_INTERNAL_SHA384 + CONFIG_INTERNAL_SHA512 + CONFIG_CTRL_IFACE + CONFIG_CTRL_IFACE_UDP + CONFIG_IBSS_RSN + IEEE8021X_EAPOL + USERSPACE_CLIENT_SUPPORT + CONFIG_BACKEND_FILE + CONFIG_NO_CONFIG_WRITE + CONFIG_NO_CONFIG_BLOBS + CONFIG_NO_ACCOUNTING + EAP_SERVER_IDENTITY + CONFIG_IEEE80211N + HOSTAPD + NEED_AP_MLME + CONFIG_WPS + CONFIG_AP + CONFIG_P2P + EAP_WSC + EAP_SERVER_WSC + EAP_SERVER + CONFIG_GAS + CONFIG_OFFCHANNEL + CONFIG_MAGICLINK + CONFIG_DEBUG_FILE + CONFIG_DRIVER_NL80211 + CONFIG_LIBNL32 + CONFIG_OPEN_HARMONY_PATCH + CONFIG_OPEN_HARMONY_HUKS_TLS + EAP_MSCHAPV2 + EAP_TLS + EAP_PEAP + EAP_TTLS + EAP_SIM + EAP_PWD + CONFIG_SHA256 + CONFIG_ECC + EAP_AKA + EAP_AKA_PRIME + EAP_TLS_OPENSSL + CONFIG_WEP) diff --git a/wpa_supplicant-2.9_standard/CONTRIBUTIONS b/wpa_supplicant-2.9_standard/CONTRIBUTIONS index b2064dc83443c1a5288022ae37561f4e16857db5..4dd89cd6b35a06a789fe67d8fb0635af62766c12 100644 --- a/wpa_supplicant-2.9_standard/CONTRIBUTIONS +++ b/wpa_supplicant-2.9_standard/CONTRIBUTIONS @@ -1,174 +1,174 @@ -Contributions to hostap.git ---------------------------- - -This software is distributed under a permissive open source license to -allow it to be used in any projects, whether open source or proprietary. -Contributions to the project are welcome and it is important to maintain -clear record of contributions and terms under which they are licensed. -To help with this, following procedure is used to allow acceptance and -recording of the terms. - -All contributions are expected to be licensed under the modified BSD -license (see below). Acknowledgment of the terms is tracked through -inclusion of Signed-off-by tag in the contributions at the end of the -commit log message. This tag indicates that the contributor agrees with -the Developer Certificate of Origin (DCO) version 1.1 terms (see below; -also available from http://developercertificate.org/). - - -The current requirements for contributions to hostap.git --------------------------------------------------------- - -To indicate your acceptance of Developer's Certificate of Origin 1.1 -terms, please add the following line to the end of the commit message -for each contribution you make to the project: - -Signed-off-by: Your Name - -using your real name. Pseudonyms or anonymous contributions cannot -unfortunately be accepted. - - -The preferred method of submitting the contribution to the project is by -email to the hostap mailing list: -hostap@lists.infradead.org -Note that the list may require subscription before accepting message -without moderation. You can subscribe to the list at this address: -http://lists.infradead.org/mailman/listinfo/hostap - -The message should contain an inlined patch against the current -development branch (i.e., the master branch of -git://w1.fi/hostap.git). Please make sure the software you use for -sending the patch does not corrupt whitespace. If that cannot be fixed -for some reason, it is better to include an attached version of the -patch file than just send a whitespace damaged version in the message -body. - -The patches should be separate logical changes rather than doing -everything in a single patch. In other words, please keep cleanup, new -features, and bug fixes all in their own patches. Each patch needs a -commit log that describes the changes (what the changes fix, what -functionality is added, why the changes are useful, etc.). - -Please try to follow the coding style used in the project. - -In general, the best way of generating a suitable formatted patch file -is by committing the changes to a cloned git repository and using git -format-patch. The patch can then be sent, e.g., with git send-email. - -A list of pending patches waiting for review is available in -Patchwork: https://patchwork.ozlabs.org/project/hostap/list/ - - -History of license and contributions terms ------------------------------------------- - -Until February 11, 2012, in case of most files in hostap.git, "under the -open source license indicated in the file" means that the contribution -is licensed both under GPL v2 and modified BSD license (see below) and -the choice between these licenses is given to anyone who redistributes -or uses the software. As such, the contribution has to be licensed under -both options to allow this choice. - -As of February 11, 2012, the project has chosen to use only the BSD -license option for future distribution. As such, the GPL v2 license -option is no longer used and the contributions are not required to be -licensed until GPL v2. In case of most files in hostap.git, "under the -open source license indicated in the file" means that the contribution -is licensed under the modified BSD license (see below). - -Until February 13, 2014, the project used an extended version of the DCO -that included the identical items (a) through (d) from DCO 1.1 and an -additional item (e): - -(e) The contribution can be licensed under the modified BSD license - as shown below even in case of files that are currently licensed - under other terms. - -This was used during the period when some of the files included the old -license terms. Acceptance of this extended DCO version was indicated -with a Signed-hostap tag in the commit message. This additional item (e) -was used to collect explicit approval to license the contribution with -only the modified BSD license (see below), i.e., without the GPL v2 -option. This was done to allow simpler licensing terms to be used in the -future. It should be noted that the modified BSD license is compatible -with GNU GPL and as such, this possible move to simpler licensing option -does not prevent use of this software in GPL projects. - - -===[ start quote from http://developercertificate.org/ ]======================= - -Developer Certificate of Origin -Version 1.1 - -Copyright (C) 2004, 2006 The Linux Foundation and its contributors. -660 York Street, Suite 102, -San Francisco, CA 94110 USA - -Everyone is permitted to copy and distribute verbatim copies of this -license document, but changing it is not allowed. - - -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -(d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. - -===[ end quote from http://developercertificate.org/ ]========================= - - -The license terms used for hostap.git files -------------------------------------------- - -Modified BSD license (no advertisement clause): - -Copyright (c) 2002-2022, Jouni Malinen and contributors -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. Neither the name(s) of the above-listed copyright holder(s) nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"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 THE COPYRIGHT -OWNER OR CONTRIBUTORS 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. +Contributions to hostap.git +--------------------------- + +This software is distributed under a permissive open source license to +allow it to be used in any projects, whether open source or proprietary. +Contributions to the project are welcome and it is important to maintain +clear record of contributions and terms under which they are licensed. +To help with this, following procedure is used to allow acceptance and +recording of the terms. + +All contributions are expected to be licensed under the modified BSD +license (see below). Acknowledgment of the terms is tracked through +inclusion of Signed-off-by tag in the contributions at the end of the +commit log message. This tag indicates that the contributor agrees with +the Developer Certificate of Origin (DCO) version 1.1 terms (see below; +also available from http://developercertificate.org/). + + +The current requirements for contributions to hostap.git +-------------------------------------------------------- + +To indicate your acceptance of Developer's Certificate of Origin 1.1 +terms, please add the following line to the end of the commit message +for each contribution you make to the project: + +Signed-off-by: Your Name + +using your real name. Pseudonyms or anonymous contributions cannot +unfortunately be accepted. + + +The preferred method of submitting the contribution to the project is by +email to the hostap mailing list: +hostap@lists.infradead.org +Note that the list may require subscription before accepting message +without moderation. You can subscribe to the list at this address: +http://lists.infradead.org/mailman/listinfo/hostap + +The message should contain an inlined patch against the current +development branch (i.e., the master branch of +git://w1.fi/hostap.git). Please make sure the software you use for +sending the patch does not corrupt whitespace. If that cannot be fixed +for some reason, it is better to include an attached version of the +patch file than just send a whitespace damaged version in the message +body. + +The patches should be separate logical changes rather than doing +everything in a single patch. In other words, please keep cleanup, new +features, and bug fixes all in their own patches. Each patch needs a +commit log that describes the changes (what the changes fix, what +functionality is added, why the changes are useful, etc.). + +Please try to follow the coding style used in the project. + +In general, the best way of generating a suitable formatted patch file +is by committing the changes to a cloned git repository and using git +format-patch. The patch can then be sent, e.g., with git send-email. + +A list of pending patches waiting for review is available in +Patchwork: https://patchwork.ozlabs.org/project/hostap/list/ + + +History of license and contributions terms +------------------------------------------ + +Until February 11, 2012, in case of most files in hostap.git, "under the +open source license indicated in the file" means that the contribution +is licensed both under GPL v2 and modified BSD license (see below) and +the choice between these licenses is given to anyone who redistributes +or uses the software. As such, the contribution has to be licensed under +both options to allow this choice. + +As of February 11, 2012, the project has chosen to use only the BSD +license option for future distribution. As such, the GPL v2 license +option is no longer used and the contributions are not required to be +licensed until GPL v2. In case of most files in hostap.git, "under the +open source license indicated in the file" means that the contribution +is licensed under the modified BSD license (see below). + +Until February 13, 2014, the project used an extended version of the DCO +that included the identical items (a) through (d) from DCO 1.1 and an +additional item (e): + +(e) The contribution can be licensed under the modified BSD license + as shown below even in case of files that are currently licensed + under other terms. + +This was used during the period when some of the files included the old +license terms. Acceptance of this extended DCO version was indicated +with a Signed-hostap tag in the commit message. This additional item (e) +was used to collect explicit approval to license the contribution with +only the modified BSD license (see below), i.e., without the GPL v2 +option. This was done to allow simpler licensing terms to be used in the +future. It should be noted that the modified BSD license is compatible +with GNU GPL and as such, this possible move to simpler licensing option +does not prevent use of this software in GPL projects. + + +===[ start quote from http://developercertificate.org/ ]======================= + +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. + +===[ end quote from http://developercertificate.org/ ]========================= + + +The license terms used for hostap.git files +------------------------------------------- + +Modified BSD license (no advertisement clause): + +Copyright (c) 2002-2022, Jouni Malinen and contributors +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. Neither the name(s) of the above-listed copyright holder(s) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 THE COPYRIGHT +OWNER OR CONTRIBUTORS 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. diff --git a/wpa_supplicant-2.9_standard/COPYING b/wpa_supplicant-2.9_standard/COPYING index 7ca30301e28bd2a3e453a9ed58117bd9acbf0e1a..d2cc7cc87cbe0842e8a5efa33814cfd9ffb1ab11 100644 --- a/wpa_supplicant-2.9_standard/COPYING +++ b/wpa_supplicant-2.9_standard/COPYING @@ -1,22 +1,22 @@ -wpa_supplicant and hostapd --------------------------- - -Copyright (c) 2002-2022, Jouni Malinen and contributors -All Rights Reserved. - - -See the README file for the current license terms. - -This software was previously distributed under BSD/GPL v2 dual license -terms that allowed either of those license alternatives to be -selected. As of February 11, 2012, the project has chosen to use only -the BSD license option for future distribution. As such, the GPL v2 -license option is no longer used. It should be noted that the BSD -license option (the one with advertisement clause removed) is compatible -with GPL and as such, does not prevent use of this software in projects -that use GPL. - -Some of the files may still include pointers to GPL version 2 license -terms. However, such copyright and license notifications are maintained -only for attribution purposes and any distribution of this software -after February 11, 2012 is no longer under the GPL v2 option. +wpa_supplicant and hostapd +-------------------------- + +Copyright (c) 2002-2022, Jouni Malinen and contributors +All Rights Reserved. + + +See the README file for the current license terms. + +This software was previously distributed under BSD/GPL v2 dual license +terms that allowed either of those license alternatives to be +selected. As of February 11, 2012, the project has chosen to use only +the BSD license option for future distribution. As such, the GPL v2 +license option is no longer used. It should be noted that the BSD +license option (the one with advertisement clause removed) is compatible +with GPL and as such, does not prevent use of this software in projects +that use GPL. + +Some of the files may still include pointers to GPL version 2 license +terms. However, such copyright and license notifications are maintained +only for attribution purposes and any distribution of this software +after February 11, 2012 is no longer under the GPL v2 option. diff --git a/wpa_supplicant-2.9_standard/build.sh b/wpa_supplicant-2.9_standard/build.sh index 42531b873e85ef1fe7243113a86e95478a109727..2b5642f4de522a1f4b63ef773d93977b863bf930 100755 --- a/wpa_supplicant-2.9_standard/build.sh +++ b/wpa_supplicant-2.9_standard/build.sh @@ -1,100 +1,100 @@ -#!/bin/bash -set -e -ROOT_DIR=$(dirname "$0") - -strip_and_copy_to() -{ - if [ "$3" == "clang" ]; - then - $COMPILER_DIR/bin/llvm-strip $ROOT_DIR/build/$2 - else - if [ "$4" == "linux" ]; - then - arm-himix410-linux-strip $ROOT_DIR/build/$2 - else - $ROOT_DIR/../../../prebuilts/gcc/linux-x86/arm/arm-linux-ohoseabi-gcc/bin/arm-linux-ohoseabi-strip $ROOT_DIR/build/$2 - fi - fi - - cp $ROOT_DIR/build/$2 $1 -} - -copy_to() -{ - if [ -f $ROOT_DIR/build/$2 ];then - mkdir -p $1/obj/third_party/wpa_supplicant/wpa_supplicant-2.9 - cp $ROOT_DIR/build/$2 $1/obj/third_party/wpa_supplicant/wpa_supplicant-2.9/ - fi -} - -build_for_ndk() -{ - cp $ROOT_DIR/build/libwpa_client.so $1/ndk/sysroot/usr/lib - cp $ROOT_DIR/build/libwpa.so $1/ndk/sysroot/usr/lib - cp $ROOT_DIR/src/common/wpa_ctrl.h $1/ndk/sysroot/usr/include -} - -# LIB_TYPE: 0 is static library, 1 is sharedlibrary -# COMPILER_TYPE gcc or clang -do_build() -{ - if [ -d "$ROOT_DIR/build/objs" ]; then - rm -rf $ROOT_DIR/build/objs - fi - mkdir -p $ROOT_DIR/build/objs - - make -C $ROOT_DIR/wpa_supplicant/ clean - make DEPDIR=$1 COMPILER_TYPE=$3 LIB_TYPE=$2 DEBUG=$4 COMPILER_DIR=$5 KERNEL_TYPE=$6 -C $ROOT_DIR/wpa_supplicant/ -j - - make -C $ROOT_DIR/hostapd/ clean - make DEPDIR=$1 COMPILER_TYPE=$3 LIB_TYPE=$2 DEBUG=$4 COMPILER_DIR=$5 KERNEL_TYPE=$6 -C $ROOT_DIR/hostapd/ -j - - make -C $ROOT_DIR/build/ clean - make DEPDIR=$1 COMPILER_TYPE=$3 LIB_TYPE=$2 DEBUG=$4 COMPILER_DIR=$5 KERNEL_TYPE=$6 -C $ROOT_DIR/build/ - - if [ "$2" = 1 ]; then - strip_and_copy_to $1 libwpa.so $3 $6 - else - copy_to $1 libwpa.a - fi - - if [ "$2" = 1 ]; then - make DEPDIR=DEPDIR=$1 COMPILER_TYPE=$3 LIB_TYPE=$2 DEBUG=$4 COMPILER_DIR=$5 KERNEL_TYPE=$6 -C $ROOT_DIR/wpa_supplicant/ libwpa_client.so -j - strip_and_copy_to $1 libwpa_client.so $3 $6 - else - make DEPDIR=DEPDIR=$1 COMPILER_TYPE=$3 LIB_TYPE=$2 DEBUG=$4 COMPILER_DIR=$5 KERNEL_TYPE=$6 -C $ROOT_DIR/wpa_supplicant/ libwpa_client.a -j - copy_to $1 libwpa_client.a - fi -} - -main() -{ - OUT_DIR=$1 - COMPILER_TYPE=$2 - NDK_FLAG=$3 - DEBUG=$4 - COMPILER_DIR=$5 - KERNEL_TYPE=$6 - - if [ "$4" == "debug" ]; then - DEBUG=1 - else - DEBUG=0 - fi - - do_build $OUT_DIR 0 $COMPILER_TYPE $DEBUG $COMPILER_DIR $KERNEL_TYPE - do_build $OUT_DIR 1 $COMPILER_TYPE $DEBUG $COMPILER_DIR $KERNEL_TYPE - - if [ "$NDK_FLAG" = true ]; then - build_for_ndk $OUT_DIR - fi -} - -if [ "x" != "x$7" ]; then -export SYSROOT_PATH=$7 -fi -if [ "x" != "x$8" ]; then -export ARCH_CFLAGS="$8" -fi - -main $1 $2 $3 $4 $5 $6 +#!/bin/bash +set -e +ROOT_DIR=$(dirname "$0") + +strip_and_copy_to() +{ + if [ "$3" == "clang" ]; + then + $COMPILER_DIR/bin/llvm-strip $ROOT_DIR/build/$2 + else + if [ "$4" == "linux" ]; + then + arm-himix410-linux-strip $ROOT_DIR/build/$2 + else + $ROOT_DIR/../../../prebuilts/gcc/linux-x86/arm/arm-linux-ohoseabi-gcc/bin/arm-linux-ohoseabi-strip $ROOT_DIR/build/$2 + fi + fi + + cp $ROOT_DIR/build/$2 $1 +} + +copy_to() +{ + if [ -f $ROOT_DIR/build/$2 ];then + mkdir -p $1/obj/third_party/wpa_supplicant/wpa_supplicant-2.9 + cp $ROOT_DIR/build/$2 $1/obj/third_party/wpa_supplicant/wpa_supplicant-2.9/ + fi +} + +build_for_ndk() +{ + cp $ROOT_DIR/build/libwpa_client.so $1/ndk/sysroot/usr/lib + cp $ROOT_DIR/build/libwpa.so $1/ndk/sysroot/usr/lib + cp $ROOT_DIR/src/common/wpa_ctrl.h $1/ndk/sysroot/usr/include +} + +# LIB_TYPE: 0 is static library, 1 is sharedlibrary +# COMPILER_TYPE gcc or clang +do_build() +{ + if [ -d "$ROOT_DIR/build/objs" ]; then + rm -rf $ROOT_DIR/build/objs + fi + mkdir -p $ROOT_DIR/build/objs + + make -C $ROOT_DIR/wpa_supplicant/ clean + make DEPDIR=$1 COMPILER_TYPE=$3 LIB_TYPE=$2 DEBUG=$4 COMPILER_DIR=$5 KERNEL_TYPE=$6 -C $ROOT_DIR/wpa_supplicant/ -j + + make -C $ROOT_DIR/hostapd/ clean + make DEPDIR=$1 COMPILER_TYPE=$3 LIB_TYPE=$2 DEBUG=$4 COMPILER_DIR=$5 KERNEL_TYPE=$6 -C $ROOT_DIR/hostapd/ -j + + make -C $ROOT_DIR/build/ clean + make DEPDIR=$1 COMPILER_TYPE=$3 LIB_TYPE=$2 DEBUG=$4 COMPILER_DIR=$5 KERNEL_TYPE=$6 -C $ROOT_DIR/build/ + + if [ "$2" = 1 ]; then + strip_and_copy_to $1 libwpa.so $3 $6 + else + copy_to $1 libwpa.a + fi + + if [ "$2" = 1 ]; then + make DEPDIR=DEPDIR=$1 COMPILER_TYPE=$3 LIB_TYPE=$2 DEBUG=$4 COMPILER_DIR=$5 KERNEL_TYPE=$6 -C $ROOT_DIR/wpa_supplicant/ libwpa_client.so -j + strip_and_copy_to $1 libwpa_client.so $3 $6 + else + make DEPDIR=DEPDIR=$1 COMPILER_TYPE=$3 LIB_TYPE=$2 DEBUG=$4 COMPILER_DIR=$5 KERNEL_TYPE=$6 -C $ROOT_DIR/wpa_supplicant/ libwpa_client.a -j + copy_to $1 libwpa_client.a + fi +} + +main() +{ + OUT_DIR=$1 + COMPILER_TYPE=$2 + NDK_FLAG=$3 + DEBUG=$4 + COMPILER_DIR=$5 + KERNEL_TYPE=$6 + + if [ "$4" == "debug" ]; then + DEBUG=1 + else + DEBUG=0 + fi + + do_build $OUT_DIR 0 $COMPILER_TYPE $DEBUG $COMPILER_DIR $KERNEL_TYPE + do_build $OUT_DIR 1 $COMPILER_TYPE $DEBUG $COMPILER_DIR $KERNEL_TYPE + + if [ "$NDK_FLAG" = true ]; then + build_for_ndk $OUT_DIR + fi +} + +if [ "x" != "x$7" ]; then +export SYSROOT_PATH=$7 +fi +if [ "x" != "x$8" ]; then +export ARCH_CFLAGS="$8" +fi + +main $1 $2 $3 $4 $5 $6 diff --git a/wpa_supplicant-2.9_standard/build/Makefile b/wpa_supplicant-2.9_standard/build/Makefile index 2f312b057c24084930ef518f3393b2f38514741f..790b303548b134981b62d91c6499f9a49264ecd9 100755 --- a/wpa_supplicant-2.9_standard/build/Makefile +++ b/wpa_supplicant-2.9_standard/build/Makefile @@ -1,72 +1,72 @@ -ifeq ($(KERNEL_TYPE), linux) -CC = arm-himix410-linux-gcc -AR = arm-himix410-linux-ar -LD=arm-himix410-linux-ld -CFLAGS := -MMD -O2 -g -w -fsigned-char -else -CC = ../../../../prebuilts/gcc/linux-x86/arm/arm-linux-ohoseabi-gcc/bin/arm-linux-ohoseabi-gcc -AR = ../../../../prebuilts/gcc/linux-x86/arm/arm-linux-ohoseabi-gcc/bin/arm-linux-ohoseabi-ar -CFLAGS := -flto -MMD -O2 -g -w -fsigned-char -endif - -ifeq ($(COMPILER_TYPE), clang) -SYSROOT_PATH ?= ../../../../sysroot -ARCH_CFLAGS ?= --target=arm-liteos-ohos -march=armv7-a -mfloat-abi=softfp -CC := $(COMPILER_DIR)/bin/clang -AR := $(COMPILER_DIR)/bin/llvm-ar -CFLAGS += --sysroot=$(SYSROOT_PATH) $(ARCH_CFLAGS) -CFLAGS += -I$(abspath ../../../../drivers/peripheral/wlan/client/include) -LDFLAGS += --sysroot=$(SYSROOT_PATH) $(ARCH_CFLAGS) -LDFLAGS += -lc -LDFLAGS += -v -endif - -#TEST_AP = testap -#TEST_WPA = testwpa - -WPA_LDFLAGS = -L$(DEPDIR) -lsec_shared -lrt -lm -lpthread -lhilog_shared -lwifi_driver_client -TEST_LDFLAGS = -L./ -lwpa -L$(DEPDIR) -lsec_shared -lrt -lm -lpthread -lhilog_shared -lwifi_driver_client - -WPA_SHARED = libwpa.so -WPA_STATIC = libwpa.a -#OBJS_WPA = test_wpa.o -#OBJS_AP = test_hostapd.o - -CDEPS = $(patsubst %.c,%.d,test_wpa.c test_hostapd.c) - -ifeq ($(LIB_TYPE), 1) -all : $(WPA_SHARED) -else -all : $(WPA_STATIC) -endif - -%.o : %.c - $(CC) $(CFLAGS) -c $< -o $@ - -$(WPA_SHARED) : -ifeq ($(KERNEL_TYPE), linux) - $(CC) -O2 -shared -fPIC -Wl,-z,defs objs/*.o -o $@ $(WPA_LDFLAGS) $(LDFLAGS) -else - $(CC) -flto -O2 -shared -fPIC -Wl,-z,defs objs/*.o -o $@ $(WPA_LDFLAGS) $(LDFLAGS) -endif - -$(WPA_STATIC) : - $(AR) -crs $@ objs/*.o - -$(TEST_WPA) : $(OBJS_WPA) - $(CC) -o $@ $< $(TEST_LDFLAGS) $(LDFLAGS) - rm -f $(CDEPS) - -$(TEST_AP) : $(OBJS_AP) - $(CC) -o $@ $< $(TEST_LDFLAGS) $(LDFLAGS) - rm -f $(CDEPS) - - -clean: - rm -f $(WPA_SHARED) - rm -f $(WPA_STATIC) - rm -f $(OBJS_AP) - rm -f $(TEST_AP) - rm -f $(OBJS_WPA) - rm -f $(TEST_WPA) - rm -f $(CDEPS) +ifeq ($(KERNEL_TYPE), linux) +CC = arm-himix410-linux-gcc +AR = arm-himix410-linux-ar +LD=arm-himix410-linux-ld +CFLAGS := -MMD -O2 -g -w -fsigned-char +else +CC = ../../../../prebuilts/gcc/linux-x86/arm/arm-linux-ohoseabi-gcc/bin/arm-linux-ohoseabi-gcc +AR = ../../../../prebuilts/gcc/linux-x86/arm/arm-linux-ohoseabi-gcc/bin/arm-linux-ohoseabi-ar +CFLAGS := -flto -MMD -O2 -g -w -fsigned-char +endif + +ifeq ($(COMPILER_TYPE), clang) +SYSROOT_PATH ?= ../../../../sysroot +ARCH_CFLAGS ?= --target=arm-liteos-ohos -march=armv7-a -mfloat-abi=softfp +CC := $(COMPILER_DIR)/bin/clang +AR := $(COMPILER_DIR)/bin/llvm-ar +CFLAGS += --sysroot=$(SYSROOT_PATH) $(ARCH_CFLAGS) +CFLAGS += -I$(abspath ../../../../drivers/peripheral/wlan/client/include) +LDFLAGS += --sysroot=$(SYSROOT_PATH) $(ARCH_CFLAGS) +LDFLAGS += -lc +LDFLAGS += -v +endif + +#TEST_AP = testap +#TEST_WPA = testwpa + +WPA_LDFLAGS = -L$(DEPDIR) -lsec_shared -lrt -lm -lpthread -lhilog_shared -lwifi_driver_client +TEST_LDFLAGS = -L./ -lwpa -L$(DEPDIR) -lsec_shared -lrt -lm -lpthread -lhilog_shared -lwifi_driver_client + +WPA_SHARED = libwpa.so +WPA_STATIC = libwpa.a +#OBJS_WPA = test_wpa.o +#OBJS_AP = test_hostapd.o + +CDEPS = $(patsubst %.c,%.d,test_wpa.c test_hostapd.c) + +ifeq ($(LIB_TYPE), 1) +all : $(WPA_SHARED) +else +all : $(WPA_STATIC) +endif + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +$(WPA_SHARED) : +ifeq ($(KERNEL_TYPE), linux) + $(CC) -O2 -shared -fPIC -Wl,-z,defs objs/*.o -o $@ $(WPA_LDFLAGS) $(LDFLAGS) +else + $(CC) -flto -O2 -shared -fPIC -Wl,-z,defs objs/*.o -o $@ $(WPA_LDFLAGS) $(LDFLAGS) +endif + +$(WPA_STATIC) : + $(AR) -crs $@ objs/*.o + +$(TEST_WPA) : $(OBJS_WPA) + $(CC) -o $@ $< $(TEST_LDFLAGS) $(LDFLAGS) + rm -f $(CDEPS) + +$(TEST_AP) : $(OBJS_AP) + $(CC) -o $@ $< $(TEST_LDFLAGS) $(LDFLAGS) + rm -f $(CDEPS) + + +clean: + rm -f $(WPA_SHARED) + rm -f $(WPA_STATIC) + rm -f $(OBJS_AP) + rm -f $(TEST_AP) + rm -f $(OBJS_WPA) + rm -f $(TEST_WPA) + rm -f $(CDEPS) diff --git a/wpa_supplicant-2.9_standard/hostapd/Android.mk b/wpa_supplicant-2.9_standard/hostapd/Android.mk index 4727f35d59e19a3d9f38d00f2b6a6d328d17ec02..573564d5b0de904fda7120029aaebff045dc9535 100644 --- a/wpa_supplicant-2.9_standard/hostapd/Android.mk +++ b/wpa_supplicant-2.9_standard/hostapd/Android.mk @@ -154,6 +154,7 @@ OBJS += src/utils/crc32.c OBJS += src/common/ieee802_11_common.c OBJS += src/common/wpa_common.c OBJS += src/common/hw_features_common.c +OBJS += src/common/ptksa_cache.c OBJS += src/eapol_auth/eapol_auth_sm.c @@ -237,6 +238,8 @@ L_CFLAGS += -DCONFIG_OCV OBJS += src/common/ocv.c endif +NEED_AES_UNWRAP=y + ifdef CONFIG_IEEE80211R L_CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP OBJS += src/ap/wpa_auth_ft.c @@ -256,6 +259,7 @@ L_CFLAGS += -DCONFIG_SAE OBJS += src/common/sae.c ifdef CONFIG_SAE_PK L_CFLAGS += -DCONFIG_SAE_PK +NEED_AES_SIV=y OBJS += src/common/sae_pk.c endif NEED_ECC=y @@ -294,6 +298,12 @@ ifdef CONFIG_IEEE80211AC L_CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_IEEE80211BE +CONFIG_IEEE80211AX=y +L_CFLAGS += -DCONFIG_IEEE80211BE +OBJS += src/ap/ieee802_11_eht.c +endif + ifdef CONFIG_IEEE80211AX L_CFLAGS += -DCONFIG_IEEE80211AX endif @@ -572,6 +582,12 @@ L_CFLAGS += -DCONFIG_DPP3 endif endif +ifdef CONFIG_NAN_USD +OBJS += src/common/nan_de.c +OBJS += src/ap/nan_usd_ap.c +L_CFLAGS += -DCONFIG_NAN_USD +endif + ifdef CONFIG_PASN L_CFLAGS += -DCONFIG_PASN L_CFLAGS += -DCONFIG_PTKSA_CACHE @@ -579,7 +595,6 @@ NEED_HMAC_SHA256_KDF=y NEED_HMAC_SHA384_KDF=y NEED_SHA256=y NEED_SHA384=y -OBJS += src/common/ptksa_cache.c endif ifdef CONFIG_EAP_IKEV2 @@ -632,6 +647,11 @@ ifdef CHAP OBJS += src/eap_common/chap.c endif +ifdef CONFIG_RADIUS_TLS +TLS_FUNCS=y +L_CFLAGS += -DCONFIG_RADIUS_TLS +endif + ifdef TLS_FUNCS NEED_DES=y # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS) @@ -653,6 +673,7 @@ L_CFLAGS += -DCONFIG_TLSV12 endif ifeq ($(CONFIG_TLS), openssl) +L_CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 ifdef TLS_FUNCS OBJS += src/crypto/tls_openssl.c OBJS += src/crypto/tls_openssl_ocsp.c @@ -825,7 +846,9 @@ endif ifdef NEED_AES_ENCBLOCK AESOBJS += src/crypto/aes-encblock.c endif +ifneq ($(CONFIG_TLS), openssl) AESOBJS += src/crypto/aes-omac1.c +endif ifdef NEED_AES_UNWRAP ifneq ($(CONFIG_TLS), openssl) NEED_AES_DEC=y @@ -1026,6 +1049,9 @@ endif ifdef NEED_AP_MLME OBJS += src/ap/wmm.c OBJS += src/ap/ap_list.c +OBJS += src/ap/comeback_token.c +OBJS += src/pasn/pasn_responder.c +OBJS += src/pasn/pasn_common.c OBJS += src/ap/ieee802_11.c OBJS += src/ap/hw_features.c OBJS += src/ap/dfs.c @@ -1152,4 +1178,4 @@ LOCAL_C_INCLUDES := $(INCLUDES) LOCAL_INIT_RC := hostapd.android.rc include $(BUILD_EXECUTABLE) -endif # ifeq ($(WPA_BUILD_HOSTAPD),true) \ No newline at end of file +endif # ifeq ($(WPA_BUILD_HOSTAPD),true) diff --git a/wpa_supplicant-2.9_standard/hostapd/ChangeLog b/wpa_supplicant-2.9_standard/hostapd/ChangeLog index 279298e4d4d44f5f07af707454dc8e72073813c3..1c8240d333c4a194c12d126f528e103eafcb7688 100644 --- a/wpa_supplicant-2.9_standard/hostapd/ChangeLog +++ b/wpa_supplicant-2.9_standard/hostapd/ChangeLog @@ -1,5 +1,42 @@ ChangeLog for hostapd +2024-07-20 - v2.11 + * Wi-Fi Easy Connect + - add support for DPP release 3 + - allow Configurator parameters to be provided during config exchange + * HE/IEEE 802.11ax/Wi-Fi 6 + - various fixes + * EHT/IEEE 802.11be/Wi-Fi 7 + - add preliminary support + * SAE: add support for fetching the password from a RADIUS server + * support OpenSSL 3.0 API changes + * support background radar detection and CAC with some additional + drivers + * support RADIUS ACL/PSK check during 4-way handshake (wpa_psk_radius=3) + * EAP-SIM/AKA: support IMSI privacy + * improve 4-way handshake operations + - use Secure=1 in message 3 during PTK rekeying + * OCV: do not check Frequency Segment 1 Channel Number for 160 MHz cases + to avoid interoperability issues + * support new SAE AKM suites with variable length keys + * support new AKM for 802.1X/EAP with SHA384 + * extend PASN support for secure ranging + * FT: Use SHA256 to derive PMKID for AKM 00-0F-AC:3 (FT-EAP) + - this is based on additional details being added in the IEEE 802.11 + standard + - the new implementation is not backwards compatible + * improved ACS to cover additional channel types/bandwidths + * extended Multiple BSSID support + * fix beacon protection with FT protocol (incorrect BIGTK was provided) + * support unsynchronized service discovery (USD) + * add preliminary support for RADIUS/TLS + * add support for explicit SSID protection in 4-way handshake + (a mitigation for CVE-2023-52424; disabled by default for now, can be + enabled with ssid_protection=1) + * fix SAE H2E rejected groups validation to avoid downgrade attacks + * use stricter validation for some RADIUS messages + * a large number of other fixes, cleanup, and extensions + 2022-01-16 - v2.10 * SAE changes - improved protection against side channel attacks diff --git a/wpa_supplicant-2.9_standard/hostapd/Makefile b/wpa_supplicant-2.9_standard/hostapd/Makefile index 50cf1ff03f543c429108fb757b5fe6cb37441d09..406140310f3f8557d8fc55a9d7eece72af61d14a 100755 --- a/wpa_supplicant-2.9_standard/hostapd/Makefile +++ b/wpa_supplicant-2.9_standard/hostapd/Makefile @@ -60,7 +60,6 @@ CFLAGS += -DUSERSPACE_CLIENT_SUPPORT LIBS += -L$(DEPDIR) -lsec_shared -lhilog_shared -lwifi_driver_client export BINDIR ?= /usr/local/bin/ - ifeq ($(COMPILER_TYPE), clang) SYSROOT_PATH ?= ../../../../sysroot ARCH_CFLAGS ?= --target=arm-liteos-ohos -march=armv7-a -mfloat-abi=softfp @@ -127,6 +126,7 @@ OBJS += ../src/ap/beacon.o OBJS += ../src/ap/bss_load.o OBJS += ../src/ap/neighbor_db.o OBJS += ../src/ap/ap_rrm.o +OBJS += ../src/common/ptksa_cache.o OBJS_c = hostapd_cli.o OBJS_c += ../src/common/wpa_ctrl.o @@ -210,7 +210,7 @@ OBJS += ../src/eapol_auth/eapol_auth_sm.o ifdef CONFIG_CODE_COVERAGE -CFLAGS += -O0 -fprofile-arcs -ftest-coverage +CFLAGS += -O0 -fprofile-arcs -ftest-coverage -U_FORTIFY_SOURCE LIBS += -lgcov LIBS_c += -lgcov LIBS_h += -lgcov @@ -319,6 +319,8 @@ CFLAGS += -DCONFIG_OCV OBJS += ../src/common/ocv.o endif +NEED_AES_UNWRAP=y + ifdef CONFIG_IEEE80211R CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP OBJS += ../src/ap/wpa_auth_ft.o @@ -338,6 +340,7 @@ CFLAGS += -DCONFIG_SAE OBJS += ../src/common/sae.o ifdef CONFIG_SAE_PK CFLAGS += -DCONFIG_SAE_PK +NEED_AES_SIV=y OBJS += ../src/common/sae_pk.o endif NEED_ECC=y @@ -382,6 +385,12 @@ ifdef CONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_IEEE80211BE +CONFIG_IEEE80211AX=y +CFLAGS += -DCONFIG_IEEE80211BE +OBJS += ../src/ap/ieee802_11_eht.o +endif + ifdef CONFIG_IEEE80211AX CFLAGS += -DCONFIG_IEEE80211AX OBJS += ../src/ap/ieee802_11_he.o @@ -666,6 +675,12 @@ CFLAGS += -DCONFIG_DPP3 endif endif +ifdef CONFIG_NAN_USD +OBJS += ../src/common/nan_de.o +OBJS += ../src/ap/nan_usd_ap.o +CFLAGS += -DCONFIG_NAN_USD +endif + ifdef CONFIG_PASN CFLAGS += -DCONFIG_PASN CFLAGS += -DCONFIG_PTKSA_CACHE @@ -673,7 +688,6 @@ NEED_HMAC_SHA256_KDF=y NEED_HMAC_SHA384_KDF=y NEED_SHA256=y NEED_SHA384=y -OBJS += ../src/common/ptksa_cache.o endif ifdef CONFIG_EAP_IKEV2 @@ -735,6 +749,11 @@ ifdef CHAP OBJS += ../src/eap_common/chap.o endif +ifdef CONFIG_RADIUS_TLS +TLS_FUNCS=y +CFLAGS += -DCONFIG_RADIUS_TLS +endif + ifdef TLS_FUNCS NEED_DES=y # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS) @@ -776,6 +795,7 @@ endif endif ifeq ($(CONFIG_TLS), openssl) +CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 CONFIG_CRYPTO=openssl ifdef TLS_FUNCS OBJS += ../src/crypto/tls_openssl.o @@ -1000,11 +1020,13 @@ endif ifdef NEED_AES_ENCBLOCK AESOBJS += ../src/crypto/aes-encblock.o endif +ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), wolfssl) AESOBJS += ../src/crypto/aes-omac1.o endif endif +endif ifdef NEED_AES_UNWRAP ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) @@ -1240,6 +1262,9 @@ endif ifdef NEED_AP_MLME OBJS += ../src/ap/wmm.o OBJS += ../src/ap/ap_list.o +OBJS += ../src/ap/comeback_token.o +OBJS += ../src/pasn/pasn_responder.o +OBJS += ../src/pasn/pasn_common.o OBJS += ../src/ap/ieee802_11.o OBJS += ../src/ap/hw_features.o OBJS += ../src/ap/dfs.o @@ -1363,6 +1388,7 @@ include ../src/objs.mk hostapd: $(OBJS) $(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS) @$(E) " LD " $@ + BCHECK=../src/drivers/build.hostapd $(COPY_OBJS): $(OBJS) diff --git a/wpa_supplicant-2.9_standard/hostapd/README b/wpa_supplicant-2.9_standard/hostapd/README index 739c964d44d82ef5a55569a3a51ddbe48777fbe3..1a0248fce422c0d89997f0c410640cb2a3bd7204 100644 --- a/wpa_supplicant-2.9_standard/hostapd/README +++ b/wpa_supplicant-2.9_standard/hostapd/README @@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator and RADIUS authentication server ================================================================ -Copyright (c) 2002-2022, Jouni Malinen and contributors +Copyright (c) 2002-2024, Jouni Malinen and contributors All Rights Reserved. This program is licensed under the BSD license (the one with diff --git a/wpa_supplicant-2.9_standard/hostapd/README.OpenSource b/wpa_supplicant-2.9_standard/hostapd/README.OpenSource index c08e619dcce80978781a2b2be4b9ce32f863d00a..d895dfb91c84b452c0b1471d8ad9bfe583142895 100644 --- a/wpa_supplicant-2.9_standard/hostapd/README.OpenSource +++ b/wpa_supplicant-2.9_standard/hostapd/README.OpenSource @@ -1,12 +1,12 @@ -[ - { - "Name": "hostapd", - "License": "BSD 3-Clause License", - "License File": "../COPYING", - "Version Number": "2.10", - "Owner": "maoyufeng3@huawei.com", - "Upstream URL": "http://w1.fi/releases/hostapd-2.10.tar.gz", - "Description": "hostapd is a user space daemon for access point and authentication servers. It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators, RADIUS client, EAP server, and RADIUS authentication server." - } -] - +[ + { + "Name": "hostapd", + "License": "BSD 3-Clause License", + "License File": "../COPYING", + "Version Number": "2.11", + "Owner": "maoyufeng3@huawei.com", + "Upstream URL": "https://w1.fi/releases/hostapd-2.11.tar.gz", + "Description": "hostapd is a user space daemon for access point and authentication servers. It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators, RADIUS client, EAP server, and RADIUS authentication server." + } +] + diff --git a/wpa_supplicant-2.9_standard/hostapd/android.config b/wpa_supplicant-2.9_standard/hostapd/android.config index df540bc983ebf8eff6edf701526b578550b6b23e..522de87266d5e268aa6a77b8d43d305aece3bbaf 100644 --- a/wpa_supplicant-2.9_standard/hostapd/android.config +++ b/wpa_supplicant-2.9_standard/hostapd/android.config @@ -121,6 +121,9 @@ CONFIG_PKCS12=y # Build IPv6 support for RADIUS operations CONFIG_IPV6=y +# Include support fo RADIUS/TLS into the RADIUS client +#CONFIG_RADIUS_TLS=y + # IEEE Std 802.11r-2008 (Fast BSS Transition) #CONFIG_IEEE80211R=y @@ -211,4 +214,7 @@ CONFIG_NO_RANDOM_POOL=y # functionality needed to use WEP is available in the current hostapd # release under this optional build parameter. This functionality is subject to # be completely removed in a future release. -CONFIG_WEP=y \ No newline at end of file +CONFIG_WEP=y + +# Wi-Fi Aware unsynchronized service discovery (NAN USD) +#CONFIG_NAN_USD=y diff --git a/wpa_supplicant-2.9_standard/hostapd/ap_config_file.c b/wpa_supplicant-2.9_standard/hostapd/ap_config_file.c index 76e62383dca2f309888c1750a9c0ab4a5e3d45d5..0a94e378921e19a34db0143b9f9bf0c4db69ce3b 100755 --- a/wpa_supplicant-2.9_standard/hostapd/ap_config_file.c +++ b/wpa_supplicant-2.9_standard/hostapd/ap_config_file.c @@ -1,6 +1,6 @@ /* * hostapd / Configuration file parser - * Copyright (c) 2003-2018, Jouni Malinen + * Copyright (c) 2003-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -122,52 +122,6 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, #endif /* CONFIG_NO_VLAN */ -int hostapd_acl_comp(const void *a, const void *b) -{ - const struct mac_acl_entry *aa = a; - const struct mac_acl_entry *bb = b; - return os_memcmp(aa->addr, bb->addr, sizeof(macaddr)); -} - - -int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num, - int vlan_id, const u8 *addr) -{ - struct mac_acl_entry *newacl; - - newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl)); - if (!newacl) { - wpa_printf(MSG_ERROR, "MAC list reallocation failed"); - return -1; - } - - *acl = newacl; - os_memcpy((*acl)[*num].addr, addr, ETH_ALEN); - os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id)); - (*acl)[*num].vlan_id.untagged = vlan_id; - (*acl)[*num].vlan_id.notempty = !!vlan_id; - (*num)++; - - return 0; -} - - -void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num, - const u8 *addr) -{ - int i = 0; - - while (i < *num) { - if (os_memcmp((*acl)[i].addr, addr, ETH_ALEN) == 0) { - os_remove_in_array(*acl, *num, sizeof(**acl), i); - (*num)--; - } else { - i++; - } - } -} - - static int hostapd_config_read_maclist(const char *fname, struct mac_acl_entry **acl, int *num) { @@ -717,6 +671,10 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value) val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384; #endif /* CONFIG_SHA384 */ #endif /* CONFIG_IEEE80211R_AP */ +#ifdef CONFIG_SHA384 + else if (os_strcmp(start, "WPA-EAP-SHA384") == 0) + val |= WPA_KEY_MGMT_IEEE8021X_SHA384; +#endif /* CONFIG_SHA384 */ else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) val |= WPA_KEY_MGMT_PSK_SHA256; else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) @@ -724,8 +682,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value) #ifdef CONFIG_SAE else if (os_strcmp(start, "SAE") == 0) val |= WPA_KEY_MGMT_SAE; + else if (os_strcmp(start, "SAE-EXT-KEY") == 0) + val |= WPA_KEY_MGMT_SAE_EXT_KEY; else if (os_strcmp(start, "FT-SAE") == 0) val |= WPA_KEY_MGMT_FT_SAE; + else if (os_strcmp(start, "FT-SAE-EXT-KEY") == 0) + val |= WPA_KEY_MGMT_FT_SAE_EXT_KEY; #endif /* CONFIG_SAE */ #ifdef CONFIG_SUITEB else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0) @@ -1062,6 +1024,78 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value) return 0; } + + +int hostapd_config_read_rxkh_file(struct hostapd_bss_config *conf, + const char *fname) +{ + FILE *f; + char buf[256], *pos; + int line = 0, errors = 0; + + if (!fname) + return 0; + + f = fopen(fname, "r"); + if (!f) { + wpa_printf(MSG_ERROR, "rxkh file '%s' not found.", fname); + return -1; + } + + while (fgets(buf, sizeof(buf), f)) { + line++; + + if (buf[0] == '#') + continue; + pos = buf; + while (*pos != '\0') { + if (*pos == '\n') { + *pos = '\0'; + break; + } + pos++; + } + if (buf[0] == '\0') + continue; + + pos = os_strchr(buf, '='); + if (!pos) { + wpa_printf(MSG_ERROR, "Line %d: Invalid line '%s'", + line, buf); + errors++; + continue; + } + *pos = '\0'; + pos++; + + if (os_strcmp(buf, "r0kh") == 0) { + if (add_r0kh(conf, pos) < 0) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid r0kh '%s'", + line, pos); + errors++; + } + } else if (os_strcmp(buf, "r1kh") == 0) { + if (add_r1kh(conf, pos) < 0) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid r1kh '%s'", + line, pos); + errors++; + } + } + } + + fclose(f); + + if (errors) { + wpa_printf(MSG_ERROR, + "%d errors in configuring RxKHs from '%s'", + errors, fname); + return -1; + } + return 0; +} + #endif /* CONFIG_IEEE80211R_AP */ @@ -1650,6 +1684,8 @@ static int parse_anqp_elem(struct hostapd_bss_config *bss, char *buf, int line) return 0; } +#endif /* CONFIG_INTERWORKING */ + static int parse_qos_map_set(struct hostapd_bss_config *bss, char *buf, int line) @@ -1691,8 +1727,6 @@ static int parse_qos_map_set(struct hostapd_bss_config *bss, return 0; } -#endif /* CONFIG_INTERWORKING */ - #ifdef CONFIG_HS20 static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf, @@ -2203,6 +2237,7 @@ static int add_airtime_weight(struct hostapd_bss_config *bss, char *value) #ifdef CONFIG_SAE + static int parse_sae_password(struct hostapd_bss_config *bss, const char *val) { struct sae_password_entry *pw; @@ -2306,6 +2341,40 @@ fail: os_free(pw); return -1; } + + +static int parse_sae_password_file(struct hostapd_bss_config *bss, + const char *fname) +{ + FILE *f; + char buf[500], *pos; + unsigned int line = 0; + + f = fopen(fname, "r"); + if (!f) { + wpa_printf(MSG_ERROR, "sae_password_file '%s' not found.", + fname); + return -1; + } + + while (fgets(buf, sizeof(buf), f)) { + pos = os_strchr(buf, '\n'); + if (pos) + *pos = '\0'; + line++; + if (parse_sae_password(bss, buf)) { + wpa_printf(MSG_ERROR, + "Invalid SAE password at line %d in '%s'", + line, fname); + fclose(f); + return -1; + } + } + + fclose(f); + return 0; +} + #endif /* CONFIG_SAE */ @@ -2434,6 +2503,23 @@ static void hostapd_config_bw_auto_adaptation(struct hostapd_config *conf) } #endif /* CONFIG_IEEE80211AC */ } +#ifdef CONFIG_IEEE80211BE +static int get_u16(const char *pos, int line, u16 *ret_val) +{ + char *end; + long int val = strtol(pos, &end, 0); + + if (*end || val < 0 || val > 0xffff) { + wpa_printf(MSG_ERROR, "Line %d: Invalid value '%s'", + line, pos); + return -1; + } + + *ret_val = val; + return 0; +} +#endif /* CONFIG_IEEE80211BE */ + static int hostapd_config_fill(struct hostapd_config *conf, struct hostapd_bss_config *bss, @@ -2444,6 +2530,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, sizeof(conf->bss[0]->iface)); } else if (os_strcmp(buf, "bridge") == 0) { os_strlcpy(bss->bridge, pos, sizeof(bss->bridge)); + } else if (os_strcmp(buf, "bridge_hairpin") == 0) { + bss->bridge_hairpin = atoi(pos); } else if (os_strcmp(buf, "vlan_bridge") == 0) { os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge)); } else if (os_strcmp(buf, "wds_bridge") == 0) { @@ -2493,7 +2581,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, } os_memcpy(ssid->ssid, pos, ssid->ssid_len); ssid->ssid_set = 1; - ssid->short_ssid = crc32(ssid->ssid, ssid->ssid_len); + ssid->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len); } else if (os_strcmp(buf, "ssid2") == 0) { struct hostapd_ssid *ssid = &bss->ssid; size_t slen; @@ -2507,7 +2595,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, os_memcpy(ssid->ssid, str, slen); ssid->ssid_len = slen; ssid->ssid_set = 1; - ssid->short_ssid = crc32(ssid->ssid, ssid->ssid_len); + ssid->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len); os_free(str); } else if (os_strcmp(buf, "utf8_ssid") == 0) { bss->ssid.utf8_ssid = atoi(pos) > 0; @@ -2546,6 +2634,30 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->ap_max_inactivity = atoi(pos); } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) { bss->skip_inactivity_poll = atoi(pos); + } else if (os_strcmp(buf, "bss_max_idle") == 0) { + int val = atoi(pos); + + if (val < 0 || val > 2) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid bss_max_idle value", line); + return 1; + } + bss->bss_max_idle = val; + } else if (os_strcmp(buf, "max_acceptable_idle_period") == 0) { + bss->max_acceptable_idle_period = atoi(pos); + } else if (os_strcmp(buf, "no_disconnect_on_group_keyerror") == 0) { + int val = atoi(pos); + + if (val < 0 || val > 1) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid no_disconnect_on_group_keyerror", + line); + return 1; + } + bss->no_disconnect_on_group_keyerror = val; + } else if (os_strcmp(buf, "config_id") == 0) { + os_free(bss->config_id); + bss->config_id = os_strdup(pos); } else if (os_strcmp(buf, "country_code") == 0) { if (pos[0] < 'A' || pos[0] > 'Z' || pos[1] < 'A' || pos[1] > 'Z') { @@ -2710,6 +2822,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->eap_teap_separate_result = atoi(pos); } else if (os_strcmp(buf, "eap_teap_id") == 0) { bss->eap_teap_id = atoi(pos); + } else if (os_strcmp(buf, "eap_teap_method_sequence") == 0) { + bss->eap_teap_method_sequence = atoi(pos); #endif /* EAP_SERVER_TEAP */ #ifdef EAP_SERVER_SIM } else if (os_strcmp(buf, "eap_sim_db") == 0) { @@ -2721,6 +2835,11 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->eap_sim_aka_result_ind = atoi(pos); } else if (os_strcmp(buf, "eap_sim_id") == 0) { bss->eap_sim_id = atoi(pos); + } else if (os_strcmp(buf, "imsi_privacy_key") == 0) { + os_free(bss->imsi_privacy_key); + bss->imsi_privacy_key = os_strdup(pos); + } else if (os_strcmp(buf, "eap_sim_aka_fast_reauth_limit") == 0) { + bss->eap_sim_aka_fast_reauth_limit = atoi(pos); #endif /* EAP_SERVER_SIM */ #ifdef EAP_SERVER_TNC } else if (os_strcmp(buf, "tnc") == 0) { @@ -2856,6 +2975,37 @@ static int hostapd_config_fill(struct hostapd_config *conf, os_free(bss->radius->auth_server->shared_secret); bss->radius->auth_server->shared_secret = (u8 *) os_strdup(pos); bss->radius->auth_server->shared_secret_len = len; + } else if (bss->radius->auth_server && + os_strcmp(buf, "auth_server_type") == 0) { + if (os_strcmp(pos, "UDP") == 0) { + bss->radius->auth_server->tls = false; +#ifdef CONFIG_RADIUS_TLS + } else if (os_strcmp(pos, "TLS") == 0) { + bss->radius->auth_server->tls = true; +#endif /* CONFIG_RADIUS_TLS */ + } else { + wpa_printf(MSG_ERROR, "Line %d: unsupported RADIUS type '%s'", + line, pos); + return 1; + } +#ifdef CONFIG_RADIUS_TLS + } else if (bss->radius->auth_server && + os_strcmp(buf, "auth_server_ca_cert") == 0) { + os_free(bss->radius->auth_server->ca_cert); + bss->radius->auth_server->ca_cert = os_strdup(pos); + } else if (bss->radius->auth_server && + os_strcmp(buf, "auth_server_client_cert") == 0) { + os_free(bss->radius->auth_server->client_cert); + bss->radius->auth_server->client_cert = os_strdup(pos); + } else if (bss->radius->auth_server && + os_strcmp(buf, "auth_server_private_key") == 0) { + os_free(bss->radius->auth_server->private_key); + bss->radius->auth_server->private_key = os_strdup(pos); + } else if (bss->radius->auth_server && + os_strcmp(buf, "auth_server_private_key_passwd") == 0) { + os_free(bss->radius->auth_server->private_key_passwd); + bss->radius->auth_server->private_key_passwd = os_strdup(pos); +#endif /* CONFIG_RADIUS_TLS */ } else if (os_strcmp(buf, "acct_server_addr") == 0) { if (hostapd_config_read_radius_addr( &bss->radius->acct_servers, @@ -2890,8 +3040,42 @@ static int hostapd_config_fill(struct hostapd_config *conf, os_free(bss->radius->acct_server->shared_secret); bss->radius->acct_server->shared_secret = (u8 *) os_strdup(pos); bss->radius->acct_server->shared_secret_len = len; + } else if (bss->radius->acct_server && + os_strcmp(buf, "acct_server_type") == 0) { + if (os_strcmp(pos, "UDP") == 0) { + bss->radius->acct_server->tls = false; +#ifdef CONFIG_RADIUS_TLS + } else if (os_strcmp(pos, "TLS") == 0) { + bss->radius->acct_server->tls = true; +#endif /* CONFIG_RADIUS_TLS */ + } else { + wpa_printf(MSG_ERROR, "Line %d: unsupported RADIUS type '%s'", + line, pos); + return 1; + } +#ifdef CONFIG_RADIUS_TLS + } else if (bss->radius->acct_server && + os_strcmp(buf, "acct_server_ca_cert") == 0) { + os_free(bss->radius->acct_server->ca_cert); + bss->radius->acct_server->ca_cert = os_strdup(pos); + } else if (bss->radius->acct_server && + os_strcmp(buf, "acct_server_client_cert") == 0) { + os_free(bss->radius->acct_server->client_cert); + bss->radius->acct_server->client_cert = os_strdup(pos); + } else if (bss->radius->acct_server && + os_strcmp(buf, "acct_server_private_key") == 0) { + os_free(bss->radius->acct_server->private_key); + bss->radius->acct_server->private_key = os_strdup(pos); + } else if (bss->radius->acct_server && + os_strcmp(buf, "acct_server_private_key_passwd") == 0) { + os_free(bss->radius->acct_server->private_key_passwd); + bss->radius->acct_server->private_key_passwd = os_strdup(pos); +#endif /* CONFIG_RADIUS_TLS */ } else if (os_strcmp(buf, "radius_retry_primary_interval") == 0) { bss->radius->retry_primary_interval = atoi(pos); + } else if (os_strcmp(buf, + "radius_require_message_authenticator") == 0) { + bss->radius_require_message_authenticator = atoi(pos); } else if (os_strcmp(buf, "radius_acct_interim_interval") == 0) { bss->acct_interim_interval = atoi(pos); } else if (os_strcmp(buf, "radius_request_cui") == 0) { @@ -3061,7 +3245,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->wpa_psk_radius = atoi(pos); if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED && bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED && - bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) { + bss->wpa_psk_radius != PSK_RADIUS_REQUIRED && + bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS) { wpa_printf(MSG_ERROR, "Line %d: unknown wpa_psk_radius %d", line, bss->wpa_psk_radius); @@ -3158,6 +3343,21 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + } else if (os_strcmp(buf, "rxkh_file") == 0) { + os_free(bss->rxkh_file); + bss->rxkh_file = os_strdup(pos); + if (!bss->rxkh_file) { + wpa_printf(MSG_ERROR, "Line %d: allocation failed", + line); + return 1; + } + if (hostapd_config_read_rxkh_file(bss, pos)) { + wpa_printf(MSG_DEBUG, + "Line %d: failed to read rxkh_file '%s'", + line, pos); + /* Allow the file to be created later and read into + * already operating AP context. */ + } } else if (os_strcmp(buf, "pmk_r1_push") == 0) { bss->pmk_r1_push = atoi(pos); } else if (os_strcmp(buf, "ft_over_ds") == 0) { @@ -3225,6 +3425,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + conf->hw_mode_set = true; } else if (os_strcmp(buf, "wps_rf_bands") == 0) { if (os_strcmp(pos, "ad") == 0) bss->wps_rf_bands = WPS_RF_60GHZ; @@ -3288,6 +3489,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->acs_freq_list_present = 1; } else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) { conf->acs_exclude_6ghz_non_psc = atoi(pos); + } else if (os_strcmp(buf, "enable_background_radar") == 0) { + conf->enable_background_radar = atoi(pos); } else if (os_strcmp(buf, "min_tx_power") == 0) { int val = atoi(pos); @@ -3579,6 +3782,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "require_ht") == 0) { conf->require_ht = atoi(pos); + } else if (os_strcmp(buf, "ht_vht_twt_responder") == 0) { + conf->ht_vht_twt_responder = atoi(pos); } else if (os_strcmp(buf, "obss_interval") == 0) { conf->obss_interval = atoi(pos); #ifdef CONFIG_IEEE80211AC @@ -3606,6 +3811,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, #ifdef CONFIG_IEEE80211AX } else if (os_strcmp(buf, "ieee80211ax") == 0) { conf->ieee80211ax = atoi(pos); + } else if (os_strcmp(buf, "require_he") == 0) { + conf->require_he = atoi(pos); } else if (os_strcmp(buf, "he_su_beamformer") == 0) { conf->he_phy_capab.he_su_beamformer = atoi(pos); } else if (os_strcmp(buf, "he_su_beamformee") == 0) { @@ -3737,6 +3944,20 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + } else if (os_strcmp(buf, "he_6ghz_reg_pwr_type") == 0) { + conf->he_6ghz_reg_pwr_type = atoi(pos); + if (conf->he_6ghz_reg_pwr_type > HE_REG_INFO_6GHZ_AP_TYPE_MAX) { + wpa_printf(MSG_ERROR, + "Line %d: invalid he_6ghz_reg_pwr_type value", + line); + return 1; + } + } else if (os_strcmp(buf, "reg_def_cli_eirp_psd") == 0) { + conf->reg_def_cli_eirp_psd = atoi(pos); + } else if (os_strcmp(buf, "reg_sub_cli_eirp_psd") == 0) { + conf->reg_sub_cli_eirp_psd = atoi(pos); + } else if (os_strcmp(buf, "reg_def_cli_eirp") == 0) { + conf->reg_def_cli_eirp = atoi(pos); } else if (os_strcmp(buf, "he_oper_chwidth") == 0) { conf->he_oper_chwidth = atoi(pos); } else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) { @@ -3761,6 +3982,15 @@ static int hostapd_config_fill(struct hostapd_config *conf, return 1; } bss->unsol_bcast_probe_resp_interval = val; + } else if (os_strcmp(buf, "mbssid") == 0) { + int mbssid = atoi(pos); + if (mbssid < 0 || mbssid > ENHANCED_MBSSID_ENABLED) { + wpa_printf(MSG_ERROR, + "Line %d: invalid mbssid (%d): '%s'.", + line, mbssid, pos); + return 1; + } + conf->mbssid = mbssid; #endif /* CONFIG_IEEE80211AX */ } else if (os_strcmp(buf, "max_listen_interval") == 0) { bss->max_listen_interval = atoi(pos); @@ -4148,10 +4378,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->gas_frag_limit = val; } else if (os_strcmp(buf, "gas_comeback_delay") == 0) { bss->gas_comeback_delay = atoi(pos); +#endif /* CONFIG_INTERWORKING */ } else if (os_strcmp(buf, "qos_map_set") == 0) { if (parse_qos_map_set(bss, pos, line) < 0) return 1; -#endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_RADIUS_TEST } else if (os_strcmp(buf, "dump_msk_file") == 0) { os_free(bss->dump_msk_file); @@ -4392,6 +4622,23 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->oci_freq_override_fils_assoc = atoi(pos); } else if (os_strcmp(buf, "oci_freq_override_wnm_sleep") == 0) { bss->oci_freq_override_wnm_sleep = atoi(pos); + } else if (os_strcmp(buf, "eap_skip_prot_success") == 0) { + bss->eap_skip_prot_success = atoi(pos); + } else if (os_strcmp(buf, "delay_eapol_tx") == 0) { + conf->delay_eapol_tx = atoi(pos); + } else if (os_strcmp(buf, "eapol_m1_elements") == 0) { + if (parse_wpabuf_hex(line, buf, &bss->eapol_m1_elements, pos)) + return 1; + } else if (os_strcmp(buf, "eapol_m3_elements") == 0) { + if (parse_wpabuf_hex(line, buf, &bss->eapol_m3_elements, pos)) + return 1; + } else if (os_strcmp(buf, "eapol_m3_no_encrypt") == 0) { + bss->eapol_m3_no_encrypt = atoi(pos); + } else if (os_strcmp(buf, "test_assoc_comeback_type") == 0) { + bss->test_assoc_comeback_type = atoi(pos); + } else if (os_strcmp(buf, "presp_elements") == 0) { + if (parse_wpabuf_hex(line, buf, &bss->presp_elements, pos)) + return 1; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_SAE } else if (os_strcmp(buf, "sae_password") == 0) { @@ -4400,6 +4647,13 @@ static int hostapd_config_fill(struct hostapd_config *conf, line); return 1; } + } else if (os_strcmp(buf, "sae_password_file") == 0) { + if (parse_sae_password_file(bss, pos) < 0) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid sae_password in file", + line); + return 1; + } #endif /* CONFIG_SAE */ } else if (os_strcmp(buf, "vendor_elements") == 0) { if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos)) @@ -4531,6 +4785,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE | WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE | WLAN_RRM_CAPS_BEACON_REPORT_TABLE; + } else if (os_strcmp(buf, "rrm_link_measurement_report") == 0) { + if (atoi(pos)) + bss->radio_measurements[0] |= + WLAN_RRM_CAPS_LINK_MEASUREMENT; } else if (os_strcmp(buf, "gas_address3") == 0) { bss->gas_address3 = atoi(pos); } else if (os_strcmp(buf, "stationary_ap") == 0) { @@ -4575,6 +4833,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, #endif /* CONFIG_FILS */ } else if (os_strcmp(buf, "multicast_to_unicast") == 0) { bss->multicast_to_unicast = atoi(pos); + } else if (os_strcmp(buf, "bridge_multicast_to_unicast") == 0) { + bss->bridge_multicast_to_unicast = atoi(pos); } else if (os_strcmp(buf, "broadcast_deauth") == 0) { bss->broadcast_deauth = atoi(pos); } else if (os_strcmp(buf, "notify_mgmt_frames") == 0) { @@ -4586,6 +4846,12 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "dpp_mud_url") == 0) { os_free(bss->dpp_mud_url); bss->dpp_mud_url = os_strdup(pos); + } else if (os_strcmp(buf, "dpp_extra_conf_req_name") == 0) { + os_free(bss->dpp_extra_conf_req_name); + bss->dpp_extra_conf_req_name = os_strdup(pos); + } else if (os_strcmp(buf, "dpp_extra_conf_req_value") == 0) { + os_free(bss->dpp_extra_conf_req_value); + bss->dpp_extra_conf_req_value = os_strdup(pos); } else if (os_strcmp(buf, "dpp_connector") == 0) { os_free(bss->dpp_connector); bss->dpp_connector = os_strdup(pos); @@ -4601,6 +4867,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "dpp_controller") == 0) { if (hostapd_dpp_controller_parse(bss, pos)) return 1; + } else if (os_strcmp(buf, "dpp_relay_port") == 0) { + bss->dpp_relay_port = atoi(pos); } else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) { bss->dpp_configurator_connectivity = atoi(pos); } else if (os_strcmp(buf, "dpp_pfs") == 0) { @@ -4661,6 +4929,36 @@ static int hostapd_config_fill(struct hostapd_config *conf, } bss->multi_ap = val; + } else if (os_strcmp(buf, "multi_ap_profile") == 0) { + int val = atoi(pos); + + if (val < MULTI_AP_PROFILE_1 || val > MULTI_AP_PROFILE_MAX) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid multi_ap_profile '%s'", + line, buf); + return -1; + } + bss->multi_ap_profile = val; + } else if (os_strcmp(buf, "multi_ap_client_disallow") == 0) { + int val = atoi(pos); + + if (val < 0 || val > 3) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid multi_ap_client_allow '%s'", + line, buf); + return -1; + } + bss->multi_ap_client_disallow = val; + } else if (os_strcmp(buf, "multi_ap_vlanid") == 0) { + int val = atoi(pos); + + if (val < 0 || val > MAX_VLAN_ID) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid multi_ap_vlan_id '%s'", + line, buf); + return -1; + } + bss->multi_ap_vlanid = val; } else if (os_strcmp(buf, "rssi_reject_assoc_rssi") == 0) { conf->rssi_reject_assoc_rssi = atoi(pos); } else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) { @@ -4736,6 +5034,16 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->macsec_replay_protect = macsec_replay_protect; } else if (os_strcmp(buf, "macsec_replay_window") == 0) { bss->macsec_replay_window = atoi(pos); + } else if (os_strcmp(buf, "macsec_offload") == 0) { + int macsec_offload = atoi(pos); + + if (macsec_offload < 0 || macsec_offload > 2) { + wpa_printf(MSG_ERROR, + "Line %d: invalid macsec_offload (%d): '%s'.", + line, macsec_offload, pos); + return 1; + } + bss->macsec_offload = macsec_offload; } else if (os_strcmp(buf, "macsec_port") == 0) { int macsec_port = atoi(pos); @@ -4756,6 +5064,16 @@ static int hostapd_config_fill(struct hostapd_config *conf, return 1; } bss->mka_priority = mka_priority; + } else if (os_strcmp(buf, "macsec_csindex") == 0) { + int macsec_csindex = atoi(pos); + + if (macsec_csindex < 0 || macsec_csindex > 1) { + wpa_printf(MSG_ERROR, + "Line %d: invalid macsec_csindex (%d): '%s'.", + line, macsec_csindex, pos); + return 1; + } + bss->macsec_csindex = macsec_csindex; } else if (os_strcmp(buf, "mka_cak") == 0) { size_t len = os_strlen(pos); @@ -4792,6 +5110,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->disable_11ac = !!atoi(pos); } else if (os_strcmp(buf, "disable_11ax") == 0) { bss->disable_11ax = !!atoi(pos); + } else if (os_strcmp(buf, "disable_11be") == 0) { + bss->disable_11be = !!atoi(pos); #ifdef CONFIG_PASN #ifdef CONFIG_TESTING_OPTIONS } else if (os_strcmp(buf, "force_kdk_derivation") == 0) { @@ -4808,6 +5128,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "pasn_comeback_after") == 0) { bss->pasn_comeback_after = atoi(pos); + } else if (os_strcmp(buf, "pasn_noauth") == 0) { + bss->pasn_noauth = atoi(pos); #endif /* CONFIG_PASN */ } else if (os_strcmp(buf, "ext_capa_mask") == 0) { if (get_hex_config(bss->ext_capa_mask, EXT_CAPA_MAX_LEN, @@ -4819,6 +5141,58 @@ static int hostapd_config_fill(struct hostapd_config *conf, return 1; } else if (os_strcmp(buf, "rnr") == 0) { bss->rnr = atoi(pos); + } else if (os_strcmp(buf, "ssid_protection") == 0) { + int val = atoi(pos); + + if (val < 0 || val > 1) + return 1; + bss->ssid_protection = val; +#ifdef CONFIG_IEEE80211BE + } else if (os_strcmp(buf, "ieee80211be") == 0) { + conf->ieee80211be = atoi(pos); + } else if (os_strcmp(buf, "eht_oper_chwidth") == 0) { + conf->eht_oper_chwidth = atoi(pos); + } else if (os_strcmp(buf, "eht_oper_centr_freq_seg0_idx") == 0) { + conf->eht_oper_centr_freq_seg0_idx = atoi(pos); + } else if (os_strcmp(buf, "eht_su_beamformer") == 0) { + conf->eht_phy_capab.su_beamformer = atoi(pos); + } else if (os_strcmp(buf, "eht_su_beamformee") == 0) { + conf->eht_phy_capab.su_beamformee = atoi(pos); + } else if (os_strcmp(buf, "eht_mu_beamformer") == 0) { + conf->eht_phy_capab.mu_beamformer = atoi(pos); + } else if (os_strcmp(buf, "eht_default_pe_duration") == 0) { + conf->eht_default_pe_duration = atoi(pos); + } else if (os_strcmp(buf, "punct_bitmap") == 0) { + if (get_u16(pos, line, &conf->punct_bitmap)) + return 1; + } else if (os_strcmp(buf, "punct_acs_threshold") == 0) { + int val = atoi(pos); + + if (val < 0 || val > 100) { + wpa_printf(MSG_ERROR, + "Line %d: punct_acs_threshold must be between 0 and 100", + line); + return 1; + } + conf->punct_acs_threshold = val; + } else if (os_strcmp(buf, "mld_ap") == 0) { + bss->mld_ap = !!atoi(pos); + } else if (os_strcmp(buf, "mld_addr") == 0) { + if (hwaddr_aton(pos, bss->mld_addr)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid mld_addr", + line); + return 1; + } + } else if (os_strcmp(buf, "eht_bw320_offset") == 0) { + conf->eht_bw320_offset = atoi(pos); +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strcmp(buf, "eht_oper_puncturing_override") == 0) { + if (get_u16(pos, line, &bss->eht_oper_puncturing_override)) + return 1; + } else if (os_strcmp(buf, "mld_indicate_disabled") == 0) { + bss->mld_indicate_disabled = atoi(pos); +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_IEEE80211BE */ } else { wpa_printf(MSG_ERROR, "Line %d: unknown configuration item '%s'", @@ -4965,7 +5339,6 @@ struct hostapd_config * hostapd_config_read(const char *fname) } fclose(f); - #ifdef CONFIG_OPEN_HARMONY_PATCH if ((conf->ieee80211n) && (HOSTAPD_MODE_IEEE80211G == conf->hw_mode)) { if ((!(conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) && (!conf->ht20_set_flag)) { diff --git a/wpa_supplicant-2.9_standard/hostapd/ap_ctrl_iface.c b/wpa_supplicant-2.9_standard/hostapd/ap_ctrl_iface.c index bb3450e9d6972e3eaa750ca3e12c4c9e5b5745df..c67d226195cb472ff91c5afacc7e5fd09a5ad644 100755 --- a/wpa_supplicant-2.9_standard/hostapd/ap_ctrl_iface.c +++ b/wpa_supplicant-2.9_standard/hostapd/ap_ctrl_iface.c @@ -38,6 +38,8 @@ #endif /* CONFIG_DPP */ #include "common/wpa_ctrl.h" #include "common/ptksa_cache.h" +#include "common/hw_features_common.h" +#include "common/nan_de.h" #include "crypto/tls.h" #include "drivers/driver.h" #include "eapol_auth/eapol_auth_sm.h" @@ -62,6 +64,7 @@ #include "ap/rrm.h" #include "ap/dpp_hostapd.h" #include "ap/dfs.h" +#include "ap/nan_usd_ap.h" #include "wps/wps_defs.h" #include "wps/wps.h" #include "fst/fst_ctrl_iface.h" @@ -772,235 +775,6 @@ static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd, #ifdef CONFIG_WNM_AP -static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - int disassoc_timer; - struct sta_info *sta; - - if (hwaddr_aton(cmd, addr)) - return -1; - if (cmd[17] != ' ') - return -1; - disassoc_timer = atoi(cmd + 17); - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR_SEC - " not found for disassociation imminent message", - MAC2STR_SEC(addr)); - return -1; - } - - return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer); -} - - -static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - const char *url, *timerstr; - int disassoc_timer; - struct sta_info *sta; - - if (hwaddr_aton(cmd, addr)) - return -1; - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR_SEC - " not found for ESS disassociation imminent message", - MAC2STR_SEC(addr)); - return -1; - } - - timerstr = cmd + 17; - if (*timerstr != ' ') - return -1; - timerstr++; - disassoc_timer = atoi(timerstr); - if (disassoc_timer < 0 || disassoc_timer > 65535) - return -1; - - url = os_strchr(timerstr, ' '); - if (url == NULL) - return -1; - url++; - - return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer); -} - - -static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - const char *pos, *end; - int disassoc_timer = 0; - struct sta_info *sta; - u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01; - u8 bss_term_dur[12]; - char *url = NULL; - int ret; - u8 nei_rep[1000]; - int nei_len; - u8 mbo[10]; - size_t mbo_len = 0; - - if (hwaddr_aton(cmd, addr)) { - wpa_printf(MSG_DEBUG, "Invalid STA MAC address"); - return -1; - } - - sta = ap_get_sta(hapd, addr); - if (sta == NULL) { - wpa_printf(MSG_DEBUG, "Station " MACSTR_SEC - " not found for BSS TM Request message", - MAC2STR_SEC(addr)); - return -1; - } - - pos = os_strstr(cmd, " disassoc_timer="); - if (pos) { - pos += 16; - disassoc_timer = atoi(pos); - if (disassoc_timer < 0 || disassoc_timer > 65535) { - wpa_printf(MSG_DEBUG, "Invalid disassoc_timer"); - return -1; - } - } - - pos = os_strstr(cmd, " valid_int="); - if (pos) { - pos += 11; - valid_int = atoi(pos); - } - - pos = os_strstr(cmd, " dialog_token="); - if (pos) { - pos += 14; - dialog_token = atoi(pos); - } - - pos = os_strstr(cmd, " bss_term="); - if (pos) { - pos += 10; - req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED; - /* TODO: TSF configurable/learnable */ - bss_term_dur[0] = 4; /* Subelement ID */ - bss_term_dur[1] = 10; /* Length */ - os_memset(&bss_term_dur[2], 0, 8); - end = os_strchr(pos, ','); - if (end == NULL) { - wpa_printf(MSG_DEBUG, "Invalid bss_term data"); - return -1; - } - end++; - WPA_PUT_LE16(&bss_term_dur[10], atoi(end)); - } - - nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep, - sizeof(nei_rep)); - if (nei_len < 0) - return -1; - - pos = os_strstr(cmd, " url="); - if (pos) { - size_t len; - pos += 5; - end = os_strchr(pos, ' '); - if (end) - len = end - pos; - else - len = os_strlen(pos); - url = os_malloc(len + 1); - if (url == NULL) - return -1; - os_memcpy(url, pos, len); - url[len] = '\0'; - req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; - } - - if (os_strstr(cmd, " pref=1")) - req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; - if (os_strstr(cmd, " abridged=1")) - req_mode |= WNM_BSS_TM_REQ_ABRIDGED; - if (os_strstr(cmd, " disassoc_imminent=1")) - req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT; - -#ifdef CONFIG_MBO - pos = os_strstr(cmd, "mbo="); - if (pos) { - unsigned int mbo_reason, cell_pref, reassoc_delay; - u8 *mbo_pos = mbo; - - ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason, - &reassoc_delay, &cell_pref); - if (ret != 3) { - wpa_printf(MSG_DEBUG, - "MBO requires three arguments: mbo=::"); - ret = -1; - goto fail; - } - - if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) { - wpa_printf(MSG_DEBUG, - "Invalid MBO transition reason code %u", - mbo_reason); - ret = -1; - goto fail; - } - - /* Valid values for Cellular preference are: 0, 1, 255 */ - if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) { - wpa_printf(MSG_DEBUG, - "Invalid MBO cellular capability %u", - cell_pref); - ret = -1; - goto fail; - } - - if (reassoc_delay > 65535 || - (reassoc_delay && - !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) { - wpa_printf(MSG_DEBUG, - "MBO: Assoc retry delay is only valid in disassoc imminent mode"); - ret = -1; - goto fail; - } - - *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON; - *mbo_pos++ = 1; - *mbo_pos++ = mbo_reason; - *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF; - *mbo_pos++ = 1; - *mbo_pos++ = cell_pref; - - if (reassoc_delay) { - *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY; - *mbo_pos++ = 2; - WPA_PUT_LE16(mbo_pos, reassoc_delay); - mbo_pos += 2; - } - - mbo_len = mbo_pos - mbo; - } -#endif /* CONFIG_MBO */ - - ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, - valid_int, bss_term_dur, dialog_token, url, - nei_len ? nei_rep : NULL, nei_len, - mbo_len ? mbo : NULL, mbo_len); -#ifdef CONFIG_MBO -fail: -#endif /* CONFIG_MBO */ - os_free(url); - return ret; -} - - static int hostapd_ctrl_iface_coloc_intf_req(struct hostapd_data *hapd, const char *cmd) { @@ -1090,6 +864,12 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd, return pos - buf; pos += ret; } + if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) { + ret = os_snprintf(pos, end - pos, "FT-SAE-EXT-KEY "); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } #endif /* CONFIG_SAE */ #ifdef CONFIG_FILS if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) { @@ -1125,6 +905,12 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd, return pos - buf; pos += ret; } + if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) { + ret = os_snprintf(pos, end - pos, "SAE-EXT-KEY "); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } #endif /* CONFIG_SAE */ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B "); @@ -1172,6 +958,14 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd, pos += ret; } #endif /* CONFIG_DPP */ +#ifdef CONFIG_SHA384 + if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) { + ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA384 "); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_SHA384 */ if (pos > buf && *(pos - 1) == ' ') { *(pos - 1) = '\0'; @@ -1200,6 +994,14 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, return pos - buf; pos += ret; + if ((hapd->conf->config_id)) { + ret = os_snprintf(pos, end - pos, "config_id=%s\n", + hapd->conf->config_id); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + #ifdef CONFIG_WPS ret = os_snprintf(pos, end - pos, "wps_state=%s\n", hapd->conf->wps_state == 0 ? "disabled" : @@ -1362,43 +1164,6 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, } -static void hostapd_disassoc_accept_mac(struct hostapd_data *hapd) -{ - struct sta_info *sta; - struct vlan_description vlan_id; - - if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED) - return; - - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (!hostapd_maclist_found(hapd->conf->accept_mac, - hapd->conf->num_accept_mac, - sta->addr, &vlan_id) || - (vlan_id.notempty && - vlan_compare(&vlan_id, sta->vlan_desc))) - ap_sta_disconnect(hapd, sta, sta->addr, - WLAN_REASON_UNSPECIFIED); - } -} - - -void hostapd_disassoc_deny_mac(struct hostapd_data *hapd) -{ - struct sta_info *sta; - struct vlan_description vlan_id; - - for (sta = hapd->sta_list; sta; sta = sta->next) { - if (hostapd_maclist_found(hapd->conf->deny_mac, - hapd->conf->num_deny_mac, sta->addr, - &vlan_id) && - (!vlan_id.notempty || - !vlan_compare(&vlan_id, sta->vlan_desc))) - ap_sta_disconnect(hapd, sta, sta->addr, - WLAN_REASON_UNSPECIFIED); - } -} - - static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd, const char *bands) { @@ -1518,6 +1283,9 @@ int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) { os_free(hapd->dpp_configurator_params); hapd->dpp_configurator_params = os_strdup(value); +#ifdef CONFIG_DPP2 + dpp_controller_set_params(hapd->iface->interfaces->dpp, value); +#endif /* CONFIG_DPP2 */ } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) { hapd->dpp_init_max_tries = atoi(value); } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) { @@ -1540,6 +1308,8 @@ int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) hostapd_disassoc_deny_mac(hapd); } else if (os_strcasecmp(cmd, "accept_mac_file") == 0) { hostapd_disassoc_accept_mac(hapd); + } else if (os_strcasecmp(cmd, "ssid") == 0) { + hostapd_neighbor_sync_own_report(hapd); } else if (os_strncmp(cmd, "wme_ac_", 7) == 0 || os_strncmp(cmd, "wmm_ac_", 7) == 0) { hapd->parameter_set_count++; @@ -1626,6 +1396,16 @@ static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface) } +static int hostapd_ctrl_iface_reload_bss(struct hostapd_data *bss) +{ + if (hostapd_reload_bss_only(bss) < 0) { + wpa_printf(MSG_ERROR, "Reloading of BSS failed"); + return -1; + } + return 0; +} + + int hostapd_ctrl_iface_disable(struct hostapd_iface *iface) { if (hostapd_disable_iface(iface) < 0) { @@ -1654,7 +1434,7 @@ hostapd_ctrl_iface_kick_mismatch_psk_sta_iter(struct hostapd_data *hapd, pmk_match = PMK_LEN == pmk_len && os_memcmp(psk->psk, pmk, pmk_len) == 0; sta_match = psk->group == 0 && - os_memcmp(sta->addr, psk->addr, ETH_ALEN) == 0; + ether_addr_equal(sta->addr, psk->addr); bss_match = psk->group == 1; if (pmk_match && (sta_match || bss_match)) @@ -1693,6 +1473,79 @@ static int hostapd_ctrl_iface_reload_wpa_psk(struct hostapd_data *hapd) } +#ifdef CONFIG_IEEE80211R_AP + +static int hostapd_ctrl_iface_get_rxkhs(struct hostapd_data *hapd, + char *buf, size_t buflen) +{ + int ret, start_pos; + char *pos, *end; + struct ft_remote_r0kh *r0kh; + struct ft_remote_r1kh *r1kh; + struct hostapd_bss_config *conf = hapd->conf; + + pos = buf; + end = buf + buflen; + + for (r0kh = conf->r0kh_list; r0kh; r0kh=r0kh->next) { + start_pos = pos - buf; + ret = os_snprintf(pos, end - pos, "r0kh=" MACSTR " ", + MAC2STR(r0kh->addr)); + if (os_snprintf_error(end - pos, ret)) + return start_pos; + pos += ret; + if (r0kh->id_len + 1 >= (size_t) (end - pos)) + return start_pos; + os_memcpy(pos, r0kh->id, r0kh->id_len); + pos += r0kh->id_len; + *pos++ = ' '; + pos += wpa_snprintf_hex(pos, end - pos, r0kh->key, + sizeof(r0kh->key)); + ret = os_snprintf(pos, end - pos, "\n"); + if (os_snprintf_error(end - pos, ret)) + return start_pos; + pos += ret; + } + + for (r1kh = conf->r1kh_list; r1kh; r1kh=r1kh->next) { + start_pos = pos - buf; + ret = os_snprintf(pos, end - pos, "r1kh=" MACSTR " " MACSTR " ", + MAC2STR(r1kh->addr), MAC2STR(r1kh->id)); + if (os_snprintf_error(end - pos, ret)) + return start_pos; + pos += ret; + pos += wpa_snprintf_hex(pos, end - pos, r1kh->key, + sizeof(r1kh->key)); + ret = os_snprintf(pos, end - pos, "\n"); + if (os_snprintf_error(end - pos, ret)) + return start_pos; + pos += ret; + } + + return pos - buf; +} + + +static int hostapd_ctrl_iface_reload_rxkhs(struct hostapd_data *hapd) +{ + struct hostapd_bss_config *conf = hapd->conf; + int err; + + hostapd_config_clear_rxkhs(conf); + + err = hostapd_config_read_rxkh_file(conf, conf->rxkh_file); + if (err < 0) { + wpa_printf(MSG_ERROR, "Reloading RxKHs failed: %d", + err); + return -1; + } + + return 0; +} + +#endif /* CONFIG_IEEE80211R_AP */ + + #ifdef CONFIG_TESTING_OPTIONS static int hostapd_ctrl_iface_radar(struct hostapd_data *hapd, char *cmd) @@ -1944,7 +1797,7 @@ static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd) return -1; } - ieee802_1x_receive(hapd, src, buf, len); + ieee802_1x_receive(hapd, src, buf, len, FRAME_ENCRYPTION_UNKNOWN); os_free(buf); return 0; @@ -2069,6 +1922,7 @@ static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd, int enabled = atoi(cmd); char *pos; const char *ifname; + const u8 *addr = hapd->own_addr; if (!enabled) { if (hapd->l2_test) { @@ -2089,7 +1943,11 @@ static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd, else ifname = hapd->conf->iface; - hapd->l2_test = l2_packet_init(ifname, hapd->own_addr, +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) + addr = hapd->mld->mld_addr; +#endif /* CONFIG_IEEE80211BE */ + hapd->l2_test = l2_packet_init(ifname, addr, ETHERTYPE_IP, hostapd_data_test_rx, hapd, 1); if (hapd->l2_test == NULL) @@ -2228,74 +2086,6 @@ done: } -static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd) -{ -#ifdef WPA_TRACE_BFD - char *pos; - - wpa_trace_fail_after = atoi(cmd); - pos = os_strchr(cmd, ':'); - if (pos) { - pos++; - os_strlcpy(wpa_trace_fail_func, pos, - sizeof(wpa_trace_fail_func)); - } else { - wpa_trace_fail_after = 0; - } - - return 0; -#else /* WPA_TRACE_BFD */ - return -1; -#endif /* WPA_TRACE_BFD */ -} - - -static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd, - char *buf, size_t buflen) -{ -#ifdef WPA_TRACE_BFD - return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after, - wpa_trace_fail_func); -#else /* WPA_TRACE_BFD */ - return -1; -#endif /* WPA_TRACE_BFD */ -} - - -static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd) -{ -#ifdef WPA_TRACE_BFD - char *pos; - - wpa_trace_test_fail_after = atoi(cmd); - pos = os_strchr(cmd, ':'); - if (pos) { - pos++; - os_strlcpy(wpa_trace_test_fail_func, pos, - sizeof(wpa_trace_test_fail_func)); - } else { - wpa_trace_test_fail_after = 0; - } - - return 0; -#else /* WPA_TRACE_BFD */ - return -1; -#endif /* WPA_TRACE_BFD */ -} - - -static int hostapd_ctrl_get_fail(struct hostapd_data *hapd, - char *buf, size_t buflen) -{ -#ifdef WPA_TRACE_BFD - return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after, - wpa_trace_test_fail_func); -#else /* WPA_TRACE_BFD */ - return -1; -#endif /* WPA_TRACE_BFD */ -} - - static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd) { struct sta_info *sta; @@ -2667,8 +2457,46 @@ static int hostapd_ctrl_register_frame(struct hostapd_data *hapd, #ifdef NEED_AP_MLME -static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params) +static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params, + u16 punct_bitmap) { + u32 start_freq; + + if (is_6ghz_freq(params->freq)) { + const int bw_idx[] = { 20, 40, 80, 160, 320 }; + int idx, bw; + + /* The 6 GHz band requires HE to be enabled. */ + params->he_enabled = 1; + + if (params->center_freq1) { + if (params->freq == 5935) + idx = (params->center_freq1 - 5925) / 5; + else + idx = (params->center_freq1 - 5950) / 5; + + bw = center_idx_to_bw_6ghz(idx); + if (bw < 0 || bw > (int) ARRAY_SIZE(bw_idx) || + bw_idx[bw] != params->bandwidth) + return -1; + } + } else { /* Non-6 GHz channel */ + /* An EHT STA is also an HE STA as defined in + * IEEE P802.11be/D5.0, 4.3.16a. */ + if (params->he_enabled || params->eht_enabled) { + params->he_enabled = 1; + /* An HE STA is also a VHT STA if operating in the 5 GHz + * band and an HE STA is also an HT STA in the 2.4 GHz + * band as defined in IEEE Std 802.11ax-2021, 4.3.15a. + * A VHT STA is an HT STA as defined in IEEE + * Std 802.11, 4.3.15. */ + if (IS_5GHZ(params->freq)) + params->vht_enabled = 1; + + params->ht_enabled = 1; + } + } + switch (params->bandwidth) { case 0: /* bandwidth not specified: use 20 MHz by default */ @@ -2680,11 +2508,17 @@ static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params) if (params->center_freq2 || params->sec_channel_offset) return -1; - break; + + if (punct_bitmap) + return -1; + break; case 40: if (params->center_freq2 || !params->sec_channel_offset) return -1; + if (punct_bitmap) + return -1; + if (!params->center_freq1) break; switch (params->sec_channel_offset) { @@ -2719,6 +2553,9 @@ static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params) return -1; } + if (params->center_freq2 && punct_bitmap) + return -1; + /* Adjacent and overlapped are not allowed for 80+80 */ if (params->center_freq2 && params->center_freq1 - params->center_freq2 <= 80 && @@ -2749,10 +2586,63 @@ static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params) return -1; } break; + case 320: + if (!params->center_freq1 || params->center_freq2 || + !params->sec_channel_offset) + return -1; + + switch (params->sec_channel_offset) { + case 1: + if (params->freq + 150 != params->center_freq1 && + params->freq + 110 != params->center_freq1 && + params->freq + 70 != params->center_freq1 && + params->freq + 30 != params->center_freq1 && + params->freq - 10 != params->center_freq1 && + params->freq - 50 != params->center_freq1 && + params->freq - 90 != params->center_freq1 && + params->freq - 130 != params->center_freq1) + return -1; + break; + case -1: + if (params->freq + 130 != params->center_freq1 && + params->freq + 90 != params->center_freq1 && + params->freq + 50 != params->center_freq1 && + params->freq + 10 != params->center_freq1 && + params->freq - 30 != params->center_freq1 && + params->freq - 70 != params->center_freq1 && + params->freq - 110 != params->center_freq1 && + params->freq - 150 != params->center_freq1) + return -1; + break; + } + break; default: return -1; } + if (!punct_bitmap) + return 0; + + if (!params->eht_enabled) { + wpa_printf(MSG_ERROR, + "Preamble puncturing supported only in EHT"); + return -1; + } + + if (params->freq >= 2412 && params->freq <= 2484) { + wpa_printf(MSG_ERROR, + "Preamble puncturing is not supported in 2.4 GHz"); + return -1; + } + + start_freq = params->center_freq1 - (params->bandwidth / 2); + if (!is_punct_bitmap_valid(params->bandwidth, + (params->freq - start_freq) / 20, + punct_bitmap)) { + wpa_printf(MSG_ERROR, "Invalid preamble puncturing bitmap"); + return -1; + } + return 0; } #endif /* NEED_AP_MLME */ @@ -2768,12 +2658,21 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface, unsigned int i; int bandwidth; u8 chan; + unsigned int num_err = 0; + int err = 0; ret = hostapd_parse_csa_settings(pos, &settings); if (ret) return ret; - ret = hostapd_ctrl_check_freq_params(&settings.freq_params); + settings.link_id = -1; +#ifdef CONFIG_IEEE80211BE + if (iface->num_bss && iface->bss[0]->conf->mld_ap) + settings.link_id = iface->bss[0]->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ + + ret = hostapd_ctrl_check_freq_params(&settings.freq_params, + settings.punct_bitmap); if (ret) { wpa_printf(MSG_INFO, "chanswitch: invalid frequency settings provided"); @@ -2793,6 +2692,9 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface, case 160: bandwidth = CHAN_WIDTH_160; break; + case 320: + bandwidth = CHAN_WIDTH_320; + break; default: bandwidth = CHAN_WIDTH_20; break; @@ -2831,29 +2733,271 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface, settings.freq_params.center_freq1); /* Perform CAC and switch channel */ + iface->is_ch_switch_dfs = true; hostapd_switch_channel_fallback(iface, &settings.freq_params); return 0; } for (i = 0; i < iface->num_bss; i++) { - /* Save CHAN_SWITCH VHT and HE config */ + /* Save CHAN_SWITCH VHT, HE, and EHT config */ hostapd_chan_switch_config(iface->bss[i], &settings.freq_params); - ret = hostapd_switch_channel(iface->bss[i], &settings); - if (ret) { - /* FIX: What do we do if CSA fails in the middle of - * submitting multi-BSS CSA requests? */ - return ret; + err = hostapd_switch_channel(iface->bss[i], &settings); + if (err) { + ret = err; + num_err++; } } + return (iface->num_bss == num_err) ? ret : 0; +#else /* NEED_AP_MLME */ + return -1; +#endif /* NEED_AP_MLME */ +} + + +#ifdef CONFIG_IEEE80211AX +static int hostapd_ctrl_iface_color_change(struct hostapd_iface *iface, + const char *pos) +{ +#ifdef NEED_AP_MLME + struct cca_settings settings; + struct hostapd_data *hapd = iface->bss[0]; + int ret, color; + unsigned int i; + char *end; + + os_memset(&settings, 0, sizeof(settings)); + + color = strtol(pos, &end, 10); + if (pos == end || color < 0 || color > 63) { + wpa_printf(MSG_ERROR, "color_change: Invalid color provided"); + return -1; + } + + /* Color value is expected to be [1-63]. If 0 comes, assumption is this + * is to disable the color. In this case no need to do CCA, just + * changing Beacon frames is sufficient. */ + if (color == 0) { + if (iface->conf->he_op.he_bss_color_disabled) { + wpa_printf(MSG_ERROR, + "color_change: Color is already disabled"); + return -1; + } + + iface->conf->he_op.he_bss_color_disabled = 1; + + for (i = 0; i < iface->num_bss; i++) + ieee802_11_set_beacon(iface->bss[i]); + + return 0; + } + + if (color == iface->conf->he_op.he_bss_color) { + if (!iface->conf->he_op.he_bss_color_disabled) { + wpa_printf(MSG_ERROR, + "color_change: Provided color is already set"); + return -1; + } + + iface->conf->he_op.he_bss_color_disabled = 0; + + for (i = 0; i < iface->num_bss; i++) + ieee802_11_set_beacon(iface->bss[i]); + + return 0; + } + + if (hapd->cca_in_progress) { + wpa_printf(MSG_ERROR, + "color_change: CCA is already in progress"); + return -1; + } + + iface->conf->he_op.he_bss_color_disabled = 0; + + for (i = 0; i < iface->num_bss; i++) { + struct hostapd_data *bss = iface->bss[i]; + + hostapd_cleanup_cca_params(bss); + + bss->cca_color = color; + bss->cca_count = 10; + + if (hostapd_fill_cca_settings(bss, &settings)) { + wpa_printf(MSG_DEBUG, + "color_change: Filling CCA settings failed for color: %d\n", + color); + hostapd_cleanup_cca_params(bss); + continue; + } + + wpa_printf(MSG_DEBUG, "Setting user selected color: %d", color); + ret = hostapd_drv_switch_color(bss, &settings); + if (ret) + hostapd_cleanup_cca_params(bss); + + free_beacon_data(&settings.beacon_cca); + free_beacon_data(&settings.beacon_after); + } + return 0; #else /* NEED_AP_MLME */ return -1; #endif /* NEED_AP_MLME */ } +#endif /* CONFIG_IEEE80211AX */ + + +static u8 hostapd_maxnss(struct hostapd_data *hapd, struct sta_info *sta) +{ + u8 *mcs_set = NULL; + u16 mcs_map; + u8 ht_rx_nss = 0; + u8 vht_rx_nss = 1; + u8 mcs; + bool ht_supported = false; + bool vht_supported = false; + int i; + + if (sta->ht_capabilities && (sta->flags & WLAN_STA_HT)) { + mcs_set = sta->ht_capabilities->supported_mcs_set; + ht_supported = true; + } + + if (sta->vht_capabilities && (sta->flags & WLAN_STA_VHT)) { + mcs_map = le_to_host16( + sta->vht_capabilities->vht_supported_mcs_set.rx_map); + vht_supported = true; + } + + if (ht_supported && mcs_set) { + if (mcs_set[0]) + ht_rx_nss++; + if (mcs_set[1]) + ht_rx_nss++; + if (mcs_set[2]) + ht_rx_nss++; + if (mcs_set[3]) + ht_rx_nss++; + } + if (vht_supported) { + for (i = 7; i >= 0; i--) { + mcs = (mcs_map >> (2 * i)) & 0x03; + if (mcs != 0x03) { + vht_rx_nss = i + 1; + break; + } + } + } + + return ht_rx_nss > vht_rx_nss ? ht_rx_nss : vht_rx_nss; +} + + +static char hostapd_ctrl_iface_notify_cw_htaction(struct hostapd_data *hapd, + const u8 *addr, u8 width) +{ + u8 buf[3]; + char ret; + + width = width >= 1 ? 1 : 0; + + buf[0] = WLAN_ACTION_HT; + buf[1] = WLAN_HT_ACTION_NOTIFY_CHANWIDTH; + buf[2] = width; + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + buf, sizeof(buf)); + if (ret) + wpa_printf(MSG_DEBUG, + "Failed to send Notify Channel Width frame to " + MACSTR, MAC2STR(addr)); + + return ret; +} + + +static char hostapd_ctrl_iface_notify_cw_vhtaction(struct hostapd_data *hapd, + const u8 *addr, u8 width) +{ + u8 buf[3]; + char ret; + + buf[0] = WLAN_ACTION_VHT; + buf[1] = WLAN_VHT_ACTION_OPMODE_NOTIF; + buf[2] = width; + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + buf, sizeof(buf)); + if (ret) + wpa_printf(MSG_DEBUG, + "Failed to send Opeating Mode Notification frame to " + MACSTR, MAC2STR(addr)); + + return ret; +} + + +static char hostapd_ctrl_iface_notify_cw_change(struct hostapd_data *hapd, + const char *cmd) +{ + u8 cw, operating_mode = 0, nss; + struct sta_info *sta; + enum hostapd_hw_mode hw_mode; + + if (is_6ghz_freq(hapd->iface->freq)) { + wpa_printf(MSG_ERROR, "20/40 BSS coex not supported in 6 GHz"); + return -1; + } + + cw = atoi(cmd); + hw_mode = hapd->iface->current_mode->mode; + if ((hw_mode == HOSTAPD_MODE_IEEE80211G || + hw_mode == HOSTAPD_MODE_IEEE80211B) && + !(cw == 0 || cw == 1)) { + wpa_printf(MSG_ERROR, + "Channel width should be either 20 MHz or 40 MHz for 2.4 GHz band"); + return -1; + } + + switch (cw) { + case 0: + operating_mode = 0; + break; + case 1: + operating_mode = VHT_OPMODE_CHANNEL_40MHZ; + break; + case 2: + operating_mode = VHT_OPMODE_CHANNEL_80MHZ; + break; + case 3: + operating_mode = VHT_OPMODE_CHANNEL_160MHZ; + break; + default: + wpa_printf(MSG_ERROR, "Channel width should be between 0 to 3"); + return -1; + } + + for (sta = hapd->sta_list; sta; sta = sta->next) { + if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) { + nss = hostapd_maxnss(hapd, sta) - 1; + hostapd_ctrl_iface_notify_cw_vhtaction(hapd, sta->addr, + operating_mode | + (u8) (nss << 4)); + continue; + } + + if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) == + WLAN_STA_HT && sta->ht_capabilities) + hostapd_ctrl_iface_notify_cw_htaction(hapd, sta->addr, + cw); + } + + return 0; +} static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply, @@ -3174,6 +3318,26 @@ static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd, } +static int hostapd_ctrl_iface_req_link_measurement(struct hostapd_data *hapd, + const char *cmd, char *reply, + size_t reply_size) +{ + u8 addr[ETH_ALEN]; + int ret; + + if (hwaddr_aton(cmd, addr)) { + wpa_printf(MSG_ERROR, + "CTRL: REQ_LINK_MEASUREMENT: Invalid MAC address"); + return -1; + } + + ret = hostapd_send_link_measurement_req(hapd, addr); + if (ret >= 0) + ret = os_snprintf(reply, reply_size, "%d", ret); + return ret; +} + + static int hostapd_ctrl_iface_show_neighbor(struct hostapd_data *hapd, char *buf, size_t buflen) { @@ -3382,80 +3546,6 @@ static int hostapd_ctrl_driver_flags2(struct hostapd_iface *iface, char *buf, } -int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num, - const char *txtaddr) -{ - u8 addr[ETH_ALEN]; - struct vlan_description vlan_id; - - if (!(*num)) - return 0; - - if (hwaddr_aton(txtaddr, addr)) - return -1; - - if (hostapd_maclist_found(*acl, *num, addr, &vlan_id)) - hostapd_remove_acl_mac(acl, num, addr); - - return 0; -} - - -static void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl, - int *num) -{ - while (*num) - hostapd_remove_acl_mac(acl, num, (*acl)[0].addr); -} - - -static int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num, - char *buf, size_t buflen) -{ - int i = 0, len = 0, ret = 0; - - if (!acl) - return 0; - - while (i < num) { - ret = os_snprintf(buf + len, buflen - len, - MACSTR " VLAN_ID=%d\n", - MAC2STR(acl[i].addr), - acl[i].vlan_id.untagged); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - i++; - len += ret; - } - return len; -} - - -int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num, - const char *cmd) -{ - u8 addr[ETH_ALEN]; - struct vlan_description vlan_id; - int ret = 0, vlanid = 0; - const char *pos; - - if (hwaddr_aton(cmd, addr)) - return -1; - - pos = os_strstr(cmd, "VLAN_ID="); - if (pos) - vlanid = atoi(pos + 8); - - if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) { - ret = hostapd_add_acl_maclist(acl, num, vlanid, addr); - if (ret != -1 && *acl) - qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); - } - - return ret < 0 ? -1 : 0; -} - - static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd, const char *field, char *buf, size_t buflen) @@ -3503,6 +3593,395 @@ static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd, #endif /* ANDROID */ +#ifdef CONFIG_IEEE80211BE + +static int hostapd_ctrl_iface_enable_mld(struct hostapd_iface *iface) +{ + unsigned int i; + + if (!iface || !iface->bss[0]->conf->mld_ap) { + wpa_printf(MSG_ERROR, + "Trying to enable AP MLD on an interface that is not affiliated with an AP MLD"); + return -1; + } + + for (i = 0; i < iface->interfaces->count; ++i) { + struct hostapd_iface *h_iface = iface->interfaces->iface[i]; + struct hostapd_data *h_hapd = h_iface->bss[0]; + + if (!hostapd_is_ml_partner(h_hapd, iface->bss[0])) + continue; + + if (hostapd_enable_iface(h_iface)) { + wpa_printf(MSG_ERROR, "Enabling of AP MLD failed"); + return -1; + } + } + return 0; +} + + +static void hostapd_disable_iface_bss(struct hostapd_iface *iface) +{ + unsigned int i; + + for (i = 0; i < iface->num_bss; i++) + hostapd_bss_deinit_no_free(iface->bss[i]); +} + + +static int hostapd_ctrl_iface_disable_mld(struct hostapd_iface *iface) +{ + unsigned int i; + + if (!iface || !iface->bss[0]->conf->mld_ap) { + wpa_printf(MSG_ERROR, + "Trying to disable AP MLD on an interface that is not affiliated with an AP MLD."); + return -1; + } + + /* First, disable BSSs before stopping beaconing and doing driver + * deinit so that the broadcast Deauthentication frames go out. */ + + for (i = 0; i < iface->interfaces->count; ++i) { + struct hostapd_iface *h_iface = iface->interfaces->iface[i]; + struct hostapd_data *h_hapd = h_iface->bss[0]; + + if (!hostapd_is_ml_partner(h_hapd, iface->bss[0])) + continue; + + hostapd_disable_iface_bss(iface); + } + + /* Then, fully disable interfaces */ + for (i = 0; i < iface->interfaces->count; ++i) { + struct hostapd_iface *h_iface = iface->interfaces->iface[i]; + struct hostapd_data *h_hapd = h_iface->bss[0]; + + if (!hostapd_is_ml_partner(h_hapd, iface->bss[0])) + continue; + + if (hostapd_disable_iface(h_iface)) { + wpa_printf(MSG_ERROR, "Disabling AP MLD failed"); + return -1; + } + } + + return 0; +} + + +#ifdef CONFIG_TESTING_OPTIONS +static int hostapd_ctrl_iface_link_remove(struct hostapd_data *hapd, char *cmd, + char *buf, size_t buflen) +{ + int ret; + u32 count = atoi(cmd); + + if (!count) + count = 1; + + ret = hostapd_link_remove(hapd, count); + if (ret == 0) { + ret = os_snprintf(buf, buflen, "%s\n", "OK"); + if (os_snprintf_error(buflen, ret)) + ret = -1; + else + ret = 0; + } + + return ret; +} +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_IEEE80211BE */ + + +#ifdef CONFIG_NAN_USD + +static int hostapd_ctrl_nan_publish(struct hostapd_data *hapd, char *cmd, + char *buf, size_t buflen) +{ + char *token, *context = NULL; + int publish_id; + struct nan_publish_params params; + const char *service_name = NULL; + struct wpabuf *ssi = NULL; + int ret = -1; + enum nan_service_protocol_type srv_proto_type = 0; + + os_memset(¶ms, 0, sizeof(params)); + /* USD shall use both solicited and unsolicited transmissions */ + params.unsolicited = true; + params.solicited = true; + /* USD shall require FSD without GAS */ + params.fsd = true; + + while ((token = str_token(cmd, " ", &context))) { + if (os_strncmp(token, "service_name=", 13) == 0) { + service_name = token + 13; + continue; + } + + if (os_strncmp(token, "ttl=", 4) == 0) { + params.ttl = atoi(token + 4); + continue; + } + + if (os_strncmp(token, "srv_proto_type=", 15) == 0) { + srv_proto_type = atoi(token + 15); + continue; + } + + if (os_strncmp(token, "ssi=", 4) == 0) { + if (ssi) + goto fail; + ssi = wpabuf_parse_bin(token + 4); + if (!ssi) + goto fail; + continue; + } + + if (os_strcmp(token, "solicited=0") == 0) { + params.solicited = false; + continue; + } + + if (os_strcmp(token, "unsolicited=0") == 0) { + params.unsolicited = false; + continue; + } + + if (os_strcmp(token, "fsd=0") == 0) { + params.fsd = false; + continue; + } + + wpa_printf(MSG_INFO, "CTRL: Invalid NAN_PUBLISH parameter: %s", + token); + goto fail; + } + + publish_id = hostapd_nan_usd_publish(hapd, service_name, srv_proto_type, + ssi, ¶ms); + if (publish_id > 0) + ret = os_snprintf(buf, buflen, "%d", publish_id); +fail: + wpabuf_free(ssi); + return ret; +} + + +static int hostapd_ctrl_nan_cancel_publish(struct hostapd_data *hapd, + char *cmd) +{ + char *token, *context = NULL; + int publish_id = 0; + + while ((token = str_token(cmd, " ", &context))) { + if (sscanf(token, "publish_id=%i", &publish_id) == 1) + continue; + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_CANCEL_PUBLISH parameter: %s", + token); + return -1; + } + + if (publish_id <= 0) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_CANCEL_PUBLISH publish_id"); + return -1; + } + + hostapd_nan_usd_cancel_publish(hapd, publish_id); + return 0; +} + + +static int hostapd_ctrl_nan_update_publish(struct hostapd_data *hapd, + char *cmd) +{ + char *token, *context = NULL; + int publish_id = 0; + struct wpabuf *ssi = NULL; + int ret = -1; + + while ((token = str_token(cmd, " ", &context))) { + if (sscanf(token, "publish_id=%i", &publish_id) == 1) + continue; + if (os_strncmp(token, "ssi=", 4) == 0) { + if (ssi) + goto fail; + ssi = wpabuf_parse_bin(token + 4); + if (!ssi) + goto fail; + continue; + } + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_UPDATE_PUBLISH parameter: %s", + token); + goto fail; + } + + if (publish_id <= 0) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_UPDATE_PUBLISH publish_id"); + goto fail; + } + + ret = hostapd_nan_usd_update_publish(hapd, publish_id, ssi); +fail: + wpabuf_free(ssi); + return ret; +} + + +static int hostapd_ctrl_nan_subscribe(struct hostapd_data *hapd, char *cmd, + char *buf, size_t buflen) +{ + char *token, *context = NULL; + int subscribe_id; + struct nan_subscribe_params params; + const char *service_name = NULL; + struct wpabuf *ssi = NULL; + int ret = -1; + enum nan_service_protocol_type srv_proto_type = 0; + + os_memset(¶ms, 0, sizeof(params)); + + while ((token = str_token(cmd, " ", &context))) { + if (os_strncmp(token, "service_name=", 13) == 0) { + service_name = token + 13; + continue; + } + + if (os_strcmp(token, "active=1") == 0) { + params.active = true; + continue; + } + + if (os_strncmp(token, "ttl=", 4) == 0) { + params.ttl = atoi(token + 4); + continue; + } + + if (os_strncmp(token, "srv_proto_type=", 15) == 0) { + srv_proto_type = atoi(token + 15); + continue; + } + + if (os_strncmp(token, "ssi=", 4) == 0) { + if (ssi) + goto fail; + ssi = wpabuf_parse_bin(token + 4); + if (!ssi) + goto fail; + continue; + } + + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_SUBSCRIBE parameter: %s", + token); + goto fail; + } + + subscribe_id = hostapd_nan_usd_subscribe(hapd, service_name, + srv_proto_type, ssi, + ¶ms); + if (subscribe_id > 0) + ret = os_snprintf(buf, buflen, "%d", subscribe_id); +fail: + wpabuf_free(ssi); + return ret; +} + + +static int hostapd_ctrl_nan_cancel_subscribe(struct hostapd_data *hapd, + char *cmd) +{ + char *token, *context = NULL; + int subscribe_id = 0; + + while ((token = str_token(cmd, " ", &context))) { + if (sscanf(token, "subscribe_id=%i", &subscribe_id) == 1) + continue; + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_CANCEL_SUBSCRIBE parameter: %s", + token); + return -1; + } + + if (subscribe_id <= 0) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_CANCEL_SUBSCRIBE subscribe_id"); + return -1; + } + + hostapd_nan_usd_cancel_subscribe(hapd, subscribe_id); + return 0; +} + + +static int hostapd_ctrl_nan_transmit(struct hostapd_data *hapd, char *cmd) +{ + char *token, *context = NULL; + int handle = 0; + int req_instance_id = 0; + struct wpabuf *ssi = NULL; + u8 peer_addr[ETH_ALEN]; + int ret = -1; + + os_memset(peer_addr, 0, ETH_ALEN); + + while ((token = str_token(cmd, " ", &context))) { + if (sscanf(token, "handle=%i", &handle) == 1) + continue; + + if (sscanf(token, "req_instance_id=%i", &req_instance_id) == 1) + continue; + + if (os_strncmp(token, "address=", 8) == 0) { + if (hwaddr_aton(token + 8, peer_addr) < 0) + return -1; + continue; + } + + if (os_strncmp(token, "ssi=", 4) == 0) { + if (ssi) + goto fail; + ssi = wpabuf_parse_bin(token + 4); + if (!ssi) + goto fail; + continue; + } + + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_TRANSMIT parameter: %s", + token); + goto fail; + } + + if (handle <= 0) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_TRANSMIT handle"); + goto fail; + } + + if (is_zero_ether_addr(peer_addr)) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_TRANSMIT address"); + goto fail; + } + + ret = hostapd_nan_usd_transmit(hapd, handle, ssi, NULL, peer_addr, + req_instance_id); +fail: + wpabuf_free(ssi); + return ret; +} + +#endif /* CONFIG_NAN_USD */ + + static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, char *buf, char *reply, int reply_size, @@ -3520,6 +3999,8 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "RELOG", 5) == 0) { if (wpa_debug_reopen_file() < 0) reply_len = -1; + } else if (os_strcmp(buf, "CLOSE_LOG") == 0) { + wpa_debug_stop_log(); } else if (os_strncmp(buf, "NOTE ", 5) == 0) { wpa_printf(MSG_INFO, "NOTE: %s", buf + 5); } else if (os_strcmp(buf, "STATUS") == 0) { @@ -3685,16 +4166,30 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "GET ", 4) == 0) { reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply, reply_size); - } else if (os_strncmp(buf, "ENABLE", 6) == 0) { + } else if (os_strcmp(buf, "ENABLE") == 0) { if (hostapd_ctrl_iface_enable(hapd->iface)) reply_len = -1; } else if (os_strcmp(buf, "RELOAD_WPA_PSK") == 0) { if (hostapd_ctrl_iface_reload_wpa_psk(hapd)) reply_len = -1; - } else if (os_strncmp(buf, "RELOAD", 6) == 0) { +#ifdef CONFIG_IEEE80211R_AP + } else if (os_strcmp(buf, "GET_RXKHS") == 0) { + reply_len = hostapd_ctrl_iface_get_rxkhs(hapd, reply, + reply_size); + } else if (os_strcmp(buf, "RELOAD_RXKHS") == 0) { + if (hostapd_ctrl_iface_reload_rxkhs(hapd)) + reply_len = -1; +#endif /* CONFIG_IEEE80211R_AP */ + } else if (os_strcmp(buf, "RELOAD_BSS") == 0) { + if (hostapd_ctrl_iface_reload_bss(hapd)) + reply_len = -1; + } else if (os_strcmp(buf, "RELOAD_CONFIG") == 0) { + if (hostapd_reload_config(hapd->iface)) + reply_len = -1; + } else if (os_strcmp(buf, "RELOAD") == 0) { if (hostapd_ctrl_iface_reload(hapd->iface)) reply_len = -1; - } else if (os_strncmp(buf, "DISABLE", 7) == 0) { + } else if (os_strcmp(buf, "DISABLE") == 0) { if (hostapd_ctrl_iface_disable(hapd->iface)) reply_len = -1; } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) { @@ -3730,16 +4225,15 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0) reply_len = -1; } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) { - if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0) + if (testing_set_fail_pattern(true, buf + 16) < 0) reply_len = -1; } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) { - reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply, - reply_size); + reply_len = testing_get_fail_pattern(true, reply, reply_size); } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) { - if (hostapd_ctrl_test_fail(hapd, buf + 10) < 0) + if (testing_set_fail_pattern(false, buf + 10) < 0) reply_len = -1; } else if (os_strcmp(buf, "GET_FAIL") == 0) { - reply_len = hostapd_ctrl_get_fail(hapd, reply, reply_size); + reply_len = testing_get_fail_pattern(false, reply, reply_size); } else if (os_strncmp(buf, "RESET_PN ", 9) == 0) { if (hostapd_ctrl_reset_pn(hapd, buf + 9) < 0) reply_len = -1; @@ -3771,6 +4265,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) reply_len = -1; +#ifdef CONFIG_IEEE80211AX + } else if (os_strncmp(buf, "COLOR_CHANGE ", 13) == 0) { + if (hostapd_ctrl_iface_color_change(hapd->iface, buf + 13)) + reply_len = -1; +#endif /* CONFIG_IEEE80211AX */ + } else if (os_strncmp(buf, "NOTIFY_CW_CHANGE ", 17) == 0) { + if (hostapd_ctrl_iface_notify_cw_change(hapd, buf + 17)) + reply_len = -1; } else if (os_strncmp(buf, "VENDOR ", 7) == 0) { reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply, reply_size); @@ -3819,6 +4321,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "REQ_BEACON ", 11) == 0) { reply_len = hostapd_ctrl_iface_req_beacon(hapd, buf + 11, reply, reply_size); + } else if (os_strncmp(buf, "REQ_LINK_MEASUREMENT ", 21) == 0) { + reply_len = hostapd_ctrl_iface_req_link_measurement( + hapd, buf + 21, reply, reply_size); } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) { reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply, reply_size); @@ -3831,14 +4336,15 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) { if (hostapd_ctrl_iface_acl_add_mac( &hapd->conf->accept_mac, - &hapd->conf->num_accept_mac, buf + 19)) + &hapd->conf->num_accept_mac, buf + 19) || + hostapd_set_acl(hapd)) reply_len = -1; } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) { - if (!hostapd_ctrl_iface_acl_del_mac( + if (hostapd_ctrl_iface_acl_del_mac( &hapd->conf->accept_mac, - &hapd->conf->num_accept_mac, buf + 19)) - hostapd_disassoc_accept_mac(hapd); - else + &hapd->conf->num_accept_mac, buf + 19) || + hostapd_set_acl(hapd) || + hostapd_disassoc_accept_mac(hapd)) reply_len = -1; } else if (os_strcmp(buf + 11, "SHOW") == 0) { reply_len = hostapd_ctrl_iface_acl_show_mac( @@ -3848,20 +4354,25 @@ 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); + if (hostapd_set_acl(hapd) || + hostapd_disassoc_accept_mac(hapd)) + reply_len = -1; + } else { + reply_len = -1; } } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) { if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) { - if (!hostapd_ctrl_iface_acl_add_mac( + if (hostapd_ctrl_iface_acl_add_mac( &hapd->conf->deny_mac, - &hapd->conf->num_deny_mac, buf + 17)) - hostapd_disassoc_deny_mac(hapd); - else + &hapd->conf->num_deny_mac, buf + 17) || + hostapd_set_acl(hapd) || + hostapd_disassoc_deny_mac(hapd)) reply_len = -1; } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) { if (hostapd_ctrl_iface_acl_del_mac( &hapd->conf->deny_mac, - &hapd->conf->num_deny_mac, buf + 17)) + &hapd->conf->num_deny_mac, buf + 17) || + hostapd_set_acl(hapd)) reply_len = -1; } else if (os_strcmp(buf + 9, "SHOW") == 0) { reply_len = hostapd_ctrl_iface_acl_show_mac( @@ -3871,6 +4382,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, hostapd_ctrl_iface_acl_clear_list( &hapd->conf->deny_mac, &hapd->conf->num_deny_mac); + if (hostapd_set_acl(hapd)) + reply_len = -1; + } else { + reply_len = -1; } #ifdef CONFIG_DPP } else if (os_strncmp(buf, "DPP_QR_CODE ", 12) == 0) { @@ -3962,6 +4477,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, if (os_snprintf_error(reply_size, reply_len)) reply_len = -1; } + } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SET ", 21) == 0) { + if (dpp_configurator_set(hapd->iface->interfaces->dpp, + buf + 20) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) { if (dpp_configurator_remove(hapd->iface->interfaces->dpp, buf + 24) < 0) @@ -4000,8 +4519,41 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, reply_len = -1; } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) { hostapd_dpp_chirp_stop(hapd); + } else if (os_strncmp(buf, "DPP_RELAY_ADD_CONTROLLER ", 25) == 0) { + if (hostapd_dpp_add_controller(hapd, buf + 25) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DPP_RELAY_REMOVE_CONTROLLER ", 28) == 0) { + hostapd_dpp_remove_controller(hapd, buf + 28); #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + } else if (os_strcmp(buf, "DPP_PUSH_BUTTON") == 0) { + if (hostapd_dpp_push_button(hapd, NULL) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DPP_PUSH_BUTTON ", 16) == 0) { + if (hostapd_dpp_push_button(hapd, buf + 15) < 0) + reply_len = -1; +#endif /* CONFIG_DPP3 */ #endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + } else if (os_strncmp(buf, "NAN_PUBLISH ", 12) == 0) { + reply_len = hostapd_ctrl_nan_publish(hapd, buf + 12, reply, + reply_size); + } else if (os_strncmp(buf, "NAN_CANCEL_PUBLISH ", 19) == 0) { + if (hostapd_ctrl_nan_cancel_publish(hapd, buf + 19) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "NAN_UPDATE_PUBLISH ", 19) == 0) { + if (hostapd_ctrl_nan_update_publish(hapd, buf + 19) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "NAN_SUBSCRIBE ", 14) == 0) { + reply_len = hostapd_ctrl_nan_subscribe(hapd, buf + 14, reply, + reply_size); + } else if (os_strncmp(buf, "NAN_CANCEL_SUBSCRIBE ", 21) == 0) { + if (hostapd_ctrl_nan_cancel_subscribe(hapd, buf + 21) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "NAN_TRANSMIT ", 13) == 0) { + if (hostapd_ctrl_nan_transmit(hapd, buf + 13) < 0) + reply_len = -1; +#endif /* CONFIG_NAN_USD */ #ifdef RADIUS_SERVER } else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) { if (radius_server_dac_request(hapd->radius_srv, buf + 12) < 0) @@ -4019,6 +4571,20 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply, reply_size); #endif /* ANDROID */ +#ifdef CONFIG_IEEE80211BE + } else if (os_strcmp(buf, "ENABLE_MLD") == 0) { + if (hostapd_ctrl_iface_enable_mld(hapd->iface)) + reply_len = -1; + } else if (os_strcmp(buf, "DISABLE_MLD") == 0) { + if (hostapd_ctrl_iface_disable_mld(hapd->iface)) + reply_len = -1; +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strncmp(buf, "LINK_REMOVE ", 12) == 0) { + if (hostapd_ctrl_iface_link_remove(hapd, buf + 12, + reply, reply_size)) + reply_len = -1; +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_IEEE80211BE */ } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; @@ -4512,6 +5078,20 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces) #ifdef CONFIG_DPP dpp_global_clear(interfaces->dpp); +#ifdef CONFIG_DPP3 + interfaces->dpp_pb_bi = NULL; + { + int i; + + for (i = 0; i < DPP_PB_INFO_COUNT; i++) { + struct dpp_pb_info *info; + + info = &interfaces->dpp_pb[i]; + info->rx_time.sec = 0; + info->rx_time.usec = 0; + } + } +#endif /* CONFIG_DPP3 */ #endif /* CONFIG_DPP */ } @@ -4917,7 +5497,7 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, reply_len = -1; } else if (os_strncmp(buf, "INTERFACES", 10) == 0) { reply_len = hostapd_global_ctrl_iface_interfaces( - interfaces, buf + 10, reply, sizeof(buffer)); + interfaces, buf + 10, reply, reply_size); } else if (os_strcmp(buf, "TERMINATE") == 0) { eloop_terminate(); } else { diff --git a/wpa_supplicant-2.9_standard/hostapd/ap_ctrl_iface.h b/wpa_supplicant-2.9_standard/hostapd/ap_ctrl_iface.h index a78f92c0e8be5fe6289eac1e4a19b92108f002e2..5f442b8b1fdeebb05406f145075c068453bc1de3 100644 --- a/wpa_supplicant-2.9_standard/hostapd/ap_ctrl_iface.h +++ b/wpa_supplicant-2.9_standard/hostapd/ap_ctrl_iface.h @@ -12,20 +12,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + #ifndef AP_CTRL_IFACE_H #define AP_CTRL_IFACE_H - + int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd); - -int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num, - const char *cmd); int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num, const char *txtaddr); -void hostapd_disassoc_deny_mac(struct hostapd_data *hapd); - int hostapd_ctrl_iface_enable(struct hostapd_iface *iface); int hostapd_ctrl_iface_disable(struct hostapd_iface *iface); diff --git a/wpa_supplicant-2.9_standard/hostapd/ap_main.c b/wpa_supplicant-2.9_standard/hostapd/ap_main.c index 0bf23a03828ec5b710bc6a241c9a0ae87c7d17d4..0a3ed3eb763345141b8d6043e23930bb2cf218b7 100644 --- a/wpa_supplicant-2.9_standard/hostapd/ap_main.c +++ b/wpa_supplicant-2.9_standard/hostapd/ap_main.c @@ -15,6 +15,7 @@ #include "utils/common.h" #include "utils/eloop.h" #include "utils/uuid.h" +#include "crypto/crypto.h" #include "crypto/random.h" #include "crypto/tls.h" #include "common/version.h" @@ -160,11 +161,47 @@ static int hostapd_driver_init(struct hostapd_iface *iface) struct hostapd_bss_config *conf = hapd->conf; u8 *b = conf->bssid; struct wpa_driver_capa capa; +#ifdef CONFIG_IEEE80211BE + struct hostapd_data *h_hapd = NULL; +#endif /* CONFIG_IEEE80211BE */ if (hapd->driver == NULL || hapd->driver->hapd_init == NULL || global.drv_count == 0) { wpa_printf(MSG_ERROR, "No hostapd driver wrapper available"); return -1; } + +#ifdef CONFIG_IEEE80211BE + if (conf->mld_ap) + h_hapd = hostapd_mld_get_first_bss(hapd); + + if (h_hapd) { + hapd->drv_priv = h_hapd->drv_priv; + hapd->interface_added = h_hapd->interface_added; + + /* + * All interfaces participating in the AP MLD would have + * the same MLD address, which is the interface hardware + * address, while the interface address would be + * derived from the original interface address if BSSID + * is not configured, and otherwise it would be the + * configured BSSID. + */ + if (is_zero_ether_addr(b)) { + os_memcpy(hapd->own_addr, h_hapd->mld->mld_addr, + ETH_ALEN); + random_mac_addr_keep_oui(hapd->own_addr); + } else { + os_memcpy(hapd->own_addr, b, ETH_ALEN); + } + + hostapd_mld_add_link(hapd); + wpa_printf(MSG_DEBUG, + "Setup of non first link (%d) BSS of MLD %s", + hapd->mld_link_id, hapd->conf->iface); + + goto setup_mld; + } +#endif /* CONFIG_IEEE80211BE */ if (hapd->conf == NULL) { wpa_printf(MSG_ERROR, "hapd->conf == NULL"); return -1; @@ -177,7 +214,7 @@ static int hostapd_driver_init(struct hostapd_iface *iface) } /* Initialize the driver interface */ - if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5])) + if (is_zero_ether_addr(b)) b = NULL; os_memset(¶ms, 0, sizeof(params)); @@ -201,6 +238,19 @@ static int hostapd_driver_init(struct hostapd_iface *iface) break; } params.bssid = b; +#ifdef CONFIG_IEEE80211BE + /* + * Use the configured MLD MAC address as the interface hardware address + * if this AP is a part of an AP MLD. + */ + if (hapd->conf->mld_ap) { + if (!is_zero_ether_addr(hapd->conf->mld_addr)) + params.bssid = hapd->conf->mld_addr; + else + params.bssid = NULL; + } +#endif /* CONFIG_IEEE80211BE */ + params.ifname = hapd->conf->iface; params.driver_params = hapd->iconf->driver_params; params.use_pae_group_addr = hapd->conf->use_pae_group_addr; @@ -226,12 +276,36 @@ static int hostapd_driver_init(struct hostapd_iface *iface) return -1; } +#ifdef CONFIG_IEEE80211BE + /* + * This is the first interface added to the AP MLD, so have the + * interface hardware address be the MLD address, while the link address + * would be derived from the original interface address if BSSID is not + * configured, and otherwise it would be the configured BSSID. + */ + if (hapd->conf->mld_ap) { + os_memcpy(hapd->mld->mld_addr, hapd->own_addr, ETH_ALEN); + + if (!b) + random_mac_addr_keep_oui(hapd->own_addr); + else + os_memcpy(hapd->own_addr, b, ETH_ALEN); + + hostapd_mld_add_link(hapd); + wpa_printf(MSG_DEBUG, "Setup of first link (%d) BSS of MLD %s", + hapd->mld_link_id, hapd->conf->iface); + } + +setup_mld: +#endif /* CONFIG_IEEE80211BE */ + if (hapd->driver->get_capa && hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) { struct wowlan_triggers *triggs; iface->drv_flags = capa.flags; iface->drv_flags2 = capa.flags2; + iface->drv_rrm_flags = capa.rrm_flags; iface->probe_resp_offloads = capa.probe_resp_offloads; /* * Use default extended capa values from per-radio information @@ -247,13 +321,40 @@ static int hostapd_driver_init(struct hostapd_iface *iface) */ hostapd_get_ext_capa(iface); + hostapd_get_mld_capa(iface); + triggs = wpa_get_wowlan_triggers(conf->wowlan_triggers, &capa); if (triggs && hapd->driver->set_wowlan) { if (hapd->driver->set_wowlan(hapd->drv_priv, triggs)) wpa_printf(MSG_ERROR, "set_wowlan failed"); } os_free(triggs); + + iface->mbssid_max_interfaces = capa.mbssid_max_interfaces; + iface->ema_max_periodicity = capa.ema_max_periodicity; + } + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) { + if (!(iface->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)) { + wpa_printf(MSG_INFO, + "MLD: Not supported by the driver"); + return -1; + } + + /* Initialize the BSS parameter change to 1 */ + hapd->eht_mld_bss_param_change = 1; + + wpa_printf(MSG_DEBUG, + "MLD: Set link_id=%u, mld_addr=" MACSTR + ", own_addr=" MACSTR, + hapd->mld_link_id, MAC2STR(hapd->mld->mld_addr), + MAC2STR(hapd->own_addr)); + + hostapd_drv_link_add(hapd, hapd->mld_link_id, + hapd->own_addr); } +#endif /* CONFIG_IEEE80211BE */ return 0; } @@ -475,7 +576,7 @@ static void show_version(void) "hostapd v%s\n" "User space daemon for IEEE 802.11 AP management,\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" - "Copyright (c) 2002-2022, Jouni Malinen " + "Copyright (c) 2002-2024, Jouni Malinen " "and contributors\n", VERSION_STR); } @@ -486,7 +587,7 @@ static void usage(void) show_version(); fprintf(stderr, "\n" - "usage: hostapd [-hdBKtv] [-P ] [-e ] " + "usage: hostapd [-hdBKtvq] [-P ] [-e ] " "\\\n" " [-g ] [-G ]\\\n" " [-i ]\\\n" @@ -514,7 +615,8 @@ static void usage(void) #endif /* CONFIG_DEBUG_SYSLOG */ " -S start all the interfaces synchronously\n" " -t include timestamps in some debug messages\n" - " -v show hostapd version\n"); + " -v show hostapd version\n" + " -q show less debug messages (-qq for even less)\n"); exit(1); } @@ -654,6 +756,30 @@ static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx) hostapd_for_each_interface(interfaces, hostapd_periodic_call, NULL); } + +static void hostapd_global_cleanup_mld(struct hapd_interfaces *interfaces) +{ +#ifdef CONFIG_IEEE80211BE + size_t i; + + if (!interfaces || !interfaces->mld) + return; + + for (i = 0; i < interfaces->mld_count; i++) { + if (!interfaces->mld[i]) + continue; + + os_free(interfaces->mld[i]); + interfaces->mld[i] = NULL; + } + + os_free(interfaces->mld); + interfaces->mld = NULL; + interfaces->mld_count = 0; +#endif /* CONFIG_IEEE80211BE */ +} + + void set_running_hostap(); __attribute__ ((visibility ("default"))) int ap_main(int argc, char *argv[]) @@ -712,7 +838,7 @@ __attribute__ ((visibility ("default"))) int ap_main(int argc, char *argv[]) #endif /* CONFIG_DPP */ for (;;) { - c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:"); + c = getopt(argc, argv, "b:Bde:f:hi:KP:sSTtu:vg:G:q"); if (c < 0) break; switch (c) { @@ -751,7 +877,6 @@ __attribute__ ((visibility ("default"))) int ap_main(int argc, char *argv[]) case 'v': show_version(); exit(1); - break; case 'g': if (hostapd_get_global_ctrl_iface(&interfaces, optarg)) return -1; @@ -786,6 +911,9 @@ __attribute__ ((visibility ("default"))) int ap_main(int argc, char *argv[]) &if_names_size, optarg)) goto out; break; + case 'q': + wpa_debug_level++; + break; default: usage(); break; @@ -941,6 +1069,8 @@ __attribute__ ((visibility ("default"))) int ap_main(int argc, char *argv[]) interfaces.iface = NULL; interfaces.count = 0; + hostapd_global_cleanup_mld(&interfaces); + #ifdef CONFIG_DPP dpp_global_deinit(interfaces.dpp); #endif /* CONFIG_DPP */ @@ -963,6 +1093,7 @@ __attribute__ ((visibility ("default"))) int ap_main(int argc, char *argv[]) fst_global_deinit(); + crypto_unload(); os_program_deinit(); return ret; @@ -971,4 +1102,4 @@ __attribute__ ((visibility ("default"))) int ap_main(int argc, char *argv[]) struct hostapd_data* getHostapd() { return gHostapd; -} +} \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/hostapd/config_file.h b/wpa_supplicant-2.9_standard/hostapd/config_file.h index 9830f5a2232f6d4d0ab0a86ec9254825a31d9a38..9ef6ac82913013ca494333806dcdab9e68d0c600 100644 --- a/wpa_supplicant-2.9_standard/hostapd/config_file.h +++ b/wpa_supplicant-2.9_standard/hostapd/config_file.h @@ -10,13 +10,10 @@ #define CONFIG_FILE_H struct hostapd_config * hostapd_config_read(const char *fname); +int hostapd_config_read_rxkh_file(struct hostapd_bss_config *conf, + const char *fname); int hostapd_set_iface(struct hostapd_config *conf, struct hostapd_bss_config *bss, const char *field, char *value); -int hostapd_acl_comp(const void *a, const void *b); -int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num, - int vlan_id, const u8 *addr); -void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num, - const u8 *addr); #endif /* CONFIG_FILE_H */ diff --git a/wpa_supplicant-2.9_standard/hostapd/defconfig b/wpa_supplicant-2.9_standard/hostapd/defconfig index 6b50b6c59b462734831339220c2326a72c877b68..550db697bc0ad99febbb2874f383623db55769fb 100644 --- a/wpa_supplicant-2.9_standard/hostapd/defconfig +++ b/wpa_supplicant-2.9_standard/hostapd/defconfig @@ -141,6 +141,9 @@ CONFIG_PKCS12=y # Build IPv6 support for RADIUS operations CONFIG_IPV6=y +# Include support fo RADIUS/TLS into the RADIUS client +#CONFIG_RADIUS_TLS=y + # IEEE Std 802.11r-2008 (Fast BSS Transition) #CONFIG_IEEE80211R=y @@ -156,10 +159,20 @@ CONFIG_IPV6=y #CONFIG_IEEE80211AC=y # IEEE 802.11ax HE support +#CONFIG_IEEE80211AX=y + +# IEEE 802.11be EHT support +# CONFIG_IEEE80211AX is mandatory for setting CONFIG_IEEE80211BE. # Note: This is experimental and work in progress. The definitions are still # subject to change and this should not be expected to interoperate with the -# final IEEE 802.11ax version. -#CONFIG_IEEE80211AX=y +# final IEEE 802.11be version. +#CONFIG_IEEE80211BE=y + +# Simultaneous Authentication of Equals (SAE), WPA3-Personal +#CONFIG_SAE=y + +# SAE Public Key, WPA3-Personal +#CONFIG_SAE_PK=y # Remove debugging code that is printing out debug messages to stdout. # This can be used to reduce the size of the hostapd considerably if debugging @@ -400,7 +413,6 @@ CONFIG_IPV6=y # Experimental implementation based on IEEE P802.11z/D2.6 and the protocol # design is still subject to change. As such, this should not yet be enabled in # production use. -# This requires CONFIG_IEEE80211W=y to be enabled, too. #CONFIG_PASN=y # Device Provisioning Protocol (DPP) (also known as Wi-Fi Easy Connect) @@ -410,3 +422,6 @@ CONFIG_DPP2=y # DPP version 3 support (experimental and still changing; do not enable for # production use) #CONFIG_DPP3=y + +# Wi-Fi Aware unsynchronized service discovery (NAN USD) +#CONFIG_NAN_USD=y diff --git a/wpa_supplicant-2.9_standard/hostapd/hostapd.conf b/wpa_supplicant-2.9_standard/hostapd/hostapd.conf index 3c2019f730485f4047566a95fd4eb8230cbfb4db..d875d5fc63b05af8994db2c692c64d849dac4045 100644 --- a/wpa_supplicant-2.9_standard/hostapd/hostapd.conf +++ b/wpa_supplicant-2.9_standard/hostapd/hostapd.conf @@ -225,6 +225,16 @@ channel=1 # Default behavior is to include all PSC and non-PSC channels. #acs_exclude_6ghz_non_psc=1 +# Enable background radar feature +# This feature allows CAC to be run on dedicated radio RF chains while the +# radio(s) are otherwise running normal AP activities on other channels. +# This requires that the driver and the radio support it before feature will +# actually be enabled, i.e., this parameter value is ignored with drivers that +# do not advertise support for the capability. +# 0: Leave disabled (default) +# 1: Enable it. +#enable_background_radar=1 + # Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection. # (default 0, i.e., not constraint) #min_tx_power=20 @@ -512,6 +522,25 @@ wmm_ac_vo_acm=0 # even if they are still in range of the AP. This can be done by setting # skip_inactivity_poll to 1 (default 0). #skip_inactivity_poll=0 +# +# BSS max idle period management +# 0 = disabled (do not advertise and manage BSS max idle period) +# 1 = enabled (advertise and manage BSS max idle period; default) +# 2 = enabled requiring protected frames (advertise and manage BSS max idle +# period and require STAs to use protected keep-alive frames) +#bss_max_idle=1 +# +# Maximum acceptable BSS maximum idle period +# If this is set to a nonzero value, the AP allows STAs to request different +# maximum idle period values. This is in the units to 1000 TUs (1.024 s) +#max_acceptable_idle_period=600 +# +# Allow STA to skip group key handshake without getting disconnection when +# BSS max idle period management is enabled. +# 0 = disconnect STA if it does not reply to group key handshake (default) +# 1 = do not disconnect STA if it does not reply to group key handshake and +# if BSS max idle period management is enabled +#no_disconnect_on_group_keyerror=0 # Disassociate stations based on excessive transmission failures or other # indications of connection loss. This depends on the driver capabilities and @@ -636,6 +665,12 @@ wmm_ac_vo_acm=0 # no co-existence issues with neighboring devices are found. #obss_interval=0 +# ht_vht_twt_responder: Whether TWT responder is enabled in HT and VHT modes +# 0 = disable; Disable TWT responder support in HT and VHT modes (default). +# 1 = enable; Enable TWT responder support in HT and VHT modes if supported by +# the driver. +#ht_vht_twt_responder=0 + ##### IEEE 802.11ac related configuration ##################################### # ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled @@ -802,6 +837,9 @@ wmm_ac_vo_acm=0 # 1 = enabled #ieee80211ax=1 +# Require stations to support HE PHY (reject association if they do not) +#require_he=1 + # disable_11ax: Boolean (0/1) to disable HE for a specific BSS #disable_11ax=0 @@ -861,7 +899,7 @@ wmm_ac_vo_acm=0 # he_oper_chwidth is ignored, and the channel width is derived from the # configured operating class or center frequency indexes (see # IEEE P802.11ax/D6.1 Annex E, Table E-4). -#he_oper_chwidth +#he_oper_chwidth (see vht_oper_chwidth) #he_oper_centr_freq_seg0_idx #he_oper_centr_freq_seg1_idx @@ -965,6 +1003,25 @@ wmm_ac_vo_acm=0 # (default) #he_6ghz_tx_ant_pat=1 +# 6 GHz Access Point type +# This config is to set the 6 GHz Access Point type. Possible options are: +# 0 = Indoor AP +# 1 = Standard power AP +# 2 = Very low power AP (default) +# 3 = Indoor enabled AP +# 4 = Indoor standard power AP +# This has no impact for operation on other bands. +# See IEEE P802.11-REVme/D4.0, Table E-12 (Regulatory Info subfield encoding) +# for more details. +#he_6ghz_reg_pwr_type=0 +# +# 6 GHz Maximum Tx Power used in Transmit Power Envelope elements, where the +# "Transmit Power Interpretation" is set to "Regulatory client EIRP PSD". +# For Maximum Transmit Power Category subfield encoding set to default (0): +#reg_def_cli_eirp_psd=-1 +# For Maximum Transmit Power Category subfield encoding set to subordinate (1): +#reg_sub_cli_eirp_psd=-1 + # Unsolicited broadcast Probe Response transmission settings # This is for the 6 GHz band only. If the interval is set to a non-zero value, # the AP schedules unsolicited broadcast Probe Response frames to be @@ -973,6 +1030,78 @@ wmm_ac_vo_acm=0 # Valid range: 0..20 TUs; default is 0 (disabled) #unsol_bcast_probe_resp_interval=0 +##### IEEE 802.11be related configuration ##################################### + +#ieee80211be: Whether IEEE 802.11be (EHT) is enabled +# 0 = disabled (default) +# 1 = enabled +#ieee80211be=1 + +#disable_11be: Boolean (0/1) to disable EHT for a specific BSS +#disable_11be=0 + +#eht_su_beamformer: EHT single user beamformer support +# 0 = not supported (default) +# 1 = supported +#eht_su_beamformer=1 + +#eht_su_beamformee: EHT single user beamformee support +# 0 = not supported (default) +# 1 = supported +#eht_su_beamformee=1 + +#eht_mu_beamformer: EHT multiple user beamformer support +# 0 = not supported (default) +# 1 = supported +#eht_mu_beamformer=1 + +# EHT operating channel information; see matching he_* parameters for details. +# The field eht_oper_centr_freq_seg0_idx field is used to indicate center +# frequency of 40, 80, and 160 MHz bandwidth operation. +# In the 6 GHz band, eht_oper_chwidth is ignored and the channel width is +# derived from the configured operating class (IEEE P802.11be/D1.5, +# Annex E.1 - Country information and operating classes). +#eht_oper_chwidth (see vht_oper_chwidth) +#eht_oper_centr_freq_seg0_idx + +#eht_default_pe_duration: The duration of PE field in EHT TB PPDU +# 0 = PE field duration is the same as he_default_pe_duration (default) +# 1 = PE field duration is 20 us +#eht_default_pe_duration=0 + +#eht_bw320_offset: For automatic channel selection (ACS) to indicate a preferred +# 320 MHz channelization in EHT mode. +# If the channel is decided or the bandwidth is not 320 MHz, this option is +# meaningless. +# 0 = auto-detect by hostapd +# 1 = 320 MHz-1 (channel center frequency 31, 95, 159) +# 2 = 320 MHz-2 (channel center frequency 63, 127, 191) +#eht_bw320_offset=0 + +# Disabled subchannel bitmap (16 bits) as per IEEE P802.11be/3.0, +# Figure 9-1002c (EHT Operation Information field format). Each bit corresponds +# to a 20 MHz channel, the lowest bit corresponds to the lowest frequency. A +# bit set to 1 indicates that the channel is punctured (disabled). The default +# value is 0 indicating that all channels are active. +#punct_bitmap=0 + +# Preamble puncturing threshold in automatic channel selection (ACS). +# The value indicates the percentage of ideal channel average interference +# factor above which a channel should be punctured. +# Default is 0, indicates that ACS algorithm should not puncture any channel. +#punct_acs_threshold=75 + +# AP MLD - Whether this AP is a part of an AP MLD +# 0 = no (no MLO) +# 1 = yes (MLO) +#mld_ap=0 + +# AP MLD MAC address +# The configured address will be set as the interface hardware address and used +# as the AP MLD MAC address. If not set, the current interface hardware address +# will be used as the AP MLD MAC address. +#mld_addr=02:03:04:05:06:07 + ##### IEEE 802.1X-2004 related configuration ################################## # Require IEEE 802.1X authorization @@ -1063,6 +1192,14 @@ eapol_key_index_workaround=0 # 0: No replay window, strict check (default) # 1..2^32-1: number of packets that could be misordered # +# macsec_offload: IEEE 802.1X/MACsec hardware offload +# This setting applies only when MACsec is in use, i.e., +# - macsec_policy is enabled +# - the key server has decided to enable MACsec +# 0 = MACSEC_OFFLOAD_OFF (default) +# 1 = MACSEC_OFFLOAD_PHY +# 2 = MACSEC_OFFLOAD_MAC +# # macsec_port: IEEE 802.1X/MACsec port # Port component of the SCI # Range: 1-65534 (default: 1) @@ -1070,6 +1207,10 @@ eapol_key_index_workaround=0 # mka_priority (Priority of MKA Actor) # Range: 0..255 (default: 255) # +# macsec_csindex: IEEE 802.1X/MACsec cipher suite +# 0 = GCM-AES-128 (default) +# 1 = GCM-AES-256 (default) +# # mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode # This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair. # In this mode, instances of hostapd can act as MACsec peers. The peer @@ -1243,12 +1384,11 @@ eap_server=0 # dh_file: File path to DH/DSA parameters file (in PEM format) # This is an optional configuration file for setting parameters for an -# ephemeral DH key exchange. In most cases, the default RSA authentication does -# not use this configuration. However, it is possible setup RSA to use -# ephemeral DH key exchange. In addition, ciphers with DSA keys always use -# ephemeral DH keys. This can be used to achieve forward secrecy. If the file -# is in DSA parameters format, it will be automatically converted into DH -# params. This parameter is required if anonymous EAP-FAST is used. +# ephemeral DH key exchange. If the file is in DSA parameters format, it will +# be automatically converted into DH params. If the used TLS library supports +# automatic DH parameter selection, that functionality will be used if this +# parameter is not set. DH parameters are required if anonymous EAP-FAST is +# used. # You can generate DH parameters file with OpenSSL, e.g., # "openssl dhparam -out /etc/hostapd.dh.pem 2048" #dh_file=/etc/hostapd.dh.pem @@ -1358,6 +1498,12 @@ eap_server=0 # 5 = require both user and machine identity #eap_teap_id=0 +# EAP-TEAP tunneled EAP method behavior +# 0 = minimize roundtrips by merging start of the next EAP method with the +# crypto-binding of the previous one. +# 1 = complete crypto-binding before starting the next EAP method +#eap_teap_method_sequence=0 + # EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND # (default: 0 = disabled). #eap_sim_aka_result_ind=1 @@ -1367,8 +1513,25 @@ eap_server=0 # 1 = use pseudonyms, but not fast reauthentication # 2 = do not use pseudonyms, but use fast reauthentication # 3 = use pseudonyms and use fast reauthentication (default) +# 4 = do not use pseudonyms or fast reauthentication and allow +# EAP-Response/Identity to be used without method specific identity exchange +# 5 = use pseudonyms, but not fast reauthentication and allow +# EAP-Response/Identity to be used without method specific identity exchange +# 6 = do not use pseudonyms, but use fast reauthentication and allow +# EAP-Response/Identity to be used without method specific identity exchange +# 7 = use pseudonyms and use fast reauthentication and allow +# EAP-Response/Identity to be used without method specific identity exchange #eap_sim_id=3 +# IMSI privacy key (PEM encoded RSA 2048-bit private key) for decrypting +# permanent identity when using EAP-SIM/AKA/AKA'. +#imsi_privacy_key=imsi-privacy-key.pem + +# EAP-SIM and EAP-AKA fast re-authentication limit +# Maximum number of fast re-authentications allowed after each full +# authentication. +#eap_sim_aka_fast_reauth_limit=1000 + # Trusted Network Connect (TNC) # If enabled, TNC validation will be required before the peer is allowed to # connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other @@ -1440,6 +1603,16 @@ own_ip_addr=127.0.0.1 #acct_server_port=1813 #acct_server_shared_secret=secret2 +# RADIUS/TLS instead of RADIUS/UDP +#auth_server_addr=127.0.0.1 +#auth_server_port=2083 +#auth_server_type=TLS +#auth_server_shared_secret=radsec +#auth_server_ca_cert= +#auth_server_client_cert= +#auth_server_private_key= +#auth_server_private_key_passwd= + # Retry interval for trying to return to the primary RADIUS server (in # seconds). RADIUS client code will automatically try to use the next server # when the current server is not replying to requests. If this interval is set, @@ -1447,6 +1620,17 @@ own_ip_addr=127.0.0.1 # currently used secondary server is still working. #radius_retry_primary_interval=600 +# Message-Authenticator attribute requirement for non-EAP cases +# hostapd requires Message-Authenticator attribute to be included in all cases +# where RADIUS is used for EAP authentication. This is also required for cases +# where RADIUS is used for MAC ACL (macaddr_acl=2) by default, but that case +# can be configured to not require this for compatibility with RADIUS servers +# that do not include the attribute. This is not recommended due to potential +# security concerns, but can be used as a temporary workaround in networks where +# the connection to the RADIUS server is secure. +# 0 = Do not require Message-Authenticator in MAC ACL response +# 1 = Require Message-Authenticator in all authentication cases (default) +#radius_require_message_authenticator=1 # Interim accounting update interval # If this is set (larger than 0) and acct_server is configured, hostapd will @@ -1651,12 +1835,19 @@ own_ip_addr=127.0.0.1 #wpa_psk_file=/etc/hostapd.wpa_psk # Optionally, WPA passphrase can be received from RADIUS authentication server -# This requires macaddr_acl to be set to 2 (RADIUS) +# This requires macaddr_acl to be set to 2 (RADIUS) for wpa_psk_radius values +# 1 and 2. # 0 = disabled (default) # 1 = optional; use default passphrase/psk if RADIUS server does not include # Tunnel-Password # 2 = required; reject authentication if RADIUS server does not include # Tunnel-Password +# 3 = ask RADIUS server during 4-way handshake if there is no locally +# configured PSK/passphrase for the STA +# +# The Tunnel-Password attribute in Access-Accept can contain either the +# 8..63 character ASCII passphrase or a 64 hex character encoding of the PSK. +# #wpa_psk_radius=0 # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The @@ -1914,6 +2105,10 @@ own_ip_addr=127.0.0.1 #sae_password=really secret|mac=ff:ff:ff:ff:ff:ff #sae_password=example secret|mac=02:03:04:05:06:07|id=pw identifier #sae_password=example secret|vlanid=3|id=pw identifier +# +# SAE passwords can also be read from a separate file in which each line +# contains and entry in the same format as sae_password uses. +#sae_password_file=/tc/hostapd.sae_passwords # SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold) # This parameter defines how many open SAE instances can be in progress at the @@ -1924,7 +2119,7 @@ own_ip_addr=127.0.0.1 # Maximum number of SAE synchronization errors (dot11RSNASAESync) # The offending SAE peer will be disconnected if more than this many # synchronization errors happen. -#sae_sync=5 +#sae_sync=3 # Enabled SAE finite cyclic groups # SAE implementation are required to support group 19 (ECC group defined over a @@ -2042,6 +2237,8 @@ own_ip_addr=127.0.0.1 # If fils_discovery_max_interval is non-zero, the AP enables FILS Discovery # frame transmission. These values use TUs as the unit and have allowed range # of 0-10000. fils_discovery_min_interval defaults to 20. +# This feature is currently supported only when ieee80211ax is enabled for +# the radio and disable_11ax is not set for the BSS. #fils_discovery_min_interval=20 #fils_discovery_max_interval=0 @@ -2077,6 +2274,30 @@ own_ip_addr=127.0.0.1 # (default: 10 TUs) #pasn_comeback_after=10 +# Unauthenticated PASN activated (dot11NoAuthPASNActivated) +# This indicates whether PASN without mutual authentication is allowed. +# (default: 1 = activated) +#pasn_noauth=1 + +# SSID protection in 4-way handshake +# The IEEE 802.11i-2004 RSN design did not provide means for protecting the +# SSID in the general case. IEEE P802.11REVme/D6.0 added support for this in +# 4-way handshake. This capability allows a STA to confirm that the AP has the +# same understanding on which SSID is being used for an association in a +# protected manner in cases where both the AP and the STA has this capability. +# This can be used to mitigate CVE-2023-52424 (a.k.a. the SSID Confusion +# Attack). +# +# Ideally, this capability would be enabled by default on the AP, but since this +# is new functionality with limited testing, the default is to disable this for +# now and require explicitly configuration to enable. The default behavior is +# like to change once this capability has received more testing. +# +# 0 = SSID protection in 4-way handshake disabled (default) +# 1 = SSID protection in 4-way handshake enabled +# +#ssid_protection=0 + ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) @@ -2136,6 +2357,12 @@ own_ip_addr=127.0.0.1 # list and thus will receive push notifications. #r1kh=00:00:00:00:00:00 00:00:00:00:00:00 00112233445566778899aabbccddeeff +# Optionally, the list of RxKHs can be read from a text file. Format is the same +# as specified above. File shall contain both r0kh and r1kh. Once this variable +# is set, RxKHs can be reloaded at runtime without bringing down an interface +# using the RELOAD_RXKHS command. +#rxkh_file= + # Timeout (seconds) for newly discovered R0KH/R1KH (see wildcard entries above) # Special values: 0 -> do not expire # Warning: do not cache implies no sequence number validation with wildcards @@ -2390,6 +2617,23 @@ own_ip_addr=127.0.0.1 #multi_ap_backhaul_wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef #multi_ap_backhaul_wpa_passphrase=secret passphrase +# Multi-AP Profile +# Indicate the supported Multi-AP profile (default: 2) +# 1 = Supports Multi-AP profile 1 as defined in Wi-Fi EasyMesh specification +# 2 = Supports Multi-AP profile 2 as defined in Wi-Fi EasyMesh specification +#multi_ap_profile=2 + +# Multi-AP client disallow +# Used to disallow profile specific backhaul STA association +# Bitmap of the disallowed Profile-X profiles +# 1 = Profile-1 Backhaul STA association disallowed +# 2 = Profile-2 Backhaul STA association disallowed +#multi_ap_client_disallow=0 + +# Multi-AP VLAN ID +# A valid non-zero VLAN ID will be used to update Default IEEE 802.1Q Setting +#multi_ap_vlanid=0 + # WPS UPnP interface # If set, support for external Registrars is enabled. #upnp_iface=br0 @@ -2453,12 +2697,24 @@ own_ip_addr=127.0.0.1 # MUD URL for Enrollee's DPP Configuration Request (optional) #dpp_mud_url=https://example.com/mud +# JSON node name of additional data for Enrollee's DPP Configuration Request +#dpp_extra_conf_req_name=org.example + +# JSON node data of additional data for Enrollee's DPP Configuration Request +#dpp_extra_conf_req_value="abc":123 + #dpp_connector #dpp_netaccesskey #dpp_netaccesskey_expiry #dpp_csign #dpp_controller +# DPP Relay port number +# TCP port to listen to for incoming connections from a Controller. This can be +# used to allow Controller initiated exchanges in addition to the +# Controller-as-responder cases covered by the dpp_controller parameter. +#dpp_relay_port=12345 + # Configurator Connectivity indication # 0: no Configurator is currently connected (default) # 1: advertise that a Configurator is available @@ -2726,7 +2982,12 @@ own_ip_addr=127.0.0.1 # If the RADIUS server indicates that the station is not allowed to connect to # the BSS/ESS, the AP can allow the station some time to download a # notification page (URL included in the message). This parameter sets that -# timeout in seconds. +# timeout in seconds. If the RADIUS server provides no URL, this value is +# reduced to two seconds with an additional trigger for immediate +# deauthentication when the STA acknowledges reception of the deauthentication +# imminent indication. Note that setting this value to 0 will prevent delivery +# of the notification to the STA, so a value of at least 1 should be used here +# for normal use cases. #hs20_deauth_req_timeout=60 # Operator Friendly Name @@ -2906,6 +3167,9 @@ own_ip_addr=127.0.0.1 # Enable neighbor report via radio measurements #rrm_neighbor_report=1 +# Enable link measurement report via radio measurements +#rrm_link_measurement_report=1 + # Enable beacon report via radio measurements #rrm_beacon_report=1 @@ -3002,6 +3266,18 @@ own_ip_addr=127.0.0.1 # Include only ECSA IE without CSA IE where possible # (channel switch operating class is needed) #ecsa_ie_only=0 +# +# Delay EAPOL-Key messages 1/4 and 3/4 by not sending the frame until the last +# attempt (wpa_pairwise_update_count). This will trigger a timeout on all +# previous attempts and thus delays the frame. (testing only) +#delay_eapol_tx=0 +# +# Additional elements for Probe Response frames. +# This parameter can be used to add additional element(s) to the end of the +# Probe Response frames. The format for these element(s) is a hexdump of the +# raw information elements (id+len+payload for one or more elements). +# These elements are added after the 'vendor_elements'. +#presp_elements= ##### Multiple BSSID support ################################################## # @@ -3045,3 +3321,63 @@ own_ip_addr=127.0.0.1 #bss=wlan0_1 #bssid=00:13:10:95:fe:0b # ... +# +# Multiple BSSID Advertisement in IEEE 802.11ax +# IEEE Std 802.11ax-2021 added a feature where instead of multiple interfaces +# on a common radio transmitting individual Beacon frames, those interfaces can +# form a set with a common Beacon frame transmitted for all. The interface +# which is brought up first is called the transmitting profile of the MBSSID +# set which transmits the Beacon frames. The remaining interfaces are called +# the non-transmitting profiles and these are advertised inside the Multiple +# BSSID element in the Beacon and Probe Response frames from the first +# interface. +# +# The transmitting interface is visible to all stations in the vicinity, however +# the stations that do not support parsing of the Multiple BSSID element will +# not be able to connect to the non-transmitting interfaces. +# +# Enhanced Multiple BSSID Advertisements (EMA) +# When enabled, the non-transmitting interfaces are split into multiple +# Beacon frames. The number of Beacon frames required to cover all the +# non-transmitting profiles is called the profile periodicity. +# +# Refer to IEEE Std 802.11-2020 for details regarding the procedure and +# required MAC address assignment. +# +# Following configuration is per radio. +# 0 = Disabled (default) +# 1 = Multiple BSSID advertisement enabled. +# 2 = Enhanced multiple BSSID advertisement enabled. +#mbssid=0 +# +# The transmitting interface should be added with the 'interface' option while +# the non-transmitting interfaces should be added using the 'bss' option. +# Security configuration should be added separately per interface, if required. +# +# Example: +#mbssid=2 +#interface=wlan2 +#ctrl_interface=/var/run/hostapd +#wpa_passphrase=0123456789 +#ieee80211w=2 +#sae_pwe=1 +#auth_algs=1 +#wpa=2 +#wpa_pairwise=CCMP +#ssid= +#bridge=br-lan +#wpa_key_mgmt=SAE +#bssid=00:03:7f:12:84:84 +# +#bss=wlan2-1 +#ctrl_interface=/var/run/hostapd +#wpa_passphrase=0123456789 +#ieee80211w=2 +#sae_pwe=1 +#auth_algs=1 +#wpa=2 +#wpa_pairwise=CCMP +#ssid= +#bridge=br-lan +#wpa_key_mgmt=SAE +#bssid=00:03:7f:12:84:85 diff --git a/wpa_supplicant-2.9_standard/hostapd/hostapd.eap_user b/wpa_supplicant-2.9_standard/hostapd/hostapd.eap_user index 00edc95af5cd0f3a6b9cb6dd0dd9e453c84b71f6..61ef9375b27645e6058a8c59d3616b3951e9137a 100644 --- a/wpa_supplicant-2.9_standard/hostapd/hostapd.eap_user +++ b/wpa_supplicant-2.9_standard/hostapd/hostapd.eap_user @@ -52,8 +52,8 @@ # Arbitrary RADIUS attributes can be added into Access-Accept packets similarly # to the way radius_auth_req_attr is used for Access-Request packet in # hostapd.conf. For EAP server, this is configured separately for each user -# entry with radius_accept_attr= line(s) following the main user entry -# line. +# entry with radius_accept_attr=[:] line(s) following +# the main user entry line. # Phase 1 users "user" MD5 "password" diff --git a/wpa_supplicant-2.9_standard/hostapd/hostapd_cli.c b/wpa_supplicant-2.9_standard/hostapd/hostapd_cli.c index 2609121116b5e6822fa283eacca1057669ba6b42..eb8a38350bd112da7cccec7a7077229a6258b32a 100644 --- a/wpa_supplicant-2.9_standard/hostapd/hostapd_cli.c +++ b/wpa_supplicant-2.9_standard/hostapd/hostapd_cli.c @@ -21,7 +21,7 @@ static const char *const hostapd_cli_version = "hostapd_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2022, Jouni Malinen and contributors"; +"Copyright (c) 2004-2024, Jouni Malinen and contributors"; static struct wpa_ctrl *ctrl_conn; static int hostapd_cli_quit = 0; @@ -252,6 +252,13 @@ static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[]) } +static int hostapd_cli_cmd_close_log(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "CLOSE_LOG"); +} + + static int hostapd_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc > 0 && os_strcmp(argv[0], "driver") == 0) @@ -307,6 +314,12 @@ static void hostapd_cli_action_process(char *msg, size_t len) } +static void hostapd_cli_action_cb(char *msg, size_t len) +{ + hostapd_cli_action_process(msg, len); +} + + static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char buf[64]; @@ -1155,6 +1168,15 @@ static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[]) #endif /* CONFIG_FST */ +#ifdef CONFIG_IEEE80211AX +static int hostapd_cli_cmd_color_change(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "COLOR_CHANGE", 1, argc, argv); +} +#endif /* CONFIG_IEEE80211AX */ + + static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1169,7 +1191,7 @@ static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl, "arguments (count and freq)\n" "usage: [sec_channel_offset=] " "[center_freq1=] [center_freq2=] [bandwidth=] " - "[blocktx] [ht|vht]\n"); + "[blocktx] [ht|vht|he|eht]\n"); return -1; } @@ -1194,34 +1216,76 @@ static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl, } +static int hostapd_cli_cmd_notify_cw_change(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "NOTIFY_CW_CHANGE", 1, argc, argv); +} + + static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc, - char *argv[]) + char *argv[]) { return wpa_ctrl_command(ctrl, "ENABLE"); } static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc, - char *argv[]) + char *argv[]) { return wpa_ctrl_command(ctrl, "RELOAD"); } -static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc, +static int hostapd_cli_cmd_reload_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RELOAD_BSS"); +} + + +static int hostapd_cli_cmd_reload_config(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RELOAD_CONFIG"); +} + + +static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc, + char *argv[]) { return wpa_ctrl_command(ctrl, "DISABLE"); } -static int hostapd_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc, +static int hostapd_cli_cmd_enable_mld(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return wpa_ctrl_command(ctrl, "ENABLE_MLD"); +} + + +static int hostapd_cli_cmd_disable_mld(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DISABLE_MLD"); +} + + +static int hostapd_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc, + char *argv[]) { return wpa_ctrl_command(ctrl, "UPDATE_BEACON"); } +static int hostapd_cli_cmd_stop_ap(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "STOP_AP"); +} + + static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[]) { char cmd[256]; @@ -1366,6 +1430,13 @@ static int hostapd_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc, } +static int hostapd_cli_cmd_driver_flags2(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DRIVER_FLAGS2"); +} + + #ifdef CONFIG_DPP static int hostapd_cli_cmd_dpp_qr_code(struct wpa_ctrl *ctrl, int argc, @@ -1478,7 +1549,7 @@ static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc, static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv); + return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 0, argc, argv); } @@ -1503,6 +1574,15 @@ static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc, } #endif /* CONFIG_DPP2 */ + + +#ifdef CONFIG_DPP3 +static int hostapd_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 0, argc, argv); +} +#endif /* CONFIG_DPP3 */ #endif /* CONFIG_DPP */ @@ -1534,6 +1614,13 @@ static int hostapd_cli_cmd_req_beacon(struct wpa_ctrl *ctrl, int argc, } +static int hostapd_cli_cmd_req_link_measurement(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "REQ_LINK_MEASUREMENT", 1, argc, argv); +} + + static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1541,6 +1628,24 @@ static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc, } +#ifdef CONFIG_IEEE80211R_AP + +static int hostapd_cli_cmd_get_rxkhs(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "GET_RXKHS"); +} + + +static int hostapd_cli_cmd_reload_rxkhs(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "RELOAD_RXKHS"); +} + +#endif /* CONFIG_IEEE80211R_AP */ + + #ifdef ANDROID static int hostapd_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1563,6 +1668,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { "= get MIB variables (dot1x, dot11, radius)" }, { "relog", hostapd_cli_cmd_relog, NULL, "= reload/truncate debug log output file" }, + { "close_log", hostapd_cli_cmd_close_log, NULL, + "= disable debug log output file" }, { "status", hostapd_cli_cmd_status, NULL, "= show interface status info" }, { "sta", hostapd_cli_cmd_sta, hostapd_complete_stations, @@ -1648,6 +1755,13 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { " [sec_channel_offset=] [center_freq1=]\n" " [center_freq2=] [bandwidth=] [blocktx] [ht|vht]\n" " = initiate channel switch announcement" }, +#ifdef CONFIG_IEEE80211AX + { "color_change", hostapd_cli_cmd_color_change, NULL, + " = initiate BSS color change to set the specified color\n" + "Value 0 will disable the color.\n"}, +#endif /* CONFIG_IEEE80211AX */ + { "notify_cw_change", hostapd_cli_cmd_notify_cw_change, NULL, + " = 0 - 20 MHz, 1 - 40 MHz, 2 - 80 MHz, 3 - 160 MHz" }, { "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL, " \n" " = send WNM-Notification Subscription Remediation Request" }, @@ -1661,10 +1775,20 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { "= enable hostapd on current interface" }, { "reload", hostapd_cli_cmd_reload, NULL, "= reload configuration for current interface" }, + { "reload_bss", hostapd_cli_cmd_reload_bss, NULL, + "= reload configuration for current BSS" }, + { "reload_config", hostapd_cli_cmd_reload_config, NULL, + "= reload configuration for current interface" }, { "disable", hostapd_cli_cmd_disable, NULL, "= disable hostapd on current interface" }, + { "enable_mld", hostapd_cli_cmd_enable_mld, NULL, + "= enable AP MLD to which the interface is affiliated" }, + { "disable_mld", hostapd_cli_cmd_disable_mld, NULL, + "= disable AP MLD to which the interface is affiliated" }, { "update_beacon", hostapd_cli_cmd_update_beacon, NULL, "= update Beacon frame contents\n"}, + { "stop_ap", hostapd_cli_cmd_stop_ap, NULL, + "= stop AP\n"}, { "erp_flush", hostapd_cli_cmd_erp_flush, NULL, "= drop all ERP keys"}, { "log_level", hostapd_cli_cmd_log_level, NULL, @@ -1686,6 +1810,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { " = send FTM range request"}, { "driver_flags", hostapd_cli_cmd_driver_flags, NULL, " = show supported driver flags"}, + { "driver_flags2", hostapd_cli_cmd_driver_flags2, NULL, + " = show supported driver flags2"}, #ifdef CONFIG_DPP { "dpp_qr_code", hostapd_cli_cmd_dpp_qr_code, NULL, "report a scanned DPP URI from a QR Code" }, @@ -1729,6 +1855,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { { "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL, "= stop DPP chirp" }, #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + { "dpp_push_button", hostapd_cli_cmd_dpp_push_button, NULL, + "= press DPP push button" }, +#endif /* CONFIG_DPP3 */ #endif /* CONFIG_DPP */ { "accept_acl", hostapd_cli_cmd_accept_macacl, NULL, "=Add/Delete/Show/Clear accept MAC ACL" }, @@ -1738,8 +1868,16 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { " = poll a STA to check connectivity with a QoS null frame" }, { "req_beacon", hostapd_cli_cmd_req_beacon, NULL, " [req_mode=] = send a Beacon report request to a station" }, + { "req_link_measurement", hostapd_cli_cmd_req_link_measurement, NULL, + " = send a link measurement report request to a station"}, { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL, "= reload wpa_psk_file only" }, +#ifdef CONFIG_IEEE80211R_AP + { "reload_rxkhs", hostapd_cli_cmd_reload_rxkhs, NULL, + "= reload R0KHs and R1KHs" }, + { "get_rxkhs", hostapd_cli_cmd_get_rxkhs, NULL, + "= get R0KHs and R1KHs" }, +#endif /* CONFIG_IEEE80211R_AP */ #ifdef ANDROID { "driver", hostapd_cli_cmd_driver, NULL, " [] = send driver command data" }, @@ -2002,7 +2140,6 @@ static void hostapd_cli_interactive(void) os_snprintf(hfile, hfile_len, "%s/%s", home, fname); } - eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL); edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb, hostapd_cli_edit_completion_cb, NULL, hfile, NULL); eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL); @@ -2026,40 +2163,46 @@ static void hostapd_cli_cleanup(void) } -static void hostapd_cli_action(struct wpa_ctrl *ctrl) +static void hostapd_cli_action_ping(void *eloop_ctx, void *timeout_ctx) { - fd_set rfds; - int fd, res; - struct timeval tv; + struct wpa_ctrl *ctrl = eloop_ctx; char buf[256]; size_t len; - fd = wpa_ctrl_get_fd(ctrl); + /* verify that connection is still working */ + len = sizeof(buf) - 1; + if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, + hostapd_cli_action_cb) < 0 || + len < 4 || os_memcmp(buf, "PONG", 4) != 0) { + printf("hostapd did not reply to PING command - exiting\n"); + eloop_terminate(); + return; + } + eloop_register_timeout(ping_interval, 0, hostapd_cli_action_ping, + ctrl, NULL); +} - while (!hostapd_cli_quit) { - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - tv.tv_sec = ping_interval; - tv.tv_usec = 0; - res = select(fd + 1, &rfds, NULL, NULL, &tv); - if (res < 0 && errno != EINTR) { - perror("select"); - break; - } - if (FD_ISSET(fd, &rfds)) - hostapd_cli_recv_pending(ctrl, 0, 1); - else { - len = sizeof(buf) - 1; - if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len, - hostapd_cli_action_process) < 0 || - len < 4 || os_memcmp(buf, "PONG", 4) != 0) { - printf("hostapd did not reply to PING " - "command - exiting\n"); - break; - } - } - } +static void hostapd_cli_action_receive(int sock, void *eloop_ctx, + void *sock_ctx) +{ + struct wpa_ctrl *ctrl = eloop_ctx; + + hostapd_cli_recv_pending(ctrl, 0, 1); +} + + +static void hostapd_cli_action(struct wpa_ctrl *ctrl) +{ + int fd; + + fd = wpa_ctrl_get_fd(ctrl); + eloop_register_timeout(ping_interval, 0, hostapd_cli_action_ping, + ctrl, NULL); + eloop_register_read_sock(fd, hostapd_cli_action_receive, ctrl, NULL); + eloop_run(); + eloop_cancel_timeout(hostapd_cli_action_ping, ctrl, NULL); + eloop_unregister_read_sock(fd); } @@ -2162,6 +2305,8 @@ int main(int argc, char *argv[]) continue; } + eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL); + if (action_file && !hostapd_cli_attached) return -1; if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue()) diff --git a/wpa_supplicant-2.9_standard/hs20/client/Android.mk b/wpa_supplicant-2.9_standard/hs20/client/Android.mk index e4db32208d506ba668a6da48002acc1e20bdfb95..8d208b25901b0d8ffdcc35a160218212687094e1 100644 --- a/wpa_supplicant-2.9_standard/hs20/client/Android.mk +++ b/wpa_supplicant-2.9_standard/hs20/client/Android.mk @@ -60,6 +60,10 @@ L_CFLAGS += -DEAP_TLS_OPENSSL L_CFLAGS += -Wno-unused-parameter +ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0) +L_CFLAGS += -DCONFIG_ANDROID_LOG +L_CFLAGS += -DANDROID_LOG_NAME='"hs20-osu-client"' +endif ######################## include $(CLEAR_VARS) @@ -68,9 +72,15 @@ LOCAL_MODULE_TAGS := optional LOCAL_SHARED_LIBRARIES := libc libcutils LOCAL_SHARED_LIBRARIES += libcrypto libssl +ifeq ($(shell test $(PLATFORM_VERSION_LAST_STABLE) -ge 8 ; echo $$?), 0) +LOCAL_VENDOR_MODULE := true +LOCAL_SHARED_LIBRARIES += libxml2 +LOCAL_SHARED_LIBRARIES += liblog +else #LOCAL_SHARED_LIBRARIES += libxml2 LOCAL_STATIC_LIBRARIES += libxml2 LOCAL_SHARED_LIBRARIES += libicuuc +endif # End of check for platform version LOCAL_SHARED_LIBRARIES += libcurl LOCAL_CFLAGS := $(L_CFLAGS) diff --git a/wpa_supplicant-2.9_standard/hs20/client/est.c b/wpa_supplicant-2.9_standard/hs20/client/est.c index 97f9132100c46cafaa7e4c908868db3d894a4be5..425b72d18e6a41f95b0a9d67f7d86a0d5ff2329b 100644 --- a/wpa_supplicant-2.9_standard/hs20/client/est.c +++ b/wpa_supplicant-2.9_standard/hs20/client/est.c @@ -11,15 +11,12 @@ #include #include #include -#include #include #include #include #include #include -#ifdef OPENSSL_IS_BORINGSSL -#include -#endif /* OPENSSL_IS_BORINGSSL */ +#include #include "common.h" #include "utils/base64.h" @@ -220,7 +217,7 @@ typedef struct { } d; } AttrOrOID; -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L DEFINE_STACK_OF(AttrOrOID) #endif @@ -340,30 +337,13 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs, if (!csrattrs || ! csrattrs->attrs) return; -#ifdef OPENSSL_IS_BORINGSSL - num = sk_num(CHECKED_CAST(_STACK *, STACK_OF(AttrOrOID) *, - csrattrs->attrs)); - for (i = 0; i < num; i++) { - AttrOrOID *ao = sk_value( - CHECKED_CAST(_STACK *, const STACK_OF(AttrOrOID) *, - csrattrs->attrs), i); - switch (ao->type) { - case 0: - add_csrattrs_oid(ctx, ao->d.oid, exts); - break; - case 1: - add_csrattrs_attr(ctx, ao->d.attribute, exts); - break; - } - } -#else /* OPENSSL_IS_BORINGSSL */ -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L num = sk_AttrOrOID_num(csrattrs->attrs); #else num = SKM_sk_num(AttrOrOID, csrattrs->attrs); #endif for (i = 0; i < num; i++) { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L AttrOrOID *ao = sk_AttrOrOID_value(csrattrs->attrs, i); #else AttrOrOID *ao = SKM_sk_value(AttrOrOID, csrattrs->attrs, i); @@ -377,7 +357,6 @@ static void add_csrattrs(struct hs20_osu_client *ctx, CsrAttrs *csrattrs, break; } } -#endif /* OPENSSL_IS_BORINGSSL */ } @@ -387,7 +366,6 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem, { EVP_PKEY_CTX *pctx = NULL; EVP_PKEY *pkey = NULL; - RSA *rsa; X509_REQ *req = NULL; int ret = -1; unsigned int val; @@ -415,16 +393,11 @@ static int generate_csr(struct hs20_osu_client *ctx, char *key_pem, EVP_PKEY_CTX_free(pctx); pctx = NULL; - rsa = EVP_PKEY_get1_RSA(pkey); - if (rsa == NULL) - goto fail; - if (key_pem) { FILE *f = fopen(key_pem, "wb"); if (f == NULL) goto fail; - if (!PEM_write_RSAPrivateKey(f, rsa, NULL, NULL, 0, NULL, - NULL)) { + if (!PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL)) { wpa_printf(MSG_INFO, "Could not write private key: %s", ERR_error_string(ERR_get_error(), NULL)); fclose(f); diff --git a/wpa_supplicant-2.9_standard/hs20/client/osu_client.c b/wpa_supplicant-2.9_standard/hs20/client/osu_client.c index 77eacc70a793b2f2f30013cc3a650e767402d745..c307393ec52c2fb9cd61d7c00ace323653c68992 100644 --- a/wpa_supplicant-2.9_standard/hs20/client/osu_client.c +++ b/wpa_supplicant-2.9_standard/hs20/client/osu_client.c @@ -1229,12 +1229,13 @@ static void set_pps_cred_home_sp_oi(struct hs20_osu_client *ctx, int id, homeoi, required); if (required) { - if (set_cred(ctx->ifname, id, "required_roaming_consortium", - homeoi) < 0) - wpa_printf(MSG_INFO, "Failed to set cred required_roaming_consortium"); + if (set_cred_quoted(ctx->ifname, id, "required_home_ois", + homeoi) < 0) + wpa_printf(MSG_INFO, + "Failed to set cred required_home_ois"); } else { - if (set_cred(ctx->ifname, id, "roaming_consortium", homeoi) < 0) - wpa_printf(MSG_INFO, "Failed to set cred roaming_consortium"); + if (set_cred_quoted(ctx->ifname, id, "home_ois", homeoi) < 0) + wpa_printf(MSG_INFO, "Failed to set cred home_ois"); } xml_node_get_text_free(ctx->xml, homeoi); @@ -2016,6 +2017,7 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count) struct osu_data *osu = NULL, *last = NULL; size_t osu_count = 0; char *pos, *end; + int res; f = fopen(fname, "r"); if (f == NULL) { @@ -2035,15 +2037,20 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count) osu = last; last = &osu[osu_count++]; memset(last, 0, sizeof(*last)); - snprintf(last->bssid, sizeof(last->bssid), "%s", - buf + 13); + res = os_snprintf(last->bssid, sizeof(last->bssid), + "%s", buf + 13); + if (os_snprintf_error(sizeof(last->bssid), res)) + break; continue; } if (!last) continue; if (strncmp(buf, "uri=", 4) == 0) { - snprintf(last->url, sizeof(last->url), "%s", buf + 4); + res = os_snprintf(last->url, sizeof(last->url), + "%s", buf + 4); + if (os_snprintf_error(sizeof(last->url), res)) + break; continue; } @@ -2053,26 +2060,37 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count) } if (strncmp(buf, "osu_ssid=", 9) == 0) { - snprintf(last->osu_ssid, sizeof(last->osu_ssid), - "%s", buf + 9); + res = os_snprintf(last->osu_ssid, + sizeof(last->osu_ssid), + "%s", buf + 9); + if (os_snprintf_error(sizeof(last->osu_ssid), res)) + break; continue; } if (strncmp(buf, "osu_ssid2=", 10) == 0) { - snprintf(last->osu_ssid2, sizeof(last->osu_ssid2), - "%s", buf + 10); + res = os_snprintf(last->osu_ssid2, + sizeof(last->osu_ssid2), + "%s", buf + 10); + if (os_snprintf_error(sizeof(last->osu_ssid2), res)) + break; continue; } if (os_strncmp(buf, "osu_nai=", 8) == 0) { - os_snprintf(last->osu_nai, sizeof(last->osu_nai), - "%s", buf + 8); + res = os_snprintf(last->osu_nai, sizeof(last->osu_nai), + "%s", buf + 8); + if (os_snprintf_error(sizeof(last->osu_nai), res)) + break; continue; } if (os_strncmp(buf, "osu_nai2=", 9) == 0) { - os_snprintf(last->osu_nai2, sizeof(last->osu_nai2), - "%s", buf + 9); + res = os_snprintf(last->osu_nai2, + sizeof(last->osu_nai2), + "%s", buf + 9); + if (os_snprintf_error(sizeof(last->osu_nai2), res)) + break; continue; } @@ -2085,8 +2103,14 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count) continue; *pos++ = '\0'; txt = &last->friendly_name[last->friendly_name_count++]; - snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 14); - snprintf(txt->text, sizeof(txt->text), "%s", pos); + res = os_snprintf(txt->lang, sizeof(txt->lang), + "%s", buf + 14); + if (os_snprintf_error(sizeof(txt->lang), res)) + break; + res = os_snprintf(txt->text, sizeof(txt->text), + "%s", pos); + if (os_snprintf_error(sizeof(txt->text), res)) + break; } if (strncmp(buf, "desc=", 5) == 0) { @@ -2098,8 +2122,14 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count) continue; *pos++ = '\0'; txt = &last->serv_desc[last->serv_desc_count++]; - snprintf(txt->lang, sizeof(txt->lang), "%s", buf + 5); - snprintf(txt->text, sizeof(txt->text), "%s", pos); + res = os_snprintf(txt->lang, sizeof(txt->lang), + "%s", buf + 5); + if (os_snprintf_error(sizeof(txt->lang), res)) + break; + res = os_snprintf(txt->text, sizeof(txt->text), + "%s", pos); + if (os_snprintf_error(sizeof(txt->text), res)) + break; } if (strncmp(buf, "icon=", 5) == 0) { @@ -2122,23 +2152,30 @@ static struct osu_data * parse_osu_providers(const char *fname, size_t *count) if (!end) continue; *end = '\0'; - snprintf(icon->lang, sizeof(icon->lang), "%s", pos); + res = os_snprintf(icon->lang, sizeof(icon->lang), + "%s", pos); + if (os_snprintf_error(sizeof(icon->lang), res)) + break; pos = end + 1; end = strchr(pos, ':'); if (end) *end = '\0'; - snprintf(icon->mime_type, sizeof(icon->mime_type), - "%s", pos); - if (!pos) + res = os_snprintf(icon->mime_type, + sizeof(icon->mime_type), "%s", pos); + if (os_snprintf_error(sizeof(icon->mime_type), res)) + break; + if (!end) continue; pos = end + 1; end = strchr(pos, ':'); if (end) *end = '\0'; - snprintf(icon->filename, sizeof(icon->filename), - "%s", pos); + res = os_snprintf(icon->filename, + sizeof(icon->filename), "%s", pos); + if (os_snprintf_error(sizeof(icon->filename), res)) + break; continue; } } @@ -2909,20 +2946,27 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert) int found; char *host = NULL; - wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)", - !ctx->no_osu_cert_validation, ctx->server_url); + wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s server_url=%s)", + !ctx->no_osu_cert_validation, cert->url ? cert->url : "N/A", + ctx->server_url); - host = get_hostname(ctx->server_url); + if (ctx->no_osu_cert_validation && cert->url) + host = get_hostname(cert->url); + else + host = get_hostname(ctx->server_url); - for (i = 0; i < ctx->server_dnsname_count; i++) - os_free(ctx->server_dnsname[i]); - os_free(ctx->server_dnsname); - ctx->server_dnsname = os_calloc(cert->num_dnsname, sizeof(char *)); - ctx->server_dnsname_count = 0; + if (!ctx->no_osu_cert_validation) { + for (i = 0; i < ctx->server_dnsname_count; i++) + os_free(ctx->server_dnsname[i]); + os_free(ctx->server_dnsname); + ctx->server_dnsname = os_calloc(cert->num_dnsname, + sizeof(char *)); + ctx->server_dnsname_count = 0; + } found = 0; for (i = 0; i < cert->num_dnsname; i++) { - if (ctx->server_dnsname) { + if (!ctx->no_osu_cert_validation && ctx->server_dnsname) { ctx->server_dnsname[ctx->server_dnsname_count] = os_strdup(cert->dnsname[i]); if (ctx->server_dnsname[ctx->server_dnsname_count]) @@ -3247,7 +3291,6 @@ int main(int argc, char *argv[]) default: usage(); exit(0); - break; } } diff --git a/wpa_supplicant-2.9_standard/hs20/client/spp_client.c b/wpa_supplicant-2.9_standard/hs20/client/spp_client.c index 39d10e0362f640deff8a95737b97a369598c7aec..194518e5aba71c25a8ec7d95776f4d444eee726e 100644 --- a/wpa_supplicant-2.9_standard/hs20/client/spp_client.c +++ b/wpa_supplicant-2.9_standard/hs20/client/spp_client.c @@ -564,7 +564,6 @@ static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec, free(id); return -1; } - return 0; } if (strcasecmp(name, "uploadMO") == 0) { diff --git a/wpa_supplicant-2.9_standard/libwpa.map.txt b/wpa_supplicant-2.9_standard/libwpa.map.txt index 2042956282cdc8c434601f9c54ba08fafbcbd778..f8a9a9242400d4863d956fead924dff2e1fb7742 100644 --- a/wpa_supplicant-2.9_standard/libwpa.map.txt +++ b/wpa_supplicant-2.9_standard/libwpa.map.txt @@ -1,101 +1,101 @@ -# Copyright (c) 2024 Huawei Device Co., Ltd. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -1.0 { - global: - *wpa_ctrl*; - *hostapd_mac*; - *hostapd_config*; - *hostapd_maclist*; - *hostapd_rate*; - *hostapd_get*; - *hostapd_setup*; - *hostapd_vlan*; - *hostapd_parse*; - *hostapd_set*; - *hostapd_sae*; - *hostapd_ctrl*; - *hostapd_disassoc*; - *wpa_config*; - *wpa_supplicant*; - *wpa_set*; - *wpas_set*; - *wpas_restore*; - *wpa_clear*; - *wpas_auth*; - *wpas_remove*; - *free_hw*; - *wpa_show*; - *fils*; - *wpas_driver*; - *wpas_is*; - *disallowed*; - *wpas_request*; - *wpas_build*; - *wpas_update*; - *add_freq*; - *wpas_get*; - *wpas_twt*; - *wpas_rrm*; - *wpas_beacon*; - *wpas_clear*; - *wpas_flush*; - *wpas_mbo*; - *mbo_attr*; - *mbo_get*; - *mbo_build*; - *mbo_parse*; - *verify_channel*; - *wpas_supp_op*; - *wpas_enable*; - *wpas_disable*; - *wpa_supp_ctl*; - *ibss_mesh*; - *wnm_bss*; - *wpas_temp*; - *wpas_reset*; - *wpas_network*; - *wpa_s_setup*; - *wpas_init*; - *dump_freq*; - *get_shared*; - *wpas_vendor*; - *fst_wpa_supplicant*; - *wpas_sched_scan*; - *hostapd_hw*; - *wpa_bss*; - *wpa_is*; - *free_bss*; - *wpa_scan*; - *wpas_ctrl*; - *wpas_send*; - *wpas_populate*; - *wpas_handle*; - *free_up*; - *wpas_scs*; - *wpas_dscp*; - *p2p_ctrl*; - *p2p_wifi*; - *hw_magiclink*; - *channel_to*; - *wpas_wps*; - *wps_request*; - *wpas_er_wps*; - *wpas_p2p*; - *wpas_sd*; - *wpa_main*; - *ap_main*; - *getHost*; - local: - *; +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +1.0 { + global: + *wpa_ctrl*; + *hostapd_mac*; + *hostapd_config*; + *hostapd_maclist*; + *hostapd_rate*; + *hostapd_get*; + *hostapd_setup*; + *hostapd_vlan*; + *hostapd_parse*; + *hostapd_set*; + *hostapd_sae*; + *hostapd_ctrl*; + *hostapd_disassoc*; + *wpa_config*; + *wpa_supplicant*; + *wpa_set*; + *wpas_set*; + *wpas_restore*; + *wpa_clear*; + *wpas_auth*; + *wpas_remove*; + *free_hw*; + *wpa_show*; + *fils*; + *wpas_driver*; + *wpas_is*; + *disallowed*; + *wpas_request*; + *wpas_build*; + *wpas_update*; + *add_freq*; + *wpas_get*; + *wpas_twt*; + *wpas_rrm*; + *wpas_beacon*; + *wpas_clear*; + *wpas_flush*; + *wpas_mbo*; + *mbo_attr*; + *mbo_get*; + *mbo_build*; + *mbo_parse*; + *verify_channel*; + *wpas_supp_op*; + *wpas_enable*; + *wpas_disable*; + *wpa_supp_ctl*; + *ibss_mesh*; + *wnm_bss*; + *wpas_temp*; + *wpas_reset*; + *wpas_network*; + *wpa_s_setup*; + *wpas_init*; + *dump_freq*; + *get_shared*; + *wpas_vendor*; + *fst_wpa_supplicant*; + *wpas_sched_scan*; + *hostapd_hw*; + *wpa_bss*; + *wpa_is*; + *free_bss*; + *wpa_scan*; + *wpas_ctrl*; + *wpas_send*; + *wpas_populate*; + *wpas_handle*; + *free_up*; + *wpas_scs*; + *wpas_dscp*; + *p2p_ctrl*; + *p2p_wifi*; + *hw_magiclink*; + *channel_to*; + *wpas_wps*; + *wps_request*; + *wpas_er_wps*; + *wpas_p2p*; + *wpas_sd*; + *wpa_main*; + *ap_main*; + *getHost*; + local: + *; }; \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/src/Makefile b/wpa_supplicant-2.9_standard/src/Makefile index 6eb7f2acb5a1e9740994c0d1c7f80b50413f825c..d15cf329a5a9e52290eeceeed4abc5c6c657a09e 100644 --- a/wpa_supplicant-2.9_standard/src/Makefile +++ b/wpa_supplicant-2.9_standard/src/Makefile @@ -1,4 +1,4 @@ -SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p pae radius rsn_supp tls utils wps +SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p pae pasn radius rsn_supp tls utils wps SUBDIRS += fst all: diff --git a/wpa_supplicant-2.9_standard/src/ap/acs.c b/wpa_supplicant-2.9_standard/src/ap/acs.c index 0030edc2a90f1271bb9d8d690dbf3d01bf39499b..f5b36d327a74f39fe3c7bcd7571661214fa572e8 100644 --- a/wpa_supplicant-2.9_standard/src/ap/acs.c +++ b/wpa_supplicant-2.9_standard/src/ap/acs.c @@ -12,6 +12,7 @@ #include "utils/common.h" #include "utils/list.h" +#include "utils/eloop.h" #include "common/ieee802_11_defs.h" #include "common/hw_features_common.h" #include "common/wpa_ctrl.h" @@ -75,7 +76,7 @@ * * This corresponds to: * --- - * (busy time - tx time) / (active time - tx time) * 2^(chan_nf + band_min_nf) + * (busy time - tx time) / (active time - tx time) * 2^(chan_nf - band_min_nf) * --- * * The coefficient of 2 reflects the way power in "far-field" @@ -92,7 +93,7 @@ * calculated easily. * --- * (busy time - tx time) / (active time - tx time) * - * 2^(10^(chan_nf/10) + 10^(band_min_nf/10)) + * 2^(10^(chan_nf/10) - 10^(band_min_nf/10)) * --- * * However to account for cases where busy/rx time is 0 (channel load is then @@ -100,7 +101,7 @@ * channel with lower noise floor is preferred. The equation becomes: * --- * 10^(chan_nf/5) + (busy time - tx time) / (active time - tx time) * - * 2^(10^(chan_nf/10) + 10^(band_min_nf/10)) + * 2^(10^(chan_nf/10) - 10^(band_min_nf/10)) * --- * * All this "interference factor" is purely subjective and only time @@ -241,9 +242,73 @@ * [1] http://en.wikipedia.org/wiki/Near_and_far_field */ +enum bw_type { + ACS_BW40, + ACS_BW80, + ACS_BW160, + ACS_BW320_1, + ACS_BW320_2, +}; + +struct bw_item { + int first; + int last; + int center_chan; +}; + +static const struct bw_item bw_40[] = { + { 5180, 5200, 38 }, { 5220, 5240, 46 }, { 5260, 5280, 54 }, + { 5300, 5320, 62 }, { 5500, 5520, 102 }, { 5540, 5560, 110 }, + { 5580, 5600, 118 }, { 5620, 5640, 126 }, { 5660, 5680, 134 }, + { 5700, 5720, 142 }, { 5745, 5765, 151 }, { 5785, 5805, 159 }, + { 5825, 5845, 167 }, { 5865, 5885, 175 }, + { 5955, 5975, 3 }, { 5995, 6015, 11 }, { 6035, 6055, 19 }, + { 6075, 6095, 27 }, { 6115, 6135, 35 }, { 6155, 6175, 43 }, + { 6195, 6215, 51 }, { 6235, 6255, 59 }, { 6275, 6295, 67 }, + { 6315, 6335, 75 }, { 6355, 6375, 83 }, { 6395, 6415, 91 }, + { 6435, 6455, 99 }, { 6475, 6495, 107 }, { 6515, 6535, 115 }, + { 6555, 6575, 123 }, { 6595, 6615, 131 }, { 6635, 6655, 139 }, + { 6675, 6695, 147 }, { 6715, 6735, 155 }, { 6755, 6775, 163 }, + { 6795, 6815, 171 }, { 6835, 6855, 179 }, { 6875, 6895, 187 }, + { 6915, 6935, 195 }, { 6955, 6975, 203 }, { 6995, 7015, 211 }, + { 7035, 7055, 219 }, { 7075, 7095, 227}, { -1, -1, -1 } +}; +static const struct bw_item bw_80[] = { + { 5180, 5240, 42 }, { 5260, 5320, 58 }, { 5500, 5560, 106 }, + { 5580, 5640, 122 }, { 5660, 5720, 138 }, { 5745, 5805, 155 }, + { 5825, 5885, 171}, + { 5955, 6015, 7 }, { 6035, 6095, 23 }, { 6115, 6175, 39 }, + { 6195, 6255, 55 }, { 6275, 6335, 71 }, { 6355, 6415, 87 }, + { 6435, 6495, 103 }, { 6515, 6575, 119 }, { 6595, 6655, 135 }, + { 6675, 6735, 151 }, { 6755, 6815, 167 }, { 6835, 6895, 183 }, + { 6915, 6975, 199 }, { 6995, 7055, 215 }, { -1, -1, -1 } +}; +static const struct bw_item bw_160[] = { + { 5180, 5320, 50 }, { 5500, 5640, 114 }, { 5745, 5885, 163 }, + { 5955, 6095, 15 }, { 6115, 6255, 47 }, { 6275, 6415, 79 }, + { 6435, 6575, 111 }, { 6595, 6735, 143 }, + { 6755, 6895, 175 }, { 6915, 7055, 207 }, { -1, -1, -1 } +}; +static const struct bw_item bw_320_1[] = { + { 5955, 6255, 31 }, { 6275, 6575, 95 }, { 6595, 6895, 159 }, + { -1, -1, -1 } +}; +static const struct bw_item bw_320_2[] = { + { 6115, 6415, 63 }, { 6435, 6735, 127 }, { 6755, 7055, 191 }, + { -1, -1, -1 } +}; +static const struct bw_item *bw_desc[] = { + [ACS_BW40] = bw_40, + [ACS_BW80] = bw_80, + [ACS_BW160] = bw_160, + [ACS_BW320_1] = bw_320_1, + [ACS_BW320_2] = bw_320_2, +}; + static int acs_request_scan(struct hostapd_iface *iface); static int acs_survey_is_sufficient(struct freq_survey *survey); +static void acs_scan_retry(void *eloop_data, void *user_data); static void acs_clean_chan_surveys(struct hostapd_channel_data *chan) @@ -275,6 +340,7 @@ static void acs_cleanup_mode(struct hostapd_hw_modes *mode) dl_list_init(&chan->survey_list); chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED; chan->min_nf = 0; + chan->punct_bitmap = 0; } } @@ -288,6 +354,8 @@ void acs_cleanup(struct hostapd_iface *iface) iface->chans_surveyed = 0; iface->acs_num_completed_scans = 0; + iface->acs_num_retries = 0; + eloop_cancel_timeout(acs_scan_retry, iface, NULL); } @@ -370,48 +438,31 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface, } -static int acs_usable_bw40_chan(const struct hostapd_channel_data *chan) -{ - const int allowed[] = { 5180, 5220, 5260, 5300, 5500, 5540, 5580, 5620, - 5660, 5745, 5785, 4920, 4960, 5955, 5995, 6035, - 6075, 6115, 6155, 6195, 6235, 6275, 6315, 6355, - 6395, 6435, 6475, 6515, 6555, 6595, 6635, 6675, - 6715, 6755, 6795, 6835, 6875, 6915, 6955, 6995, - 7035, 7075 }; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(allowed); i++) - if (chan->freq == allowed[i]) - return 1; - - return 0; -} - - -static int acs_usable_bw80_chan(const struct hostapd_channel_data *chan) +static bool acs_usable_bw_chan(const struct hostapd_channel_data *chan, + enum bw_type bw) { - const int allowed[] = { 5180, 5260, 5500, 5580, 5660, 5745, 5955, 6035, - 6115, 6195, 6275, 6355, 6435, 6515, 6595, 6675, - 6755, 6835, 6915, 6995 }; - unsigned int i; + unsigned int i = 0; - for (i = 0; i < ARRAY_SIZE(allowed); i++) - if (chan->freq == allowed[i]) - return 1; + while (bw_desc[bw][i].first != -1) { + if (chan->freq == bw_desc[bw][i].first) + return true; + i++; + } - return 0; + return false; } -static int acs_usable_bw160_chan(const struct hostapd_channel_data *chan) +static int acs_get_bw_center_chan(int freq, enum bw_type bw) { - const int allowed[] = { 5180, 5500, 5955, 6115, 6275, 6435, 6595, 6755, - 6915 }; - unsigned int i; + unsigned int i = 0; - for (i = 0; i < ARRAY_SIZE(allowed); i++) - if (chan->freq == allowed[i]) - return 1; + while (bw_desc[bw][i].first != -1) { + if (freq >= bw_desc[bw][i].first && + freq <= bw_desc[bw][i].last) + return bw_desc[bw][i].center_chan; + i++; + } return 0; } @@ -420,19 +471,24 @@ static int acs_usable_bw160_chan(const struct hostapd_channel_data *chan) static int acs_survey_is_sufficient(struct freq_survey *survey) { if (!(survey->filled & SURVEY_HAS_NF)) { - wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor"); + wpa_printf(MSG_INFO, + "ACS: Survey for freq %d is missing noise floor", + survey->freq); return 0; } if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) { - wpa_printf(MSG_INFO, "ACS: Survey is missing channel time"); + wpa_printf(MSG_INFO, + "ACS: Survey for freq %d is missing channel time", + survey->freq); return 0; } if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) && !(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) { wpa_printf(MSG_INFO, - "ACS: Survey is missing RX and busy time (at least one is required)"); + "ACS: Survey for freq %d is missing RX and busy time (at least one is required)", + survey->freq); return 0; } @@ -455,7 +511,7 @@ static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan) } if (ret == -1) - ret = 1; /* no survey list entries */ + ret = 0; /* no survey list entries */ if (!ret) { wpa_printf(MSG_INFO, @@ -540,6 +596,10 @@ static void acs_survey_mode_interference_factor( if (!acs_usable_chan(chan)) continue; + if ((chan->flag & HOSTAPD_CHAN_RADAR) && + iface->conf->acs_exclude_dfs) + continue; + if (!is_in_chanlist(iface, chan)) continue; @@ -549,6 +609,10 @@ static void acs_survey_mode_interference_factor( if (chan->max_tx_power < iface->conf->min_tx_power) continue; + if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) && + iface->conf->country[2] == 0x4f) + continue; + wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)", chan->chan, chan->freq); @@ -594,6 +658,26 @@ acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq) } +static enum hostapd_hw_mode +acs_find_mode(struct hostapd_iface *iface, int freq) +{ + int i; + struct hostapd_hw_modes *mode; + struct hostapd_channel_data *chan; + + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + if (!hostapd_hw_skip_mode(iface, mode)) { + chan = acs_find_chan_mode(mode, freq); + if (chan) + return mode->mode; + } + } + + return HOSTAPD_MODE_IEEE80211ANY; +} + + static struct hostapd_channel_data * acs_find_chan(struct hostapd_iface *iface, int freq) { @@ -644,6 +728,98 @@ static int is_common_24ghz_chan(int chan) #define ACS_24GHZ_PREFER_1_6_11 0.8 #endif /* ACS_24GHZ_PREFER_1_6_11 */ + +#ifdef CONFIG_IEEE80211BE +static void acs_update_puncturing_bitmap(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode, u32 bw, + int n_chans, + struct hostapd_channel_data *chan, + long double factor, + int index_primary) +{ + struct hostapd_config *conf = iface->conf; + struct hostapd_channel_data *adj_chan = NULL, *first_chan = chan; + int i; + long double threshold; + + /* + * If threshold is 0 or user configured puncturing pattern is + * available then don't add additional puncturing. + */ + if (!conf->punct_acs_threshold || conf->punct_bitmap) + return; + + if (is_24ghz_mode(mode->mode) || bw < 80) + return; + + threshold = factor * conf->punct_acs_threshold / 100; + for (i = 0; i < n_chans; i++) { + int adj_freq; + + if (i == index_primary) + continue; /* Cannot puncture primary channel */ + + if (i > index_primary) + adj_freq = chan->freq + (i - index_primary) * 20; + else + adj_freq = chan->freq - (index_primary - i) * 20; + + adj_chan = acs_find_chan(iface, adj_freq); + if (!adj_chan) { + chan->punct_bitmap = 0; + return; + } + + if (i == 0) + first_chan = adj_chan; + + if (adj_chan->interference_factor > threshold) + chan->punct_bitmap |= BIT(i); + } + + if (!is_punct_bitmap_valid(bw, (chan->freq - first_chan->freq) / 20, + chan->punct_bitmap)) + chan->punct_bitmap = 0; +} +#endif /* CONFIG_IEEE80211BE */ + + +static bool +acs_usable_bw320_chan(struct hostapd_iface *iface, + struct hostapd_channel_data *chan, int *bw320_offset) +{ + const char *bw320_str[] = { "320 MHz", "320 MHz-1", "320 MHz-2" }; + int conf_bw320_offset = hostapd_get_bw320_offset(iface->conf); + + *bw320_offset = 0; + switch (conf_bw320_offset) { + case 1: + if (acs_usable_bw_chan(chan, ACS_BW320_1)) + *bw320_offset = 1; + break; + case 2: + if (acs_usable_bw_chan(chan, ACS_BW320_2)) + *bw320_offset = 2; + break; + case 0: + default: + conf_bw320_offset = 0; + if (acs_usable_bw_chan(chan, ACS_BW320_1)) + *bw320_offset = 1; + else if (acs_usable_bw_chan(chan, ACS_BW320_2)) + *bw320_offset = 2; + break; + } + + if (!*bw320_offset) + wpa_printf(MSG_DEBUG, + "ACS: Channel %d: not allowed as primary channel for %s bandwidth", + chan->chan, bw320_str[conf_bw320_offset]); + + return *bw320_offset != 0; +} + + static void acs_find_ideal_chan_mode(struct hostapd_iface *iface, struct hostapd_hw_modes *mode, @@ -652,13 +828,21 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, struct hostapd_channel_data **ideal_chan, long double *ideal_factor) { - struct hostapd_channel_data *chan, *adj_chan = NULL; + struct hostapd_channel_data *chan, *adj_chan = NULL, *best; long double factor; int i, j; + int bw320_offset = 0, ideal_bw320_offset = 0; unsigned int k; + int secondary_channel = 1, freq_offset; +#ifdef CONFIG_IEEE80211BE + int index_primary = 0; +#endif /* CONFIG_IEEE80211BE */ + + if (is_24ghz_mode(mode->mode)) + secondary_channel = iface->conf->secondary_channel; for (i = 0; i < mode->num_channels; i++) { - double total_weight; + double total_weight = 0; struct acs_bias *bias, tmp_bias; chan = &mode->channels[i]; @@ -666,10 +850,20 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, /* Since in the current ACS implementation the first channel is * always a primary channel, skip channels not available as * primary until more sophisticated channel selection is - * implemented. */ + * implemented. + * + * If this implementation is changed to allow any channel in + * the bandwidth to be the primary one, the last parameter to + * acs_update_puncturing_bitmap() should be changed to the index + * of the primary channel + */ if (!chan_pri_allowed(chan)) continue; + if ((chan->flag & HOSTAPD_CHAN_RADAR) && + iface->conf->acs_exclude_dfs) + continue; + if (!is_in_chanlist(iface, chan)) continue; @@ -679,7 +873,11 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, if (chan->max_tx_power < iface->conf->min_tx_power) continue; - if (!chan_bw_allowed(chan, bw, 1, 1)) { + if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) && + iface->conf->country[2] == 0x4f) + continue; + + if (!chan_bw_allowed(chan, bw, secondary_channel != -1, 1)) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: BW %u is not supported", chan->chan, bw); @@ -692,7 +890,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, ((iface->conf->ieee80211n && iface->conf->secondary_channel) || is_6ghz_freq(chan->freq)) && - !acs_usable_bw40_chan(chan)) { + !acs_usable_bw_chan(chan, ACS_BW40)) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for 40 MHz bandwidth", chan->chan); @@ -700,10 +898,11 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, } if (mode->mode == HOSTAPD_MODE_IEEE80211A && - (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) { + (iface->conf->ieee80211ac || iface->conf->ieee80211ax || + iface->conf->ieee80211be)) { if (hostapd_get_oper_chwidth(iface->conf) == - CHANWIDTH_80MHZ && - !acs_usable_bw80_chan(chan)) { + CONF_OPER_CHWIDTH_80MHZ && + !acs_usable_bw_chan(chan, ACS_BW80)) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for 80 MHz bandwidth", chan->chan); @@ -711,8 +910,8 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, } if (hostapd_get_oper_chwidth(iface->conf) == - CHANWIDTH_160MHZ && - !acs_usable_bw160_chan(chan)) { + CONF_OPER_CHWIDTH_160MHZ && + !acs_usable_bw_chan(chan, ACS_BW160)) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for 160 MHz bandwidth", chan->chan); @@ -720,13 +919,25 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, } } + if (mode->mode == HOSTAPD_MODE_IEEE80211A && + iface->conf->ieee80211be) { + if (hostapd_get_oper_chwidth(iface->conf) == + CONF_OPER_CHWIDTH_320MHZ && + !acs_usable_bw320_chan(iface, chan, &bw320_offset)) + continue; + } + factor = 0; - if (acs_usable_chan(chan)) + best = NULL; + if (acs_usable_chan(chan)) { factor = chan->interference_factor; - total_weight = 1; + total_weight = 1; + best = chan; + } for (j = 1; j < n_chans; j++) { - adj_chan = acs_find_chan(iface, chan->freq + (j * 20)); + adj_chan = acs_find_chan(iface, chan->freq + + j * secondary_channel * 20); if (!adj_chan) break; @@ -737,10 +948,16 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, break; } - if (acs_usable_chan(adj_chan)) { - factor += adj_chan->interference_factor; - total_weight += 1; - } + if (!acs_usable_chan(adj_chan)) + continue; + + factor += adj_chan->interference_factor; + total_weight += 1; + + /* find the best channel in this segment */ + if (!best || adj_chan->interference_factor < + best->interference_factor) + best = adj_chan; } if (j != n_chans) { @@ -749,12 +966,29 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, continue; } + /* If the AP is in the 5 GHz or 6 GHz band, lets prefer a less + * crowded primary channel if one was found in the segment */ + if (iface->current_mode && + iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && + best && chan != best) { + wpa_printf(MSG_DEBUG, + "ACS: promoting channel %d over %d (less interference %Lg/%Lg)", + best->chan, chan->chan, + chan->interference_factor, + best->interference_factor); +#ifdef CONFIG_IEEE80211BE + index_primary = (chan->freq - best->freq) / 20; +#endif /* CONFIG_IEEE80211BE */ + chan = best; + } + /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent * channel interference factor. */ if (is_24ghz_mode(mode->mode)) { for (j = 0; j < n_chans; j++) { + freq_offset = j * 20 * secondary_channel; adj_chan = acs_find_chan(iface, chan->freq + - (j * 20) - 5); + freq_offset - 5); if (adj_chan && acs_usable_chan(adj_chan)) { factor += ACS_ADJ_WEIGHT * adj_chan->interference_factor; @@ -762,7 +996,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, } adj_chan = acs_find_chan(iface, chan->freq + - (j * 20) - 10); + freq_offset - 10); if (adj_chan && acs_usable_chan(adj_chan)) { factor += ACS_NEXT_ADJ_WEIGHT * adj_chan->interference_factor; @@ -770,7 +1004,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, } adj_chan = acs_find_chan(iface, chan->freq + - (j * 20) + 5); + freq_offset + 5); if (adj_chan && acs_usable_chan(adj_chan)) { factor += ACS_ADJ_WEIGHT * adj_chan->interference_factor; @@ -778,7 +1012,7 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, } adj_chan = acs_find_chan(iface, chan->freq + - (j * 20) + 10); + freq_offset + 10); if (adj_chan && acs_usable_chan(adj_chan)) { factor += ACS_NEXT_ADJ_WEIGHT * adj_chan->interference_factor; @@ -787,6 +1021,9 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, } } + if (total_weight == 0) + continue; + factor /= total_weight; bias = NULL; @@ -817,14 +1054,32 @@ acs_find_ideal_chan_mode(struct hostapd_iface *iface, if (acs_usable_chan(chan) && (!*ideal_chan || factor < *ideal_factor)) { + /* Reset puncturing bitmap for the previous ideal + * channel */ + if (*ideal_chan) + (*ideal_chan)->punct_bitmap = 0; + *ideal_factor = factor; *ideal_chan = chan; + ideal_bw320_offset = bw320_offset; + +#ifdef CONFIG_IEEE80211BE + if (iface->conf->ieee80211be) + acs_update_puncturing_bitmap(iface, mode, bw, + n_chans, chan, + factor, + index_primary); +#endif /* CONFIG_IEEE80211BE */ } /* This channel would at least be usable */ - if (!(*rand_chan)) + if (!(*rand_chan)) { *rand_chan = chan; + ideal_bw320_offset = bw320_offset; + } } + + hostapd_set_and_check_bw320_offset(iface->conf, ideal_bw320_offset); } @@ -851,26 +1106,24 @@ acs_find_ideal_chan(struct hostapd_iface *iface) goto bw_selected; } - /* TODO: HT40- support */ - - if (iface->conf->ieee80211n && - iface->conf->secondary_channel == -1) { - wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+"); - return NULL; - } - if (iface->conf->ieee80211n && iface->conf->secondary_channel) n_chans = 2; - if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { + if (iface->conf->ieee80211ac || iface->conf->ieee80211ax || + iface->conf->ieee80211be) { switch (hostapd_get_oper_chwidth(iface->conf)) { - case CHANWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: n_chans = 4; break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: n_chans = 8; break; + case CONF_OPER_CHWIDTH_320MHZ: + n_chans = 16; + break; + default: + break; } } @@ -893,6 +1146,13 @@ bw_selected: if (ideal_chan) { wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg", ideal_chan->chan, ideal_chan->freq, ideal_factor); + +#ifdef CONFIG_IEEE80211BE + if (iface->conf->punct_acs_threshold) + wpa_printf(MSG_DEBUG, "ACS: RU puncturing bitmap 0x%x", + ideal_chan->punct_bitmap); +#endif /* CONFIG_IEEE80211BE */ + return ideal_chan; } @@ -900,32 +1160,78 @@ bw_selected: } +static void acs_adjust_secondary(struct hostapd_iface *iface) +{ + unsigned int i; + + /* When working with bandwidth over 20 MHz on the 5 GHz or 6 GHz band, + * ACS can return a secondary channel which is not the first channel of + * the segment and we need to adjust. */ + if (!iface->conf->secondary_channel || + acs_find_mode(iface, iface->freq) != HOSTAPD_MODE_IEEE80211A) + return; + + wpa_printf(MSG_DEBUG, + "ACS: Adjusting HT/VHT/HE/EHT secondary frequency"); + + for (i = 0; bw_desc[ACS_BW40][i].first != -1; i++) { + if (iface->freq == bw_desc[ACS_BW40][i].first) + iface->conf->secondary_channel = 1; + else if (iface->freq == bw_desc[ACS_BW40][i].last) + iface->conf->secondary_channel = -1; + } +} + + static void acs_adjust_center_freq(struct hostapd_iface *iface) { - int offset; + int center; - wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency"); + wpa_printf(MSG_DEBUG, "ACS: Adjusting center frequency"); switch (hostapd_get_oper_chwidth(iface->conf)) { - case CHANWIDTH_USE_HT: - offset = 2 * iface->conf->secondary_channel; + case CONF_OPER_CHWIDTH_USE_HT: + if (iface->conf->secondary_channel && + iface->freq >= 2400 && iface->freq < 2500) + center = iface->conf->channel + + 2 * iface->conf->secondary_channel; + else if (iface->conf->secondary_channel) + center = acs_get_bw_center_chan(iface->freq, ACS_BW40); + else + center = iface->conf->channel; break; - case CHANWIDTH_80MHZ: - offset = 6; + case CONF_OPER_CHWIDTH_80MHZ: + center = acs_get_bw_center_chan(iface->freq, ACS_BW80); break; - case CHANWIDTH_160MHZ: - offset = 14; + case CONF_OPER_CHWIDTH_160MHZ: + center = acs_get_bw_center_chan(iface->freq, ACS_BW160); + break; + case CONF_OPER_CHWIDTH_320MHZ: + switch (hostapd_get_bw320_offset(iface->conf)) { + case 1: + center = acs_get_bw_center_chan(iface->freq, + ACS_BW320_1); + break; + case 2: + center = acs_get_bw_center_chan(iface->freq, + ACS_BW320_2); + break; + default: + wpa_printf(MSG_INFO, + "ACS: BW320 offset is not selected"); + return; + } + break; default: /* TODO: How can this be calculated? Adjust * acs_find_ideal_chan() */ wpa_printf(MSG_INFO, - "ACS: Only VHT20/40/80/160 is supported now"); + "ACS: Only VHT20/40/80/160/320 is supported now"); return; } - hostapd_set_oper_centr_freq_seg0_idx(iface->conf, - iface->conf->channel + offset); + hostapd_set_oper_centr_freq_seg0_idx(iface->conf, center); } @@ -980,9 +1286,24 @@ static void acs_study(struct hostapd_iface *iface) iface->conf->channel = ideal_chan->chan; iface->freq = ideal_chan->freq; +#ifdef CONFIG_IEEE80211BE + iface->conf->punct_bitmap = ideal_chan->punct_bitmap; +#endif /* CONFIG_IEEE80211BE */ - if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) + if (iface->conf->ieee80211ac || iface->conf->ieee80211ax || + iface->conf->ieee80211be) { + acs_adjust_secondary(iface); acs_adjust_center_freq(iface); + } + + err = hostapd_select_hw_mode(iface); + if (err) { + wpa_printf(MSG_ERROR, + "ACS: Could not (err: %d) select hw_mode for freq=%d channel=%d", + err, iface->freq, iface->conf->channel); + err = -1; + goto fail; + } err = 0; fail: @@ -1007,6 +1328,7 @@ static void acs_scan_complete(struct hostapd_iface *iface) int err; iface->scan_cb = NULL; + iface->acs_num_retries = 0; wpa_printf(MSG_DEBUG, "ACS: Using survey based algorithm (acs_num_scans=%d)", iface->conf->acs_num_scans); @@ -1019,7 +1341,7 @@ static void acs_scan_complete(struct hostapd_iface *iface) if (++iface->acs_num_completed_scans < iface->conf->acs_num_scans) { err = acs_request_scan(iface); - if (err) { + if (err && err != -EBUSY) { wpa_printf(MSG_ERROR, "ACS: Failed to request scan"); goto fail; } @@ -1044,7 +1366,9 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface, for (i = 0; i < mode->num_channels; i++) { chan = &mode->channels[i]; - if (chan->flag & HOSTAPD_CHAN_DISABLED) + if ((chan->flag & HOSTAPD_CHAN_DISABLED) || + ((chan->flag & HOSTAPD_CHAN_RADAR) && + iface->conf->acs_exclude_dfs)) continue; if (!is_in_chanlist(iface, chan)) @@ -1056,6 +1380,10 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface, if (chan->max_tx_power < iface->conf->min_tx_power) continue; + if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) && + iface->conf->country[2] == 0x4f) + continue; + *freq++ = chan->freq; } @@ -1066,7 +1394,7 @@ static int * acs_request_scan_add_freqs(struct hostapd_iface *iface, static int acs_request_scan(struct hostapd_iface *iface) { struct wpa_driver_scan_params params; - int i, *freq; + int i, *freq, ret; int num_channels; struct hostapd_hw_modes *mode; @@ -1099,32 +1427,78 @@ static int acs_request_scan(struct hostapd_iface *iface) return -1; } - iface->scan_cb = acs_scan_complete; + if (!iface->acs_num_retries) + wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d", + iface->acs_num_completed_scans + 1, + iface->conf->acs_num_scans); + else + wpa_printf(MSG_DEBUG, + "ACS: Re-try scanning attempt %d (%d / %d)", + iface->acs_num_retries, + iface->acs_num_completed_scans + 1, + iface->conf->acs_num_scans); + + ret = hostapd_driver_scan(iface->bss[0], ¶ms); + os_free(params.freqs); - wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d", - iface->acs_num_completed_scans + 1, - iface->conf->acs_num_scans); + if (ret == -EBUSY) { + iface->acs_num_retries++; + if (iface->acs_num_retries >= ACS_SCAN_RETRY_MAX_COUNT) { + wpa_printf(MSG_ERROR, + "ACS: Failed to request initial scan (all re-attempts failed)"); + acs_fail(iface); + return -1; + } - if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) { + wpa_printf(MSG_INFO, + "Failed to request acs scan ret=%d (%s) - try to scan after %d seconds", + ret, strerror(-ret), ACS_SCAN_RETRY_INTERVAL); + eloop_cancel_timeout(acs_scan_retry, iface, NULL); + eloop_register_timeout(ACS_SCAN_RETRY_INTERVAL, 0, + acs_scan_retry, iface, NULL); + return 0; + } + + if (ret < 0) { wpa_printf(MSG_ERROR, "ACS: Failed to request initial scan"); acs_cleanup(iface); - os_free(params.freqs); return -1; } - os_free(params.freqs); + iface->scan_cb = acs_scan_complete; + return 0; } +static void acs_scan_retry(void *eloop_data, void *user_data) +{ + struct hostapd_iface *iface = eloop_data; + + if (acs_request_scan(iface)) { + wpa_printf(MSG_ERROR, + "ACS: Failed to request re-try of initial scan"); + acs_fail(iface); + } +} + + enum hostapd_chan_status acs_init(struct hostapd_iface *iface) { + int err; + wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit"); if (iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) { wpa_printf(MSG_INFO, "ACS: Offloading to driver"); - if (hostapd_drv_do_acs(iface->bss[0])) + + err = hostapd_drv_do_acs(iface->bss[0]); + if (err) { + if (err == 1) + return HOSTAPD_CHAN_INVALID_NO_IR; return HOSTAPD_CHAN_INVALID; + } + return HOSTAPD_CHAN_ACS; } diff --git a/wpa_supplicant-2.9_standard/src/ap/acs.h b/wpa_supplicant-2.9_standard/src/ap/acs.h index ec84f0ee97f34d501069f171e3494833be6af884..8be3de5b5f7862f877f7c39adb9641738c9dcbf9 100644 --- a/wpa_supplicant-2.9_standard/src/ap/acs.h +++ b/wpa_supplicant-2.9_standard/src/ap/acs.h @@ -15,6 +15,9 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface); void acs_cleanup(struct hostapd_iface *iface); +#define ACS_SCAN_RETRY_MAX_COUNT 15 +#define ACS_SCAN_RETRY_INTERVAL 5 + #else /* CONFIG_ACS */ static inline enum hostapd_chan_status acs_init(struct hostapd_iface *iface) diff --git a/wpa_supplicant-2.9_standard/src/ap/airtime_policy.c b/wpa_supplicant-2.9_standard/src/ap/airtime_policy.c index abe817c5b01585c052f0949414ed6fde933ea131..68443115f16bce2e31f6602f635a55d841a67648 100644 --- a/wpa_supplicant-2.9_standard/src/ap/airtime_policy.c +++ b/wpa_supplicant-2.9_standard/src/ap/airtime_policy.c @@ -232,7 +232,7 @@ static int get_weight_for_sta(struct hostapd_data *hapd, const u8 *sta) struct airtime_sta_weight *wt; wt = hapd->conf->airtime_weight_list; - while (wt && os_memcmp(wt->addr, sta, ETH_ALEN) != 0) + while (wt && !ether_addr_equal(wt->addr, sta)) wt = wt->next; return wt ? wt->weight : hapd->conf->airtime_weight; diff --git a/wpa_supplicant-2.9_standard/src/ap/ap_config.c b/wpa_supplicant-2.9_standard/src/ap/ap_config.c index 9d47b31e91def4f672a3994d1ccd4f8ded864c18..139f46dbe8375679ee5c8a4d7214b3ab11d4c729 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ap_config.c +++ b/wpa_supplicant-2.9_standard/src/ap/ap_config.c @@ -1,6 +1,6 @@ /* * hostapd / Configuration helper functions - * Copyright (c) 2003-2014, Jouni Malinen + * Copyright (c) 2003-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -90,7 +90,9 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->radius_server_auth_port = 1812; bss->eap_sim_db_timeout = 1; bss->eap_sim_id = 3; + bss->eap_sim_aka_fast_reauth_limit = 1000; bss->ap_max_inactivity = AP_MAX_INACTIVITY; + bss->bss_max_idle = 1; bss->eapol_version = EAPOL_VERSION; bss->max_listen_interval = 65535; @@ -120,9 +122,10 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #endif /* CONFIG_IEEE80211R_AP */ bss->radius_das_time_window = 300; + bss->radius_require_message_authenticator = 1; bss->anti_clogging_threshold = 5; - bss->sae_sync = 5; + bss->sae_sync = 3; bss->gas_frag_limit = 1400; @@ -162,13 +165,17 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) /* Default to strict CRL checking. */ bss->check_crl_strict = 1; + bss->multi_ap_profile = MULTI_AP_PROFILE_2; + #ifdef CONFIG_TESTING_OPTIONS bss->sae_commit_status = -1; + bss->test_assoc_comeback_type = -1; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_PASN /* comeback after 10 TUs */ bss->pasn_comeback_after = 10; + bss->pasn_noauth = 1; #endif /* CONFIG_PASN */ } @@ -279,6 +286,10 @@ struct hostapd_config * hostapd_config_defaults(void) conf->he_6ghz_max_ampdu_len_exp = 7; conf->he_6ghz_rx_ant_pat = 1; conf->he_6ghz_tx_ant_pat = 1; + conf->he_6ghz_reg_pwr_type = HE_REG_INFO_6GHZ_AP_TYPE_VLP; + conf->reg_def_cli_eirp_psd = -1; + conf->reg_sub_cli_eirp_psd = -1; + conf->reg_def_cli_eirp = -1; #endif /* CONFIG_IEEE80211AX */ /* The third octet of the country string uses an ASCII space character @@ -293,6 +304,8 @@ struct hostapd_config * hostapd_config_defaults(void) conf->airtime_update_interval = AIRTIME_DEFAULT_UPDATE_INTERVAL; #endif /* CONFIG_AIRTIME_POLICY */ + hostapd_set_and_check_bw320_offset(conf, 0); + return conf; } @@ -461,9 +474,12 @@ static int hostapd_derive_psk(struct hostapd_ssid *ssid) wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)", (u8 *) ssid->wpa_passphrase, os_strlen(ssid->wpa_passphrase)); - pbkdf2_sha1(ssid->wpa_passphrase, - ssid->ssid, ssid->ssid_len, - 4096, ssid->wpa_psk->psk, PMK_LEN); + if (pbkdf2_sha1(ssid->wpa_passphrase, + ssid->ssid, ssid->ssid_len, + 4096, ssid->wpa_psk->psk, PMK_LEN) != 0) { + wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()"); + return -1; + } wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)", ssid->wpa_psk->psk, PMK_LEN); return 0; @@ -476,10 +492,11 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf) struct hostapd_ssid *ssid = &conf->ssid; struct sae_password_entry *pw; - if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) && + if ((conf->sae_pwe == SAE_PWE_HUNT_AND_PECK && + !hostapd_sae_pw_id_in_use(conf) && !wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt) && !hostapd_sae_pk_in_use(conf)) || - conf->sae_pwe == 3 || + conf->sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK || !wpa_key_mgmt_sae(conf->wpa_key_mgmt)) return 0; /* PT not needed */ @@ -542,6 +559,10 @@ static void hostapd_config_free_radius(struct hostapd_radius_server *servers, for (i = 0; i < num_servers; i++) { os_free(servers[i].shared_secret); + os_free(servers[i].ca_cert); + os_free(servers[i].client_cert); + os_free(servers[i].private_key); + os_free(servers[i].private_key_passwd); } os_free(servers); } @@ -687,6 +708,33 @@ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l) } +#ifdef CONFIG_IEEE80211R_AP + +void hostapd_config_clear_rxkhs(struct hostapd_bss_config *conf) +{ + struct ft_remote_r0kh *r0kh, *r0kh_prev; + struct ft_remote_r1kh *r1kh, *r1kh_prev; + + r0kh = conf->r0kh_list; + conf->r0kh_list = NULL; + while (r0kh) { + r0kh_prev = r0kh; + r0kh = r0kh->next; + os_free(r0kh_prev); + } + + r1kh = conf->r1kh_list; + conf->r1kh_list = NULL; + while (r1kh) { + r1kh_prev = r1kh; + r1kh = r1kh->next; + os_free(r1kh_prev); + } +} + +#endif /* CONFIG_IEEE80211R_AP */ + + static void hostapd_config_free_anqp_elem(struct hostapd_bss_config *conf) { struct anqp_element *elem; @@ -793,6 +841,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->radius_req_attr_sqlite); os_free(conf->rsn_preauth_interfaces); os_free(conf->ctrl_interface); + os_free(conf->config_id); os_free(conf->ca_cert); os_free(conf->server_cert); os_free(conf->server_cert2); @@ -810,6 +859,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->eap_fast_a_id); os_free(conf->eap_fast_a_id_info); os_free(conf->eap_sim_db); + os_free(conf->imsi_privacy_key); os_free(conf->radius_server_clients); os_free(conf->radius); os_free(conf->radius_das_shared_secret); @@ -817,26 +867,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->time_zone); #ifdef CONFIG_IEEE80211R_AP - { - struct ft_remote_r0kh *r0kh, *r0kh_prev; - struct ft_remote_r1kh *r1kh, *r1kh_prev; - - r0kh = conf->r0kh_list; - conf->r0kh_list = NULL; - while (r0kh) { - r0kh_prev = r0kh; - r0kh = r0kh->next; - os_free(r0kh_prev); - } - - r1kh = conf->r1kh_list; - conf->r1kh_list = NULL; - while (r1kh) { - r1kh_prev = r1kh; - r1kh = r1kh->next; - os_free(r1kh_prev); - } - } + hostapd_config_clear_rxkhs(conf); + os_free(conf->rxkh_file); + conf->rxkh_file = NULL; #endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_WPS @@ -934,6 +967,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) wpabuf_free(conf->rsnxe_override_ft); wpabuf_free(conf->gtk_rsc_override); wpabuf_free(conf->igtk_rsc_override); + wpabuf_free(conf->eapol_m1_elements); + wpabuf_free(conf->eapol_m3_elements); + wpabuf_free(conf->presp_elements); #endif /* CONFIG_TESTING_OPTIONS */ os_free(conf->no_probe_resp_if_seen_on); @@ -944,6 +980,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) #ifdef CONFIG_DPP os_free(conf->dpp_name); os_free(conf->dpp_mud_url); + os_free(conf->dpp_extra_conf_req_name); + os_free(conf->dpp_extra_conf_req_value); os_free(conf->dpp_connector); wpabuf_free(conf->dpp_netaccesskey); wpabuf_free(conf->dpp_csign); @@ -1119,10 +1157,9 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) { if (next_ok && (psk->group || - (addr && os_memcmp(psk->addr, addr, ETH_ALEN) == 0) || + (addr && ether_addr_equal(psk->addr, addr)) || (!addr && p2p_dev_addr && - os_memcmp(psk->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) == - 0))) { + ether_addr_equal(psk->p2p_dev_addr, p2p_dev_addr)))) { if (vlan_id) *vlan_id = psk->vlan_id; return psk->psk; @@ -1203,6 +1240,14 @@ static bool hostapd_config_check_bss_6g(struct hostapd_bss_config *bss) return false; } +#ifdef CONFIG_SAE + if (wpa_key_mgmt_sae(bss->wpa_key_mgmt) && + bss->sae_pwe == SAE_PWE_HUNT_AND_PECK) { + wpa_printf(MSG_INFO, "SAE: Enabling SAE H2E on 6 GHz"); + bss->sae_pwe = SAE_PWE_BOTH; + } +#endif /* CONFIG_SAE */ + return true; } @@ -1244,15 +1289,18 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, if (full_config && bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED && + bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS && bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) { wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no " "RADIUS checking (macaddr_acl=2) enabled."); return -1; } - if (full_config && bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) && + if (full_config && bss->wpa && + wpa_key_mgmt_wpa_psk_no_sae(bss->wpa_key_mgmt) && bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL && bss->ssid.wpa_psk_file == NULL && + bss->wpa_psk_radius != PSK_RADIUS_DURING_4WAY_HS && (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED || bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) { wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase " @@ -1425,7 +1473,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, #endif /* CONFIG_SAE_PK */ #ifdef CONFIG_FILS - if (full_config && bss->fils_discovery_min_int && + if (full_config && bss->fils_discovery_max_int && + (!conf->ieee80211ax || bss->disable_11ax)) { + wpa_printf(MSG_ERROR, + "Currently IEEE 802.11ax support is mandatory to enable FILS discovery transmission."); + return -1; + } + + if (full_config && bss->fils_discovery_max_int && bss->unsol_bcast_probe_resp_interval) { wpa_printf(MSG_ERROR, "Cannot enable both FILS discovery and unsolicited broadcast Probe Response at the same time"); @@ -1433,6 +1488,20 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, } #endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211BE + if (full_config && !bss->disable_11be && bss->disable_11ax) { + bss->disable_11be = true; + wpa_printf(MSG_INFO, + "Disabling IEEE 802.11be as IEEE 802.11ax is disabled for this BSS"); + } +#endif /* CONFIG_IEEE80211BE */ + + if (full_config && bss->ignore_broadcast_ssid && conf->mbssid) { + wpa_printf(MSG_ERROR, + "Hidden SSID is not suppored when MBSSID is enabled"); + return -1; + } + return 0; } @@ -1464,6 +1533,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config) { size_t i; + if (full_config && is_6ghz_op_class(conf->op_class) && + !conf->hw_mode_set) { + /* Use the appropriate hw_mode value automatically when the + * op_class parameter has been set, but hw_mode was not. */ + conf->hw_mode = HOSTAPD_MODE_IEEE80211A; + } + if (full_config && conf->ieee80211d && (!conf->country[0] || !conf->country[1])) { wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without " @@ -1501,6 +1577,24 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config) return -1; } +#ifdef CONFIG_IEEE80211BE + if (full_config && conf->ieee80211be && !conf->ieee80211ax) { + wpa_printf(MSG_ERROR, + "Cannot set ieee80211be without ieee80211ax"); + return -1; + } + + if (full_config) + hostapd_set_and_check_bw320_offset(conf, + conf->eht_bw320_offset); +#endif /* CONFIG_IEEE80211BE */ + + if (full_config && conf->mbssid && !conf->ieee80211ax) { + wpa_printf(MSG_ERROR, + "Cannot enable multiple BSSID support without ieee80211ax"); + return -1; + } + for (i = 0; i < conf->num_bss; i++) { if (hostapd_config_check_bss(conf->bss[i], conf, full_config)) return -1; @@ -1647,3 +1741,49 @@ bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf) return with_pk; } #endif /* CONFIG_SAE_PK */ + + +int hostapd_acl_comp(const void *a, const void *b) +{ + const struct mac_acl_entry *aa = a; + const struct mac_acl_entry *bb = b; + return os_memcmp(aa->addr, bb->addr, sizeof(macaddr)); +} + + +int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num, + int vlan_id, const u8 *addr) +{ + struct mac_acl_entry *newacl; + + newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl)); + if (!newacl) { + wpa_printf(MSG_ERROR, "MAC list reallocation failed"); + return -1; + } + + *acl = newacl; + os_memcpy((*acl)[*num].addr, addr, ETH_ALEN); + os_memset(&(*acl)[*num].vlan_id, 0, sizeof((*acl)[*num].vlan_id)); + (*acl)[*num].vlan_id.untagged = vlan_id; + (*acl)[*num].vlan_id.notempty = !!vlan_id; + (*num)++; + + return 0; +} + + +void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num, + const u8 *addr) +{ + int i = 0; + + while (i < *num) { + if (ether_addr_equal((*acl)[i].addr, addr)) { + os_remove_in_array(*acl, *num, sizeof(**acl), i); + (*num)--; + } else { + i++; + } + } +} diff --git a/wpa_supplicant-2.9_standard/src/ap/ap_config.h b/wpa_supplicant-2.9_standard/src/ap/ap_config.h index 6a24607827bc4563a0bde555d90405ee15dd4a16..421994a6ebfdc5410f0be55d67c8c338673297e3 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ap_config.h +++ b/wpa_supplicant-2.9_standard/src/ap/ap_config.h @@ -1,6 +1,6 @@ /* * hostapd / Configuration definitions and helpers functions - * Copyright (c) 2003-2015, Jouni Malinen + * Copyright (c) 2003-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -20,6 +20,12 @@ #include "fst/fst.h" #include "vlan.h" +enum macaddr_acl { + ACCEPT_UNLESS_DENIED = 0, + DENY_UNLESS_ACCEPTED = 1, + USE_EXTERNAL_RADIUS_AUTH = 2 +}; + /** * mesh_conf - local MBSS state and settings */ @@ -278,6 +284,7 @@ struct hostapd_bss_config { char bridge[IFNAMSIZ + 1]; char vlan_bridge[IFNAMSIZ + 1]; char wds_bridge[IFNAMSIZ + 1]; + int bridge_hairpin; /* hairpin_mode on bridge members */ enum hostapd_logger_level logger_syslog_level, logger_stdout_level; @@ -302,6 +309,7 @@ struct hostapd_bss_config { struct hostapd_ip_addr own_ip_addr; char *nas_identifier; struct hostapd_radius_servers *radius; + int radius_require_message_authenticator; int acct_interim_interval; int radius_request_cui; struct hostapd_radius_attr *radius_auth_req_attr; @@ -331,12 +339,11 @@ struct hostapd_bss_config { int eap_reauth_period; int erp_send_reauth_start; char *erp_domain; +#ifdef CONFIG_TESTING_OPTIONS + bool eap_skip_prot_success; +#endif /* CONFIG_TESTING_OPTIONS */ - enum macaddr_acl { - ACCEPT_UNLESS_DENIED = 0, - DENY_UNLESS_ACCEPTED = 1, - USE_EXTERNAL_RADIUS_AUTH = 2 - } macaddr_acl; + enum macaddr_acl macaddr_acl; struct mac_acl_entry *accept_mac; int num_accept_mac; struct mac_acl_entry *deny_mac; @@ -364,7 +371,8 @@ struct hostapd_bss_config { enum { PSK_RADIUS_IGNORED = 0, PSK_RADIUS_ACCEPTED = 1, - PSK_RADIUS_REQUIRED = 2 + PSK_RADIUS_REQUIRED = 2, + PSK_RADIUS_DURING_4WAY_HS = 3, } wpa_psk_radius; int wpa_pairwise; int group_cipher; /* wpa_group value override from configuation */ @@ -398,6 +406,7 @@ struct hostapd_bss_config { int ft_over_ds; int ft_psk_generate_local; int r1_max_key_lifetime; + char *rxkh_file; #endif /* CONFIG_IEEE80211R_AP */ char *ctrl_interface; /* directory for UNIX domain sockets */ @@ -437,8 +446,11 @@ struct hostapd_bss_config { int eap_teap_pac_no_inner; int eap_teap_separate_result; int eap_teap_id; + int eap_teap_method_sequence; int eap_sim_aka_result_ind; int eap_sim_id; + char *imsi_privacy_key; + int eap_sim_aka_fast_reauth_limit; int tnc; int fragment_size; u16 pwd_group; @@ -454,6 +466,9 @@ struct hostapd_bss_config { */ int ap_max_inactivity; + int bss_max_idle; + int max_acceptable_idle_period; + bool no_disconnect_on_group_keyerror; int ignore_broadcast_ssid; int no_probe_resp_if_max_sta; @@ -537,6 +552,7 @@ struct hostapd_bss_config { bool disable_11n; bool disable_11ac; bool disable_11ax; + bool disable_11be; /* IEEE 802.11v */ int time_advertisement; @@ -662,7 +678,7 @@ struct hostapd_bss_config { unsigned int sae_sync; int sae_require_mfp; int sae_confirm_immediate; - int sae_pwe; + enum sae_pwe sae_pwe; int *sae_groups; struct sae_password_entry *sae_passwords; @@ -693,6 +709,15 @@ struct hostapd_bss_config { unsigned int oci_freq_override_ft_assoc; unsigned int oci_freq_override_fils_assoc; unsigned int oci_freq_override_wnm_sleep; + struct wpabuf *eapol_m1_elements; + struct wpabuf *eapol_m3_elements; + bool eapol_m3_no_encrypt; + int test_assoc_comeback_type; + struct wpabuf *presp_elements; + +#ifdef CONFIG_IEEE80211BE + u16 eht_oper_puncturing_override; +#endif /* CONFIG_IEEE80211BE */ #endif /* CONFIG_TESTING_OPTIONS */ #define MESH_ENABLED BIT(0) @@ -739,6 +764,7 @@ struct hostapd_bss_config { #endif /* CONFIG_FILS */ int multicast_to_unicast; + int bridge_multicast_to_unicast; int broadcast_deauth; @@ -747,12 +773,15 @@ struct hostapd_bss_config { #ifdef CONFIG_DPP char *dpp_name; char *dpp_mud_url; + char *dpp_extra_conf_req_name; + char *dpp_extra_conf_req_value; char *dpp_connector; struct wpabuf *dpp_netaccesskey; unsigned int dpp_netaccesskey_expiry; struct wpabuf *dpp_csign; #ifdef CONFIG_DPP2 struct dpp_controller_conf *dpp_controller; + int dpp_relay_port; int dpp_configurator_connectivity; int dpp_pfs; #endif /* CONFIG_DPP2 */ @@ -776,6 +805,14 @@ struct hostapd_bss_config { #define BACKHAUL_BSS 1 #define FRONTHAUL_BSS 2 int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */ + int multi_ap_profile; + /* Multi-AP Profile-1 clients not allowed to connect */ +#define PROFILE1_CLIENT_ASSOC_DISALLOW BIT(0) + /* Multi-AP Profile-2 clients not allowed to connect */ +#define PROFILE2_CLIENT_ASSOC_DISALLOW BIT(1) + unsigned int multi_ap_client_disallow; + /* Primary VLAN ID to use in Multi-AP */ + int multi_ap_vlanid; #ifdef CONFIG_AIRTIME_POLICY unsigned int airtime_weight; @@ -832,6 +869,19 @@ struct hostapd_bss_config { */ u32 macsec_replay_window; + /** + * macsec_offload - Enable MACsec offload + * + * This setting applies only when MACsec is in use, i.e., + * - macsec_policy is enabled + * - the key server has decided to enable MACsec + * + * 0 = MACSEC_OFFLOAD_OFF (default) + * 1 = MACSEC_OFFLOAD_PHY + * 2 = MACSEC_OFFLOAD_MAC + */ + int macsec_offload; + /** * macsec_port - MACsec port (in SCI) * @@ -848,6 +898,13 @@ struct hostapd_bss_config { */ int mka_priority; + /** + * macsec_csindex - Cipher suite index for MACsec + * + * Range: 0-1 (default: 0) + */ + int macsec_csindex; + /** * mka_ckn - MKA pre-shared CKN */ @@ -872,6 +929,9 @@ struct hostapd_bss_config { #endif /* CONFIG_MACSEC */ #ifdef CONFIG_PASN + /* Whether to allow PASN-UNAUTH */ + int pasn_noauth; + #ifdef CONFIG_TESTING_OPTIONS /* * Normally, KDK should be derived if and only if both sides support @@ -898,6 +958,29 @@ struct hostapd_bss_config { u8 ext_capa[EXT_CAPA_MAX_LEN]; u8 rnr; + char *config_id; + bool xrates_supported; + + bool ssid_protection; + +#ifdef CONFIG_IEEE80211BE + /* The AP is part of an AP MLD */ + u8 mld_ap; + + /* The MLD ID to which the AP MLD is affiliated with */ + u8 mld_id; + + /* The AP's MLD MAC address within the AP MLD */ + u8 mld_addr[ETH_ALEN]; + +#ifdef CONFIG_TESTING_OPTIONS + /* + * If set indicate the AP as disabled in the RNR element included in the + * other APs in the AP MLD. + */ + bool mld_indicate_disabled; +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_IEEE80211BE */ }; /** @@ -936,6 +1019,15 @@ struct spatial_reuse { u8 srg_partial_bssid_bitmap[8]; }; +/** + * struct eht_phy_capabilities_info - EHT PHY capabilities + */ +struct eht_phy_capabilities_info { + bool su_beamformer; + bool su_beamformee; + bool mu_beamformer; +}; + /** * struct hostapd_config - Per-radio interface configuration */ @@ -957,7 +1049,9 @@ struct hostapd_config { int acs_exclude_dfs; u8 min_tx_power; enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ + bool hw_mode_set; int acs_exclude_6ghz_non_psc; + int enable_background_radar; enum { LONG_PREAMBLE = 0, SHORT_PREAMBLE = 1 @@ -1022,7 +1116,7 @@ struct hostapd_config { u32 vht_capab; int ieee80211ac; int require_vht; - u8 vht_oper_chwidth; + enum oper_chan_width vht_oper_chwidth; u8 vht_oper_centr_freq_seg0_idx; u8 vht_oper_centr_freq_seg1_idx; u8 ht40_plus_minus_allowed; @@ -1045,6 +1139,7 @@ struct hostapd_config { double ignore_reassoc_probability; double corrupt_gtk_rekey_mic_probability; int ecsa_ie_only; + bool delay_eapol_tx; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_ACS @@ -1066,13 +1161,28 @@ struct hostapd_config { struct he_operation he_op; struct ieee80211_he_mu_edca_parameter_set he_mu_edca; struct spatial_reuse spr; - u8 he_oper_chwidth; + enum oper_chan_width he_oper_chwidth; u8 he_oper_centr_freq_seg0_idx; u8 he_oper_centr_freq_seg1_idx; u8 he_6ghz_max_mpdu; u8 he_6ghz_max_ampdu_len_exp; u8 he_6ghz_rx_ant_pat; u8 he_6ghz_tx_ant_pat; + u8 he_6ghz_reg_pwr_type; + + int reg_def_cli_eirp_psd; + int reg_sub_cli_eirp_psd; + + /* + * This value should be used when regulatory client EIRP PSD values + * advertised by an AP that is an SP AP or an indoor SP AP are + * insufficient to ensure that regulatory client limits on total EIRP + * are always met for all transmission bandwidths within the bandwidth + * of the AP’s BSS. + */ + int reg_def_cli_eirp; + + bool require_he; #endif /* CONFIG_IEEE80211AX */ /* VHT enable/disable config from CHAN_SWITCH */ @@ -1103,11 +1213,41 @@ struct hostapd_config { int ht20_set_flag; #define AP_BANDWIDTH_160M (8) u8 bandwidth; + + int ieee80211be; +#ifdef CONFIG_IEEE80211BE + enum oper_chan_width eht_oper_chwidth; + u8 eht_oper_centr_freq_seg0_idx; + struct eht_phy_capabilities_info eht_phy_capab; + u16 punct_bitmap; /* a bitmap of disabled 20 MHz channels */ + u8 punct_acs_threshold; + u8 eht_default_pe_duration; + u8 eht_bw320_offset; +#endif /* CONFIG_IEEE80211BE */ + + /* EHT enable/disable config from CHAN_SWITCH */ +#define CH_SWITCH_EHT_ENABLED BIT(0) +#define CH_SWITCH_EHT_DISABLED BIT(1) + unsigned int ch_switch_eht_config; + + enum mbssid { + MBSSID_DISABLED = 0, + MBSSID_ENABLED = 1, + ENHANCED_MBSSID_ENABLED = 2, + } mbssid; + + /* Whether to enable TWT responder in HT and VHT modes */ + bool ht_vht_twt_responder; }; -static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf) +static inline enum oper_chan_width +hostapd_get_oper_chwidth(struct hostapd_config *conf) { +#ifdef CONFIG_IEEE80211BE + if (conf->ieee80211be) + return conf->eht_oper_chwidth; +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_IEEE80211AX if (conf->ieee80211ax) return conf->he_oper_chwidth; @@ -1116,8 +1256,15 @@ static inline u8 hostapd_get_oper_chwidth(struct hostapd_config *conf) } static inline void -hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth) +hostapd_set_oper_chwidth(struct hostapd_config *conf, + enum oper_chan_width oper_chwidth) { +#ifdef CONFIG_IEEE80211BE + if (conf->ieee80211be) + conf->eht_oper_chwidth = oper_chwidth; + if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) + oper_chwidth = CONF_OPER_CHWIDTH_160MHZ; +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_IEEE80211AX if (conf->ieee80211ax) conf->he_oper_chwidth = oper_chwidth; @@ -1128,6 +1275,10 @@ hostapd_set_oper_chwidth(struct hostapd_config *conf, u8 oper_chwidth) static inline u8 hostapd_get_oper_centr_freq_seg0_idx(struct hostapd_config *conf) { +#ifdef CONFIG_IEEE80211BE + if (conf->ieee80211be) + return conf->eht_oper_centr_freq_seg0_idx; +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_IEEE80211AX if (conf->ieee80211ax) return conf->he_oper_centr_freq_seg0_idx; @@ -1139,6 +1290,14 @@ static inline void hostapd_set_oper_centr_freq_seg0_idx(struct hostapd_config *conf, u8 oper_centr_freq_seg0_idx) { +#ifdef CONFIG_IEEE80211BE + if (conf->ieee80211be) + conf->eht_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx; + if (is_6ghz_op_class(conf->op_class) && + center_idx_to_bw_6ghz(oper_centr_freq_seg0_idx) == 4) + oper_centr_freq_seg0_idx += + conf->channel > oper_centr_freq_seg0_idx ? 16 : -16; +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_IEEE80211AX if (conf->ieee80211ax) conf->he_oper_centr_freq_seg0_idx = oper_centr_freq_seg0_idx; @@ -1167,6 +1326,43 @@ hostapd_set_oper_centr_freq_seg1_idx(struct hostapd_config *conf, conf->vht_oper_centr_freq_seg1_idx = oper_centr_freq_seg1_idx; } +static inline u8 +hostapd_get_bw320_offset(struct hostapd_config *conf) +{ +#ifdef CONFIG_IEEE80211BE + if (conf->ieee80211be && is_6ghz_op_class(conf->op_class) && + hostapd_get_oper_chwidth(conf) == CONF_OPER_CHWIDTH_320MHZ) + return conf->eht_bw320_offset; +#endif /* CONFIG_IEEE80211BE */ + return 0; +} + +static inline void +hostapd_set_and_check_bw320_offset(struct hostapd_config *conf, + u8 bw320_offset) +{ +#ifdef CONFIG_IEEE80211BE + if (conf->ieee80211be && is_6ghz_op_class(conf->op_class) && + op_class_to_ch_width(conf->op_class) == CONF_OPER_CHWIDTH_320MHZ) { + if (conf->channel) { + /* If the channel is set, then calculate bw320_offset + * by center frequency segment 0. + */ + u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf); + + conf->eht_bw320_offset = (seg0 - 31) % 64 ? 2 : 1; + } else { + /* If the channel is not set, bw320_offset indicates + * preferred offset of 320 MHz. + */ + conf->eht_bw320_offset = bw320_offset; + } + } else { + conf->eht_bw320_offset = 0; + } +#endif /* CONFIG_IEEE80211BE */ +} + int hostapd_mac_comp(const void *a, const void *b); struct hostapd_config * hostapd_config_defaults(void); @@ -1175,6 +1371,7 @@ void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr); void hostapd_config_free_eap_user(struct hostapd_eap_user *user); void hostapd_config_free_eap_users(struct hostapd_eap_user *user); void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p); +void hostapd_config_clear_rxkhs(struct hostapd_bss_config *conf); void hostapd_config_free_bss(struct hostapd_bss_config *conf); void hostapd_config_free(struct hostapd_config *conf); int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, @@ -1198,5 +1395,10 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf); bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf); bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf); int hostapd_setup_sae_pt(struct hostapd_bss_config *conf); +int hostapd_acl_comp(const void *a, const void *b); +int hostapd_add_acl_maclist(struct mac_acl_entry **acl, int *num, + int vlan_id, const u8 *addr); +void hostapd_remove_acl_mac(struct mac_acl_entry **acl, int *num, + const u8 *addr); #endif /* HOSTAPD_CONFIG_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ap_drv_ops.c b/wpa_supplicant-2.9_standard/src/ap/ap_drv_ops.c index 52437b46440abcf85a2d0df96d650c5770de77ca..0e3bf2f48a6501e09e1170e75f5a72b7011613fc 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ap_drv_ops.c +++ b/wpa_supplicant-2.9_standard/src/ap/ap_drv_ops.c @@ -80,6 +80,14 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, *beacon_ret = *proberesp_ret = *assocresp_ret = NULL; +#ifdef NEED_AP_MLME + pos = buf; + pos = hostapd_eid_rm_enabled_capab(hapd, pos, sizeof(buf)); + if (add_buf_data(&assocresp, buf, pos - buf) < 0 || + add_buf_data(&proberesp, buf, pos - buf) < 0) + goto fail; +#endif /* NEED_AP_MLME */ + pos = buf; pos = hostapd_eid_time_adv(hapd, pos); if (add_buf_data(&beacon, buf, pos - buf) < 0) @@ -89,7 +97,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, goto fail; pos = buf; - pos = hostapd_eid_ext_capab(hapd, pos); + pos = hostapd_eid_ext_capab(hapd, pos, false); if (add_buf_data(&assocresp, buf, pos - buf) < 0) goto fail; pos = hostapd_eid_interworking(hapd, pos); @@ -205,7 +213,11 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, add_buf(&beacon, hapd->conf->vendor_elements); add_buf(&proberesp, hapd->conf->vendor_elements); +#ifdef CONFIG_TESTING_OPTIONS + add_buf(&proberesp, hapd->conf->presp_elements); +#endif /* CONFIG_TESTING_OPTIONS */ add_buf(&assocresp, hapd->conf->assocresp_elements); + *beacon_ret = beacon; *proberesp_ret = proberesp; *assocresp_ret = assocresp; @@ -261,9 +273,35 @@ int hostapd_set_ap_wps_ie(struct hostapd_data *hapd) } +bool hostapd_sta_is_link_sta(struct hostapd_data *hapd, + struct sta_info *sta) +{ +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta) && + sta->mld_assoc_link_id != hapd->mld_link_id) + return true; +#endif /* CONFIG_IEEE80211BE */ + + return false; +} + + int hostapd_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized) { + /* + * The WPA_STA_AUTHORIZED flag is relevant only for the MLD station and + * not to the link stations (as the authorization is done between the + * MLD peers). Thus, do not propagate the change to the driver for the + * link stations. + */ + if (hostapd_sta_is_link_sta(hapd, sta)) { + wpa_printf(MSG_DEBUG, + "%s: Do not update link station flags (" MACSTR ")", + __func__, MAC2STR(sta->addr)); + return 0; + } + if (authorized) { return hostapd_sta_set_flags(hapd, sta->addr, hostapd_sta_flags_to_drv( @@ -281,11 +319,24 @@ int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta) { int set_flags, total_flags, flags_and, flags_or; total_flags = hostapd_sta_flags_to_drv(sta->flags); - set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP; - if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || - sta->auth_alg == WLAN_AUTH_FT) && - sta->flags & WLAN_STA_AUTHORIZED) - set_flags |= WPA_STA_AUTHORIZED; + set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP | + WPA_STA_AUTHORIZED; + + /* + * All the station flags other than WPA_STA_SHORT_PREAMBLE are relevant + * only for the MLD station and not to the link stations (as these flags + * are related to the MLD state and not the link state). As for the + * WPA_STA_SHORT_PREAMBLE, since the station is an EHT station, it must + * support short preamble. Thus, do not propagate the change to the + * driver for the link stations. + */ + if (hostapd_sta_is_link_sta(hapd, sta)) { + wpa_printf(MSG_DEBUG, + "%s: Do not update link station flags (" MACSTR ")", + __func__, MAC2STR(sta->addr)); + return 0; + } + flags_or = total_flags & set_flags; flags_and = total_flags | ~set_flags; return hostapd_sta_set_flags(hapd, sta->addr, total_flags, @@ -422,9 +473,11 @@ int hostapd_sta_add(struct hostapd_data *hapd, const struct ieee80211_vht_capabilities *vht_capab, const struct ieee80211_he_capabilities *he_capab, size_t he_capab_len, + const struct ieee80211_eht_capabilities *eht_capab, + size_t eht_capab_len, const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab, u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, - int set) + int set, const u8 *link_addr, bool mld_link_sta) { struct hostapd_sta_add_params params; @@ -444,6 +497,8 @@ int hostapd_sta_add(struct hostapd_data *hapd, params.vht_capabilities = vht_capab; params.he_capab = he_capab; params.he_capab_len = he_capab_len; + params.eht_capab = eht_capab; + params.eht_capab_len = eht_capab_len; params.he_6ghz_capab = he_6ghz_capab; params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED); params.vht_opmode = vht_opmode; @@ -451,6 +506,20 @@ int hostapd_sta_add(struct hostapd_data *hapd, params.qosinfo = qosinfo; params.support_p2p_ps = supp_p2p_ps; params.set = set; + params.mld_link_id = -1; + +#ifdef CONFIG_IEEE80211BE + /* + * An AP MLD needs to always specify to what link the station needs + * to be added. + */ + if (hapd->conf->mld_ap) { + params.mld_link_id = hapd->mld_link_id; + params.mld_link_addr = link_addr; + params.mld_link_sta = mld_link_sta; + } +#endif /* CONFIG_IEEE80211BE */ + return hapd->driver->sta_add(hapd->drv_priv, ¶ms); } @@ -511,12 +580,33 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type, } +#ifdef CONFIG_IEEE80211BE +int hostapd_if_link_remove(struct hostapd_data *hapd, + enum wpa_driver_if_type type, + const char *ifname, u8 link_id) +{ + if (!hapd->driver || !hapd->drv_priv || !hapd->driver->link_remove) + return -1; + + return hapd->driver->link_remove(hapd->drv_priv, type, ifname, + hapd->mld_link_id); +} +#endif /* CONFIG_IEEE80211BE */ + + int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type, const char *ifname) { if (hapd->driver == NULL || hapd->drv_priv == NULL || hapd->driver->if_remove == NULL) return -1; + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) + return hostapd_if_link_remove(hapd, type, ifname, + hapd->mld_link_id); +#endif /* CONFIG_IEEE80211BE */ + return hapd->driver->if_remove(hapd->drv_priv, type, ifname); } @@ -531,27 +621,35 @@ int hostapd_set_ieee8021x(struct hostapd_data *hapd, int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, - const u8 *addr, int idx, u8 *seq) + const u8 *addr, int idx, int link_id, u8 *seq) { if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL) return 0; return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx, - seq); + link_id, seq); } int hostapd_flush(struct hostapd_data *hapd) { + int link_id = -1; + if (hapd->driver == NULL || hapd->driver->flush == NULL) return 0; - return hapd->driver->flush(hapd->drv_priv); + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf && hapd->conf->mld_ap) + link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ + + return hapd->driver->flush(hapd->drv_priv, link_id); } int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode, int freq, int channel, int edmg, u8 edmg_channel, int ht_enabled, int vht_enabled, - int he_enabled, + int he_enabled, bool eht_enabled, int sec_channel_offset, int oper_chwidth, int center_segment0, int center_segment1) { @@ -560,18 +658,32 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode, if (hostapd_set_freq_params(&data, mode, freq, channel, edmg, edmg_channel, ht_enabled, - vht_enabled, he_enabled, sec_channel_offset, - oper_chwidth, + vht_enabled, he_enabled, eht_enabled, + sec_channel_offset, oper_chwidth, center_segment0, center_segment1, cmode ? cmode->vht_capab : 0, cmode ? - &cmode->he_capab[IEEE80211_MODE_AP] : NULL)) + &cmode->he_capab[IEEE80211_MODE_AP] : NULL, + cmode ? + &cmode->eht_capab[IEEE80211_MODE_AP] : + NULL, hostapd_get_punct_bitmap(hapd))) return -1; if (hapd->driver == NULL) return 0; if (hapd->driver->set_freq == NULL) return 0; + + data.link_id = -1; + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) { + data.link_id = hapd->mld_link_id; + wpa_printf(MSG_DEBUG, + "hostapd_set_freq: link_id=%d", data.link_id); + } +#endif /* CONFIG_IEEE80211BE */ + return hapd->driver->set_freq(hapd->drv_priv, &data); } @@ -623,10 +735,19 @@ int hostapd_set_country(struct hostapd_data *hapd, const char *country) int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs, int cw_min, int cw_max, int burst_time) { + int link_id = -1; + if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL) return 0; + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) + link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ + return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs, - cw_min, cw_max, burst_time); + cw_min, cw_max, burst_time, + link_id); } @@ -634,8 +755,8 @@ struct hostapd_hw_modes * hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, u16 *flags, u8 *dfs_domain) { - if (hapd->driver == NULL || - hapd->driver->get_hw_feature_data == NULL) + if (!hapd->driver || !hapd->driver->get_hw_feature_data || + !hapd->drv_priv) return NULL; return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes, flags, dfs_domain); @@ -674,6 +795,8 @@ int hostapd_driver_scan(struct hostapd_data *hapd, struct wpa_scan_results * hostapd_driver_get_scan_results( struct hostapd_data *hapd) { + if (hapd->driver && hapd->driver->get_scan_results) + return hapd->driver->get_scan_results(hapd->drv_priv, NULL); if (hapd->driver && hapd->driver->get_scan_results2) return hapd->driver->get_scan_results2(hapd->drv_priv); return NULL; @@ -713,9 +836,13 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd, params.key_len = key_len; params.vlan_id = vlan_id; params.key_flag = key_flag; -#ifdef CONFIG_MLD_PATCH params.link_id = -1; -#endif + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap && !(key_flag & KEY_FLAG_PAIRWISE)) + params.link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ + return hapd->driver->set_key(hapd->drv_priv, ¶ms); } @@ -725,37 +852,69 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd, const u16 *csa_offs, size_t csa_offs_len, int no_encrypt) { + int link_id = -1; + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) + link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ + if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv) return 0; return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0, - csa_offs, csa_offs_len, no_encrypt, 0); + csa_offs, csa_offs_len, no_encrypt, 0, + link_id); } int hostapd_drv_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason) { + int link_id = -1; + const u8 *own_addr = hapd->own_addr; + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) { + struct sta_info *sta = ap_get_sta(hapd, addr); + + link_id = hapd->mld_link_id; + if (ap_sta_is_mld(hapd, sta)) + own_addr = hapd->mld->mld_addr; + } +#endif /* CONFIG_IEEE80211BE */ + if (!hapd->driver || !hapd->driver->sta_deauth || !hapd->drv_priv) return 0; #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_go_p2p_state(hapd, addr, P2P_INTERFACE_STATE_DISCONNECTED, reason); #endif - return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr, - reason); + return hapd->driver->sta_deauth(hapd->drv_priv, own_addr, addr, + reason, link_id); } int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, const u8 *addr, int reason) { + const u8 *own_addr = hapd->own_addr; + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) { + struct sta_info *sta = ap_get_sta(hapd, addr); + + if (ap_sta_is_mld(hapd, sta)) + own_addr = hapd->mld->mld_addr; + } +#endif /* CONFIG_IEEE80211BE */ + if (!hapd->driver || !hapd->driver->sta_disassoc || !hapd->drv_priv) return 0; #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_go_p2p_state(hapd, addr, P2P_INTERFACE_STATE_DISCONNECTED, reason); #endif - return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr, + return hapd->driver->sta_disassoc(hapd->drv_priv, own_addr, addr, reason); } @@ -770,22 +929,22 @@ int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper, } -int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq, - unsigned int wait, const u8 *dst, const u8 *data, - size_t len) +static int hapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq, + unsigned int wait, const u8 *dst, + const u8 *data, size_t len, bool addr3_ap) { + const u8 *own_addr = hapd->own_addr; const u8 *bssid; const u8 wildcard_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct sta_info *sta; if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv) return 0; bssid = hapd->own_addr; - if (!is_multicast_ether_addr(dst) && + if (!addr3_ap && !is_multicast_ether_addr(dst) && len > 0 && data[0] == WLAN_ACTION_PUBLIC) { - struct sta_info *sta; - /* * Public Action frames to a STA that is not a member of the BSS * shall use wildcard BSSID value. @@ -793,7 +952,7 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq, sta = ap_get_sta(hapd, dst); if (!sta || !(sta->flags & WLAN_STA_ASSOC)) bssid = wildcard_bssid; - } else if (is_broadcast_ether_addr(dst) && + } else if (!addr3_ap && is_broadcast_ether_addr(dst) && len > 0 && data[0] == WLAN_ACTION_PUBLIC) { /* * The only current use case of Public Action frames with @@ -802,9 +961,27 @@ int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq, * so have to use the wildcard BSSID value. */ bssid = wildcard_bssid; +#ifdef CONFIG_IEEE80211BE + } else if (hapd->conf->mld_ap) { + sta = ap_get_sta(hapd, dst); + + if (ap_sta_is_mld(hapd, sta)) { + own_addr = hapd->mld->mld_addr; + bssid = own_addr; + } +#endif /* CONFIG_IEEE80211BE */ } + return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst, - hapd->own_addr, bssid, data, len, 0); + own_addr, bssid, data, len, 0); +} + + +int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq, + unsigned int wait, const u8 *dst, const u8 *data, + size_t len) +{ + return hapd_drv_send_action(hapd, freq, wait, dst, data, len, false); } @@ -813,20 +990,17 @@ int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd, unsigned int wait, const u8 *dst, const u8 *data, size_t len) { - if (hapd->driver == NULL || hapd->driver->send_action == NULL) - return 0; - return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst, - hapd->own_addr, hapd->own_addr, data, - len, 0); + return hapd_drv_send_action(hapd, freq, wait, dst, data, len, true); } int hostapd_start_dfs_cac(struct hostapd_iface *iface, enum hostapd_hw_mode mode, int freq, int channel, int ht_enabled, int vht_enabled, - int he_enabled, + int he_enabled, bool eht_enabled, int sec_channel_offset, int oper_chwidth, - int center_segment0, int center_segment1) + int center_segment0, int center_segment1, + bool radar_background) { struct hostapd_data *hapd = iface->bss[0]; struct hostapd_freq_params data; @@ -844,18 +1018,25 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0, ht_enabled, - vht_enabled, he_enabled, sec_channel_offset, + vht_enabled, he_enabled, eht_enabled, + sec_channel_offset, oper_chwidth, center_segment0, center_segment1, cmode->vht_capab, - &cmode->he_capab[IEEE80211_MODE_AP])) { + &cmode->he_capab[IEEE80211_MODE_AP], + &cmode->eht_capab[IEEE80211_MODE_AP], + hostapd_get_punct_bitmap(hapd))) { wpa_printf(MSG_ERROR, "Can't set freq params"); return -1; } + data.radar_background = radar_background; res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data); if (!res) { - iface->cac_started = 1; + if (radar_background) + iface->radar_background.cac_started = 1; + else + iface->cac_started = 1; os_get_reltime(&iface->dfs_cac_start); } @@ -866,19 +1047,21 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set, u8 qos_map_set_len) { - if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv) + if (!hapd->driver || !hapd->driver->set_qos_map || !hapd->drv_priv || + !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING)) return 0; return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set, qos_map_set_len); } -static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, - struct hostapd_hw_modes *mode, - int acs_ch_list_all, - int **freq_list) +void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, + struct hostapd_hw_modes *mode, + int acs_ch_list_all, bool allow_disabled, + int **freq_list) { int i; + bool is_no_ir = false; for (i = 0; i < mode->num_channels; i++) { struct hostapd_channel_data *chan = &mode->channels[i]; @@ -897,15 +1080,22 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, chan->chan))) continue; if (is_6ghz_freq(chan->freq) && - hapd->iface->conf->acs_exclude_6ghz_non_psc && - !is_6ghz_psc_frequency(chan->freq)) + ((hapd->iface->conf->acs_exclude_6ghz_non_psc && + !is_6ghz_psc_frequency(chan->freq)) || + (!hapd->iface->conf->ieee80211ax && + !hapd->iface->conf->ieee80211be))) continue; - if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && + if ((!(chan->flag & HOSTAPD_CHAN_DISABLED) || allow_disabled) && !(hapd->iface->conf->acs_exclude_dfs && (chan->flag & HOSTAPD_CHAN_RADAR)) && !(chan->max_tx_power < hapd->iface->conf->min_tx_power)) int_array_add_unique(freq_list, chan->freq); + else if ((chan->flag & HOSTAPD_CHAN_NO_IR) && + is_6ghz_freq(chan->freq)) + is_no_ir = true; } + + hapd->iface->is_no_ir = is_no_ir; } @@ -923,6 +1113,24 @@ void hostapd_get_ext_capa(struct hostapd_iface *iface) } +void hostapd_get_mld_capa(struct hostapd_iface *iface) +{ + struct hostapd_data *hapd = iface->bss[0]; + + if (!hapd->driver || !hapd->driver->get_mld_capab) + return; + + hapd->driver->get_mld_capab(hapd->drv_priv, WPA_IF_AP_BSS, + &iface->mld_eml_capa, + &iface->mld_mld_capa); +} + + +/** + * hostapd_drv_do_acs - Start automatic channel selection + * @hapd: BSS data for the device initiating ACS + * Returns: 0 on success, -1 on failure, 1 on failure due to NO_IR (AFC) + */ int hostapd_drv_do_acs(struct hostapd_data *hapd) { struct drv_acs_params params; @@ -936,6 +1144,12 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd) os_memset(¶ms, 0, sizeof(params)); params.hw_mode = hapd->iface->conf->hw_mode; + params.link_id = -1; +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap && hapd->iconf->ieee80211be && + !hapd->conf->disable_11be) + params.link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ /* * If no chanlist config parameter is provided, include all enabled @@ -957,7 +1171,13 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd) selected_mode != mode->mode) continue; hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all, - &freq_list); + false, &freq_list); + } + + if (!freq_list && hapd->iface->is_no_ir) { + wpa_printf(MSG_ERROR, + "NO_IR: Interface freq_list is empty. Failing do_acs."); + return 1; } params.freq_list = freq_list; @@ -967,22 +1187,27 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd) params.ht40_enabled = !!(hapd->iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET); params.vht_enabled = !!(hapd->iface->conf->ieee80211ac); + params.eht_enabled = !!(hapd->iface->conf->ieee80211be); params.ch_width = 20; if (hapd->iface->conf->ieee80211n && params.ht40_enabled) params.ch_width = 40; /* Note: VHT20 is defined by combination of ht_capab & oper_chwidth */ - if ((hapd->iface->conf->ieee80211ax || + if ((hapd->iface->conf->ieee80211be || + hapd->iface->conf->ieee80211ax || hapd->iface->conf->ieee80211ac) && params.ht40_enabled) { - u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf); + enum oper_chan_width oper_chwidth; - if (oper_chwidth == CHANWIDTH_80MHZ) + oper_chwidth = hostapd_get_oper_chwidth(hapd->iface->conf); + if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ) params.ch_width = 80; - else if (oper_chwidth == CHANWIDTH_160MHZ || - oper_chwidth == CHANWIDTH_80P80MHZ) + else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ || + oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) params.ch_width = 160; + else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) + params.ch_width = 320; } if (hapd->iface->conf->op_class) @@ -1011,3 +1236,30 @@ int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable) return 0; return hapd->driver->dpp_listen(hapd->drv_priv, enable); } + + +#ifdef CONFIG_PASN +int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd, + const u8 *own_addr, const u8 *peer_addr, + u32 cipher, u8 tk_len, const u8 *tk, + u8 ltf_keyseed_len, + const u8 *ltf_keyseed, u32 action) +{ + struct secure_ranging_params params; + + if (!hapd->driver || !hapd->driver->set_secure_ranging_ctx) + return 0; + + os_memset(¶ms, 0, sizeof(params)); + params.own_addr = own_addr; + params.peer_addr = peer_addr; + params.cipher = cipher; + params.tk_len = tk_len; + params.tk = tk; + params.ltf_keyseed_len = ltf_keyseed_len; + params.ltf_keyseed = ltf_keyseed; + params.action = action; + + return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, ¶ms); +} +#endif /* CONFIG_PASN */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ap_drv_ops.h b/wpa_supplicant-2.9_standard/src/ap/ap_drv_ops.h index 0e80c7866d09df822c8107509b6b30639df75d51..0d0a5036aa87c579928168323da670bc0662634e 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ap_drv_ops.h +++ b/wpa_supplicant-2.9_standard/src/ap/ap_drv_ops.h @@ -27,6 +27,8 @@ void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon, struct wpabuf *assocresp); int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd); int hostapd_set_ap_wps_ie(struct hostapd_data *hapd); +bool hostapd_sta_is_link_sta(struct hostapd_data *hapd, + struct sta_info *sta); int hostapd_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized); int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta); @@ -44,9 +46,11 @@ int hostapd_sta_add(struct hostapd_data *hapd, const struct ieee80211_vht_capabilities *vht_capab, const struct ieee80211_he_capabilities *he_capab, size_t he_capab_len, + const struct ieee80211_eht_capabilities *eht_capab, + size_t eht_capab_len, const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab, u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, - int set); + int set, const u8 *link_addr, bool mld_link_sta); int hostapd_set_privacy(struct hostapd_data *hapd, int enabled); int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem, size_t elem_len); @@ -58,15 +62,18 @@ int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type, const char *bridge, int use_existing); int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type, const char *ifname); +int hostapd_if_link_remove(struct hostapd_data *hapd, + enum wpa_driver_if_type type, + const char *ifname, u8 link_id); int hostapd_set_ieee8021x(struct hostapd_data *hapd, struct wpa_bss_params *params); int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, - const u8 *addr, int idx, u8 *seq); + const u8 *addr, int idx, int link_id, u8 *seq); int hostapd_flush(struct hostapd_data *hapd); int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode, int freq, int channel, int edmg, u8 edmg_channel, - int ht_enabled, int vht_enabled, - int he_enabled, int sec_channel_offset, int oper_chwidth, + int ht_enabled, int vht_enabled, int he_enabled, + bool eht_enabled, int sec_channel_offset, int oper_chwidth, int center_segment0, int center_segment1); int hostapd_set_rts(struct hostapd_data *hapd, int rts); int hostapd_set_frag(struct hostapd_data *hapd, int frag); @@ -129,13 +136,19 @@ int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr, int hostapd_start_dfs_cac(struct hostapd_iface *iface, enum hostapd_hw_mode mode, int freq, int channel, int ht_enabled, int vht_enabled, - int he_enabled, + int he_enabled, bool eht_enabled, int sec_channel_offset, int oper_chwidth, - int center_segment0, int center_segment1); + int center_segment0, int center_segment1, + bool radar_background); int hostapd_drv_do_acs(struct hostapd_data *hapd); int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer, u16 reason_code, const u8 *ie, size_t ielen); int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable); +int hostapd_drv_set_secure_ranging_ctx(struct hostapd_data *hapd, + const u8 *own_addr, const u8 *addr, + u32 cipher, u8 key_len, const u8 *key, + u8 ltf_keyseed_len, + const u8 *ltf_keyseed, u32 action); int add_buf_data(struct wpabuf **dst, const u8 *data, size_t len); @@ -149,6 +162,12 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set, u8 qos_map_set_len); void hostapd_get_ext_capa(struct hostapd_iface *iface); +void hostapd_get_mld_capa(struct hostapd_iface *iface); + +void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, + struct hostapd_hw_modes *mode, + int acs_ch_list_all, bool allow_disabled, + int **freq_list); static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd, int enabled) @@ -161,12 +180,13 @@ static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd, static inline int hostapd_drv_set_sta_vlan(const char *ifname, struct hostapd_data *hapd, - const u8 *addr, int vlan_id) + const u8 *addr, int vlan_id, + int link_id) { if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL) return 0; return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname, - vlan_id); + vlan_id, link_id); } static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd, @@ -188,13 +208,13 @@ static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd, static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd, const u8 *addr, const u8 *data, size_t data_len, int encrypt, - u32 flags) + u32 flags, int link_id) { if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL) return 0; return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data, data_len, encrypt, - hapd->own_addr, flags); + hapd->own_addr, flags, link_id); } static inline int hostapd_drv_read_sta_data( @@ -301,6 +321,17 @@ static inline int hostapd_drv_switch_channel(struct hostapd_data *hapd, return hapd->driver->switch_channel(hapd->drv_priv, settings); } +#ifdef CONFIG_IEEE80211AX +static inline int hostapd_drv_switch_color(struct hostapd_data *hapd, + struct cca_settings *settings) +{ + if (!hapd->driver || !hapd->driver->switch_color || !hapd->drv_priv) + return -1; + + return hapd->driver->switch_color(hapd->drv_priv, settings); +} +#endif /* CONFIG_IEEE80211AX */ + static inline int hostapd_drv_status(struct hostapd_data *hapd, char *buf, size_t buflen) { @@ -364,9 +395,15 @@ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd, static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd) { + int link_id = -1; + if (!hapd->driver || !hapd->driver->stop_ap || !hapd->drv_priv) return 0; - return hapd->driver->stop_ap(hapd->drv_priv); +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) + link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ + return hapd->driver->stop_ap(hapd->drv_priv, link_id); } static inline int hostapd_drv_channel_info(struct hostapd_data *hapd, @@ -418,4 +455,29 @@ hostapd_drv_register_frame(struct hostapd_data *hapd, u16 type, } #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_IEEE80211BE + +static inline int hostapd_drv_link_add(struct hostapd_data *hapd, + u8 link_id, const u8 *addr) +{ + if (!hapd->driver || !hapd->drv_priv || !hapd->driver->link_add) + return -1; + + return hapd->driver->link_add(hapd->drv_priv, link_id, addr, hapd); + +} + +static inline int hostapd_drv_link_sta_remove(struct hostapd_data *hapd, + const u8 *addr) +{ + if (!hapd->conf->mld_ap || !hapd->driver || !hapd->drv_priv || + !hapd->driver->link_sta_remove) + return -1; + + return hapd->driver->link_sta_remove(hapd->drv_priv, hapd->mld_link_id, + addr); +} + +#endif /* CONFIG_IEEE80211BE */ + #endif /* AP_DRV_OPS */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ap_list.c b/wpa_supplicant-2.9_standard/src/ap/ap_list.c index 1116b4078fe82373d83d1ba1f9b270489691958f..2c0177ab3e92b17e57ba7fcb94fbd2290c6589c2 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ap_list.c +++ b/wpa_supplicant-2.9_standard/src/ap/ap_list.c @@ -55,7 +55,7 @@ static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap) struct ap_info *s; s = iface->ap_hash[STA_HASH(ap)]; - while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0) + while (s != NULL && !ether_addr_equal(s->addr, ap)) s = s->hnext; return s; } @@ -100,13 +100,13 @@ static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap) s = iface->ap_hash[STA_HASH(ap->addr)]; if (s == NULL) return; - if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) { + if (ether_addr_equal(s->addr, ap->addr)) { iface->ap_hash[STA_HASH(ap->addr)] = s->hnext; return; } while (s->hnext != NULL && - os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0) + !ether_addr_equal(s->hnext->addr, ap->addr)) s = s->hnext; if (s->hnext != NULL) s->hnext = s->hnext->hnext; diff --git a/wpa_supplicant-2.9_standard/src/ap/ap_mlme.c b/wpa_supplicant-2.9_standard/src/ap/ap_mlme.c index db8a26759c2868f4a925d47abaa47da8745529ce..309e69a3f95d79e4dd6f0b0031d5e2d45aa03ff7 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ap_mlme.c +++ b/wpa_supplicant-2.9_standard/src/ap/ap_mlme.c @@ -29,9 +29,9 @@ static const char * mlme_auth_alg_str(int alg) return "SHARED_KEY"; case WLAN_AUTH_FT: return "FT"; + default: + return "unknown"; } - - return "unknown"; } #endif /* CONFIG_NO_HOSTAPD_LOGGER */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ap_rrm.c b/wpa_supplicant-2.9_standard/src/ap/ap_rrm.c index 175a9e8f0bf6cfbe9d3ddf8dc0dedfdf1befa69b..ec6b148acad4b41dd13e26055d553d8017bf9426 100755 --- a/wpa_supplicant-2.9_standard/src/ap/ap_rrm.c +++ b/wpa_supplicant-2.9_standard/src/ap/ap_rrm.c @@ -1,674 +1,795 @@ -/* - * hostapd / Radio Measurement (RRM) - * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH. - * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved. - * Copyright (c) 2016-2017, Jouni Malinen - * - * 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 "hostapd.h" -#include "ap_drv_ops.h" -#include "sta_info.h" -#include "eloop.h" -#include "neighbor_db.h" -#include "rrm.h" - -#define HOSTAPD_RRM_REQUEST_TIMEOUT 5 - - -static void hostapd_lci_rep_timeout_handler(void *eloop_data, void *user_ctx) -{ - struct hostapd_data *hapd = eloop_data; - - wpa_printf(MSG_DEBUG, "RRM: LCI request (token %s) timed out", - anonymize_token(hapd->lci_req_token)); - hapd->lci_req_active = 0; -} - - -static void hostapd_handle_lci_report(struct hostapd_data *hapd, u8 token, - const u8 *pos, size_t len) -{ - if (!hapd->lci_req_active || hapd->lci_req_token != token) { - wpa_printf(MSG_DEBUG, "Unexpected LCI report, token %s", anonymize_token(token)); - return; - } - - hapd->lci_req_active = 0; - eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL); - wpa_printf(MSG_DEBUG, "LCI report token %s len %zu", anonymize_token(token), len); -} - - -static void hostapd_range_rep_timeout_handler(void *eloop_data, void *user_ctx) -{ - struct hostapd_data *hapd = eloop_data; - - wpa_printf(MSG_DEBUG, "RRM: Range request (token %s) timed out", - anonymize_token(hapd->range_req_token)); - hapd->range_req_active = 0; -} - - -static void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token, - const u8 *pos, size_t len) -{ - if (!hapd->range_req_active || hapd->range_req_token != token) { - wpa_printf(MSG_DEBUG, "Unexpected range report, token %s", - anonymize_token(token)); - return; - } - - hapd->range_req_active = 0; - eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL); - wpa_printf(MSG_DEBUG, "Range report token %s len %zu", anonymize_token(token), len); -} - - -static void hostapd_handle_beacon_report(struct hostapd_data *hapd, - const u8 *addr, u8 token, u8 rep_mode, - const u8 *pos, size_t len) -{ - char report[2 * 255 + 1]; - - wpa_printf(MSG_DEBUG, "Beacon report token %s len %zu from " MACSTR_SEC, - anonymize_token(token), len, MAC2STR_SEC(addr)); - /* Skip to the beginning of the Beacon report */ - if (len < 3) - return; - pos += 3; - len -= 3; - report[0] = '\0'; - if (wpa_snprintf_hex(report, sizeof(report), pos, len) < 0) - return; - wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s", - MAC2STR(addr), token, rep_mode, report); -} - - -static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd, - const u8 *buf, size_t len) -{ - const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; - const u8 *pos, *ie, *end; - u8 token, rep_mode; - - end = buf + len; - token = mgmt->u.action.u.rrm.dialog_token; - pos = mgmt->u.action.u.rrm.variable; - - while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) { - if (ie[1] < 3) { - wpa_printf(MSG_DEBUG, "Bad Measurement Report element"); - break; - } - - rep_mode = ie[3]; - wpa_printf(MSG_DEBUG, "Measurement report mode 0x%x type %u", - rep_mode, ie[4]); - - switch (ie[4]) { - case MEASURE_TYPE_LCI: - hostapd_handle_lci_report(hapd, token, ie + 2, ie[1]); - break; - case MEASURE_TYPE_FTM_RANGE: - hostapd_handle_range_report(hapd, token, ie + 2, ie[1]); - break; - case MEASURE_TYPE_BEACON: - hostapd_handle_beacon_report(hapd, mgmt->sa, token, - rep_mode, ie + 2, ie[1]); - break; - default: - wpa_printf(MSG_DEBUG, - "Measurement report type %u is not supported", - ie[4]); - break; - } - - pos = ie + ie[1] + 2; - } -} - - -static u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len) -{ - const u8 *subelem; - - /* Range Request element + Location Subject + Maximum Age subelement */ - if (len < 3 + 1 + 4) - return 0; - - /* Subelements are arranged as IEs */ - subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE); - if (subelem && subelem[1] == 2) - return WPA_GET_LE16(subelem + 2); - - return 0; -} - - -static int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age) -{ - struct os_time curr, diff; - unsigned long diff_l; - - if (nr->stationary || max_age == 0xffff) - return 1; - - if (!max_age) - return 0; - - if (os_get_time(&curr)) - return 0; - - os_time_sub(&curr, &nr->lci_date, &diff); - - /* avoid overflow */ - if (diff.sec > 0xffff) - return 0; - - /* LCI age is calculated in 10th of a second units. */ - diff_l = diff.sec * 10 + diff.usec / 100000; - - return max_age > diff_l; -} - - -static size_t hostapd_neighbor_report_len(struct wpabuf *buf, - struct hostapd_neighbor_entry *nr, - int send_lci, int send_civic) -{ - size_t len = 2 + wpabuf_len(nr->nr); - - if (send_lci && nr->lci) - len += 2 + wpabuf_len(nr->lci); - - if (send_civic && nr->civic) - len += 2 + wpabuf_len(nr->civic); - - return len; -} - - -static void hostapd_send_nei_report_resp(struct hostapd_data *hapd, - const u8 *addr, u8 dialog_token, - struct wpa_ssid_value *ssid, u8 lci, - u8 civic, u16 lci_max_age) -{ - struct hostapd_neighbor_entry *nr; - struct wpabuf *buf; - u8 *msmt_token; - - /* - * The number and length of the Neighbor Report elements in a Neighbor - * Report frame is limited by the maximum allowed MMPDU size; + 3 bytes - * of RRM header. - */ - buf = wpabuf_alloc(3 + IEEE80211_MAX_MMPDU_SIZE); - if (!buf) - return; - - wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); - wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_RESPONSE); - wpabuf_put_u8(buf, dialog_token); - - dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, - list) { - int send_lci; - size_t len; - - if (ssid->ssid_len != nr->ssid.ssid_len || - os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) != 0) - continue; - - send_lci = (lci != 0) && hostapd_check_lci_age(nr, lci_max_age); - len = hostapd_neighbor_report_len(buf, nr, send_lci, civic); - - if (len - 2 > 0xff) { - wpa_printf(MSG_DEBUG, - "NR entry for " MACSTR_SEC " exceeds 0xFF bytes", - MAC2STR_SEC(nr->bssid)); - continue; - } - - if (len > wpabuf_tailroom(buf)) - break; - - wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT); - wpabuf_put_u8(buf, len - 2); - wpabuf_put_buf(buf, nr->nr); - - if (send_lci && nr->lci) { - wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT); - wpabuf_put_u8(buf, wpabuf_len(nr->lci)); - /* - * Override measurement token - the first byte of the - * Measurement Report element. - */ - msmt_token = wpabuf_put(buf, 0); - wpabuf_put_buf(buf, nr->lci); - *msmt_token = lci; - } - - if (civic && nr->civic) { - wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT); - wpabuf_put_u8(buf, wpabuf_len(nr->civic)); - /* - * Override measurement token - the first byte of the - * Measurement Report element. - */ - msmt_token = wpabuf_put(buf, 0); - wpabuf_put_buf(buf, nr->civic); - *msmt_token = civic; - } - } - - hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, - wpabuf_head(buf), wpabuf_len(buf)); - wpabuf_free(buf); -} - - -static void hostapd_handle_nei_report_req(struct hostapd_data *hapd, - const u8 *buf, size_t len) -{ - const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; - const u8 *pos, *ie, *end; - struct wpa_ssid_value ssid = { - .ssid_len = 0 - }; - u8 token; - u8 lci = 0, civic = 0; /* Measurement tokens */ - u16 lci_max_age = 0; - - if (!(hapd->conf->radio_measurements[0] & - WLAN_RRM_CAPS_NEIGHBOR_REPORT)) - return; - - end = buf + len; - - token = mgmt->u.action.u.rrm.dialog_token; - pos = mgmt->u.action.u.rrm.variable; - len = end - pos; - - ie = get_ie(pos, len, WLAN_EID_SSID); - if (ie && ie[1] && ie[1] <= SSID_MAX_LEN) { - ssid.ssid_len = ie[1]; - os_memcpy(ssid.ssid, ie + 2, ssid.ssid_len); - } else { - ssid.ssid_len = hapd->conf->ssid.ssid_len; - os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len); - } - - while ((ie = get_ie(pos, len, WLAN_EID_MEASURE_REQUEST))) { - if (ie[1] < 3) - break; - - wpa_printf(MSG_DEBUG, - "Neighbor report request, measure type %u", - ie[4]); - - switch (ie[4]) { /* Measurement Type */ - case MEASURE_TYPE_LCI: - lci = ie[2]; /* Measurement Token */ - lci_max_age = hostapd_parse_location_lci_req_age(ie + 2, - ie[1]); - break; - case MEASURE_TYPE_LOCATION_CIVIC: - civic = ie[2]; /* Measurement token */ - break; - } - - pos = ie + ie[1] + 2; - len = end - pos; - } - - hostapd_send_nei_report_resp(hapd, mgmt->sa, token, &ssid, lci, civic, - lci_max_age); -} - - -void hostapd_handle_radio_measurement(struct hostapd_data *hapd, - const u8 *buf, size_t len) -{ - const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; - - /* - * Check for enough bytes: header + (1B)Category + (1B)Action + - * (1B)Dialog Token. - */ - if (len < IEEE80211_HDRLEN + 3) - return; - - wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR_SEC, - mgmt->u.action.u.rrm.action, MAC2STR_SEC(mgmt->sa)); - - switch (mgmt->u.action.u.rrm.action) { - case WLAN_RRM_RADIO_MEASUREMENT_REPORT: - hostapd_handle_radio_msmt_report(hapd, buf, len); - break; - case WLAN_RRM_NEIGHBOR_REPORT_REQUEST: - hostapd_handle_nei_report_req(hapd, buf, len); - break; - default: - wpa_printf(MSG_DEBUG, "RRM action %u is not supported", - mgmt->u.action.u.rrm.action); - break; - } -} - - -int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr) -{ - struct wpabuf *buf; - struct sta_info *sta = ap_get_sta(hapd, addr); - int ret; - - if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { - wpa_printf(MSG_INFO, - "Request LCI: Destination address is not connected"); - return -1; - } - - if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) { - wpa_printf(MSG_INFO, - "Request LCI: Station does not support LCI in RRM"); - return -1; - } - - if (hapd->lci_req_active) { - wpa_printf(MSG_DEBUG, - "Request LCI: LCI request is already in process, overriding"); - hapd->lci_req_active = 0; - eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, - NULL); - } - - /* Measurement request (5) + Measurement element with LCI (10) */ - buf = wpabuf_alloc(5 + 10); - if (!buf) - return -1; - - hapd->lci_req_token++; - /* For wraparounds - the token must be nonzero */ - if (!hapd->lci_req_token) - hapd->lci_req_token++; - - wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); - wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST); - wpabuf_put_u8(buf, hapd->lci_req_token); - wpabuf_put_le16(buf, 0); /* Number of repetitions */ - - wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); - wpabuf_put_u8(buf, 3 + 1 + 4); - - wpabuf_put_u8(buf, 1); /* Measurement Token */ - /* - * Parallel and Enable bits are 0, Duration, Request, and Report are - * reserved. - */ - wpabuf_put_u8(buf, 0); - wpabuf_put_u8(buf, MEASURE_TYPE_LCI); - - wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); - - wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE); - wpabuf_put_u8(buf, 2); - wpabuf_put_le16(buf, 0xffff); - - ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, - wpabuf_head(buf), wpabuf_len(buf)); - wpabuf_free(buf); - if (ret) - return ret; - - hapd->lci_req_active = 1; - - eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0, - hostapd_lci_rep_timeout_handler, hapd, NULL); - - return 0; -} - - -int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr, - u16 random_interval, u8 min_ap, - const u8 *responders, unsigned int n_responders) -{ - struct wpabuf *buf; - struct sta_info *sta; - u8 *len; - unsigned int i; - int ret; - - wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR_SEC - " rand interval %u min AP %u n_responders %u", MAC2STR_SEC(addr), - random_interval, min_ap, n_responders); - - if (min_ap == 0 || min_ap > n_responders) { - wpa_printf(MSG_INFO, "Request range: Wrong min AP count"); - return -1; - } - - sta = ap_get_sta(hapd, addr); - if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { - wpa_printf(MSG_INFO, - "Request range: Destination address is not connected"); - return -1; - } - - if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) { - wpa_printf(MSG_ERROR, - "Request range: Destination station does not support FTM range report in RRM"); - return -1; - } - - if (hapd->range_req_active) { - wpa_printf(MSG_DEBUG, - "Request range: Range request is already in process; overriding"); - hapd->range_req_active = 0; - eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, - NULL); - } - - /* Action + measurement type + token + reps + EID + len = 7 */ - buf = wpabuf_alloc(7 + 255); - if (!buf) - return -1; - - hapd->range_req_token++; - if (!hapd->range_req_token) /* For wraparounds */ - hapd->range_req_token++; - - /* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */ - wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); - wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST); - wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */ - wpabuf_put_le16(buf, 0); /* Number of Repetitions */ - - /* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */ - wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); - len = wpabuf_put(buf, 1); /* Length will be set later */ - - wpabuf_put_u8(buf, 1); /* Measurement Token */ - /* - * Parallel and Enable bits are 0; Duration, Request, and Report are - * reserved. - */ - wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ - wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */ - - /* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */ - wpabuf_put_le16(buf, random_interval); /* Randomization Interval */ - wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */ - - /* FTM Range Subelements */ - - /* - * Taking the neighbor report part of the range request from neighbor - * database instead of requesting the separate bits of data from the - * user. - */ - for (i = 0; i < n_responders; i++) { - struct hostapd_neighbor_entry *nr; - - nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i, - NULL); - if (!nr) { - wpa_printf(MSG_INFO, "Missing neighbor report for " - MACSTR_SEC, MAC2STR_SEC(responders + ETH_ALEN * i)); - wpabuf_free(buf); - return -1; - } - - if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) { - wpa_printf(MSG_ERROR, "Too long range request"); - wpabuf_free(buf); - return -1; - } - - wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT); - wpabuf_put_u8(buf, wpabuf_len(nr->nr)); - wpabuf_put_buf(buf, nr->nr); - } - - /* Action + measurement type + token + reps + EID + len = 7 */ - *len = wpabuf_len(buf) - 7; - - ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, - wpabuf_head(buf), wpabuf_len(buf)); - wpabuf_free(buf); - if (ret) - return ret; - - hapd->range_req_active = 1; - - eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0, - hostapd_range_rep_timeout_handler, hapd, NULL); - - return 0; -} - - -void hostapd_clean_rrm(struct hostapd_data *hapd) -{ - hostapd_free_neighbor_db(hapd); - eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL); - hapd->lci_req_active = 0; - eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL); - hapd->range_req_active = 0; -} - - -int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr, - u8 req_mode, const struct wpabuf *req) -{ - struct wpabuf *buf; - struct sta_info *sta = ap_get_sta(hapd, addr); - int ret; - enum beacon_report_mode mode; - const u8 *pos; - - /* Request data: - * Operating Class (1), Channel Number (1), Randomization Interval (2), - * Measurement Duration (2), Measurement Mode (1), BSSID (6), - * Optional Subelements (variable) - */ - if (wpabuf_len(req) < 13) { - wpa_printf(MSG_INFO, "Beacon request: Too short request data"); - return -1; - } - pos = wpabuf_head(req); - mode = pos[6]; - - if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { - wpa_printf(MSG_INFO, - "Beacon request: " MACSTR_SEC " is not connected", - MAC2STR_SEC(addr)); - return -1; - } - - switch (mode) { - case BEACON_REPORT_MODE_PASSIVE: - if (!(sta->rrm_enabled_capa[0] & - WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE)) { - wpa_printf(MSG_INFO, - "Beacon request: " MACSTR_SEC - " does not support passive beacon report", - MAC2STR_SEC(addr)); - return -1; - } - break; - case BEACON_REPORT_MODE_ACTIVE: - if (!(sta->rrm_enabled_capa[0] & - WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE)) { - wpa_printf(MSG_INFO, - "Beacon request: " MACSTR_SEC - " does not support active beacon report", - MAC2STR_SEC(addr)); - return -1; - } - break; - case BEACON_REPORT_MODE_TABLE: - if (!(sta->rrm_enabled_capa[0] & - WLAN_RRM_CAPS_BEACON_REPORT_TABLE)) { - wpa_printf(MSG_INFO, - "Beacon request: " MACSTR_SEC - " does not support table beacon report", - MAC2STR_SEC(addr)); - return -1; - } - break; - default: - wpa_printf(MSG_INFO, - "Beacon request: Unknown measurement mode %d", mode); - return -1; - } - - buf = wpabuf_alloc(5 + 2 + 3 + wpabuf_len(req)); - if (!buf) - return -1; - - hapd->beacon_req_token++; - if (!hapd->beacon_req_token) - hapd->beacon_req_token++; - - wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); - wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST); - wpabuf_put_u8(buf, hapd->beacon_req_token); - wpabuf_put_le16(buf, 0); /* Number of repetitions */ - - /* Measurement Request element */ - wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); - wpabuf_put_u8(buf, 3 + wpabuf_len(req)); - wpabuf_put_u8(buf, 1); /* Measurement Token */ - wpabuf_put_u8(buf, req_mode); /* Measurement Request Mode */ - wpabuf_put_u8(buf, MEASURE_TYPE_BEACON); /* Measurement Type */ - wpabuf_put_buf(buf, req); - - ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, - wpabuf_head(buf), wpabuf_len(buf)); - wpabuf_free(buf); - if (ret < 0) - return ret; - - return hapd->beacon_req_token; -} - - -void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, - size_t len, int ok) -{ - if (len < 24 + 3) - return; - wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_REQ_TX_STATUS MACSTR - " %u ack=%d", MAC2STR(mgmt->da), - mgmt->u.action.u.rrm.dialog_token, ok); -} +/* + * hostapd / Radio Measurement (RRM) + * Copyright(c) 2013 - 2016 Intel Mobile Communications GmbH. + * Copyright(c) 2011 - 2016 Intel Corporation. All rights reserved. + * Copyright (c) 2016-2017, Jouni Malinen + * + * 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 "hostapd.h" +#include "ap_drv_ops.h" +#include "sta_info.h" +#include "eloop.h" +#include "neighbor_db.h" +#include "rrm.h" + +#define HOSTAPD_RRM_REQUEST_TIMEOUT 5 + + +static void hostapd_lci_rep_timeout_handler(void *eloop_data, void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + + wpa_printf(MSG_DEBUG, "RRM: LCI request (token %s) timed out", + anonymize_token(hapd->lci_req_token)); + hapd->lci_req_active = 0; +} + + +static void hostapd_handle_lci_report(struct hostapd_data *hapd, u8 token, + const u8 *pos, size_t len) +{ + if (!hapd->lci_req_active || hapd->lci_req_token != token) { + wpa_printf(MSG_DEBUG, "Unexpected LCI report, token %s", anonymize_token(token)); + return; + } + + hapd->lci_req_active = 0; + eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL); + wpa_printf(MSG_DEBUG, "LCI report token %s len %zu", anonymize_token(token), len); +} + + +static void hostapd_range_rep_timeout_handler(void *eloop_data, void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + + wpa_printf(MSG_DEBUG, "RRM: Range request (token %s) timed out", + anonymize_token(hapd->range_req_token)); + hapd->range_req_active = 0; +} + + +static void hostapd_handle_range_report(struct hostapd_data *hapd, u8 token, + const u8 *pos, size_t len) +{ + if (!hapd->range_req_active || hapd->range_req_token != token) { + wpa_printf(MSG_DEBUG, "Unexpected range report, token %s", + anonymize_token(token)); + return; + } + + hapd->range_req_active = 0; + eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL); + wpa_printf(MSG_DEBUG, "Range report token %s len %zu", anonymize_token(token), len); +} + + +static void hostapd_handle_beacon_report(struct hostapd_data *hapd, + const u8 *addr, u8 token, u8 rep_mode, + const u8 *pos, size_t len) +{ + char report[2 * 255 + 1]; + + wpa_printf(MSG_DEBUG, "Beacon report token %s len %zu from " MACSTR_SEC, + anonymize_token(token), len, MAC2STR_SEC(addr)); + /* Skip to the beginning of the Beacon report */ + if (len < 3) + return; + pos += 3; + len -= 3; + report[0] = '\0'; + if (wpa_snprintf_hex(report, sizeof(report), pos, len) < 0) + return; + wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s", + MAC2STR(addr), token, rep_mode, report); +} + + +static void hostapd_handle_radio_msmt_report(struct hostapd_data *hapd, + const u8 *buf, size_t len) +{ + const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; + const u8 *pos, *ie, *end; + u8 token, rep_mode; + + end = buf + len; + token = mgmt->u.action.u.rrm.dialog_token; + pos = mgmt->u.action.u.rrm.variable; + + while ((ie = get_ie(pos, end - pos, WLAN_EID_MEASURE_REPORT))) { + if (ie[1] < 3) { + wpa_printf(MSG_DEBUG, "Bad Measurement Report element"); + break; + } + + rep_mode = ie[3]; + wpa_printf(MSG_DEBUG, "Measurement report mode 0x%x type %u", + rep_mode, ie[4]); + + switch (ie[4]) { + case MEASURE_TYPE_LCI: + hostapd_handle_lci_report(hapd, token, ie + 2, ie[1]); + break; + case MEASURE_TYPE_FTM_RANGE: + hostapd_handle_range_report(hapd, token, ie + 2, ie[1]); + break; + case MEASURE_TYPE_BEACON: + hostapd_handle_beacon_report(hapd, mgmt->sa, token, + rep_mode, ie + 2, ie[1]); + break; + default: + wpa_printf(MSG_DEBUG, + "Measurement report type %u is not supported", + ie[4]); + break; + } + + pos = ie + ie[1] + 2; + } +} + + +static u16 hostapd_parse_location_lci_req_age(const u8 *buf, size_t len) +{ + const u8 *subelem; + + /* Range Request element + Location Subject + Maximum Age subelement */ + if (len < 3 + 1 + 4) + return 0; + + /* Subelements are arranged as IEs */ + subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE); + if (subelem && subelem[1] == 2) + return WPA_GET_LE16(subelem + 2); + + return 0; +} + + +static int hostapd_check_lci_age(struct hostapd_neighbor_entry *nr, u16 max_age) +{ + struct os_time curr, diff; + unsigned long diff_l; + + if (nr->stationary || max_age == 0xffff) + return 1; + + if (!max_age) + return 0; + + if (os_get_time(&curr)) + return 0; + + os_time_sub(&curr, &nr->lci_date, &diff); + + /* avoid overflow */ + if (diff.sec > 0xffff) + return 0; + + /* LCI age is calculated in 10th of a second units. */ + diff_l = diff.sec * 10 + diff.usec / 100000; + + return max_age > diff_l; +} + + +static size_t hostapd_neighbor_report_len(struct wpabuf *buf, + struct hostapd_neighbor_entry *nr, + int send_lci, int send_civic) +{ + size_t len = 2 + wpabuf_len(nr->nr); + + if (send_lci && nr->lci) + len += 2 + wpabuf_len(nr->lci); + + if (send_civic && nr->civic) + len += 2 + wpabuf_len(nr->civic); + + return len; +} + + +static void hostapd_send_nei_report_resp(struct hostapd_data *hapd, + const u8 *addr, u8 dialog_token, + struct wpa_ssid_value *ssid, u8 lci, + u8 civic, u16 lci_max_age) +{ + struct hostapd_neighbor_entry *nr; + struct wpabuf *buf; + u8 *msmt_token; + + /* + * The number and length of the Neighbor Report elements in a Neighbor + * Report frame is limited by the maximum allowed MMPDU size; + 3 bytes + * of RRM header. + */ + buf = wpabuf_alloc(3 + IEEE80211_MAX_MMPDU_SIZE); + if (!buf) + return; + + wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_RESPONSE); + wpabuf_put_u8(buf, dialog_token); + + dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, + list) { + int send_lci; + size_t len; + + if (ssid->ssid_len != nr->ssid.ssid_len || + os_memcmp(ssid->ssid, nr->ssid.ssid, ssid->ssid_len) != 0) + continue; + + send_lci = (lci != 0) && hostapd_check_lci_age(nr, lci_max_age); + len = hostapd_neighbor_report_len(buf, nr, send_lci, civic); + + if (len - 2 > 0xff) { + wpa_printf(MSG_DEBUG, + "NR entry for " MACSTR_SEC " exceeds 0xFF bytes", + MAC2STR_SEC(nr->bssid)); + continue; + } + + if (len > wpabuf_tailroom(buf)) + break; + + wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT); + wpabuf_put_u8(buf, len - 2); + wpabuf_put_buf(buf, nr->nr); + + if (send_lci && nr->lci) { + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT); + wpabuf_put_u8(buf, wpabuf_len(nr->lci)); + /* + * Override measurement token - the first byte of the + * Measurement Report element. + */ + msmt_token = wpabuf_put(buf, 0); + wpabuf_put_buf(buf, nr->lci); + *msmt_token = lci; + } + + if (civic && nr->civic) { + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REPORT); + wpabuf_put_u8(buf, wpabuf_len(nr->civic)); + /* + * Override measurement token - the first byte of the + * Measurement Report element. + */ + msmt_token = wpabuf_put(buf, 0); + wpabuf_put_buf(buf, nr->civic); + *msmt_token = civic; + } + } + + hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + wpabuf_free(buf); +} + + +static void hostapd_handle_nei_report_req(struct hostapd_data *hapd, + const u8 *buf, size_t len) +{ + const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; + const u8 *pos, *ie, *end; + struct wpa_ssid_value ssid = { + .ssid_len = 0 + }; + u8 token; + u8 lci = 0, civic = 0; /* Measurement tokens */ + u16 lci_max_age = 0; + + if (!(hapd->conf->radio_measurements[0] & + WLAN_RRM_CAPS_NEIGHBOR_REPORT)) + return; + + end = buf + len; + + token = mgmt->u.action.u.rrm.dialog_token; + pos = mgmt->u.action.u.rrm.variable; + len = end - pos; + + ie = get_ie(pos, len, WLAN_EID_SSID); + if (ie && ie[1] && ie[1] <= SSID_MAX_LEN) { + ssid.ssid_len = ie[1]; + os_memcpy(ssid.ssid, ie + 2, ssid.ssid_len); + } else { + ssid.ssid_len = hapd->conf->ssid.ssid_len; + os_memcpy(ssid.ssid, hapd->conf->ssid.ssid, ssid.ssid_len); + } + + while ((ie = get_ie(pos, len, WLAN_EID_MEASURE_REQUEST))) { + if (ie[1] < 3) + break; + + wpa_printf(MSG_DEBUG, + "Neighbor report request, measure type %u", + ie[4]); + + switch (ie[4]) { /* Measurement Type */ + case MEASURE_TYPE_LCI: + lci = ie[2]; /* Measurement Token */ + lci_max_age = hostapd_parse_location_lci_req_age(ie + 2, + ie[1]); + break; + case MEASURE_TYPE_LOCATION_CIVIC: + civic = ie[2]; /* Measurement token */ + break; + } + + pos = ie + ie[1] + 2; + len = end - pos; + } + + hostapd_send_nei_report_resp(hapd, mgmt->sa, token, &ssid, lci, civic, + lci_max_age); +} + + +static void hostapd_link_mesr_rep_timeout_handler(void *eloop_data, + void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + + wpa_printf(MSG_DEBUG, + "RRM: Link measurement request (token %u) timed out", + hapd->link_measurement_req_token); + hapd->link_mesr_req_active = 0; +} + + +static void hostapd_handle_link_mesr_report(struct hostapd_data *hapd, + const u8 *buf, size_t len) +{ + const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; + const struct rrm_link_measurement_report *report; + const u8 *pos, *end; + char report_msg[2 * 8 + 1]; + + end = buf + len; + pos = mgmt->u.action.u.rrm.variable; + report = (const struct rrm_link_measurement_report *) (pos - 1); + if (end - (const u8 *) report < (int) sizeof(*report)) + return; + + if (!hapd->link_mesr_req_active || + (hapd->link_measurement_req_token != report->dialog_token)) { + wpa_printf(MSG_INFO, + "Unexpected Link measurement report, token %u", + report->dialog_token); + return; + } + + hapd->link_mesr_req_active = 0; + eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL); + + report_msg[0] = '\0'; + if (wpa_snprintf_hex(report_msg, sizeof(report_msg), + pos, end - pos) < 0) + return; + + wpa_msg(hapd->msg_ctx, MSG_INFO, LINK_MSR_RESP_RX MACSTR " %u %s", + MAC2STR(mgmt->sa), report->dialog_token, report_msg); +} + + +void hostapd_handle_radio_measurement(struct hostapd_data *hapd, + const u8 *buf, size_t len) +{ + const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; + + /* + * Check for enough bytes: header + (1B)Category + (1B)Action + + * (1B)Dialog Token. + */ + if (len < IEEE80211_HDRLEN + 3) + return; + + wpa_printf(MSG_DEBUG, "Radio measurement frame, action %u from " MACSTR_SEC, + mgmt->u.action.u.rrm.action, MAC2STR_SEC(mgmt->sa)); + + switch (mgmt->u.action.u.rrm.action) { + case WLAN_RRM_RADIO_MEASUREMENT_REPORT: + hostapd_handle_radio_msmt_report(hapd, buf, len); + break; + case WLAN_RRM_NEIGHBOR_REPORT_REQUEST: + hostapd_handle_nei_report_req(hapd, buf, len); + break; + case WLAN_RRM_LINK_MEASUREMENT_REPORT: + hostapd_handle_link_mesr_report(hapd, buf, len); + break; + default: + wpa_printf(MSG_DEBUG, "RRM action %u is not supported", + mgmt->u.action.u.rrm.action); + break; + } +} + + +int hostapd_send_lci_req(struct hostapd_data *hapd, const u8 *addr) +{ + struct wpabuf *buf; + struct sta_info *sta = ap_get_sta(hapd, addr); + int ret; + + if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { + wpa_printf(MSG_INFO, + "Request LCI: Destination address is not connected"); + return -1; + } + + if (!(sta->rrm_enabled_capa[1] & WLAN_RRM_CAPS_LCI_MEASUREMENT)) { + wpa_printf(MSG_INFO, + "Request LCI: Station does not support LCI in RRM"); + return -1; + } + + if (hapd->lci_req_active) { + wpa_printf(MSG_DEBUG, + "Request LCI: LCI request is already in process, overriding"); + hapd->lci_req_active = 0; + eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, + NULL); + } + + /* Measurement request (5) + Measurement element with LCI (10) */ + buf = wpabuf_alloc(5 + 10); + if (!buf) + return -1; + + hapd->lci_req_token++; + /* For wraparounds - the token must be nonzero */ + if (!hapd->lci_req_token) + hapd->lci_req_token++; + + wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST); + wpabuf_put_u8(buf, hapd->lci_req_token); + wpabuf_put_le16(buf, 0); /* Number of repetitions */ + + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); + wpabuf_put_u8(buf, 3 + 1 + 4); + + wpabuf_put_u8(buf, 1); /* Measurement Token */ + /* + * Parallel and Enable bits are 0, Duration, Request, and Report are + * reserved. + */ + wpabuf_put_u8(buf, 0); + wpabuf_put_u8(buf, MEASURE_TYPE_LCI); + + wpabuf_put_u8(buf, LOCATION_SUBJECT_REMOTE); + + wpabuf_put_u8(buf, LCI_REQ_SUBELEM_MAX_AGE); + wpabuf_put_u8(buf, 2); + wpabuf_put_le16(buf, 0xffff); + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + wpabuf_free(buf); + if (ret) + return ret; + + hapd->lci_req_active = 1; + + eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0, + hostapd_lci_rep_timeout_handler, hapd, NULL); + + return 0; +} + + +int hostapd_send_range_req(struct hostapd_data *hapd, const u8 *addr, + u16 random_interval, u8 min_ap, + const u8 *responders, unsigned int n_responders) +{ + struct wpabuf *buf; + struct sta_info *sta; + u8 *len; + unsigned int i; + int ret; + + wpa_printf(MSG_DEBUG, "Request range: dest addr " MACSTR_SEC + " rand interval %u min AP %u n_responders %u", MAC2STR_SEC(addr), + random_interval, min_ap, n_responders); + + if (min_ap == 0 || min_ap > n_responders) { + wpa_printf(MSG_INFO, "Request range: Wrong min AP count"); + return -1; + } + + sta = ap_get_sta(hapd, addr); + if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { + wpa_printf(MSG_INFO, + "Request range: Destination address is not connected"); + return -1; + } + + if (!(sta->rrm_enabled_capa[4] & WLAN_RRM_CAPS_FTM_RANGE_REPORT)) { + wpa_printf(MSG_ERROR, + "Request range: Destination station does not support FTM range report in RRM"); + return -1; + } + + if (hapd->range_req_active) { + wpa_printf(MSG_DEBUG, + "Request range: Range request is already in process; overriding"); + hapd->range_req_active = 0; + eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, + NULL); + } + + /* Action + measurement type + token + reps + EID + len = 7 */ + buf = wpabuf_alloc(7 + 255); + if (!buf) + return -1; + + hapd->range_req_token++; + if (!hapd->range_req_token) /* For wraparounds */ + hapd->range_req_token++; + + /* IEEE P802.11-REVmc/D5.0, 9.6.7.2 */ + wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST); + wpabuf_put_u8(buf, hapd->range_req_token); /* Dialog Token */ + wpabuf_put_le16(buf, 0); /* Number of Repetitions */ + + /* IEEE P802.11-REVmc/D5.0, 9.4.2.21 */ + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); + len = wpabuf_put(buf, 1); /* Length will be set later */ + + wpabuf_put_u8(buf, 1); /* Measurement Token */ + /* + * Parallel and Enable bits are 0; Duration, Request, and Report are + * reserved. + */ + wpabuf_put_u8(buf, 0); /* Measurement Request Mode */ + wpabuf_put_u8(buf, MEASURE_TYPE_FTM_RANGE); /* Measurement Type */ + + /* IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 */ + wpabuf_put_le16(buf, random_interval); /* Randomization Interval */ + wpabuf_put_u8(buf, min_ap); /* Minimum AP Count */ + + /* FTM Range Subelements */ + + /* + * Taking the neighbor report part of the range request from neighbor + * database instead of requesting the separate bits of data from the + * user. + */ + for (i = 0; i < n_responders; i++) { + struct hostapd_neighbor_entry *nr; + + nr = hostapd_neighbor_get(hapd, responders + ETH_ALEN * i, + NULL); + if (!nr) { + wpa_printf(MSG_INFO, "Missing neighbor report for " + MACSTR_SEC, MAC2STR_SEC(responders + ETH_ALEN * i)); + wpabuf_free(buf); + return -1; + } + + if (wpabuf_tailroom(buf) < 2 + wpabuf_len(nr->nr)) { + wpa_printf(MSG_ERROR, "Too long range request"); + wpabuf_free(buf); + return -1; + } + + wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT); + wpabuf_put_u8(buf, wpabuf_len(nr->nr)); + wpabuf_put_buf(buf, nr->nr); + } + + /* Action + measurement type + token + reps + EID + len = 7 */ + *len = wpabuf_len(buf) - 7; + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + wpabuf_free(buf); + if (ret) + return ret; + + hapd->range_req_active = 1; + + eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0, + hostapd_range_rep_timeout_handler, hapd, NULL); + + return 0; +} + + +void hostapd_clean_rrm(struct hostapd_data *hapd) +{ + hostapd_free_neighbor_db(hapd); + eloop_cancel_timeout(hostapd_lci_rep_timeout_handler, hapd, NULL); + hapd->lci_req_active = 0; + eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL); + hapd->range_req_active = 0; + eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL); +} + + +int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr, + u8 req_mode, const struct wpabuf *req) +{ + struct wpabuf *buf; + struct sta_info *sta = ap_get_sta(hapd, addr); + int ret; + enum beacon_report_mode mode; + const u8 *pos; + + /* Request data: + * Operating Class (1), Channel Number (1), Randomization Interval (2), + * Measurement Duration (2), Measurement Mode (1), BSSID (6), + * Optional Subelements (variable) + */ + if (wpabuf_len(req) < 13) { + wpa_printf(MSG_INFO, "Beacon request: Too short request data"); + return -1; + } + pos = wpabuf_head(req); + mode = pos[6]; + + if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { + wpa_printf(MSG_INFO, + "Beacon request: " MACSTR_SEC " is not connected", + MAC2STR_SEC(addr)); + return -1; + } + + switch (mode) { + case BEACON_REPORT_MODE_PASSIVE: + if (!(sta->rrm_enabled_capa[0] & + WLAN_RRM_CAPS_BEACON_REPORT_PASSIVE)) { + wpa_printf(MSG_INFO, + "Beacon request: " MACSTR_SEC + " does not support passive beacon report", + MAC2STR_SEC(addr)); + return -1; + } + break; + case BEACON_REPORT_MODE_ACTIVE: + if (!(sta->rrm_enabled_capa[0] & + WLAN_RRM_CAPS_BEACON_REPORT_ACTIVE)) { + wpa_printf(MSG_INFO, + "Beacon request: " MACSTR_SEC + " does not support active beacon report", + MAC2STR_SEC(addr)); + return -1; + } + break; + case BEACON_REPORT_MODE_TABLE: + if (!(sta->rrm_enabled_capa[0] & + WLAN_RRM_CAPS_BEACON_REPORT_TABLE)) { + wpa_printf(MSG_INFO, + "Beacon request: " MACSTR_SEC + " does not support table beacon report", + MAC2STR_SEC(addr)); + return -1; + } + break; + default: + wpa_printf(MSG_INFO, + "Beacon request: Unknown measurement mode %d", mode); + return -1; + } + + buf = wpabuf_alloc(5 + 2 + 3 + wpabuf_len(req)); + if (!buf) + return -1; + + hapd->beacon_req_token++; + if (!hapd->beacon_req_token) + hapd->beacon_req_token++; + + wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(buf, WLAN_RRM_RADIO_MEASUREMENT_REQUEST); + wpabuf_put_u8(buf, hapd->beacon_req_token); + wpabuf_put_le16(buf, 0); /* Number of repetitions */ + + /* Measurement Request element */ + wpabuf_put_u8(buf, WLAN_EID_MEASURE_REQUEST); + wpabuf_put_u8(buf, 3 + wpabuf_len(req)); + wpabuf_put_u8(buf, 1); /* Measurement Token */ + wpabuf_put_u8(buf, req_mode); /* Measurement Request Mode */ + wpabuf_put_u8(buf, MEASURE_TYPE_BEACON); /* Measurement Type */ + wpabuf_put_buf(buf, req); + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + wpabuf_free(buf); + if (ret < 0) + return ret; + + return hapd->beacon_req_token; +} + + +void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len, int ok) +{ + if (len < 24 + 3) + return; + wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_REQ_TX_STATUS MACSTR + " %u ack=%d", MAC2STR(mgmt->da), + mgmt->u.action.u.rrm.dialog_token, ok); +} + + +int hostapd_send_link_measurement_req(struct hostapd_data *hapd, const u8 *addr) +{ + struct wpabuf *buf; + struct sta_info *sta; + int ret; + + wpa_printf(MSG_DEBUG, "Request Link Measurement: dest addr " MACSTR, + MAC2STR(addr)); + + if (!(hapd->iface->drv_rrm_flags & + WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) { + wpa_printf(MSG_INFO, + "Request Link Measurement: the driver does not support TX power insertion"); + return -1; + } + + sta = ap_get_sta(hapd, addr); + if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { + wpa_printf(MSG_INFO, + "Request Link Measurement: specied STA is not connected"); + return -1; + } + + if (!(sta->rrm_enabled_capa[0] & WLAN_RRM_CAPS_LINK_MEASUREMENT)) { + wpa_printf(MSG_INFO, + "Request Link Measurement: destination STA does not support link measurement"); + return -1; + } + + if (hapd->link_mesr_req_active) { + wpa_printf(MSG_DEBUG, + "Request Link Measurement: request already in process - overriding"); + hapd->link_mesr_req_active = 0; + eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, + hapd, NULL); + } + + /* Action + Action type + token + Tx Power used + Max Tx Power = 5 */ + buf = wpabuf_alloc(5); + if (!buf) + return -1; + + hapd->link_measurement_req_token++; + if (!hapd->link_measurement_req_token) + hapd->link_measurement_req_token++; + + wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST); + wpabuf_put_u8(buf, hapd->link_measurement_req_token); + /* NOTE: The driver is expected to fill the Tx Power Used and Max Tx + * Power */ + wpabuf_put_u8(buf, 0); + wpabuf_put_u8(buf, 0); + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + wpabuf_free(buf); + if (ret < 0) + return ret; + + hapd->link_mesr_req_active = 1; + + eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0, + hostapd_link_mesr_rep_timeout_handler, hapd, + NULL); + + return hapd->link_measurement_req_token; +} diff --git a/wpa_supplicant-2.9_standard/src/ap/authsrv.c b/wpa_supplicant-2.9_standard/src/ap/authsrv.c index 8e12daf40a46c1d17c042c91281d477639970a19..837b6909bde505554a2c5a4d042b7685a357cb27 100644 --- a/wpa_supplicant-2.9_standard/src/ap/authsrv.c +++ b/wpa_supplicant-2.9_standard/src/ap/authsrv.c @@ -9,6 +9,7 @@ #include "utils/includes.h" #include "utils/common.h" +#include "crypto/crypto.h" #include "crypto/tls.h" #include "eap_server/eap.h" #include "eap_server/eap_sim_db.h" @@ -105,6 +106,22 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd) { struct radius_server_conf srv; struct hostapd_bss_config *conf = hapd->conf; + +#ifdef CONFIG_IEEE80211BE + if (!hostapd_mld_is_first_bss(hapd)) { + struct hostapd_data *first; + + wpa_printf(MSG_DEBUG, + "MLD: Using RADIUS server of the first BSS"); + + first = hostapd_mld_get_first_bss(hapd); + if (!first) + return -1; + hapd->radius_srv = first->radius_srv; + return 0; + } +#endif /* CONFIG_IEEE80211BE */ + os_memset(&srv, 0, sizeof(srv)); srv.client_file = conf->radius_server_clients; srv.auth_port = conf->radius_server_auth_port; @@ -168,6 +185,9 @@ static void authsrv_tls_event(void *ctx, enum tls_event ev, wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s", data->alert.description); break; + case TLS_UNSAFE_RENEGOTIATION_DISABLED: + /* Not applicable to TLS server */ + break; } } #endif /* EAP_TLS_FUNCS */ @@ -207,8 +227,12 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd) cfg->eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner; cfg->eap_teap_separate_result = hapd->conf->eap_teap_separate_result; cfg->eap_teap_id = hapd->conf->eap_teap_id; + cfg->eap_teap_method_sequence = hapd->conf->eap_teap_method_sequence; cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; cfg->eap_sim_id = hapd->conf->eap_sim_id; + cfg->imsi_privacy_key = hapd->imsi_privacy_key; + cfg->eap_sim_aka_fast_reauth_limit = + hapd->conf->eap_sim_aka_fast_reauth_limit; cfg->tnc = hapd->conf->tnc; cfg->wps = hapd->wps; cfg->fragment_size = hapd->conf->fragment_size; @@ -222,6 +246,9 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd) cfg->server_id_len = 7; } cfg->erp = hapd->conf->eap_server_erp; +#ifdef CONFIG_TESTING_OPTIONS + cfg->skip_prot_success = hapd->conf->eap_skip_prot_success; +#endif /* CONFIG_TESTING_OPTIONS */ return cfg; } @@ -229,6 +256,35 @@ static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd) int authsrv_init(struct hostapd_data *hapd) { +#ifdef CONFIG_IEEE80211BE + if (!hostapd_mld_is_first_bss(hapd)) { + struct hostapd_data *first; + + first = hostapd_mld_get_first_bss(hapd); + if (!first) + return -1; + + if (!first->eap_cfg) { + wpa_printf(MSG_DEBUG, + "MLD: First BSS auth_serv does not exist. Init on its behalf"); + + if (authsrv_init(first)) + return -1; + } + + wpa_printf(MSG_DEBUG, "MLD: Using auth_serv of the first BSS"); + +#ifdef EAP_TLS_FUNCS + hapd->ssl_ctx = first->ssl_ctx; +#endif /* EAP_TLS_FUNCS */ + hapd->eap_cfg = first->eap_cfg; +#ifdef EAP_SIM_DB + hapd->eap_sim_db_priv = first->eap_sim_db_priv; +#endif /* EAP_SIM_DB */ + return 0; + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef EAP_TLS_FUNCS if (hapd->conf->eap_server && (hapd->conf->ca_cert || hapd->conf->server_cert || @@ -292,6 +348,22 @@ int authsrv_init(struct hostapd_data *hapd) } #endif /* EAP_TLS_FUNCS */ +#ifdef CRYPTO_RSA_OAEP_SHA256 + crypto_rsa_key_free(hapd->imsi_privacy_key); + hapd->imsi_privacy_key = NULL; + if (hapd->conf->imsi_privacy_key) { + hapd->imsi_privacy_key = crypto_rsa_key_read( + hapd->conf->imsi_privacy_key, true); + if (!hapd->imsi_privacy_key) { + wpa_printf(MSG_ERROR, + "Failed to read/parse IMSI privacy key %s", + hapd->conf->imsi_privacy_key); + authsrv_deinit(hapd); + return -1; + } + } +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + #ifdef EAP_SIM_DB if (hapd->conf->eap_sim_db) { hapd->eap_sim_db_priv = @@ -327,11 +399,33 @@ int authsrv_init(struct hostapd_data *hapd) void authsrv_deinit(struct hostapd_data *hapd) { +#ifdef CONFIG_IEEE80211BE + if (!hostapd_mld_is_first_bss(hapd)) { + wpa_printf(MSG_DEBUG, + "MLD: Deinit auth_serv of a non-first BSS"); + + hapd->radius_srv = NULL; + hapd->eap_cfg = NULL; +#ifdef EAP_SIM_DB + hapd->eap_sim_db_priv = NULL; +#endif /* EAP_SIM_DB */ +#ifdef EAP_TLS_FUNCS + hapd->ssl_ctx = NULL; +#endif /* EAP_TLS_FUNCS */ + return; + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef RADIUS_SERVER radius_server_deinit(hapd->radius_srv); hapd->radius_srv = NULL; #endif /* RADIUS_SERVER */ +#ifdef CRYPTO_RSA_OAEP_SHA256 + crypto_rsa_key_free(hapd->imsi_privacy_key); + hapd->imsi_privacy_key = NULL; +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + #ifdef EAP_TLS_FUNCS if (hapd->ssl_ctx) { tls_deinit(hapd->ssl_ctx); diff --git a/wpa_supplicant-2.9_standard/src/ap/beacon.c b/wpa_supplicant-2.9_standard/src/ap/beacon.c index 3edc11a869305171af0d6493e2db4420d067fd8f..0859a98c259cc44d2a0edfc1b5dd8100cfbdc1e1 100644 --- a/wpa_supplicant-2.9_standard/src/ap/beacon.c +++ b/wpa_supplicant-2.9_standard/src/ap/beacon.c @@ -17,6 +17,7 @@ #include "common/ieee802_11_common.h" #include "common/hw_features_common.h" #include "common/wpa_ctrl.h" +#include "crypto/sha1.h" #include "wps/wps_defs.h" #include "p2p/p2p.h" #include "hostapd.h" @@ -87,6 +88,12 @@ static u8 ieee802_11_erp_info(struct hostapd_data *hapd) static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid) { + enum hostapd_hw_mode hw_mode = hapd->iconf->hw_mode; + + if (hw_mode != HOSTAPD_MODE_IEEE80211G && + hw_mode != HOSTAPD_MODE_IEEE80211B) + return eid; + *eid++ = WLAN_EID_DS_PARAMS; *eid++ = 1; *eid++ = hapd->iconf->channel; @@ -186,7 +193,8 @@ static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid) } -static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, +static u8 * hostapd_eid_country_add(struct hostapd_data *hapd, u8 *pos, + u8 *end, int chan_spacing, struct hostapd_channel_data *start, struct hostapd_channel_data *prev) { @@ -198,31 +206,23 @@ static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing, /* number of channels */ *pos++ = (prev->chan - start->chan) / chan_spacing + 1; /* maximum transmit power level */ - *pos++ = start->max_tx_power; + if (!is_6ghz_op_class(hapd->iconf->op_class)) + *pos++ = start->max_tx_power; + else + *pos++ = 0; /* Reserved when operating on the 6 GHz band */ return pos; } -static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, - int max_len) +static u8 * hostapd_fill_subband_triplets(struct hostapd_data *hapd, u8 *pos, + u8 *end) { - u8 *pos = eid; - u8 *end = eid + max_len; int i; struct hostapd_hw_modes *mode; struct hostapd_channel_data *start, *prev; int chan_spacing = 1; - if (!hapd->iconf->ieee80211d || max_len < 6 || - hapd->iface->current_mode == NULL) - return eid; - - *pos++ = WLAN_EID_COUNTRY; - pos++; /* length will be set later */ - os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ - pos += 3; - mode = hapd->iface->current_mode; if (mode->mode == HOSTAPD_MODE_IEEE80211A) chan_spacing = 4; @@ -239,21 +239,60 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, continue; /* can use same entry */ } - if (start && prev) { - pos = hostapd_eid_country_add(pos, end, chan_spacing, + if (start && prev) + pos = hostapd_eid_country_add(hapd, pos, end, + chan_spacing, start, prev); - start = NULL; - } /* Start new group */ start = prev = chan; } if (start) { - pos = hostapd_eid_country_add(pos, end, chan_spacing, + pos = hostapd_eid_country_add(hapd, pos, end, chan_spacing, start, prev); } + return pos; +} + + +static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, + int max_len) +{ + u8 *pos = eid; + u8 *end = eid + max_len; + + if (!hapd->iconf->ieee80211d || max_len < 6 || + hapd->iface->current_mode == NULL) + return eid; + + *pos++ = WLAN_EID_COUNTRY; + pos++; /* length will be set later */ + os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */ + pos += 3; + + if (is_6ghz_op_class(hapd->iconf->op_class)) { + /* Force the third octet of the country string to indicate + * Global Operating Class (Table E-4) */ + eid[4] = 0x04; + + /* Operating Triplet field */ + /* Operating Extension Identifier (>= 201 to indicate this is + * not a Subband Triplet field) */ + *pos++ = 201; + /* Operating Class */ + *pos++ = hapd->iconf->op_class; + /* Coverage Class */ + *pos++ = 0; + /* Subband Triplets are required only for the 20 MHz case */ + if (hapd->iconf->op_class == 131 || + hapd->iconf->op_class == 136) + pos = hostapd_fill_subband_triplets(hapd, pos, end); + } else { + pos = hostapd_fill_subband_triplets(hapd, pos, end); + } + if ((pos - eid) & 1) { if (end - pos < 1) return eid; @@ -428,16 +467,174 @@ static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid) } -static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, - const struct ieee80211_mgmt *req, - int is_p2p, size_t *resp_len) +static int +ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd, + struct wpa_driver_ap_params *params) { + struct hostapd_iface *iface = hapd->iface; + struct hostapd_data *tx_bss; + size_t len, rnr_len = 0; + u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end; + u8 rnr_elem_count = 0, *rnr_elem = NULL, **rnr_elem_offset = NULL; + size_t i; + + if (!iface->mbssid_max_interfaces || + iface->num_bss > iface->mbssid_max_interfaces || + (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED && + !iface->ema_max_periodicity)) + goto fail; + + /* Make sure bss->xrates_supported is set for all BSSs to know whether + * it need to be non-inherited. */ + for (i = 0; i < iface->num_bss; i++) { + u8 buf[100]; + + hostapd_eid_ext_supp_rates(iface->bss[i], buf); + } + + tx_bss = hostapd_mbssid_get_tx_bss(hapd); + len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count, + NULL, 0, &rnr_len); + if (!len || (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED && + elem_count > iface->ema_max_periodicity)) + goto fail; + + elem = os_zalloc(len); + if (!elem) + goto fail; + + elem_offset = os_zalloc(elem_count * sizeof(u8 *)); + if (!elem_offset) + goto fail; + + if (rnr_len) { + rnr_elem = os_zalloc(rnr_len); + if (!rnr_elem) + goto fail; + + rnr_elem_offset = os_calloc(elem_count + 1, sizeof(u8 *)); + if (!rnr_elem_offset) + goto fail; + } + + end = hostapd_eid_mbssid(tx_bss, elem, elem + len, WLAN_FC_STYPE_BEACON, + elem_count, elem_offset, NULL, 0, rnr_elem, + &rnr_elem_count, rnr_elem_offset, rnr_len); + + params->mbssid_tx_iface = tx_bss->conf->iface; + params->mbssid_index = hostapd_mbssid_get_bss_index(hapd); + params->mbssid_elem = elem; + params->mbssid_elem_len = end - elem; + params->mbssid_elem_count = elem_count; + params->mbssid_elem_offset = elem_offset; + params->rnr_elem = rnr_elem; + params->rnr_elem_len = rnr_len; + params->rnr_elem_count = rnr_elem_count; + params->rnr_elem_offset = rnr_elem_offset; + if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED) + params->ema = true; + + return 0; + +fail: + os_free(rnr_elem); + os_free(rnr_elem_offset); + os_free(elem_offset); + os_free(elem); + wpa_printf(MSG_ERROR, "MBSSID: Configuration failed"); + return -1; +} + + +static u8 * hostapd_eid_mbssid_config(struct hostapd_data *hapd, u8 *eid, + u8 mbssid_elem_count) +{ + struct hostapd_iface *iface = hapd->iface; + + if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED) { + *eid++ = WLAN_EID_EXTENSION; + *eid++ = 3; + *eid++ = WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION; + *eid++ = iface->num_bss; + *eid++ = mbssid_elem_count; + } + + return eid; +} + + +static size_t he_elem_len(struct hostapd_data *hapd) +{ + size_t len = 0; + +#ifdef CONFIG_IEEE80211AX + if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax) + return len; + + len += 3 + sizeof(struct ieee80211_he_capabilities) + + 3 + sizeof(struct ieee80211_he_operation) + + 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) + + 3 + sizeof(struct ieee80211_spatial_reuse); + if (is_6ghz_op_class(hapd->iconf->op_class)) { + len += sizeof(struct ieee80211_he_6ghz_oper_info) + + 3 + sizeof(struct ieee80211_he_6ghz_band_cap); + /* An additional Transmit Power Envelope element for + * subordinate client */ + if (he_reg_is_indoor(hapd->iconf->he_6ghz_reg_pwr_type)) + len += 4; + + /* An additional Transmit Power Envelope element for + * default client with unit interpretation of regulatory + * client EIRP */ + if (hapd->iconf->reg_def_cli_eirp != -1 && + he_reg_is_sp(hapd->iconf->he_6ghz_reg_pwr_type)) + len += 4; + } +#endif /* CONFIG_IEEE80211AX */ + + return len; +} + + +struct probe_resp_params { + const struct ieee80211_mgmt *req; + bool is_p2p; + + /* Generated IEs will be included inside an ML element */ + bool is_ml_sta_info; + struct hostapd_data *mld_ap; + struct mld_info *mld_info; + struct ieee80211_mgmt *resp; - u8 *pos, *epos, *csa_pos; - size_t buflen; + size_t resp_len; + u8 *csa_pos; + u8 *ecsa_pos; + const u8 *known_bss; + u8 known_bss_len; + +#ifdef CONFIG_IEEE80211AX + u8 *cca_pos; +#endif /* CONFIG_IEEE80211AX */ +}; + + +static void hostapd_free_probe_resp_params(struct probe_resp_params *params) +{ +#ifdef CONFIG_IEEE80211BE + if (!params) + return; + ap_sta_free_sta_profile(params->mld_info); + os_free(params->mld_info); + params->mld_info = NULL; +#endif /* CONFIG_IEEE80211BE */ +} + + +static size_t hostapd_probe_resp_elems_len(struct hostapd_data *hapd, + struct probe_resp_params *params) +{ + size_t buflen = 0; -#define MAX_PROBERESP_LEN 768 - buflen = MAX_PROBERESP_LEN; #ifdef CONFIG_WPS if (hapd->wps_probe_resp_ie) buflen += wpabuf_len(hapd->wps_probe_resp_ie); @@ -452,53 +649,64 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, #endif /* CONFIG_FST */ if (hapd->conf->vendor_elements) buflen += wpabuf_len(hapd->conf->vendor_elements); +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->conf->presp_elements) + buflen += wpabuf_len(hapd->conf->presp_elements); +#endif /* CONFIG_TESTING_OPTIONS */ if (hapd->conf->vendor_vht) { buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) + 2 + sizeof(struct ieee80211_vht_operation); } -#ifdef CONFIG_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) + - 3 + sizeof(struct ieee80211_spatial_reuse); - if (is_6ghz_op_class(hapd->iconf->op_class)) - buflen += sizeof(struct ieee80211_he_6ghz_oper_info) + - 3 + sizeof(struct ieee80211_he_6ghz_band_cap); + buflen += he_elem_len(hapd); + +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP); + buflen += 3 + sizeof(struct ieee80211_eht_operation); + if (hapd->iconf->punct_bitmap) + buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE; + + if (!params->is_ml_sta_info && hapd->conf->mld_ap) { + struct hostapd_data *ml_elem_ap = + params->mld_ap ? params->mld_ap : hapd; + + buflen += hostapd_eid_eht_ml_beacon_len( + ml_elem_ap, params->mld_info, !!params->mld_ap); + } } -#endif /* CONFIG_IEEE80211AX */ +#endif /* CONFIG_IEEE80211BE */ - buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP); + buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL, + params->known_bss, + params->known_bss_len, NULL); + if (!params->is_ml_sta_info) + buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP, + true); buflen += hostapd_mbo_ie_len(hapd); buflen += hostapd_eid_owe_trans_len(hapd); buflen += hostapd_eid_dpp_cc_len(hapd); - resp = os_zalloc(buflen); - if (resp == NULL) - return NULL; - - epos = ((u8 *) resp) + MAX_PROBERESP_LEN; + return buflen; +} - resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_PROBE_RESP); - if (req) - os_memcpy(resp->da, req->sa, ETH_ALEN); - os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); - resp->u.probe_resp.beacon_int = - host_to_le16(hapd->iconf->beacon_int); +static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd, + struct probe_resp_params *params, + u8 *pos, size_t len) +{ + u8 *csa_pos; + u8 *epos; - /* hardware or low-level driver will setup seq_ctrl and timestamp */ - resp->u.probe_resp.capab_info = - host_to_le16(hostapd_own_capab_info(hapd)); + epos = pos + len; - pos = resp->u.probe_resp.variable; - *pos++ = WLAN_EID_SSID; - *pos++ = hapd->conf->ssid.ssid_len; - os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len); - pos += hapd->conf->ssid.ssid_len; + if (!params->is_ml_sta_info) { + *pos++ = WLAN_EID_SSID; + *pos++ = hapd->conf->ssid.ssid_len; + os_memcpy(pos, hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len); + pos += hapd->conf->ssid.ssid_len; + } /* Supported rates */ pos = hostapd_eid_supp_rates(hapd, pos); @@ -511,11 +719,18 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, /* Power Constraint element */ pos = hostapd_eid_pwr_constraint(hapd, pos); - /* CSA IE */ - csa_pos = hostapd_eid_csa(hapd, pos); - if (csa_pos != pos) - hapd->cs_c_off_proberesp = csa_pos - (u8 *) resp - 1; - pos = csa_pos; + /* + * CSA IE + * TODO: This should be included inside the ML sta profile + */ + if (!params->is_ml_sta_info) { + csa_pos = hostapd_eid_csa(hapd, pos); + if (csa_pos != pos) + params->csa_pos = csa_pos - 1; + else + params->csa_pos = NULL; + pos = csa_pos; + } /* ERP Information element */ pos = hostapd_eid_erp_info(hapd, pos); @@ -525,20 +740,34 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_get_rsne(hapd, pos, epos - pos); pos = hostapd_eid_bss_load(hapd, pos, epos - pos); + pos = hostapd_eid_mbssid(hapd, pos, epos, WLAN_FC_STYPE_PROBE_RESP, 0, + NULL, params->known_bss, params->known_bss_len, + NULL, NULL, NULL, 0); pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos); pos = hostapd_get_mde(hapd, pos, epos - pos); - /* eCSA IE */ - csa_pos = hostapd_eid_ecsa(hapd, pos); - if (csa_pos != pos) - hapd->cs_c_off_ecsa_proberesp = csa_pos - (u8 *) resp - 1; - pos = csa_pos; + /* + * eCSA IE + * TODO: This should be included inside the ML sta profile + */ + if (!params->is_ml_sta_info) { + csa_pos = hostapd_eid_ecsa(hapd, pos); + if (csa_pos != pos) + params->ecsa_pos = csa_pos - 1; + else + params->ecsa_pos = NULL; + pos = csa_pos; + } pos = hostapd_eid_supported_op_classes(hapd, pos); pos = hostapd_eid_ht_capabilities(hapd, pos); pos = hostapd_eid_ht_operation(hapd, pos); - pos = hostapd_eid_ext_capab(hapd, pos); + /* Probe Response frames always include all non-TX profiles except + * when a list of known BSSes is included in the Probe Request frame. */ + pos = hostapd_eid_ext_capab(hapd, pos, + hapd->iconf->mbssid >= MBSSID_ENABLED && + !params->known_bss_len); pos = hostapd_eid_time_adv(hapd, pos); pos = hostapd_eid_time_zone(hapd, pos); @@ -572,20 +801,48 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_eid_wb_chsw_wrapper(hapd, pos); - pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP); + if (!params->is_ml_sta_info) + pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP, + true); pos = hostapd_eid_fils_indic(hapd, pos, 0); pos = hostapd_get_rsnxe(hapd, pos, epos - pos); #ifdef CONFIG_IEEE80211AX if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) { + u8 *cca_pos; + pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP); pos = hostapd_eid_he_operation(hapd, pos); + + /* BSS Color Change Announcement element */ + cca_pos = hostapd_eid_cca(hapd, pos); + if (cca_pos != pos) + params->cca_pos = cca_pos - 2; + else + params->cca_pos = NULL; + pos = cca_pos; + pos = hostapd_eid_spatial_reuse(hapd, pos); pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos); pos = hostapd_eid_he_6ghz_band_cap(hapd, pos); } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + struct hostapd_data *ml_elem_ap = + params->mld_ap ? params->mld_ap : hapd; + + if (ml_elem_ap->conf->mld_ap) + pos = hostapd_eid_eht_ml_beacon( + ml_elem_ap, params->mld_info, + pos, !!params->mld_ap); + + pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP); + pos = hostapd_eid_eht_operation(hapd, pos); + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211AC if (hapd->conf->vendor_vht) pos = hostapd_eid_vendor_vht(hapd, pos); @@ -607,7 +864,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P - if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p && + if ((hapd->conf->p2p & P2P_ENABLED) && params->is_p2p && hapd->p2p_probe_resp_ie) { os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie), wpabuf_len(hapd->p2p_probe_resp_ie)); @@ -624,9 +881,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_eid_hs20_indication(hapd, pos); #endif /* CONFIG_HS20 */ - pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos); - pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos); - pos = hostapd_eid_dpp_cc(hapd, pos, (u8 *) resp + buflen - pos); + pos = hostapd_eid_mbo(hapd, pos, epos - pos); + pos = hostapd_eid_owe_trans(hapd, pos, epos - pos); + pos = hostapd_eid_dpp_cc(hapd, pos, epos - pos); if (hapd->conf->vendor_elements) { os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements), @@ -634,9 +891,169 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos += wpabuf_len(hapd->conf->vendor_elements); } - *resp_len = pos - (u8 *) resp; - return (u8 *) resp; +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->conf->presp_elements) { + os_memcpy(pos, wpabuf_head(hapd->conf->presp_elements), + wpabuf_len(hapd->conf->presp_elements)); + pos += wpabuf_len(hapd->conf->presp_elements); + } +#endif /* CONFIG_TESTING_OPTIONS */ + + return pos; +} + + +static void hostapd_gen_probe_resp(struct hostapd_data *hapd, + struct probe_resp_params *params) +{ + u8 *pos; + size_t buflen; + + hapd = hostapd_mbssid_get_tx_bss(hapd); + +#define MAX_PROBERESP_LEN 768 + buflen = MAX_PROBERESP_LEN; + buflen += hostapd_probe_resp_elems_len(hapd, params); + params->resp = os_zalloc(buflen); + if (!params->resp) { + params->resp_len = 0; + return; + } + + params->resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_PROBE_RESP); + /* Unicast the response to all requests on bands other than 6 GHz. For + * the 6 GHz, unicast is used only if the actual SSID is not included in + * the Beacon frames. Otherwise, broadcast response is used per IEEE + * Std 802.11ax-2021, 26.17.2.3.2. Broadcast address is also used for + * the Probe Response frame template for the unsolicited (i.e., not as + * a response to a specific request) case. */ + if (params->req && (!is_6ghz_op_class(hapd->iconf->op_class) || + hapd->conf->ignore_broadcast_ssid)) + os_memcpy(params->resp->da, params->req->sa, ETH_ALEN); + else + os_memset(params->resp->da, 0xff, ETH_ALEN); + os_memcpy(params->resp->sa, hapd->own_addr, ETH_ALEN); + + os_memcpy(params->resp->bssid, hapd->own_addr, ETH_ALEN); + params->resp->u.probe_resp.beacon_int = + host_to_le16(hapd->iconf->beacon_int); + + /* hardware or low-level driver will setup seq_ctrl and timestamp */ + params->resp->u.probe_resp.capab_info = + host_to_le16(hostapd_own_capab_info(hapd)); + + pos = hostapd_probe_resp_fill_elems(hapd, params, + params->resp->u.probe_resp.variable, + buflen); + + params->resp_len = pos - (u8 *) params->resp; +} + + +#ifdef CONFIG_IEEE80211BE +static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd, + struct probe_resp_params *params, + const struct ieee80211_mgmt *mgmt, + int mld_id, u16 links) +{ + struct probe_resp_params sta_info_params; + struct hostapd_data *link; + + params->mld_ap = NULL; + params->mld_info = os_zalloc(sizeof(*params->mld_info)); + if (!params->mld_info) + return; + + wpa_printf(MSG_DEBUG, + "MLD: Got ML probe request with AP MLD ID %d for links %04x", + mld_id, links); + + for_each_mld_link(link, hapd) { + struct mld_link_info *link_info; + size_t buflen; + u8 mld_link_id = link->mld_link_id; + u8 *epos; + u8 buf[EHT_ML_MAX_STA_PROF_LEN]; + + /* + * Set mld_ap iff the ML probe request explicitly + * requested a specific MLD ID. In that case, the targeted + * AP may have been a nontransmitted BSSID on the same + * interface. + */ + if (mld_id != -1 && link->iface == hapd->iface) + params->mld_ap = link; + + /* Never duplicate main Probe Response frame body */ + if (link == hapd) + continue; + + /* Only include requested links */ + if (!(BIT(mld_link_id) & links)) + continue; + + link_info = ¶ms->mld_info->links[mld_link_id]; + + sta_info_params.req = params->req; + sta_info_params.is_p2p = false; + sta_info_params.is_ml_sta_info = true; + sta_info_params.mld_ap = NULL; + sta_info_params.mld_info = NULL; + + buflen = MAX_PROBERESP_LEN; + buflen += hostapd_probe_resp_elems_len(link, &sta_info_params); + + if (buflen > EHT_ML_MAX_STA_PROF_LEN) { + wpa_printf(MSG_DEBUG, + "MLD: Not including link %d in ML probe response (%zu bytes is too long)", + mld_link_id, buflen); + goto fail; + } + + /* + * NOTE: This does not properly handle inheritance and + * various other things. + */ + link_info->valid = true; + epos = buf; + + /* Capabilities is the only fixed parameter */ + WPA_PUT_LE16(epos, hostapd_own_capab_info(hapd)); + epos += 2; + + epos = hostapd_probe_resp_fill_elems( + link, &sta_info_params, epos, + EHT_ML_MAX_STA_PROF_LEN - 2); + link_info->resp_sta_profile_len = epos - buf; + os_free(link_info->resp_sta_profile); + link_info->resp_sta_profile = os_memdup( + buf, link_info->resp_sta_profile_len); + if (!link_info->resp_sta_profile) + link_info->resp_sta_profile_len = 0; + os_memcpy(link_info->local_addr, link->own_addr, ETH_ALEN); + + wpa_printf(MSG_DEBUG, + "MLD: ML probe response includes link sta info for %d: %u bytes (estimate %zu)", + mld_link_id, link_info->resp_sta_profile_len, + buflen); + } + + if (mld_id != -1 && !params->mld_ap) { + wpa_printf(MSG_DEBUG, + "MLD: No nontransmitted BSSID for MLD ID %d", + mld_id); + goto fail; + } + + return; + +fail: + hostapd_free_probe_resp_params(params); + params->mld_ap = NULL; + params->mld_info = NULL; } +#endif /* CONFIG_IEEE80211BE */ enum ssid_match_result { @@ -753,7 +1170,7 @@ static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface, struct hostapd_sta_info *info; dl_list_for_each(info, &iface->sta_seen, struct hostapd_sta_info, list) - if (os_memcmp(addr, info->addr, ETH_ALEN) == 0) + if (ether_addr_equal(addr, info->addr)) return info; return NULL; @@ -837,21 +1254,109 @@ void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr, #endif /* CONFIG_TAXONOMY */ +#ifdef CONFIG_IEEE80211BE +static bool parse_ml_probe_req(const struct ieee80211_eht_ml *ml, size_t ml_len, + int *mld_id, u16 *links) +{ + u16 ml_control; + const struct element *sub; + const u8 *pos; + size_t len; + + *mld_id = -1; + *links = 0xffff; + + if (ml_len < sizeof(struct ieee80211_eht_ml)) + return false; + + ml_control = le_to_host16(ml->ml_control); + if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) != + MULTI_LINK_CONTROL_TYPE_PROBE_REQ) { + wpa_printf(MSG_DEBUG, "MLD: Not an ML probe req"); + return false; + } + + if (sizeof(struct ieee80211_eht_ml) + 1 > ml_len) { + wpa_printf(MSG_DEBUG, "MLD: ML probe req too short"); + return false; + } + + pos = ml->variable; + len = pos[0]; + if (len < 1 || sizeof(struct ieee80211_eht_ml) + len > ml_len) { + wpa_printf(MSG_DEBUG, + "MLD: ML probe request with invalid length"); + return false; + } + + if (ml_control & EHT_ML_PRES_BM_PROBE_REQ_AP_MLD_ID) { + if (len < 2) { + wpa_printf(MSG_DEBUG, + "MLD: ML probe req too short for MLD ID"); + return false; + } + + *mld_id = pos[1]; + } + pos += len; + + /* Parse subelements (if there are any) */ + len = ml_len - len - sizeof(struct ieee80211_eht_ml); + for_each_element_id(sub, 0, pos, len) { + const struct ieee80211_eht_per_sta_profile *sta; + u16 sta_control; + + if (*links == 0xffff) + *links = 0; + + if (sub->datalen < + sizeof(struct ieee80211_eht_per_sta_profile)) { + wpa_printf(MSG_DEBUG, + "MLD: ML probe req %d too short for sta profile", + sub->datalen); + return false; + } + + sta = (struct ieee80211_eht_per_sta_profile *) sub->data; + + /* + * Extract the link ID, do not return whether a complete or + * partial profile was requested. + */ + sta_control = le_to_host16(sta->sta_control); + *links |= BIT(sta_control & EHT_PER_STA_CTRL_LINK_ID_MSK); + } + + if (!for_each_element_completed(sub, pos, len)) { + wpa_printf(MSG_DEBUG, + "MLD: ML probe req sub-elements parsing error"); + return false; + } + + return true; +} +#endif /* CONFIG_IEEE80211BE */ + + void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int ssi_signal) { - u8 *resp; struct ieee802_11_elems elems; const u8 *ie; size_t ie_len; - size_t i, resp_len; + size_t i; int noack; enum ssid_match_result res; int ret; u16 csa_offs[2]; size_t csa_offs_len; struct radius_sta rad_info; + struct probe_resp_params params; +#ifdef CONFIG_IEEE80211BE + int mld_id; + u16 links; +#endif /* CONFIG_IEEE80211BE */ if (hapd->iconf->rssi_ignore_probe_request && ssi_signal && ssi_signal < hapd->iconf->rssi_ignore_probe_request) @@ -1017,7 +1522,7 @@ void handle_probe_req(struct hostapd_data *hapd, else hessid = elems.interworking + 1 + 2; if (!is_broadcast_ether_addr(hessid) && - os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) { + !ether_addr_equal(hessid, hapd->conf->hessid)) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR_SEC " for mismatching HESSID " MACSTR_SEC " ignored", @@ -1074,12 +1579,37 @@ void handle_probe_req(struct hostapd_data *hapd, } #endif /* CONFIG_TESTING_OPTIONS */ + /* Do not send Probe Response frame from a non-transmitting multiple + * BSSID profile unless the Probe Request frame is directed at that + * particular BSS. */ + if (hapd != hostapd_mbssid_get_tx_bss(hapd) && res != EXACT_SSID_MATCH) + return; + wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR " signal=%d", MAC2STR(mgmt->sa), ssi_signal); - resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL, - &resp_len); - if (resp == NULL) + os_memset(¶ms, 0, sizeof(params)); + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap && elems.probe_req_mle && + parse_ml_probe_req((struct ieee80211_eht_ml *) elems.probe_req_mle, + elems.probe_req_mle_len, &mld_id, &links)) { + hostapd_fill_probe_resp_ml_params(hapd, ¶ms, mgmt, + mld_id, links); + } +#endif /* CONFIG_IEEE80211BE */ + + params.req = mgmt; + params.is_p2p = !!elems.p2p; + params.known_bss = elems.mbssid_known_bss; + params.known_bss_len = elems.mbssid_known_bss_len; + params.is_ml_sta_info = false; + + hostapd_gen_probe_resp(hapd, ¶ms); + + hostapd_free_probe_resp_params(¶ms); + + if (!params.resp) return; /* @@ -1091,23 +1621,23 @@ void handle_probe_req(struct hostapd_data *hapd, csa_offs_len = 0; if (hapd->csa_in_progress) { - if (hapd->cs_c_off_proberesp) + if (params.csa_pos) csa_offs[csa_offs_len++] = - hapd->cs_c_off_proberesp; + params.csa_pos - (u8 *) params.resp; - if (hapd->cs_c_off_ecsa_proberesp) + if (params.ecsa_pos) csa_offs[csa_offs_len++] = - hapd->cs_c_off_ecsa_proberesp; + params.ecsa_pos - (u8 *) params.resp; } - ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack, + ret = hostapd_drv_send_mlme(hapd, params.resp, params.resp_len, noack, csa_offs_len ? csa_offs : NULL, csa_offs_len, 0); if (ret < 0) wpa_printf(MSG_INFO, "handle_probe_req: send failed"); - os_free(resp); + os_free(params.resp); wpa_printf(MSG_EXCESSIVE, "STA " MACSTR_SEC " sent probe request for %s " "SSID", MAC2STR_SEC(mgmt->sa), @@ -1118,6 +1648,8 @@ void handle_probe_req(struct hostapd_data *hapd, static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, size_t *resp_len) { + struct probe_resp_params params; + /* check probe response offloading caps and print warnings */ if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD)) return NULL; @@ -1147,7 +1679,32 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, "this"); /* Generate a Probe Response template for the non-P2P case */ - return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len); + os_memset(¶ms, 0, sizeof(params)); + params.req = NULL; + params.is_p2p = false; + params.known_bss = NULL; + params.known_bss_len = 0; + params.is_ml_sta_info = false; + params.mld_ap = NULL; + params.mld_info = NULL; + + hostapd_gen_probe_resp(hapd, ¶ms); + *resp_len = params.resp_len; + if (!params.resp) + return NULL; + + /* TODO: Avoid passing these through struct hostapd_data */ + if (params.csa_pos) + hapd->cs_c_off_proberesp = params.csa_pos - (u8 *) params.resp; + if (params.ecsa_pos) + hapd->cs_c_off_ecsa_proberesp = params.ecsa_pos - + (u8 *) params.resp; +#ifdef CONFIG_IEEE80211AX + if (params.cca_pos) + hapd->cca_c_off_proberesp = params.cca_pos - (u8 *) params.resp; +#endif /* CONFIG_IEEE80211AX */ + + return (u8 *) params.resp; } #endif /* NEED_AP_MLME */ @@ -1155,17 +1712,29 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, #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) +u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd, + struct unsol_bcast_probe_resp *ubpr) { + struct probe_resp_params probe_params; + if (!is_6ghz_op_class(hapd->iconf->op_class)) return NULL; - params->unsol_bcast_probe_resp_interval = + ubpr->unsol_bcast_probe_resp_interval = hapd->conf->unsol_bcast_probe_resp_interval; - return hostapd_gen_probe_resp(hapd, NULL, 0, - ¶ms->unsol_bcast_probe_resp_tmpl_len); + os_memset(&probe_params, 0, sizeof(probe_params)); + probe_params.req = NULL; + probe_params.is_p2p = false; + probe_params.known_bss = NULL; + probe_params.known_bss_len = 0; + probe_params.is_ml_sta_info = false; + probe_params.mld_ap = NULL; + probe_params.mld_info = NULL; + + hostapd_gen_probe_resp(hapd, &probe_params); + ubpr->unsol_bcast_probe_resp_tmpl_len = probe_params.resp_len; + return (u8 *) probe_params.resp; } #endif /* CONFIG_IEEE80211AX */ @@ -1182,10 +1751,128 @@ void sta_track_del(struct hostapd_sta_info *info) #ifdef CONFIG_FILS +static u16 hostapd_gen_fils_discovery_phy_index(struct hostapd_data *hapd) +{ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) + return FD_CAP_PHY_INDEX_EHT; +#endif /* CONFIG_IEEE80211BE */ + +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) + return FD_CAP_PHY_INDEX_HE; +#endif /* CONFIG_IEEE80211AX */ + +#ifdef CONFIG_IEEE80211AC + if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) + return FD_CAP_PHY_INDEX_VHT; +#endif /* CONFIG_IEEE80211AC */ + + if (hapd->iconf->ieee80211n && !hapd->conf->disable_11n) + return FD_CAP_PHY_INDEX_HT; + + return 0; +} + + +static u16 hostapd_gen_fils_discovery_nss(struct hostapd_hw_modes *mode, + u16 phy_index, u8 he_mcs_nss_size) +{ + u16 nss = 0; + + if (!mode) + return 0; + + if (phy_index == FD_CAP_PHY_INDEX_HE) { + const u8 *he_mcs = mode->he_capab[IEEE80211_MODE_AP].mcs; + int i; + u16 mcs[6]; + + os_memset(mcs, 0xff, 6 * sizeof(u16)); + + if (he_mcs_nss_size == 4) { + mcs[0] = WPA_GET_LE16(&he_mcs[0]); + mcs[1] = WPA_GET_LE16(&he_mcs[2]); + } + + if (he_mcs_nss_size == 8) { + mcs[2] = WPA_GET_LE16(&he_mcs[4]); + mcs[3] = WPA_GET_LE16(&he_mcs[6]); + } + + if (he_mcs_nss_size == 12) { + mcs[4] = WPA_GET_LE16(&he_mcs[8]); + mcs[5] = WPA_GET_LE16(&he_mcs[10]); + } + + for (i = 0; i < HE_NSS_MAX_STREAMS; i++) { + u16 nss_mask = 0x3 << (i * 2); + + /* + * If Tx and/or Rx indicate support for a given NSS, + * count it towards the maximum NSS. + */ + if (he_mcs_nss_size == 4 && + (((mcs[0] & nss_mask) != nss_mask) || + ((mcs[1] & nss_mask) != nss_mask))) { + nss++; + continue; + } + + if (he_mcs_nss_size == 8 && + (((mcs[2] & nss_mask) != nss_mask) || + ((mcs[3] & nss_mask) != nss_mask))) { + nss++; + continue; + } + + if (he_mcs_nss_size == 12 && + (((mcs[4] & nss_mask) != nss_mask) || + ((mcs[5] & nss_mask) != nss_mask))) { + nss++; + continue; + } + } + } else if (phy_index == FD_CAP_PHY_INDEX_EHT) { + u8 rx_nss, tx_nss, max_nss = 0, i; + u8 *mcs = mode->eht_capab[IEEE80211_MODE_AP].mcs; + + /* + * The Supported EHT-MCS And NSS Set field for the AP contains + * one to three EHT-MCS Map fields based on the supported + * bandwidth. Check the first byte (max NSS for Rx/Tx that + * supports EHT-MCS 0-9) for each bandwidth (<= 80, + * 160, 320) to find the maximum NSS. This assumes that + * the lowest MCS rates support the largest number of spatial + * streams. If values are different between Tx, Rx or the + * bandwidths, choose the highest value. + */ + for (i = 0; i < 3; i++) { + rx_nss = mcs[3 * i] & 0x0F; + if (rx_nss > max_nss) + max_nss = rx_nss; + + tx_nss = (mcs[3 * i] & 0xF0) >> 4; + if (tx_nss > max_nss) + max_nss = tx_nss; + } + + nss = max_nss; + } + + if (nss > 4) + return FD_CAP_NSS_5_8 << FD_CAP_NSS_SHIFT; + if (nss) + return (nss - 1) << FD_CAP_NSS_SHIFT; + + return 0; +} + + 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; + u16 cap_info, phy_index; + u8 chwidth = FD_CAP_BSS_CHWIDTH_20, he_mcs_nss_size = 4; struct hostapd_hw_modes *mode = hapd->iface->current_mode; cap_info = FD_CAP_ESS; @@ -1193,14 +1880,15 @@ static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd) 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 137: + chwidth = FD_CAP_BSS_CHWIDTH_320; + break; case 135: - mcs_nss_size += 4; + he_mcs_nss_size += 4; /* fallthrough */ case 134: - mcs_nss_size += 4; + he_mcs_nss_size += 4; chwidth = FD_CAP_BSS_CHWIDTH_160_80_80; break; case 133: @@ -1212,73 +1900,32 @@ static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd) } } else { switch (hostapd_get_oper_chwidth(hapd->iconf)) { - case CHANWIDTH_80P80MHZ: - mcs_nss_size += 4; + case CONF_OPER_CHWIDTH_80P80MHZ: + he_mcs_nss_size += 4; /* fallthrough */ - case CHANWIDTH_160MHZ: - mcs_nss_size += 4; + case CONF_OPER_CHWIDTH_160MHZ: + he_mcs_nss_size += 4; chwidth = FD_CAP_BSS_CHWIDTH_160_80_80; break; - case CHANWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: chwidth = FD_CAP_BSS_CHWIDTH_80; break; - case CHANWIDTH_USE_HT: + case CONF_OPER_CHWIDTH_USE_HT: if (hapd->iconf->secondary_channel) chwidth = FD_CAP_BSS_CHWIDTH_40; else chwidth = FD_CAP_BSS_CHWIDTH_20; break; + default: + 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; } + phy_index = hostapd_gen_fils_discovery_phy_index(hapd); 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; - } - + cap_info |= hostapd_gen_fils_discovery_nss(mode, phy_index, + he_mcs_nss_size); return cap_info; } @@ -1301,6 +1948,17 @@ static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len) FD_FRAME_CTL_CAP_PRESENT; total_len += 4 + 1 + 2; + /* Fill primary channel information for 6 GHz channels with over 20 MHz + * bandwidth, if the primary channel is not a PSC */ + if (is_6ghz_op_class(hapd->iconf->op_class) && + !is_6ghz_psc_frequency(ieee80211_chan_to_freq( + NULL, hapd->iconf->op_class, + hapd->iconf->channel)) && + op_class_to_bandwidth(hapd->iconf->op_class) > 20) { + ctl |= FD_FRAME_CTL_PRI_CHAN_PRESENT; + total_len += 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; @@ -1313,12 +1971,16 @@ static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len) total_len += 3; } - total_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_ACTION); + total_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_ACTION, true); pos = hostapd_eid_fils_indic(hapd, buf, 0); buf_len = pos - buf; total_len += buf_len; + /* he_elem_len() may return too large a value for FD frame, but that is + * fine here since this is used as the maximum length of the buffer. */ + total_len += he_elem_len(hapd); + head = os_zalloc(total_len); if (!head) return NULL; @@ -1358,9 +2020,11 @@ static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len) WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd)); pos += 2; - /* Operating Class - not present */ - - /* Primary Channel - not present */ + /* Operating Class and Primary Channel - if a 6 GHz chan is non PSC */ + if (ctl & FD_FRAME_CTL_PRI_CHAN_PRESENT) { + *pos++ = hapd->iconf->op_class; + *pos++ = hapd->iconf->channel; + } /* AP Configuration Sequence Number - not present */ @@ -1383,7 +2047,7 @@ static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len) /* Fill in the Length field value */ *length_pos = pos - (length_pos + 1); - pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_ACTION); + pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_ACTION, true); /* FILS Indication element */ if (buf_len) { @@ -1391,6 +2055,9 @@ static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len) pos += buf_len; } + if (is_6ghz_op_class(hapd->iconf->op_class)) + pos = hostapd_eid_txpower_envelope(hapd, pos); + *len = pos - (u8 *) head; wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template", head, pos - (u8 *) head); @@ -1432,7 +2099,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, #ifdef NEED_AP_MLME u16 capab_info; u8 *pos, *tailpos, *tailend, *csa_pos; + bool complete = false; +#endif /* NEED_AP_MLME */ + + os_memset(params, 0, sizeof(*params)); +#ifdef NEED_AP_MLME #define BEACON_HEAD_BUF_SIZE 256 #define BEACON_TAIL_BUF_SIZE 512 head = os_zalloc(BEACON_HEAD_BUF_SIZE); @@ -1459,19 +2131,29 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, } #endif /* CONFIG_IEEE80211AC */ -#ifdef CONFIG_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) + - 3 + sizeof(struct ieee80211_spatial_reuse); - if (is_6ghz_op_class(hapd->iconf->op_class)) - tail_len += sizeof(struct ieee80211_he_6ghz_oper_info) + - 3 + sizeof(struct ieee80211_he_6ghz_band_cap); - } -#endif /* CONFIG_IEEE80211AX */ - - tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON); + tail_len += he_elem_len(hapd); + +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + tail_len += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP); + tail_len += 3 + sizeof(struct ieee80211_eht_operation); + if (hapd->iconf->punct_bitmap) + tail_len += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE; + + /* + * TODO: Multi-Link element has variable length and can be + * long based on the common info and number of per + * station profiles. For now use 256. + */ + if (hapd->conf->mld_ap) + tail_len += 256; + } +#endif /* CONFIG_IEEE80211BE */ + + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && + hapd == hostapd_mbssid_get_tx_bss(hapd)) + tail_len += 5; /* Multiple BSSID Configuration element */ + tail_len += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_BEACON, true); tail_len += hostapd_mbo_ie_len(hapd); tail_len += hostapd_eid_owe_trans_len(hapd); tail_len += hostapd_eid_dpp_cc_len(hapd); @@ -1557,7 +2239,20 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); tailpos = hostapd_eid_ht_operation(hapd, tailpos); - tailpos = hostapd_eid_ext_capab(hapd, tailpos); + if (hapd->iconf->mbssid && hapd->iconf->num_bss > 1) { + if (ieee802_11_build_ap_params_mbssid(hapd, params)) { + os_free(head); + os_free(tail); + wpa_printf(MSG_ERROR, + "MBSSID: Failed to set beacon data"); + return -1; + } + complete = hapd->iconf->mbssid == MBSSID_ENABLED || + (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && + params->mbssid_elem_count == 1); + } + + tailpos = hostapd_eid_ext_capab(hapd, tailpos, complete); /* * TODO: Time Advertisement element should only be included in some @@ -1594,21 +2289,43 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos); - tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON); + tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON, true); tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0); tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos); + tailpos = hostapd_eid_mbssid_config(hapd, tailpos, + params->mbssid_elem_count); #ifdef CONFIG_IEEE80211AX if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) { + u8 *cca_pos; + tailpos = hostapd_eid_he_capab(hapd, tailpos, IEEE80211_MODE_AP); tailpos = hostapd_eid_he_operation(hapd, tailpos); + + /* BSS Color Change Announcement element */ + cca_pos = hostapd_eid_cca(hapd, tailpos); + if (cca_pos != tailpos) + hapd->cca_c_off_beacon = cca_pos - tail - 2; + tailpos = cca_pos; + tailpos = hostapd_eid_spatial_reuse(hapd, tailpos); tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos); tailpos = hostapd_eid_he_6ghz_band_cap(hapd, tailpos); } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + if (hapd->conf->mld_ap) + tailpos = hostapd_eid_eht_ml_beacon(hapd, NULL, + tailpos, false); + tailpos = hostapd_eid_eht_capab(hapd, tailpos, + IEEE80211_MODE_AP); + tailpos = hostapd_eid_eht_operation(hapd, tailpos); + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211AC if (hapd->conf->vendor_vht) tailpos = hostapd_eid_vendor_vht(hapd, tailpos); @@ -1662,7 +2379,50 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, resp = hostapd_probe_resp_offloads(hapd, &resp_len); #endif /* NEED_AP_MLME */ - os_memset(params, 0, sizeof(*params)); + /* If key management offload is enabled, configure PSK to the driver. */ + if (wpa_key_mgmt_wpa_psk_no_sae(hapd->conf->wpa_key_mgmt) && + (hapd->iface->drv_flags2 & + WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK)) { + if (hapd->conf->ssid.wpa_psk && hapd->conf->ssid.wpa_psk_set) { + os_memcpy(params->psk, hapd->conf->ssid.wpa_psk->psk, + PMK_LEN); + params->psk_len = PMK_LEN; + } else if (hapd->conf->ssid.wpa_passphrase && + pbkdf2_sha1(hapd->conf->ssid.wpa_passphrase, + hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len, 4096, + params->psk, PMK_LEN) == 0) { + params->psk_len = PMK_LEN; + } + } + +#ifdef CONFIG_SAE + /* If SAE offload is enabled, provide password to lower layer for + * SAE authentication and PMK generation. + */ + if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && + (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP)) { + if (hostapd_sae_pk_in_use(hapd->conf)) { + wpa_printf(MSG_ERROR, + "SAE PK not supported with SAE offload"); + return -1; + } + + if (hostapd_sae_pw_id_in_use(hapd->conf)) { + wpa_printf(MSG_ERROR, + "SAE Password Identifiers not supported with SAE offload"); + return -1; + } + + params->sae_password = sae_get_password(hapd, NULL, NULL, NULL, + NULL, NULL); + if (!params->sae_password) { + wpa_printf(MSG_ERROR, "SAE password not configured for offload"); + return -1; + } + } +#endif /* CONFIG_SAE */ + params->head = (u8 *) head; params->head_len = head_len; params->tail = tail; @@ -1753,6 +2513,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, } } +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap && hapd->iconf->ieee80211be && + !hapd->conf->disable_11be) { + params->mld_ap = true; + params->mld_link_id = hapd->mld_link_id; + } +#endif /* CONFIG_IEEE80211BE */ + return 0; } @@ -1765,14 +2533,24 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) params->head = NULL; os_free(params->proberesp); params->proberesp = NULL; + os_free(params->mbssid_elem); + params->mbssid_elem = NULL; + os_free(params->mbssid_elem_offset); + params->mbssid_elem_offset = NULL; + os_free(params->rnr_elem); + params->rnr_elem = NULL; + os_free(params->rnr_elem_offset); + params->rnr_elem_offset = 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; + os_free(params->ubpr.unsol_bcast_probe_resp_tmpl); + params->ubpr.unsol_bcast_probe_resp_tmpl = NULL; #endif /* CONFIG_IEEE80211AX */ + os_free(params->allowed_freqs); + params->allowed_freqs = NULL; } @@ -1784,7 +2562,9 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd) struct hostapd_config *iconf = iface->conf; struct hostapd_hw_modes *cmode = iface->current_mode; struct wpabuf *beacon, *proberesp, *assocresp; - int res, ret = -1; + bool twt_he_responder = false; + int res, ret = -1, i; + struct hostapd_hw_modes *mode; if (!hapd->drv_priv) { wpa_printf(MSG_ERROR, "Interface is disabled"); @@ -1826,11 +2606,13 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd) params.he_bss_color_partial = hapd->iface->conf->he_op.he_bss_color_partial; params.he_bss_color = hapd->iface->conf->he_op.he_bss_color; - params.twt_responder = hostapd_get_he_twt_responder(hapd, - IEEE80211_MODE_AP); - params.unsol_bcast_probe_resp_tmpl = - hostapd_unsol_bcast_probe_resp(hapd, ¶ms); + twt_he_responder = hostapd_get_he_twt_responder(hapd, + IEEE80211_MODE_AP); + params.ubpr.unsol_bcast_probe_resp_tmpl = + hostapd_unsol_bcast_probe_resp(hapd, ¶ms.ubpr); #endif /* CONFIG_IEEE80211AX */ + params.twt_responder = + twt_he_responder || hostapd_get_ht_vht_twt_responder(hapd); hapd->reenable_beacon = 0; #ifdef CONFIG_SAE params.sae_pwe = hapd->conf->sae_pwe; @@ -1840,18 +2622,44 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd) params.fd_frame_tmpl = hostapd_fils_discovery(hapd, ¶ms); #endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211BE + params.punct_bitmap = iconf->punct_bitmap; +#endif /* CONFIG_IEEE80211BE */ + if (cmode && hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq, iconf->channel, iconf->enable_edmg, iconf->edmg_channel, iconf->ieee80211n, iconf->ieee80211ac, iconf->ieee80211ax, + iconf->ieee80211be, iconf->secondary_channel, hostapd_get_oper_chwidth(iconf), hostapd_get_oper_centr_freq_seg0_idx(iconf), hostapd_get_oper_centr_freq_seg1_idx(iconf), cmode->vht_capab, - &cmode->he_capab[IEEE80211_MODE_AP]) == 0) + &cmode->he_capab[IEEE80211_MODE_AP], + &cmode->eht_capab[IEEE80211_MODE_AP], + hostapd_get_punct_bitmap(hapd)) == 0) { + freq.link_id = -1; +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) + freq.link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ params.freq = &freq; + } + + for (i = 0; i < hapd->iface->num_hw_features; i++) { + mode = &hapd->iface->hw_features[i]; + + if (iconf->hw_mode != HOSTAPD_MODE_IEEE80211ANY && + iconf->hw_mode != mode->mode) + continue; + + hostapd_get_hw_mode_any_channels(hapd, mode, + !(iconf->acs_freq_list.num || + iconf->acs_ch_list.num), + true, ¶ms.allowed_freqs); + } res = hostapd_drv_set_ap(hapd, ¶ms); hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp); @@ -1865,12 +2673,18 @@ fail: } +void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd) +{ + __ieee802_11_set_beacon(hapd); +} + + int ieee802_11_set_beacon(struct hostapd_data *hapd) { struct hostapd_iface *iface = hapd->iface; int ret; size_t i, j; - bool is_6g; + bool is_6g, hapd_mld = false; ret = __ieee802_11_set_beacon(hapd); if (ret != 0) @@ -1879,21 +2693,35 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) if (!iface->interfaces || iface->interfaces->count <= 1) return 0; - /* Update Beacon frames in case of 6 GHz colocation */ +#ifdef CONFIG_IEEE80211BE + hapd_mld = hapd->conf->mld_ap; +#endif /* CONFIG_IEEE80211BE */ + + /* Update Beacon frames in case of 6 GHz colocation or AP MLD */ is_6g = is_6ghz_op_class(iface->conf->op_class); for (j = 0; j < iface->interfaces->count; j++) { - struct hostapd_iface *colocated; + struct hostapd_iface *other; + bool other_iface_6g; - colocated = iface->interfaces->iface[j]; - if (colocated == iface || !colocated || !colocated->conf) + other = iface->interfaces->iface[j]; + if (other == iface || !other || !other->conf) continue; - if (is_6g == is_6ghz_op_class(colocated->conf->op_class)) + other_iface_6g = is_6ghz_op_class(other->conf->op_class); + + if (is_6g == other_iface_6g && !hapd_mld) continue; - for (i = 0; i < colocated->num_bss; i++) { - if (colocated->bss[i] && colocated->bss[i]->started) - __ieee802_11_set_beacon(colocated->bss[i]); + for (i = 0; i < other->num_bss; i++) { +#ifdef CONFIG_IEEE80211BE + if (is_6g == other_iface_6g && + !(hapd_mld && other->bss[i]->conf->mld_ap && + hostapd_is_ml_partner(hapd, other->bss[i]))) + continue; +#endif /* CONFIG_IEEE80211BE */ + + if (other->bss[i] && other->bss[i]->started) + __ieee802_11_set_beacon(other->bss[i]); } } diff --git a/wpa_supplicant-2.9_standard/src/ap/beacon.h b/wpa_supplicant-2.9_standard/src/ap/beacon.h index c320825f3570c9a77400d61831221e9e1711c27a..e381542a8030eb255802d7dbdea926215e46ee6c 100644 --- a/wpa_supplicant-2.9_standard/src/ap/beacon.h +++ b/wpa_supplicant-2.9_standard/src/ap/beacon.h @@ -15,6 +15,7 @@ struct ieee80211_mgmt; void handle_probe_req(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int ssi_signal); +void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd); int ieee802_11_set_beacon(struct hostapd_data *hapd); int ieee802_11_set_beacons(struct hostapd_iface *iface); int ieee802_11_update_beacons(struct hostapd_iface *iface); @@ -32,4 +33,7 @@ void sta_track_claim_taxonomy_info(struct hostapd_iface *iface, const u8 *addr, const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid); +u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd, + struct unsol_bcast_probe_resp *ubpr); + #endif /* BEACON_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/bss_load.c b/wpa_supplicant-2.9_standard/src/ap/bss_load.c index 725d3cd3469bad25285a40002ef69307e24129f0..e9baafc962b993d4dcc549e2b17ba219994c60ab 100644 --- a/wpa_supplicant-2.9_standard/src/ap/bss_load.c +++ b/wpa_supplicant-2.9_standard/src/ap/bss_load.c @@ -55,7 +55,7 @@ static void update_channel_utilization(void *eloop_data, void *user_data) return; } - ieee802_11_set_beacon(hapd); + ieee802_11_set_beacon_per_bss_only(hapd); if (get_bss_load_update_timeout(hapd, &sec, &usec) < 0) return; diff --git a/wpa_supplicant-2.9_standard/src/ap/comeback_token.c b/wpa_supplicant-2.9_standard/src/ap/comeback_token.c new file mode 100644 index 0000000000000000000000000000000000000000..499e645d59032d8c6fefe4beffc088a5bc1fab02 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/ap/comeback_token.c @@ -0,0 +1,139 @@ +/* + * hostapd / Comeback token mechanism for SAE + * Copyright (c) 2002-2017, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "hostapd.h" +#include "crypto/sha256.h" +#include "crypto/random.h" +#include "common/ieee802_11_defs.h" +#include "comeback_token.h" + + +#if defined(CONFIG_SAE) || defined(CONFIG_PASN) + +static int comeback_token_hash(const u8 *comeback_key, const u8 *addr, u8 *idx) +{ + u8 hash[SHA256_MAC_LEN]; + + if (hmac_sha256(comeback_key, COMEBACK_KEY_SIZE, + addr, ETH_ALEN, hash) < 0) + return -1; + *idx = hash[0]; + return 0; +} + + +int check_comeback_token(const u8 *comeback_key, + u16 *comeback_pending_idx, const u8 *addr, + const u8 *token, size_t token_len) +{ + u8 mac[SHA256_MAC_LEN]; + const u8 *addrs[2]; + size_t len[2]; + u16 token_idx; + u8 idx; + + if (token_len != SHA256_MAC_LEN || + comeback_token_hash(comeback_key, addr, &idx) < 0) + return -1; + token_idx = comeback_pending_idx[idx]; + if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) { + wpa_printf(MSG_DEBUG, + "Comeback: Invalid anti-clogging token from " + MACSTR_SEC " - token_idx 0x%04x, expected 0x%04x", + MAC2STR_SEC(addr), WPA_GET_BE16(token), token_idx); + return -1; + } + + addrs[0] = addr; + len[0] = ETH_ALEN; + addrs[1] = token; + len[1] = 2; + if (hmac_sha256_vector(comeback_key, COMEBACK_KEY_SIZE, + 2, addrs, len, mac) < 0 || + os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0) + return -1; + + comeback_pending_idx[idx] = 0; /* invalidate used token */ + + return 0; +} + + +struct wpabuf * +auth_build_token_req(struct os_reltime *last_comeback_key_update, + u8 *comeback_key, u16 comeback_idx, + u16 *comeback_pending_idx, size_t idx_len, + int group, const u8 *addr, int h2e) +{ + struct wpabuf *buf; + u8 *token; + struct os_reltime now; + u8 idx[2]; + const u8 *addrs[2]; + size_t len[2]; + u8 p_idx; + u16 token_idx; + + os_get_reltime(&now); + if (!os_reltime_initialized(last_comeback_key_update) || + os_reltime_expired(&now, last_comeback_key_update, 60) || + comeback_idx == 0xffff) { + if (random_get_bytes(comeback_key, COMEBACK_KEY_SIZE) < 0) + return NULL; + wpa_hexdump(MSG_DEBUG, "Comeback: Updated token key", + comeback_key, COMEBACK_KEY_SIZE); + *last_comeback_key_update = now; + comeback_idx = 0; + os_memset(comeback_pending_idx, 0, idx_len); + } + + buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN); + if (buf == NULL) + return NULL; + + if (group) + wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ + + if (h2e) { + /* Encapsulate Anti-clogging Token field in a container IE */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN); + wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN); + } + + if (comeback_token_hash(comeback_key, addr, &p_idx) < 0) { + wpabuf_free(buf); + return NULL; + } + + token_idx = comeback_pending_idx[p_idx]; + if (!token_idx) { + comeback_idx++; + token_idx = comeback_idx; + comeback_pending_idx[p_idx] = token_idx; + } + WPA_PUT_BE16(idx, token_idx); + token = wpabuf_put(buf, SHA256_MAC_LEN); + addrs[0] = addr; + len[0] = ETH_ALEN; + addrs[1] = idx; + len[1] = sizeof(idx); + if (hmac_sha256_vector(comeback_key, COMEBACK_KEY_SIZE, + 2, addrs, len, token) < 0) { + wpabuf_free(buf); + return NULL; + } + WPA_PUT_BE16(token, token_idx); + + return buf; +} + +#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */ diff --git a/wpa_supplicant-2.9_standard/src/ap/comeback_token.h b/wpa_supplicant-2.9_standard/src/ap/comeback_token.h new file mode 100644 index 0000000000000000000000000000000000000000..d5de9e684b498eefe1762ab974f0fb26969f2a38 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/ap/comeback_token.h @@ -0,0 +1,21 @@ +/* + * hostapd / Comeback token mechanism for SAE + * Copyright (c) 2002-2017, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef COMEBACK_TOKEN_H +#define COMEBACK_TOKEN_H + +int check_comeback_token(const u8 *comeback_key, + u16 *comeback_pending_idx, const u8 *addr, + const u8 *token, size_t token_len); +struct wpabuf * +auth_build_token_req(struct os_reltime *last_comeback_key_update, + u8 *comeback_key, u16 comeback_idx, + u16 *comeback_pending_idx, size_t idx_len, + int group, const u8 *addr, int h2e); + +#endif /* COMEBACK_TOKEN_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ctrl_iface_ap.c b/wpa_supplicant-2.9_standard/src/ap/ctrl_iface_ap.c index 00e15b28433ddbf469e4b080d5c4dcef4f74a581..b32f31a28a58ddcfd909fb575cd61d50a306fadb 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ctrl_iface_ap.c +++ b/wpa_supplicant-2.9_standard/src/ap/ctrl_iface_ap.c @@ -24,6 +24,7 @@ #include "ap_drv_ops.h" #include "mbo_ap.h" #include "taxonomy.h" +#include "wnm_ap.h" static size_t hostapd_write_ht_mcs_bitmask(char *buf, size_t buflen, @@ -98,7 +99,7 @@ static int hostapd_get_sta_info(struct hostapd_data *hapd, len += ret; ret = os_snprintf(buf + len, buflen - len, "rx_rate_info=%lu", - data.current_rx_rate); + data.current_rx_rate / 100); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; @@ -130,7 +131,7 @@ static int hostapd_get_sta_info(struct hostapd_data *hapd, len += ret; ret = os_snprintf(buf + len, buflen - len, "tx_rate_info=%lu", - data.current_tx_rate); + data.current_tx_rate / 100); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; @@ -205,9 +206,29 @@ static const char * timeout_next_str(int val) return "REMOVE"; case STA_DISASSOC_FROM_CLI: return "DISASSOC_FROM_CLI"; + default: + return "?"; } +} + - return "?"; +static const char * hw_mode_str(enum hostapd_hw_mode mode) +{ + switch (mode) { + case HOSTAPD_MODE_IEEE80211B: + return "b"; + case HOSTAPD_MODE_IEEE80211G: + return "g"; + case HOSTAPD_MODE_IEEE80211A: + return "a"; + case HOSTAPD_MODE_IEEE80211AD: + return "ad"; + case HOSTAPD_MODE_IEEE80211ANY: + return "any"; + case NUM_HOSTAPD_MODES: + return "invalid"; + } + return "unknown"; } @@ -217,6 +238,7 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, { int len, res, ret, i; const char *keyid; + const u8 *dpp_pkhash; if (!sta) return 0; @@ -255,6 +277,14 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, return len; len += ret; + if (sta->max_idle_period) { + ret = os_snprintf(buf + len, buflen - len, + "max_idle_period=%d\n", sta->max_idle_period); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len); if (res >= 0) len += res; @@ -326,11 +356,15 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, if (sta->supp_op_classes && buflen - len > (unsigned) (17 + 2 * sta->supp_op_classes[0])) { - len += os_snprintf(buf + len, buflen - len, "supp_op_classes="); + res = os_snprintf(buf + len, buflen - len, "supp_op_classes="); + if (!os_snprintf_error(buflen - len, res)) + len += res; len += wpa_snprintf_hex(buf + len, buflen - len, sta->supp_op_classes + 1, sta->supp_op_classes[0]); - len += os_snprintf(buf + len, buflen - len, "\n"); + res = os_snprintf(buf + len, buflen - len, "\n"); + if (!os_snprintf_error(buflen - len, res)) + len += res; } if (sta->power_capab) { @@ -342,6 +376,34 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, len += ret; } +#ifdef CONFIG_IEEE80211AX + if ((sta->flags & WLAN_STA_HE) && sta->he_capab) { + res = os_snprintf(buf + len, buflen - len, "he_capab="); + if (!os_snprintf_error(buflen - len, res)) + len += res; + len += wpa_snprintf_hex(buf + len, buflen - len, + (const u8 *) sta->he_capab, + sta->he_capab_len); + res = os_snprintf(buf + len, buflen - len, "\n"); + if (!os_snprintf_error(buflen - len, res)) + len += res; + } +#endif /* CONFIG_IEEE80211AX */ + +#ifdef CONFIG_IEEE80211BE + if ((sta->flags & WLAN_STA_EHT) && sta->eht_capab) { + res = os_snprintf(buf + len, buflen - len, "eht_capab="); + if (!os_snprintf_error(buflen - len, res)) + len += res; + len += wpa_snprintf_hex(buf + len, buflen - len, + (const u8 *) sta->eht_capab, + sta->eht_capab_len); + res = os_snprintf(buf + len, buflen - len, "\n"); + if (!os_snprintf_error(buflen - len, res)) + len += res; + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211AC if ((sta->flags & WLAN_STA_VHT) && sta->vht_capabilities) { res = os_snprintf(buf + len, buflen - len, @@ -350,6 +412,16 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, vht_capabilities_info)); if (!os_snprintf_error(buflen - len, res)) len += res; + + res = os_snprintf(buf + len, buflen - len, "vht_capab="); + if (!os_snprintf_error(buflen - len, res)) + len += res; + len += wpa_snprintf_hex(buf + len, buflen - len, + (const u8 *) sta->vht_capabilities, + sizeof(*sta->vht_capabilities)); + res = os_snprintf(buf + len, buflen - len, "\n"); + if (!os_snprintf_error(buflen - len, res)) + len += res; } #endif /* CONFIG_IEEE80211AC */ @@ -364,11 +436,15 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, if (sta->ext_capability && buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) { - len += os_snprintf(buf + len, buflen - len, "ext_capab="); + res = os_snprintf(buf + len, buflen - len, "ext_capab="); + if (!os_snprintf_error(buflen - len, res)) + len += res; len += wpa_snprintf_hex(buf + len, buflen - len, sta->ext_capability + 1, sta->ext_capability[0]); - len += os_snprintf(buf + len, buflen - len, "\n"); + res = os_snprintf(buf + len, buflen - len, "\n"); + if (!os_snprintf_error(buflen - len, res)) + len += res; } if (sta->flags & WLAN_STA_WDS && sta->ifname_wds) { @@ -385,6 +461,33 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, len += ret; } + dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta); + if (dpp_pkhash) { + ret = os_snprintf(buf + len, buflen - len, "dpp_pkhash="); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + len += wpa_snprintf_hex(buf + len, buflen - len, dpp_pkhash, + SHA256_MAC_LEN); + ret = os_snprintf(buf + len, buflen - len, "\n"); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + +#ifdef CONFIG_IEEE80211BE + if (sta->mld_info.mld_sta) { + for (i = 0; i < MAX_NUM_MLD_LINKS; ++i) { + if (!sta->mld_info.links[i].valid) + continue; + ret = os_snprintf( + buf + len, buflen - len, + "peer_addr[%d]=" MACSTR "\n", + i, MAC2STR(sta->mld_info.links[i].peer_addr)); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + } +#endif /* CONFIG_IEEE80211BE */ + return len; } @@ -686,6 +789,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, { struct hostapd_iface *iface = hapd->iface; struct hostapd_hw_modes *mode = iface->current_mode; + struct hostapd_config *iconf = hapd->iconf; int len = 0, ret, j; size_t i; @@ -720,6 +824,24 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, return len; len += ret; + if (mode) { + ret = os_snprintf(buf + len, buflen - len, "hw_mode=%s\n", + hw_mode_str(mode->mode)); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + + if (iconf->country[0] && iconf->country[1]) { + ret = os_snprintf(buf + len, buflen - len, + "country_code=%c%c\ncountry3=0x%X\n", + iconf->country[0], iconf->country[1], + iconf->country[2]); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + if (!iface->cac_started || !iface->dfs_cac_ms) { ret = os_snprintf(buf + len, buflen - len, "cac_time_seconds=%d\n" @@ -728,15 +850,15 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, } else { /* CAC started and CAC time set - calculate remaining time */ struct os_reltime now; - unsigned int left_time; + long left_time; os_reltime_age(&iface->dfs_cac_start, &now); - left_time = iface->dfs_cac_ms / 1000 - now.sec; + left_time = (long) iface->dfs_cac_ms / 1000 - now.sec; ret = os_snprintf(buf + len, buflen - len, "cac_time_seconds=%u\n" - "cac_time_left_seconds=%u\n", + "cac_time_left_seconds=%lu\n", iface->dfs_cac_ms / 1000, - left_time); + left_time > 0 ? left_time : 0); } if (os_snprintf_error(buflen - len, ret)) return len; @@ -750,6 +872,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, "ieee80211n=%d\n" "ieee80211ac=%d\n" "ieee80211ax=%d\n" + "ieee80211be=%d\n" "beacon_int=%u\n" "dtim_period=%d\n", iface->conf->channel, @@ -762,12 +885,74 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, !hapd->conf->disable_11ac, iface->conf->ieee80211ax && !hapd->conf->disable_11ax, + iface->conf->ieee80211be && + !hapd->conf->disable_11be, iface->conf->beacon_int, hapd->conf->dtim_period); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; +#ifdef CONFIG_IEEE80211BE + if (iface->conf->ieee80211be && !hapd->conf->disable_11be) { + ret = os_snprintf(buf + len, buflen - len, + "eht_oper_chwidth=%d\n" + "eht_oper_centr_freq_seg0_idx=%d\n", + iface->conf->eht_oper_chwidth, + iface->conf->eht_oper_centr_freq_seg0_idx); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + if (is_6ghz_op_class(iface->conf->op_class) && + hostapd_get_oper_chwidth(iface->conf) == + CONF_OPER_CHWIDTH_320MHZ) { + ret = os_snprintf(buf + len, buflen - len, + "eht_bw320_offset=%d\n", + iface->conf->eht_bw320_offset); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + + if (hapd->conf->mld_ap) { + struct hostapd_data *link_bss; + + ret = os_snprintf(buf + len, buflen - len, + "num_links=%d\n", + hapd->mld->num_links); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + /* Self BSS */ + ret = os_snprintf(buf + len, buflen - len, + "link_id=%d\n" + "link_addr=" MACSTR "\n", + hapd->mld_link_id, + MAC2STR(hapd->own_addr)); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + /* Partner BSSs */ + for_each_mld_link(link_bss, hapd) { + if (link_bss == hapd) + continue; + + ret = os_snprintf(buf + len, buflen - len, + "partner_link[%d]=" MACSTR + "\n", + link_bss->mld_link_id, + MAC2STR(link_bss->own_addr)); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + } + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211AX if (iface->conf->ieee80211ax && !hapd->conf->disable_11ax) { ret = os_snprintf(buf + len, buflen - len, @@ -780,6 +965,16 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, if (os_snprintf_error(buflen - len, ret)) return len; len += ret; + + if (!iconf->he_op.he_bss_color_disabled && + iconf->he_op.he_bss_color) { + ret = os_snprintf(buf + len, buflen - len, + "he_bss_color=%d\n", + iconf->he_op.he_bss_color); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } } #endif /* CONFIG_IEEE80211AX */ @@ -873,6 +1068,21 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, if (os_snprintf_error(buflen - len, ret)) return len; len += ret; + +#ifdef CONFIG_IEEE80211BE + if (bss->conf->mld_ap) { + ret = os_snprintf(buf + len, buflen - len, + "mld_addr[%d]=" MACSTR "\n" + "mld_id[%d]=%d\n" + "mld_link_id[%d]=%d\n", + (int) i, MAC2STR(bss->mld->mld_addr), + (int) i, hostapd_get_mld_id(bss), + (int) i, bss->mld_link_id); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } +#endif /* CONFIG_IEEE80211BE */ } if (hapd->conf->chan_util_avg_period) { @@ -915,15 +1125,27 @@ int hostapd_parse_csa_settings(const char *pos, } \ } while (0) +#define SET_CSA_SETTING_EXT(str) \ + do { \ + const char *pos2 = os_strstr(pos, " " #str "="); \ + if (pos2) { \ + pos2 += sizeof(" " #str "=") - 1; \ + settings->str = atoi(pos2); \ + } \ + } while (0) + SET_CSA_SETTING(center_freq1); SET_CSA_SETTING(center_freq2); SET_CSA_SETTING(bandwidth); SET_CSA_SETTING(sec_channel_offset); + SET_CSA_SETTING_EXT(punct_bitmap); settings->freq_params.ht_enabled = !!os_strstr(pos, " ht"); settings->freq_params.vht_enabled = !!os_strstr(pos, " vht"); settings->freq_params.he_enabled = !!os_strstr(pos, " he"); + settings->freq_params.eht_enabled = !!os_strstr(pos, " eht"); settings->block_tx = !!os_strstr(pos, " blocktx"); #undef SET_CSA_SETTING +#undef SET_CSA_SETTING_EXT return 0; } @@ -992,7 +1214,7 @@ int hostapd_ctrl_iface_pmksa_add(struct hostapd_data *hapd, char *cmd) return -1; return wpa_auth_pmksa_add2(hapd->wpa_auth, spa, pmk, pmk_len, - pmkid, expiration, akmp); + pmkid, expiration, akmp, NULL); } @@ -1052,3 +1274,353 @@ void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd) #endif /* CONFIG_MESH */ #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ + + +#ifdef CONFIG_WNM_AP + +int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + int disassoc_timer; + struct sta_info *sta; + + if (hwaddr_aton(cmd, addr)) + return -1; + if (cmd[17] != ' ') + return -1; + disassoc_timer = atoi(cmd + 17); + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR_SEC + " not found for disassociation imminent message", + MAC2STR_SEC(addr)); + return -1; + } + + return wnm_send_disassoc_imminent(hapd, sta, disassoc_timer); +} + + +int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + const char *url, *timerstr; + int disassoc_timer; + struct sta_info *sta; + + if (hwaddr_aton(cmd, addr)) + return -1; + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR_SEC + " not found for ESS disassociation imminent message", + MAC2STR_SEC(addr)); + return -1; + } + + timerstr = cmd + 17; + if (*timerstr != ' ') + return -1; + timerstr++; + disassoc_timer = atoi(timerstr); + if (disassoc_timer < 0 || disassoc_timer > 65535) + return -1; + + url = os_strchr(timerstr, ' '); + if (url == NULL) + return -1; + url++; + + return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer); +} + + +int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + const char *pos, *end; + int disassoc_timer = 0; + struct sta_info *sta; + u8 req_mode = 0, valid_int = 0x01, dialog_token = 0x01; + u8 bss_term_dur[12]; + char *url = NULL; + int ret; + u8 nei_rep[1000]; + int nei_len; + u8 mbo[10]; + size_t mbo_len = 0; + + if (hwaddr_aton(cmd, addr)) { + wpa_printf(MSG_DEBUG, "Invalid STA MAC address"); + return -1; + } + + sta = ap_get_sta(hapd, addr); + if (sta == NULL) { + wpa_printf(MSG_DEBUG, "Station " MACSTR_SEC + " not found for BSS TM Request message", + MAC2STR_SEC(addr)); + return -1; + } + + pos = os_strstr(cmd, " disassoc_timer="); + if (pos) { + pos += 16; + disassoc_timer = atoi(pos); + if (disassoc_timer < 0 || disassoc_timer > 65535) { + wpa_printf(MSG_DEBUG, "Invalid disassoc_timer"); + return -1; + } + } + + pos = os_strstr(cmd, " valid_int="); + if (pos) { + pos += 11; + valid_int = atoi(pos); + } + + pos = os_strstr(cmd, " dialog_token="); + if (pos) { + pos += 14; + dialog_token = atoi(pos); + } + + pos = os_strstr(cmd, " bss_term="); + if (pos) { + pos += 10; + req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED; + /* TODO: TSF configurable/learnable */ + bss_term_dur[0] = 4; /* Subelement ID */ + bss_term_dur[1] = 10; /* Length */ + os_memset(&bss_term_dur[2], 0, 8); + end = os_strchr(pos, ','); + if (end == NULL) { + wpa_printf(MSG_DEBUG, "Invalid bss_term data"); + return -1; + } + end++; + WPA_PUT_LE16(&bss_term_dur[10], atoi(end)); + } + + nei_len = ieee802_11_parse_candidate_list(cmd, nei_rep, + sizeof(nei_rep)); + if (nei_len < 0) + return -1; + + pos = os_strstr(cmd, " url="); + if (pos) { + size_t len; + pos += 5; + end = os_strchr(pos, ' '); + if (end) + len = end - pos; + else + len = os_strlen(pos); + url = os_malloc(len + 1); + if (url == NULL) + return -1; + os_memcpy(url, pos, len); + url[len] = '\0'; + req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; + } + + if (os_strstr(cmd, " pref=1")) + req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; + if (os_strstr(cmd, " abridged=1")) + req_mode |= WNM_BSS_TM_REQ_ABRIDGED; + if (os_strstr(cmd, " disassoc_imminent=1")) + req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT; + if (os_strstr(cmd, " link_removal_imminent=1")) + req_mode |= WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT; + +#ifdef CONFIG_MBO + pos = os_strstr(cmd, "mbo="); + if (pos) { + unsigned int mbo_reason, cell_pref, reassoc_delay; + u8 *mbo_pos = mbo; + + ret = sscanf(pos, "mbo=%u:%u:%u", &mbo_reason, + &reassoc_delay, &cell_pref); + if (ret != 3) { + wpa_printf(MSG_DEBUG, + "MBO requires three arguments: mbo=::"); + ret = -1; + goto fail; + } + + if (mbo_reason > MBO_TRANSITION_REASON_PREMIUM_AP) { + wpa_printf(MSG_DEBUG, + "Invalid MBO transition reason code %u", + mbo_reason); + ret = -1; + goto fail; + } + + /* Valid values for Cellular preference are: 0, 1, 255 */ + if (cell_pref != 0 && cell_pref != 1 && cell_pref != 255) { + wpa_printf(MSG_DEBUG, + "Invalid MBO cellular capability %u", + cell_pref); + ret = -1; + goto fail; + } + + if (reassoc_delay > 65535 || + (reassoc_delay && + !(req_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT))) { + wpa_printf(MSG_DEBUG, + "MBO: Assoc retry delay is only valid in disassoc imminent mode"); + ret = -1; + goto fail; + } + + *mbo_pos++ = MBO_ATTR_ID_TRANSITION_REASON; + *mbo_pos++ = 1; + *mbo_pos++ = mbo_reason; + *mbo_pos++ = MBO_ATTR_ID_CELL_DATA_PREF; + *mbo_pos++ = 1; + *mbo_pos++ = cell_pref; + + if (reassoc_delay) { + *mbo_pos++ = MBO_ATTR_ID_ASSOC_RETRY_DELAY; + *mbo_pos++ = 2; + WPA_PUT_LE16(mbo_pos, reassoc_delay); + mbo_pos += 2; + } + + mbo_len = mbo_pos - mbo; + } +#endif /* CONFIG_MBO */ + + ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer, + valid_int, bss_term_dur, dialog_token, url, + nei_len ? nei_rep : NULL, nei_len, + mbo_len ? mbo : NULL, mbo_len); +#ifdef CONFIG_MBO +fail: +#endif /* CONFIG_MBO */ + os_free(url); + return ret; +} + +#endif /* CONFIG_WNM_AP */ + + +int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num, + const char *txtaddr) +{ + u8 addr[ETH_ALEN]; + struct vlan_description vlan_id; + + if (!(*num)) + return 0; + + if (hwaddr_aton(txtaddr, addr)) + return -1; + + if (hostapd_maclist_found(*acl, *num, addr, &vlan_id)) + hostapd_remove_acl_mac(acl, num, addr); + + return 0; +} + + +void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl, + int *num) +{ + while (*num) + hostapd_remove_acl_mac(acl, num, (*acl)[0].addr); +} + + +int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num, + char *buf, size_t buflen) +{ + int i = 0, len = 0, ret = 0; + + if (!acl) + return 0; + + while (i < num) { + ret = os_snprintf(buf + len, buflen - len, + MACSTR " VLAN_ID=%d\n", + MAC2STR(acl[i].addr), + acl[i].vlan_id.untagged); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + i++; + len += ret; + } + return len; +} + + +int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num, + const char *cmd) +{ + u8 addr[ETH_ALEN]; + struct vlan_description vlan_id; + int ret = 0, vlanid = 0; + const char *pos; + + if (hwaddr_aton(cmd, addr)) + return -1; + + pos = os_strstr(cmd, "VLAN_ID="); + if (pos) + vlanid = atoi(pos + 8); + + if (!hostapd_maclist_found(*acl, *num, addr, &vlan_id)) { + ret = hostapd_add_acl_maclist(acl, num, vlanid, addr); + if (ret != -1 && *acl) + qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp); + } + + return ret < 0 ? -1 : 0; +} + + +int hostapd_disassoc_accept_mac(struct hostapd_data *hapd) +{ + struct sta_info *sta; + struct vlan_description vlan_id; + + if (hapd->conf->macaddr_acl != DENY_UNLESS_ACCEPTED) + return 0; + + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (!hostapd_maclist_found(hapd->conf->accept_mac, + hapd->conf->num_accept_mac, + sta->addr, &vlan_id) || + (vlan_id.notempty && + vlan_compare(&vlan_id, sta->vlan_desc))) + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_UNSPECIFIED); + } + + return 0; +} + + +int hostapd_disassoc_deny_mac(struct hostapd_data *hapd) +{ + struct sta_info *sta; + struct vlan_description vlan_id; + + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (hostapd_maclist_found(hapd->conf->deny_mac, + hapd->conf->num_deny_mac, sta->addr, + &vlan_id) && + (!vlan_id.notempty || + !vlan_compare(&vlan_id, sta->vlan_desc))) + ap_sta_disconnect(hapd, sta, sta->addr, + WLAN_REASON_UNSPECIFIED); + } + + return 0; +} diff --git a/wpa_supplicant-2.9_standard/src/ap/ctrl_iface_ap.h b/wpa_supplicant-2.9_standard/src/ap/ctrl_iface_ap.h index d1dcebfb957df1e839030d2fc1aadbbf749d19e9..614f0426c1a563168bd1e44e49a20c650035a26c 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ctrl_iface_ap.h +++ b/wpa_supplicant-2.9_standard/src/ap/ctrl_iface_ap.h @@ -37,4 +37,21 @@ int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd, const u8 *addr, char *buf, size_t len); void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd); +int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd, + const char *cmd); +int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd, + const char *cmd); +int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, + const char *cmd); +int hostapd_ctrl_iface_acl_add_mac(struct mac_acl_entry **acl, int *num, + const char *cmd); +int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num, + const char *txtaddr); +void hostapd_ctrl_iface_acl_clear_list(struct mac_acl_entry **acl, + int *num); +int hostapd_ctrl_iface_acl_show_mac(struct mac_acl_entry *acl, int num, + char *buf, size_t buflen); +int hostapd_disassoc_accept_mac(struct hostapd_data *hapd); +int hostapd_disassoc_deny_mac(struct hostapd_data *hapd); + #endif /* CTRL_IFACE_AP_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/dfs.c b/wpa_supplicant-2.9_standard/src/ap/dfs.c index e096990c11dbcd969495f86fb100e34369ae44e9..4407f9c134dcb13f08eae3edbdc95511fc5fe7a1 100644 --- a/wpa_supplicant-2.9_standard/src/ap/dfs.c +++ b/wpa_supplicant-2.9_standard/src/ap/dfs.c @@ -14,11 +14,32 @@ #include "common/hw_features_common.h" #include "common/wpa_ctrl.h" #include "hostapd.h" +#include "beacon.h" #include "ap_drv_ops.h" #include "drivers/driver.h" #include "dfs.h" +enum dfs_channel_type { + DFS_ANY_CHANNEL, + DFS_AVAILABLE, /* non-radar or radar-available */ + DFS_NO_CAC_YET, /* radar-not-yet-available */ +}; + +static struct hostapd_channel_data * +dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel, + u8 *oper_centr_freq_seg0_idx, + u8 *oper_centr_freq_seg1_idx, + enum dfs_channel_type *channel_type); + + +static bool dfs_use_radar_background(struct hostapd_iface *iface) +{ + return (iface->drv_flags2 & WPA_DRIVER_FLAGS2_RADAR_BACKGROUND) && + iface->conf->enable_background_radar; +} + + static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) { int n_chans = 1; @@ -30,12 +51,12 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { switch (hostapd_get_oper_chwidth(iface->conf)) { - case CHANWIDTH_USE_HT: + case CONF_OPER_CHWIDTH_USE_HT: break; - case CHANWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: n_chans = 4; break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: #ifdef CONFIG_P2P_160M /*only need to check CH36,40,44,48 the 4 channels for P2P 160M*/ n_chans = 4; @@ -43,7 +64,7 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) n_chans = 8; #endif break; - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: n_chans = 4; *seg1 = 4; break; @@ -56,15 +77,27 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) } +/* dfs_channel_available: select new channel according to type parameter */ static int dfs_channel_available(struct hostapd_channel_data *chan, - int skip_radar) + enum dfs_channel_type type) { + if (type == DFS_NO_CAC_YET) { + /* Select only radar channel where CAC has not been + * performed yet + */ + if ((chan->flag & HOSTAPD_CHAN_RADAR) && + (chan->flag & HOSTAPD_CHAN_DFS_MASK) == + HOSTAPD_CHAN_DFS_USABLE) + return 1; + return 0; + } + /* * When radar detection happens, CSA is performed. However, there's no * time for CAC, so radar channels must be skipped when finding a new * channel for CSA, unless they are available for immediate use. */ - if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) && + if (type == DFS_AVAILABLE && (chan->flag & HOSTAPD_CHAN_RADAR) && ((chan->flag & HOSTAPD_CHAN_DFS_MASK) != HOSTAPD_CHAN_DFS_AVAILABLE)) return 0; @@ -143,7 +176,7 @@ dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx) static int dfs_chan_range_available(struct hostapd_hw_modes *mode, int first_chan_idx, int num_chans, - int skip_radar) + enum dfs_channel_type type) { struct hostapd_channel_data *first_chan, *chan; int i; @@ -161,7 +194,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode, * If it's not allowed to use the first channel as primary, decline the * whole channel range. */ if (!chan_pri_allowed(first_chan)) { - wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed"); + wpa_printf(MSG_DEBUG, "DFS: primary channel not allowed"); return 0; } @@ -182,7 +215,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode, return 0; } - if (!dfs_channel_available(chan, skip_radar)) { + if (!dfs_channel_available(chan, type)) { wpa_printf(MSG_DEBUG, "DFS: channel not available %d", first_chan->freq + i * 20); return 0; @@ -212,7 +245,7 @@ static int is_in_chanlist(struct hostapd_iface *iface, */ static int dfs_find_channel(struct hostapd_iface *iface, struct hostapd_channel_data **ret_chan, - int idx, int skip_radar) + int idx, enum dfs_channel_type type) { struct hostapd_hw_modes *mode; struct hostapd_channel_data *chan; @@ -237,7 +270,7 @@ static int dfs_find_channel(struct hostapd_iface *iface, } /* Skip incompatible chandefs */ - if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) { + if (!dfs_chan_range_available(mode, i, n_chans, type)) { wpa_printf(MSG_DEBUG, "DFS: range not available for %d (%d)", chan->freq, chan->chan); @@ -254,6 +287,10 @@ static int dfs_find_channel(struct hostapd_iface *iface, if (chan->max_tx_power < iface->conf->min_tx_power) continue; + if ((chan->flag & HOSTAPD_CHAN_INDOOR_ONLY) && + iface->conf->country[2] == 0x4f) + continue; + if (ret_chan && idx == channel_idx) { wpa_printf(MSG_DEBUG, "Selected channel %d (%d)", chan->freq, chan->chan); @@ -284,7 +321,7 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface, *oper_centr_freq_seg1_idx = 0; switch (hostapd_get_oper_chwidth(iface->conf)) { - case CHANWIDTH_USE_HT: + case CONF_OPER_CHWIDTH_USE_HT: if (secondary_channel == 1) *oper_centr_freq_seg0_idx = chan->chan + 2; else if (secondary_channel == -1) @@ -292,13 +329,13 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface, else *oper_centr_freq_seg0_idx = chan->chan; break; - case CHANWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: *oper_centr_freq_seg0_idx = chan->chan + 6; break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: *oper_centr_freq_seg0_idx = chan->chan + 14; break; - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: *oper_centr_freq_seg0_idx = chan->chan + 6; *oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6; break; @@ -331,28 +368,33 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start) if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) channel_no -= 4; - /* VHT/HE */ - if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { + /* VHT/HE/EHT */ + if (iface->conf->ieee80211ac || iface->conf->ieee80211ax || + iface->conf->ieee80211be) { switch (hostapd_get_oper_chwidth(iface->conf)) { - case CHANWIDTH_USE_HT: + case CONF_OPER_CHWIDTH_USE_HT: break; - case CHANWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: channel_no = hostapd_get_oper_centr_freq_seg0_idx( iface->conf) - 6; break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: channel_no = hostapd_get_oper_centr_freq_seg0_idx( iface->conf) - 14; break; - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: channel_no = hostapd_get_oper_centr_freq_seg0_idx( iface->conf) - 6; chan_seg1 = hostapd_get_oper_centr_freq_seg1_idx( iface->conf) - 6; break; + case CONF_OPER_CHWIDTH_320MHZ: + channel_no = hostapd_get_oper_centr_freq_seg0_idx( + iface->conf) - 30; + break; default: wpa_printf(MSG_INFO, - "DFS only VHT20/40/80/160/80+80 is supported now"); + "DFS only EHT20/40/80/160/80+80/320 is supported now"); channel_no = -1; break; } @@ -414,6 +456,8 @@ static int dfs_check_chans_radar(struct hostapd_iface *iface, mode = iface->current_mode; for (i = 0; i < n_chans; i++) { + if (start_chan_idx + i >= mode->num_channels) + break; channel = &mode->channels[start_chan_idx + i]; if (channel->flag & HOSTAPD_CHAN_RADAR) res++; @@ -480,7 +524,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface, int *secondary_channel, u8 *oper_centr_freq_seg0_idx, u8 *oper_centr_freq_seg1_idx, - int skip_radar) + enum dfs_channel_type type) { struct hostapd_hw_modes *mode; struct hostapd_channel_data *chan = NULL; @@ -504,7 +548,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface, return NULL; /* Get the count first */ - num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); + num_available_chandefs = dfs_find_channel(iface, NULL, 0, type); wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d", num_available_chandefs); if (num_available_chandefs == 0) @@ -513,7 +557,9 @@ dfs_get_valid_channel(struct hostapd_iface *iface, if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0) return NULL; chan_idx = _rand % num_available_chandefs; - dfs_find_channel(iface, &chan, chan_idx, skip_radar); + wpa_printf(MSG_DEBUG, "DFS: Picked random entry from the list: %d/%d", + chan_idx, num_available_chandefs); + dfs_find_channel(iface, &chan, chan_idx, type); if (!chan) { wpa_printf(MSG_DEBUG, "DFS: no random channel found"); return NULL; @@ -528,7 +574,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface, *secondary_channel = 0; /* Get secondary channel for HT80P80 */ - if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) { + if (hostapd_get_oper_chwidth(iface->conf) == + CONF_OPER_CHWIDTH_80P80MHZ) { if (num_available_chandefs <= 1) { wpa_printf(MSG_ERROR, "only 1 valid chan, can't support 80+80"); @@ -542,7 +589,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface, for (i = 0; i < num_available_chandefs - 1; i++) { /* start from chan_idx + 1, end when chan_idx - 1 */ chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs; - dfs_find_channel(iface, &chan2, chan_idx2, skip_radar); + dfs_find_channel(iface, &chan2, chan_idx2, type); if (chan2 && abs(chan2->chan - chan->chan) > 12) { /* two channels are not adjacent */ sec_chan_idx_80p80 = chan2->chan; @@ -573,6 +620,30 @@ dfs_get_valid_channel(struct hostapd_iface *iface, } +static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar) +{ + struct hostapd_channel_data *channel; + u8 cf1 = 0, cf2 = 0; + int sec = 0; + + channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, + skip_radar ? DFS_AVAILABLE : + DFS_ANY_CHANNEL); + if (!channel) { + wpa_printf(MSG_ERROR, "could not get valid channel"); + return -1; + } + + iface->freq = channel->freq; + iface->conf->channel = channel->chan; + iface->conf->secondary_channel = sec; + hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1); + hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2); + + return 0; +} + + static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state) { struct hostapd_hw_modes *mode; @@ -741,6 +812,8 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface, mode = iface->current_mode; for (i = 0; i < n_chans; i++) { + if (start_chan_idx + i >= mode->num_channels) + break; channel = &mode->channels[start_chan_idx + i]; if (!(channel->flag & HOSTAPD_CHAN_RADAR)) continue; @@ -760,7 +833,6 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface, */ int hostapd_handle_dfs(struct hostapd_iface *iface) { - struct hostapd_channel_data *channel; int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1; int skip_radar = 0; @@ -815,28 +887,17 @@ int hostapd_handle_dfs(struct hostapd_iface *iface) wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", res, res ? "yes": "no"); if (res) { - int sec = 0; - u8 cf1 = 0, cf2 = 0; - - channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, - skip_radar); - if (!channel) { - wpa_printf(MSG_ERROR, "could not get valid channel"); + if (dfs_set_valid_channel(iface, skip_radar) < 0) { hostapd_set_state(iface, HAPD_IFACE_DFS); return 0; } - - iface->freq = channel->freq; - iface->conf->channel = channel->chan; - iface->conf->secondary_channel = sec; - hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1); - hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2); } } while (res); /* Finally start CAC */ hostapd_set_state(iface, HAPD_IFACE_DFS); - wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); + wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz%s", iface->freq, + dfs_use_radar_background(iface) ? " (background)" : ""); wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds", iface->freq, @@ -849,17 +910,41 @@ int hostapd_handle_dfs(struct hostapd_iface *iface) res = hostapd_start_dfs_cac( iface, iface->conf->hw_mode, iface->freq, iface->conf->channel, iface->conf->ieee80211n, iface->conf->ieee80211ac, - iface->conf->ieee80211ax, + iface->conf->ieee80211ax, iface->conf->ieee80211be, iface->conf->secondary_channel, hostapd_get_oper_chwidth(iface->conf), hostapd_get_oper_centr_freq_seg0_idx(iface->conf), - hostapd_get_oper_centr_freq_seg1_idx(iface->conf)); + hostapd_get_oper_centr_freq_seg1_idx(iface->conf), + dfs_use_radar_background(iface)); if (res) { wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res); return -1; } + if (dfs_use_radar_background(iface)) { + /* Cache background radar parameters. */ + iface->radar_background.channel = iface->conf->channel; + iface->radar_background.secondary_channel = + iface->conf->secondary_channel; + iface->radar_background.freq = iface->freq; + iface->radar_background.centr_freq_seg0_idx = + hostapd_get_oper_centr_freq_seg0_idx(iface->conf); + iface->radar_background.centr_freq_seg1_idx = + hostapd_get_oper_centr_freq_seg1_idx(iface->conf); + + /* + * Let's select a random channel according to the + * regulations and perform CAC on dedicated radar chain. + */ + res = dfs_set_valid_channel(iface, 1); + if (res < 0) + return res; + + iface->radar_background.temp_ch = 1; + return 1; + } + return 0; } @@ -881,19 +966,206 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface) } +static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface, + int channel, int freq, + int secondary_channel, + u8 current_vht_oper_chwidth, + u8 oper_centr_freq_seg0_idx, + u8 oper_centr_freq_seg1_idx) +{ + struct hostapd_hw_modes *cmode = iface->current_mode; + int ieee80211_mode = IEEE80211_MODE_AP, err; + struct csa_settings csa_settings; + u8 new_vht_oper_chwidth; + unsigned int i; + unsigned int num_err = 0; + + wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel); + wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL + "freq=%d chan=%d sec_chan=%d", freq, channel, + secondary_channel); + + new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); + hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth); + + /* Setup CSA request */ + os_memset(&csa_settings, 0, sizeof(csa_settings)); + csa_settings.cs_count = 5; + csa_settings.block_tx = 1; + csa_settings.link_id = -1; +#ifdef CONFIG_IEEE80211BE + if (iface->bss[0]->conf->mld_ap) + csa_settings.link_id = iface->bss[0]->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ +#ifdef CONFIG_MESH + if (iface->mconf) + ieee80211_mode = IEEE80211_MODE_MESH; +#endif /* CONFIG_MESH */ + err = hostapd_set_freq_params(&csa_settings.freq_params, + iface->conf->hw_mode, + freq, channel, + iface->conf->enable_edmg, + iface->conf->edmg_channel, + iface->conf->ieee80211n, + iface->conf->ieee80211ac, + iface->conf->ieee80211ax, + iface->conf->ieee80211be, + secondary_channel, + new_vht_oper_chwidth, + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx, + cmode->vht_capab, + &cmode->he_capab[ieee80211_mode], + &cmode->eht_capab[ieee80211_mode], + hostapd_get_punct_bitmap(iface->bss[0])); + + if (err) { + wpa_printf(MSG_ERROR, + "DFS failed to calculate CSA freq params"); + hostapd_disable_iface(iface); + return err; + } + + for (i = 0; i < iface->num_bss; i++) { + err = hostapd_switch_channel(iface->bss[i], &csa_settings); + if (err) + num_err++; + } + + if (num_err == iface->num_bss) { + wpa_printf(MSG_WARNING, + "DFS failed to schedule CSA (%d) - trying fallback", + err); + iface->freq = freq; + iface->conf->channel = channel; + iface->conf->secondary_channel = secondary_channel; + hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth); + hostapd_set_oper_centr_freq_seg0_idx(iface->conf, + oper_centr_freq_seg0_idx); + hostapd_set_oper_centr_freq_seg1_idx(iface->conf, + oper_centr_freq_seg1_idx); + + hostapd_disable_iface(iface); + hostapd_enable_iface(iface); + + return 0; + } + + /* Channel configuration will be updated once CSA completes and + * ch_switch_notify event is received */ + wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); + + return 0; +} + + +static void hostapd_dfs_update_background_chain(struct hostapd_iface *iface) +{ + int sec = 0; + enum dfs_channel_type channel_type = DFS_NO_CAC_YET; + struct hostapd_channel_data *channel; + u8 oper_centr_freq_seg0_idx = 0; + u8 oper_centr_freq_seg1_idx = 0; + + /* + * Allow selection of DFS channel in ETSI to comply with + * uniform spreading. + */ + if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI) + channel_type = DFS_ANY_CHANNEL; + + channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx, + &oper_centr_freq_seg1_idx, + channel_type); + if (!channel || + channel->chan == iface->conf->channel || + channel->chan == iface->radar_background.channel) + channel = dfs_downgrade_bandwidth(iface, &sec, + &oper_centr_freq_seg0_idx, + &oper_centr_freq_seg1_idx, + &channel_type); + if (!channel || + hostapd_start_dfs_cac(iface, iface->conf->hw_mode, + channel->freq, channel->chan, + iface->conf->ieee80211n, + iface->conf->ieee80211ac, + iface->conf->ieee80211ax, + iface->conf->ieee80211be, + sec, hostapd_get_oper_chwidth(iface->conf), + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx, true)) { + wpa_printf(MSG_ERROR, "DFS failed to start CAC offchannel"); + iface->radar_background.channel = -1; + return; + } + + iface->radar_background.channel = channel->chan; + iface->radar_background.freq = channel->freq; + iface->radar_background.secondary_channel = sec; + iface->radar_background.centr_freq_seg0_idx = oper_centr_freq_seg0_idx; + iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx; + + wpa_printf(MSG_DEBUG, + "%s: setting background chain to chan %d (%d MHz)", + __func__, channel->chan, channel->freq); +} + + +static bool +hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq) +{ + return dfs_use_radar_background(iface) && + iface->radar_background.channel != -1 && + iface->radar_background.freq == freq; +} + + +static int +hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface) +{ + u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); + + iface->conf->channel = iface->radar_background.channel; + iface->freq = iface->radar_background.freq; + iface->conf->secondary_channel = + iface->radar_background.secondary_channel; + hostapd_set_oper_centr_freq_seg0_idx( + iface->conf, iface->radar_background.centr_freq_seg0_idx); + hostapd_set_oper_centr_freq_seg1_idx( + iface->conf, iface->radar_background.centr_freq_seg1_idx); + + hostapd_dfs_update_background_chain(iface); + + return hostapd_dfs_request_channel_switch( + iface, iface->conf->channel, iface->freq, + iface->conf->secondary_channel, current_vht_oper_chwidth, + hostapd_get_oper_centr_freq_seg0_idx(iface->conf), + hostapd_get_oper_centr_freq_seg1_idx(iface->conf)); +} + + int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2) { wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_COMPLETED - "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", - success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); + "success=%d freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d radar_detected=%d", + success, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, + iface->radar_detected); if (success) { /* Complete iface/ap configuration */ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { - /* Complete AP configuration for the first bring up. */ - if (iface->state != HAPD_IFACE_ENABLED) + /* Complete AP configuration for the first bring up. If + * a radar was detected in this channel, interface setup + * will be handled in + * 1. hostapd_event_ch_switch() if switching to a + * non-DFS channel + * 2. on next CAC complete event if switching to another + * DFS channel. + */ + if (iface->state != HAPD_IFACE_ENABLED && + !iface->radar_detected) hostapd_setup_interface_complete(iface, 0); else iface->cac_started = 0; @@ -901,6 +1173,22 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, HOSTAPD_CHAN_DFS_AVAILABLE); + + /* + * Radar event from background chain for the selected + * channel. Perform CSA, move the main chain to the + * selected channel and configure the background chain + * to a new DFS channel. + */ + if (hostapd_dfs_is_background_event(iface, freq)) { + iface->radar_background.cac_started = 0; + if (!iface->radar_background.temp_ch) + return 0; + + iface->radar_background.temp_ch = 0; + return hostapd_dfs_start_channel_switch_background(iface); + } + /* * Just mark the channel available when CAC completion * event is received in enabled state. CAC result could @@ -917,8 +1205,12 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, iface->cac_started = 0; } } + } else if (hostapd_dfs_is_background_event(iface, freq)) { + iface->radar_background.cac_started = 0; + hostapd_dfs_update_background_chain(iface); } + iface->radar_detected = false; return 0; } @@ -945,7 +1237,8 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq, static struct hostapd_channel_data * dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel, u8 *oper_centr_freq_seg0_idx, - u8 *oper_centr_freq_seg1_idx, int *skip_radar) + u8 *oper_centr_freq_seg1_idx, + enum dfs_channel_type *channel_type) { struct hostapd_channel_data *channel; @@ -953,22 +1246,22 @@ dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel, channel = dfs_get_valid_channel(iface, secondary_channel, oper_centr_freq_seg0_idx, oper_centr_freq_seg1_idx, - *skip_radar); + *channel_type); if (channel) { wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d", channel->chan); return channel; } - if (*skip_radar) { - *skip_radar = 0; + if (*channel_type != DFS_ANY_CHANNEL) { + *channel_type = DFS_ANY_CHANNEL; } else { int oper_chwidth; oper_chwidth = hostapd_get_oper_chwidth(iface->conf); - if (oper_chwidth == CHANWIDTH_USE_HT) + if (oper_chwidth == CONF_OPER_CHWIDTH_USE_HT) break; - *skip_radar = 1; + *channel_type = DFS_AVAILABLE; hostapd_set_oper_chwidth(iface->conf, oper_chwidth - 1); } } @@ -986,7 +1279,7 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) int secondary_channel; u8 oper_centr_freq_seg0_idx = 0; u8 oper_centr_freq_seg1_idx = 0; - int skip_radar = 0; + enum dfs_channel_type channel_type = DFS_ANY_CHANNEL; int err = 1; /* Radar detected during active CAC */ @@ -994,13 +1287,13 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) channel = dfs_get_valid_channel(iface, &secondary_channel, &oper_centr_freq_seg0_idx, &oper_centr_freq_seg1_idx, - skip_radar); + channel_type); if (!channel) { channel = dfs_downgrade_bandwidth(iface, &secondary_channel, &oper_centr_freq_seg0_idx, &oper_centr_freq_seg1_idx, - &skip_radar); + &channel_type); if (!channel) { wpa_printf(MSG_ERROR, "No valid channel available"); return err; @@ -1027,20 +1320,61 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) } +static int +hostapd_dfs_background_start_channel_switch(struct hostapd_iface *iface, + int freq) +{ + if (!dfs_use_radar_background(iface)) + return -1; /* Background radar chain not supported. */ + + wpa_printf(MSG_DEBUG, + "%s called (background CAC active: %s, CSA active: %s)", + __func__, iface->radar_background.cac_started ? "yes" : "no", + hostapd_csa_in_progress(iface) ? "yes" : "no"); + + /* Check if CSA in progress */ + if (hostapd_csa_in_progress(iface)) + return 0; + + if (hostapd_dfs_is_background_event(iface, freq)) { + /* + * Radar pattern is reported on the background chain. + * Just select a new random channel according to the + * regulations for monitoring. + */ + hostapd_dfs_update_background_chain(iface); + return 0; + } + + /* + * If background radar detection is supported and the radar channel + * monitored by the background chain is available switch to it without + * waiting for the CAC. + */ + if (iface->radar_background.channel == -1) + return -1; /* Background radar chain not available. */ + + if (iface->radar_background.cac_started) { + /* + * Background channel not available yet. Perform CAC on the + * main chain. + */ + iface->radar_background.temp_ch = 1; + return -1; + } + + return hostapd_dfs_start_channel_switch_background(iface); +} + + static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) { struct hostapd_channel_data *channel; int secondary_channel; u8 oper_centr_freq_seg0_idx; u8 oper_centr_freq_seg1_idx; - u8 new_vht_oper_chwidth; - int skip_radar = 1; - struct csa_settings csa_settings; - unsigned int i; - int err = 1; - struct hostapd_hw_modes *cmode = iface->current_mode; + enum dfs_channel_type channel_type = DFS_AVAILABLE; u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); - int ieee80211_mode = IEEE80211_MODE_AP; wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", __func__, iface->cac_started ? "yes" : "no", @@ -1059,13 +1393,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) * uniform spreading. */ if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI) - skip_radar = 0; + channel_type = DFS_ANY_CHANNEL; /* Perform channel switch/CSA */ channel = dfs_get_valid_channel(iface, &secondary_channel, &oper_centr_freq_seg0_idx, &oper_centr_freq_seg1_idx, - skip_radar); + channel_type); if (!channel) { /* @@ -1073,11 +1407,11 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) * there is another channel where we can switch even if it * requires to perform a CAC first. */ - skip_radar = 0; + channel_type = DFS_ANY_CHANNEL; channel = dfs_downgrade_bandwidth(iface, &secondary_channel, &oper_centr_freq_seg0_idx, &oper_centr_freq_seg1_idx, - &skip_radar); + &channel_type); if (!channel) { /* * Toggle interface state to enter DFS state @@ -1088,7 +1422,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) return 0; } - if (!skip_radar) { + if (channel_type == DFS_ANY_CHANNEL) { iface->freq = channel->freq; iface->conf->channel = channel->chan; iface->conf->secondary_channel = secondary_channel; @@ -1103,73 +1437,12 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) } } - wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", - channel->chan); - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL - "freq=%d chan=%d sec_chan=%d", channel->freq, - channel->chan, secondary_channel); - - new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); - hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth); - - /* Setup CSA request */ - os_memset(&csa_settings, 0, sizeof(csa_settings)); - csa_settings.cs_count = 5; - csa_settings.block_tx = 1; -#ifdef CONFIG_MESH - if (iface->mconf) - ieee80211_mode = IEEE80211_MODE_MESH; -#endif /* CONFIG_MESH */ - err = hostapd_set_freq_params(&csa_settings.freq_params, - iface->conf->hw_mode, - channel->freq, - channel->chan, - iface->conf->enable_edmg, - iface->conf->edmg_channel, - iface->conf->ieee80211n, - iface->conf->ieee80211ac, - iface->conf->ieee80211ax, - secondary_channel, - new_vht_oper_chwidth, - oper_centr_freq_seg0_idx, - oper_centr_freq_seg1_idx, - cmode->vht_capab, - &cmode->he_capab[ieee80211_mode]); - - if (err) { - wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); - hostapd_disable_iface(iface); - return err; - } - - for (i = 0; i < iface->num_bss; i++) { - err = hostapd_switch_channel(iface->bss[i], &csa_settings); - if (err) - break; - } - - if (err) { - wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", - err); - iface->freq = channel->freq; - iface->conf->channel = channel->chan; - iface->conf->secondary_channel = secondary_channel; - hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth); - hostapd_set_oper_centr_freq_seg0_idx(iface->conf, - oper_centr_freq_seg0_idx); - hostapd_set_oper_centr_freq_seg1_idx(iface->conf, - oper_centr_freq_seg1_idx); - - hostapd_disable_iface(iface); - hostapd_enable_iface(iface); - return 0; - } - - /* Channel configuration will be updated once CSA completes and - * ch_switch_notify event is received */ - - wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); - return 0; + return hostapd_dfs_request_channel_switch(iface, channel->chan, + channel->freq, + secondary_channel, + current_vht_oper_chwidth, + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx); } @@ -1177,12 +1450,12 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2) { - int res; - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", freq, ht_enabled, chan_offset, chan_width, cf1, cf2); + iface->radar_detected = true; + /* Proceed only if DFS is not offloaded to the driver */ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) return 0; @@ -1191,20 +1464,23 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, return 0; /* mark radar frequency as invalid */ - res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, - cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE); - if (!res) + if (!set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, + cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE)) return 0; - /* Skip if reported radar event not overlapped our channels */ - res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); - if (!res) - return 0; + if (!hostapd_dfs_is_background_event(iface, freq)) { + /* Skip if reported radar event not overlapped our channels */ + if (!dfs_are_channels_overlapped(iface, freq, chan_width, + cf1, cf2)) + return 0; + } - /* radar detected while operating, switch the channel. */ - res = hostapd_dfs_start_channel_switch(iface); + if (hostapd_dfs_background_start_channel_switch(iface, freq)) { + /* Radar detected while operating, switch the channel. */ + return hostapd_dfs_start_channel_switch(iface); + } - return res; + return 0; } @@ -1224,9 +1500,14 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); - /* Handle cases where all channels were initially unavailable */ - if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) + if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) { + /* Handle cases where all channels were initially unavailable */ hostapd_handle_dfs(iface); + } else if (dfs_use_radar_background(iface) && + iface->radar_background.channel == -1) { + /* Reset radar background chain if disabled */ + hostapd_dfs_update_background_chain(iface); + } return 0; } @@ -1264,17 +1545,32 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2) { - /* This is called when the driver indicates that an offloaded DFS has - * started CAC. */ - hostapd_set_state(iface, HAPD_IFACE_DFS); + if (hostapd_dfs_is_background_event(iface, freq)) { + iface->radar_background.cac_started = 1; + } else { + /* This is called when the driver indicates that an offloaded + * DFS has started CAC. radar_detected might be set for previous + * DFS channel. Clear it for this new CAC process. */ + hostapd_set_state(iface, HAPD_IFACE_DFS); + iface->cac_started = 1; + + /* Clear radar_detected in case it is for the previous + * frequency. Also remove disabled link's information in RNR + * element from other links. */ + iface->radar_detected = false; + if (iface->interfaces && iface->interfaces->count > 1) + ieee802_11_set_beacons(iface); + } /* TODO: How to check CAC time for ETSI weather channels? */ iface->dfs_cac_ms = 60000; wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START "freq=%d chan=%d chan_offset=%d width=%d seg0=%d " - "seg1=%d cac_time=%ds", + "seg1=%d cac_time=%ds%s", freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, - iface->dfs_cac_ms / 1000); - iface->cac_started = 1; + iface->dfs_cac_ms / 1000, + hostapd_dfs_is_background_event(iface, freq) ? + " (background)" : ""); + os_get_reltime(&iface->dfs_cac_start); return 0; } diff --git a/wpa_supplicant-2.9_standard/src/ap/dpp_hostapd.c b/wpa_supplicant-2.9_standard/src/ap/dpp_hostapd.c index d98e573e8fb2fa5ce548cfce5277abb356e5a8d5..1d30bc5bb95cd4b8939ad79fa46f9368cdbdb664 100644 --- a/wpa_supplicant-2.9_standard/src/ap/dpp_hostapd.c +++ b/wpa_supplicant-2.9_standard/src/ap/dpp_hostapd.c @@ -2,6 +2,7 @@ * hostapd / DPP integration * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -14,11 +15,13 @@ #include "common/dpp.h" #include "common/gas.h" #include "common/wpa_ctrl.h" +#include "crypto/random.h" #include "hostapd.h" #include "ap_drv_ops.h" #include "gas_query_ap.h" #include "gas_serv.h" #include "wpa_auth.h" +#include "beacon.h" #include "dpp_hostapd.h" @@ -28,12 +31,17 @@ static void hostapd_dpp_auth_conf_wait_timeout(void *eloop_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); +static void hostapd_dpp_set_testing_options(struct hostapd_data *hapd, + struct dpp_authentication *auth); +static void hostapd_dpp_start_gas_client(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); +static int hostapd_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 }; @@ -216,6 +224,270 @@ static void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd) } +static int hostapd_dpp_allow_ir(struct hostapd_data *hapd, unsigned int freq) +{ + int i, j; + + if (!hapd->iface->hw_features) + return -1; + + for (i = 0; i < hapd->iface->num_hw_features; i++) { + struct hostapd_hw_modes *mode = &hapd->iface->hw_features[i]; + + for (j = 0; j < mode->num_channels; j++) { + struct hostapd_channel_data *chan = &mode->channels[j]; + + if (chan->freq != (int) freq) + continue; + + if (chan->flag & (HOSTAPD_CHAN_DISABLED | + HOSTAPD_CHAN_NO_IR | + HOSTAPD_CHAN_RADAR)) + continue; + + return 1; + } + } + + wpa_printf(MSG_DEBUG, + "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list", + freq); + + return 0; +} + + +static int hostapd_dpp_pkex_next_channel(struct hostapd_data *hapd, + struct dpp_pkex *pkex) +{ + if (pkex->freq == 2437) + pkex->freq = 5745; + else if (pkex->freq == 5745) + pkex->freq = 5220; + else if (pkex->freq == 5220) + pkex->freq = 60480; + else + return -1; /* no more channels to try */ + + if (hostapd_dpp_allow_ir(hapd, pkex->freq) == 1) { + wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz", + pkex->freq); + return 0; + } + + /* Could not use this channel - try the next one */ + return hostapd_dpp_pkex_next_channel(hapd, pkex); +} + + +static void hostapd_dpp_pkex_clear_code(struct hostapd_data *hapd) +{ + if (!hapd->dpp_pkex_code && !hapd->dpp_pkex_identifier) + return; + + /* Delete PKEX code and identifier on successful completion of + * PKEX. We are not supposed to reuse these without being + * explicitly requested to perform PKEX again. */ + wpa_printf(MSG_DEBUG, "DPP: Delete PKEX code/identifier"); + os_free(hapd->dpp_pkex_code); + hapd->dpp_pkex_code = NULL; + os_free(hapd->dpp_pkex_identifier); + hapd->dpp_pkex_identifier = NULL; +} + + +#ifdef CONFIG_DPP2 +static int hostapd_dpp_pkex_done(void *ctx, void *conn, + struct dpp_bootstrap_info *peer_bi) +{ + struct hostapd_data *hapd = ctx; + char cmd[500]; + const char *pos; + u8 allowed_roles = DPP_CAPAB_CONFIGURATOR; + struct dpp_bootstrap_info *own_bi = NULL; + struct dpp_authentication *auth; + + hostapd_dpp_pkex_clear_code(hapd); + + os_snprintf(cmd, sizeof(cmd), " peer=%u %s", peer_bi->id, + hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : ""); + wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)", + cmd); + + pos = os_strstr(cmd, " own="); + if (pos) { + pos += 5; + own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, + atoi(pos)); + if (!own_bi) { + wpa_printf(MSG_INFO, + "DPP: Could not find bootstrapping info for the identified local entry"); + return -1; + } + + if (peer_bi->curve != own_bi->curve) { + wpa_printf(MSG_INFO, + "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)", + peer_bi->curve->name, own_bi->curve->name); + return -1; + } + } + + pos = os_strstr(cmd, " role="); + if (pos) { + pos += 6; + if (os_strncmp(pos, "configurator", 12) == 0) + allowed_roles = DPP_CAPAB_CONFIGURATOR; + else if (os_strncmp(pos, "enrollee", 8) == 0) + allowed_roles = DPP_CAPAB_ENROLLEE; + else if (os_strncmp(pos, "either", 6) == 0) + allowed_roles = DPP_CAPAB_CONFIGURATOR | + DPP_CAPAB_ENROLLEE; + else + return -1; + } + + auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx, + peer_bi, own_bi, allowed_roles, 0, + hapd->iface->hw_features, + hapd->iface->num_hw_features); + if (!auth) + return -1; + + hostapd_dpp_set_testing_options(hapd, auth); + if (dpp_set_configurator(auth, cmd) < 0) { + dpp_auth_deinit(auth); + return -1; + } + + return dpp_tcp_auth(hapd->iface->interfaces->dpp, conn, auth, + hapd->conf->dpp_name, DPP_NETROLE_AP, + hapd->conf->dpp_mud_url, + hapd->conf->dpp_extra_conf_req_name, + hapd->conf->dpp_extra_conf_req_value, + hostapd_dpp_process_conf_obj, NULL); +} +#endif /* CONFIG_DPP2 */ + + +static int hostapd_dpp_pkex_init(struct hostapd_data *hapd, + enum dpp_pkex_ver ver, + const struct hostapd_ip_addr *ipaddr, + int tcp_port) +{ + struct dpp_pkex *pkex; + struct wpabuf *msg; + unsigned int wait_time; + bool v2 = ver != PKEX_VER_ONLY_1; + + wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1); + dpp_pkex_free(hapd->dpp_pkex); + hapd->dpp_pkex = NULL; + pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi, hapd->own_addr, + hapd->dpp_pkex_identifier, + hapd->dpp_pkex_code, hapd->dpp_pkex_code_len, v2); + if (!pkex) + return -1; + pkex->forced_ver = ver != PKEX_VER_AUTO; + + if (ipaddr) { +#ifdef CONFIG_DPP2 + return dpp_tcp_pkex_init(hapd->iface->interfaces->dpp, pkex, + ipaddr, tcp_port, + hapd->msg_ctx, hapd, + hostapd_dpp_pkex_done); +#else /* CONFIG_DPP2 */ + return -1; +#endif /* CONFIG_DPP2 */ + } + + hapd->dpp_pkex = pkex; + msg = hapd->dpp_pkex->exchange_req; + wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */ + pkex->freq = 2437; + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", MAC2STR(broadcast), pkex->freq, + v2 ? DPP_PA_PKEX_EXCHANGE_REQ : + DPP_PA_PKEX_V1_EXCHANGE_REQ); + hostapd_drv_send_action(hapd, pkex->freq, 0, broadcast, + wpabuf_head(msg), wpabuf_len(msg)); + pkex->exch_req_wait_time = wait_time; + pkex->exch_req_tries = 1; + + return 0; +} + + +static void hostapd_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct dpp_pkex *pkex = hapd->dpp_pkex; + + if (!pkex || !pkex->exchange_req) + return; + if (pkex->exch_req_tries >= 5) { + if (hostapd_dpp_pkex_next_channel(hapd, pkex) < 0) { +#ifdef CONFIG_DPP3 + if (pkex->v2 && !pkex->forced_ver) { + wpa_printf(MSG_DEBUG, + "DPP: Fall back to PKEXv1"); + hostapd_dpp_pkex_init(hapd, PKEX_VER_ONLY_1, + NULL, 0); + return; + } +#endif /* CONFIG_DPP3 */ + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL + "No response from PKEX peer"); + dpp_pkex_free(pkex); + hapd->dpp_pkex = NULL; + return; + } + pkex->exch_req_tries = 0; + } + + pkex->exch_req_tries++; + wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)", + pkex->exch_req_tries); + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", + MAC2STR(broadcast), pkex->freq, + pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ : + DPP_PA_PKEX_V1_EXCHANGE_REQ); + hostapd_drv_send_action(hapd, pkex->freq, pkex->exch_req_wait_time, + broadcast, + wpabuf_head(pkex->exchange_req), + wpabuf_len(pkex->exchange_req)); +} + + +static void hostapd_dpp_pkex_tx_status(struct hostapd_data *hapd, const u8 *dst, + const u8 *data, size_t data_len, int ok) +{ + struct dpp_pkex *pkex = hapd->dpp_pkex; + + if (pkex->failed) { + wpa_printf(MSG_DEBUG, + "DPP: Terminate PKEX exchange due to an earlier error"); + if (pkex->t > pkex->own_bi->pkex_t) + pkex->own_bi->pkex_t = pkex->t; + dpp_pkex_free(pkex); + hapd->dpp_pkex = NULL; + return; + } + + if (pkex->exch_req_wait_time && pkex->exchange_req) { + /* Wait for PKEX Exchange Response frame and retry request if + * no response is seen. */ + eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd, + NULL); + eloop_register_timeout(pkex->exch_req_wait_time / 1000, + (pkex->exch_req_wait_time % 1000) * 1000, + hostapd_dpp_pkex_retry_timeout, hapd, + NULL); + } +} + + void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst, const u8 *data, size_t data_len, int ok) { @@ -227,6 +499,11 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst, " result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED"); if (!hapd->dpp_auth) { + if (hapd->dpp_pkex) { + hostapd_dpp_pkex_tx_status(hapd, dst, data, data_len, + ok); + return; + } wpa_printf(MSG_DEBUG, "DPP: Ignore TX status since there is no ongoing authentication exchange"); return; @@ -262,8 +539,15 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst, return; } - if (hapd->dpp_auth_ok_on_ack) + if (hapd->dpp_auth_ok_on_ack) { hostapd_dpp_auth_success(hapd, 1); + if (!hapd->dpp_auth) { + /* The authentication session could have been removed in + * some error cases, e.g., when starting GAS client and + * failing to send the initial request. */ + return; + } + } if (!is_broadcast_ether_addr(dst) && !ok) { wpa_printf(MSG_DEBUG, @@ -578,7 +862,17 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd) } addr = get_param(cmd, " tcp_addr="); - if (addr) { + if (addr && os_strcmp(addr, "from-uri") == 0) { + os_free(addr); + if (!peer_bi->host) { + wpa_printf(MSG_INFO, + "DPP: TCP address not available in peer URI"); + return -1; + } + tcp = 1; + os_memcpy(&ipaddr, peer_bi->host, sizeof(ipaddr)); + tcp_port = peer_bi->port; + } else if (addr) { int res; res = hostapd_parse_ip_addr(addr, &ipaddr); @@ -663,8 +957,11 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd) 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); + DPP_NETROLE_AP, hapd->conf->dpp_mud_url, + hapd->conf->dpp_extra_conf_req_name, + hapd->conf->dpp_extra_conf_req_value, + hapd->msg_ctx, hapd, + hostapd_dpp_process_conf_obj, NULL); #endif /* CONFIG_DPP2 */ hapd->dpp_auth = auth; @@ -711,6 +1008,27 @@ void hostapd_dpp_listen_stop(struct hostapd_data *hapd) } +#ifdef CONFIG_DPP2 +static void +hostapd_dpp_relay_needs_controller(struct hostapd_data *hapd, const u8 *src, + enum dpp_public_action_frame_type type) +{ + struct os_reltime now; + + if (!hapd->conf->dpp_relay_port) + return; + + os_get_reltime(&now); + if (hapd->dpp_relay_last_needs_ctrl.sec && + !os_reltime_expired(&now, &hapd->dpp_relay_last_needs_ctrl, 60)) + return; + hapd->dpp_relay_last_needs_ctrl = now; + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_RELAY_NEEDS_CONTROLLER + MACSTR " %u", MAC2STR(src), type); +} +#endif /* CONFIG_DPP2 */ + + static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src, const u8 *hdr, const u8 *buf, size_t len, unsigned int freq) @@ -759,6 +1077,8 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src, src, hdr, buf, len, freq, i_bootstrap, r_bootstrap, hapd) == 0) return; + hostapd_dpp_relay_needs_controller(hapd, src, + DPP_PA_AUTHENTICATION_REQ); } #endif /* CONFIG_DPP2 */ if (!own_bi) { @@ -767,6 +1087,21 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src, return; } + if (own_bi->type == DPP_BOOTSTRAP_PKEX) { + if (!peer_bi || peer_bi->type != DPP_BOOTSTRAP_PKEX) { + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL + "No matching peer bootstrapping key found for PKEX - ignore message"); + return; + } + + if (os_memcmp(peer_bi->pubkey_hash, own_bi->peer_pubkey_hash, + SHA256_MAC_LEN) != 0) { + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL + "Mismatching peer PKEX bootstrapping key - ignore message"); + return; + } + } + if (hapd->dpp_auth) { wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "Already in DPP authentication exchange - ignore new one"); @@ -903,6 +1238,21 @@ static int hostapd_dpp_handle_key_pkg(struct hostapd_data *hapd, } +#ifdef CONFIG_DPP3 +static void hostapd_dpp_build_new_key(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct dpp_authentication *auth = hapd->dpp_auth; + + if (!auth || !auth->waiting_new_key) + return; + + wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key"); + hostapd_dpp_start_gas_client(hapd); +} +#endif /* CONFIG_DPP3 */ + + static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, enum gas_query_ap_result result, const struct wpabuf *adv_proto, @@ -912,6 +1262,7 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, const u8 *pos; struct dpp_authentication *auth = hapd->dpp_auth; enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED; + int res; if (!auth || !auth->auth_success) { wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); @@ -942,7 +1293,16 @@ static void hostapd_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_DPP3 + if (res == -3) { + wpa_printf(MSG_DEBUG, "DPP: New protocol key needed"); + eloop_register_timeout(0, 0, hostapd_dpp_build_new_key, hapd, + NULL); + return; + } +#endif /* CONFIG_DPP3 */ + if (res < 0) { wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); goto fail; } @@ -999,7 +1359,9 @@ static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd) buf = dpp_build_conf_req_helper(auth, hapd->conf->dpp_name, DPP_NETROLE_AP, - hapd->conf->dpp_mud_url, NULL); + hapd->conf->dpp_mud_url, NULL, + hapd->conf->dpp_extra_conf_req_name, + hapd->conf->dpp_extra_conf_req_value); if (!buf) { wpa_printf(MSG_DEBUG, "DPP: No configuration request data available"); @@ -1025,8 +1387,7 @@ static void hostapd_dpp_start_gas_client(struct hostapd_data *hapd) static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator) { wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded"); - wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", - initiator); + dpp_notify_auth_success(hapd->dpp_auth, initiator); #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) { wpa_printf(MSG_INFO, @@ -1061,7 +1422,7 @@ static void hostapd_dpp_rx_auth_resp(struct hostapd_data *hapd, const u8 *src, } if (!is_zero_ether_addr(auth->peer_mac_addr) && - os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + !ether_addr_equal(src, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " MACSTR_SEC ") - drop", MAC2STR_SEC(auth->peer_mac_addr)); return; @@ -1111,7 +1472,7 @@ static void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src, return; } - if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(src, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " MACSTR_SEC ") - drop", MAC2STR_SEC(auth->peer_mac_addr)); return; @@ -1163,11 +1524,53 @@ static void hostapd_dpp_conn_status_result_wait_timeout(void *eloop_ctx, } +#ifdef CONFIG_DPP3 + +static bool hostapd_dpp_pb_active(struct hostapd_data *hapd) +{ + struct hapd_interfaces *ifaces = hapd->iface->interfaces; + + return ifaces && (ifaces->dpp_pb_time.sec || + ifaces->dpp_pb_time.usec); +} + + +static void hostapd_dpp_remove_pb_hash(struct hostapd_data *hapd) +{ + struct hapd_interfaces *ifaces = hapd->iface->interfaces; + int i; + + if (!ifaces->dpp_pb_bi) + return; + for (i = 0; i < DPP_PB_INFO_COUNT; i++) { + struct dpp_pb_info *info = &ifaces->dpp_pb[i]; + + if (info->rx_time.sec == 0 && info->rx_time.usec == 0) + continue; + if (os_memcmp(info->hash, ifaces->dpp_pb_resp_hash, + SHA256_MAC_LEN) == 0) { + /* Allow a new push button session to be established + * immediately without the successfully completed + * session triggering session overlap. */ + info->rx_time.sec = 0; + info->rx_time.usec = 0; + wpa_printf(MSG_DEBUG, + "DPP: Removed PB hash from session overlap detection due to successfully completed provisioning"); + } + } +} + +#endif /* CONFIG_DPP3 */ + + static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src, const u8 *hdr, const u8 *buf, size_t len) { struct dpp_authentication *auth = hapd->dpp_auth; enum dpp_status_error status; +#ifdef CONFIG_DPP3 + struct hapd_interfaces *ifaces = hapd->iface->interfaces; +#endif /* CONFIG_DPP3 */ wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR_SEC, MAC2STR_SEC(src)); @@ -1178,7 +1581,7 @@ static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src, return; } - if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(src, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " MACSTR_SEC ") - drop", MAC2STR_SEC(auth->peer_mac_addr)); return; @@ -1188,7 +1591,8 @@ static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src, if (status == DPP_STATUS_OK && auth->send_conn_status) { wpa_msg(hapd->msg_ctx, MSG_INFO, - DPP_EVENT_CONF_SENT "wait_conn_status=1"); + DPP_EVENT_CONF_SENT "wait_conn_status=1 conf_status=%d", + auth->conf_resp_status); wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result"); eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd, NULL); @@ -1204,13 +1608,28 @@ static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src, hostapd_drv_send_action_cancel_wait(hapd); hostapd_dpp_listen_stop(hapd); if (status == DPP_STATUS_OK) - wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT); + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT + "conf_status=%d", auth->conf_resp_status); else wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); dpp_auth_deinit(auth); hapd->dpp_auth = NULL; eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd, NULL); +#ifdef CONFIG_DPP3 + if (!ifaces->dpp_pb_result_indicated && hostapd_dpp_pb_active(hapd)) { + if (status == DPP_STATUS_OK) + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT + "success"); + else + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT + "no-configuration-available"); + ifaces->dpp_pb_result_indicated = true; + if (status == DPP_STATUS_OK) + hostapd_dpp_remove_pb_hash(hapd); + hostapd_dpp_push_button_stop(hapd); + } +#endif /* CONFIG_DPP3 */ } @@ -1286,6 +1705,8 @@ hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src, return; wpa_printf(MSG_DEBUG, "DPP: No matching bootstrapping information found"); + hostapd_dpp_relay_needs_controller( + hapd, src, DPP_PA_PRESENCE_ANNOUNCEMENT); return; } @@ -1376,6 +1797,8 @@ hostapd_dpp_rx_reconfig_announcement(struct hostapd_data *hapd, const u8 *src, return; wpa_printf(MSG_DEBUG, "DPP: No matching Configurator information found"); + hostapd_dpp_relay_needs_controller( + hapd, src, DPP_PA_RECONFIG_ANNOUNCEMENT); return; } @@ -1448,7 +1871,7 @@ hostapd_dpp_rx_reconfig_auth_resp(struct hostapd_data *hapd, const u8 *src, return; } - if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(src, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " MACSTR_SEC ") - drop", MAC2STR_SEC(auth->peer_mac_addr)); return; @@ -1581,6 +2004,13 @@ skip_connector: } #endif /* CONFIG_DPP3 */ +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_RESP) { + wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version"); + ver = 1; + } +#endif /* CONFIG_TESTING_OPTIONS */ + /* Protocol Version */ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); wpabuf_put_le16(msg, 1); @@ -1603,6 +2033,25 @@ skip_proto_ver: } +static bool hapd_dpp_connector_available(struct hostapd_data *hapd) +{ + if (!hapd->wpa_auth || + !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) || + !(hapd->conf->wpa & WPA_PROTO_RSN)) { + wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use"); + return false; + } + + if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey || + !hapd->conf->dpp_csign) { + wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set"); + return false; + } + + return true; +} + + static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, const u8 *src, const u8 *buf, size_t len, @@ -1615,21 +2064,14 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, os_time_t expire; int expiration; enum dpp_status_error res; + u8 pkhash[SHA256_MAC_LEN]; + + os_memset(&intro, 0, sizeof(intro)); wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR_SEC, MAC2STR_SEC(src)); - if (!hapd->wpa_auth || - !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) || - !(hapd->conf->wpa & WPA_PROTO_RSN)) { - wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use"); - return; - } - - if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey || - !hapd->conf->dpp_csign) { - wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set"); + if (!hapd_dpp_connector_available(hapd)) return; - } os_get_time(&now); @@ -1659,12 +2101,12 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, wpabuf_len(hapd->conf->dpp_netaccesskey), wpabuf_head(hapd->conf->dpp_csign), wpabuf_len(hapd->conf->dpp_csign), - connector, connector_len, &expire); + connector, connector_len, &expire, pkhash); if (res == 255) { wpa_printf(MSG_INFO, "DPP: Network Introduction protocol resulted in internal failure (peer " MACSTR_SEC ")", MAC2STR_SEC(src)); - return; + goto done; } if (res != DPP_STATUS_OK) { wpa_printf(MSG_INFO, @@ -1672,7 +2114,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, MACSTR_SEC " status %d)", MAC2STR_SEC(src), res); hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0], res); - return; + goto done; } #ifdef CONFIG_DPP3 @@ -1692,7 +2134,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0], DPP_STATUS_NO_MATCH); - return; + goto done; } } #endif /* CONFIG_DPP3 */ @@ -1706,19 +2148,21 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len, intro.pmkid, expiration, - WPA_KEY_MGMT_DPP) < 0) { + WPA_KEY_MGMT_DPP, pkhash) < 0) { wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry"); - return; + goto done; } hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0], DPP_STATUS_OK); +done: + dpp_peer_intro_deinit(&intro); } static void hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src, - const u8 *buf, size_t len, + const u8 *hdr, const u8 *buf, size_t len, unsigned int freq, bool v2) { struct wpabuf *msg; @@ -1726,20 +2170,40 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src, wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR_SEC, MAC2STR_SEC(src)); + if (hapd->dpp_pkex_ver == PKEX_VER_ONLY_1 && v2) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore PKEXv2 Exchange Request when configured to be PKEX v1 only"); + return; + } + if (hapd->dpp_pkex_ver == PKEX_VER_ONLY_2 && !v2) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore PKEXv1 Exchange Request when configured to be PKEX v2 only"); + return; + } + /* TODO: Support multiple PKEX codes by iterating over all the enabled * values here */ if (!hapd->dpp_pkex_code || !hapd->dpp_pkex_bi) { wpa_printf(MSG_DEBUG, "DPP: No PKEX code configured - ignore request"); + goto try_relay; + } + +#ifdef CONFIG_DPP2 + if (dpp_controller_is_own_pkex_req(hapd->iface->interfaces->dpp, + buf, len)) { + wpa_printf(MSG_DEBUG, + "DPP: PKEX Exchange Request is from local Controller - ignore request"); return; } +#endif /* CONFIG_DPP2 */ if (hapd->dpp_pkex) { /* TODO: Support parallel operations */ wpa_printf(MSG_DEBUG, "DPP: Already in PKEX session - ignore new request"); - return; + goto try_relay; } hapd->dpp_pkex = dpp_pkex_rx_exchange_req(hapd->msg_ctx, @@ -1747,11 +2211,12 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src, hapd->own_addr, src, hapd->dpp_pkex_identifier, hapd->dpp_pkex_code, + hapd->dpp_pkex_code_len, buf, len, v2); if (!hapd->dpp_pkex) { wpa_printf(MSG_DEBUG, "DPP: Failed to process the request - ignore it"); - return; + goto try_relay; } msg = hapd->dpp_pkex->exchange_resp; @@ -1768,6 +2233,22 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src, dpp_pkex_free(hapd->dpp_pkex); hapd->dpp_pkex = NULL; } + + return; + +try_relay: +#ifdef CONFIG_DPP2 + if (v2 && dpp_relay_rx_action(hapd->iface->interfaces->dpp, + src, hdr, buf, len, freq, NULL, NULL, + hapd) != 0) { + wpa_printf(MSG_DEBUG, + "DPP: No Relay available for the message"); + hostapd_dpp_relay_needs_controller(hapd, src, + DPP_PA_PKEX_EXCHANGE_REQ); + } +#else /* CONFIG_DPP2 */ + wpa_printf(MSG_DEBUG, "DPP: No relay functionality included - skip"); +#endif /* CONFIG_DPP2 */ } @@ -1789,6 +2270,9 @@ hostapd_dpp_rx_pkex_exchange_resp(struct hostapd_data *hapd, const u8 *src, return; } + eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd, NULL); + hapd->dpp_pkex->exch_req_wait_time = 0; + msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len); if (!msg) { wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); @@ -1848,6 +2332,7 @@ hostapd_dpp_rx_pkex_commit_reveal_req(struct hostapd_data *hapd, const u8 *src, wpabuf_head(msg), wpabuf_len(msg)); wpabuf_free(msg); + hostapd_dpp_pkex_clear_code(hapd); bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq); if (!bi) return; @@ -1860,6 +2345,7 @@ hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src, const u8 *hdr, const u8 *buf, size_t len, unsigned int freq) { + struct hapd_interfaces *ifaces = hapd->iface->interfaces; int res; struct dpp_bootstrap_info *bi; struct dpp_pkex *pkex = hapd->dpp_pkex; @@ -1879,11 +2365,34 @@ hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src, return; } - bi = dpp_pkex_finish(hapd->iface->interfaces->dpp, pkex, src, freq); + hostapd_dpp_pkex_clear_code(hapd); + bi = dpp_pkex_finish(ifaces->dpp, pkex, src, freq); if (!bi) return; hapd->dpp_pkex = NULL; +#ifdef CONFIG_DPP3 + if (ifaces->dpp_pb_bi && + os_memcmp(bi->pubkey_hash_chirp, ifaces->dpp_pb_resp_hash, + SHA256_MAC_LEN) != 0) { + char id[20]; + + wpa_printf(MSG_INFO, + "DPP: Peer bootstrap key from PKEX does not match PB announcement hash"); + wpa_hexdump(MSG_DEBUG, + "DPP: Peer provided bootstrap key hash(chirp) from PB PKEX", + bi->pubkey_hash_chirp, SHA256_MAC_LEN); + wpa_hexdump(MSG_DEBUG, + "DPP: Peer provided bootstrap key hash(chirp) from PB announcement", + ifaces->dpp_pb_resp_hash, SHA256_MAC_LEN); + + os_snprintf(id, sizeof(id), "%u", bi->id); + dpp_bootstrap_remove(ifaces->dpp, id); + hostapd_dpp_push_button_stop(hapd); + return; + } +#endif /* CONFIG_DPP3 */ + os_snprintf(cmd, sizeof(cmd), " peer=%u %s", bi->id, hapd->dpp_pkex_auth_cmd ? hapd->dpp_pkex_auth_cmd : ""); @@ -1898,6 +2407,537 @@ hostapd_dpp_rx_pkex_commit_reveal_resp(struct hostapd_data *hapd, const u8 *src, } +#ifdef CONFIG_DPP3 + +static void hostapd_dpp_pb_pkex_init(struct hostapd_data *hapd, + unsigned int freq, const u8 *src, + const u8 *r_hash) +{ + struct hapd_interfaces *ifaces = hapd->iface->interfaces; + struct dpp_pkex *pkex; + struct wpabuf *msg; + char ssid_hex[2 * SSID_MAX_LEN + 1], *pass_hex = NULL; + char cmd[300]; + const char *password = NULL; +#ifdef CONFIG_SAE + struct sae_password_entry *e; +#endif /* CONFIG_SAE */ + int conf_id = -1; + bool sae = false, psk = false; + size_t len; + + if (hapd->dpp_pkex) { + wpa_printf(MSG_DEBUG, + "PDP: Sending previously generated PKEX Exchange Request to " + MACSTR, MAC2STR(src)); + msg = hapd->dpp_pkex->exchange_req; + hostapd_drv_send_action(hapd, freq, 0, src, + wpabuf_head(msg), wpabuf_len(msg)); + return; + } + + wpa_printf(MSG_DEBUG, "DPP: Initiate PKEX for push button with " + MACSTR, MAC2STR(src)); + + hapd->dpp_pkex_bi = ifaces->dpp_pb_bi; + os_memcpy(ifaces->dpp_pb_resp_hash, r_hash, SHA256_MAC_LEN); + + pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi, hapd->own_addr, + "PBPKEX", (const char *) ifaces->dpp_pb_c_nonce, + ifaces->dpp_pb_bi->curve->nonce_len, + true); + if (!pkex) { + hostapd_dpp_push_button_stop(hapd); + return; + } + pkex->freq = freq; + + hapd->dpp_pkex = pkex; + msg = hapd->dpp_pkex->exchange_req; + + if (ifaces->dpp_pb_cmd) { + /* Use the externally provided configuration */ + os_free(hapd->dpp_pkex_auth_cmd); + len = 30 + os_strlen(ifaces->dpp_pb_cmd); + hapd->dpp_pkex_auth_cmd = os_malloc(len); + if (!hapd->dpp_pkex_auth_cmd) { + hostapd_dpp_push_button_stop(hapd); + return; + } + os_snprintf(hapd->dpp_pkex_auth_cmd, len, " own=%d %s", + hapd->dpp_pkex_bi->id, ifaces->dpp_pb_cmd); + goto send_frame; + } + + /* Build config based on the current AP configuration */ + wpa_snprintf_hex(ssid_hex, sizeof(ssid_hex), + (const u8 *) hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len); + + if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) { + /* TODO: If a local Configurator has been enabled, allow a + * DPP AKM credential to be provisioned by setting conf_id. */ + } + + if (hapd->conf->wpa & WPA_PROTO_RSN) { + psk = hapd->conf->wpa_key_mgmt & (WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_PSK_SHA256); +#ifdef CONFIG_SAE + sae = hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE; +#endif /* CONFIG_SAE */ + } + +#ifdef CONFIG_SAE + for (e = hapd->conf->sae_passwords; sae && e && !password; + e = e->next) { + if (e->identifier || !is_broadcast_ether_addr(e->peer_addr)) + continue; + password = e->password; + } +#endif /* CONFIG_SAE */ + if (!password && hapd->conf->ssid.wpa_passphrase_set && + hapd->conf->ssid.wpa_passphrase) + password = hapd->conf->ssid.wpa_passphrase; + if (password) { + len = 2 * os_strlen(password) + 1; + pass_hex = os_malloc(len); + if (!pass_hex) { + hostapd_dpp_push_button_stop(hapd); + return; + } + wpa_snprintf_hex(pass_hex, len, (const u8 *) password, + os_strlen(password)); + } + + if (conf_id > 0 && sae && psk && pass_hex) { + os_snprintf(cmd, sizeof(cmd), + "conf=sta-dpp+psk+sae configurator=%d ssid=%s pass=%s", + conf_id, ssid_hex, pass_hex); + } else if (conf_id > 0 && sae && pass_hex) { + os_snprintf(cmd, sizeof(cmd), + "conf=sta-dpp+sae configurator=%d ssid=%s pass=%s", + conf_id, ssid_hex, pass_hex); + } else if (conf_id > 0) { + os_snprintf(cmd, sizeof(cmd), + "conf=sta-dpp configurator=%d ssid=%s", + conf_id, ssid_hex); + } if (sae && psk && pass_hex) { + os_snprintf(cmd, sizeof(cmd), + "conf=sta-psk+sae ssid=%s pass=%s", + ssid_hex, pass_hex); + } else if (sae && pass_hex) { + os_snprintf(cmd, sizeof(cmd), + "conf=sta-sae ssid=%s pass=%s", + ssid_hex, pass_hex); + } else if (psk && pass_hex) { + os_snprintf(cmd, sizeof(cmd), + "conf=sta-psk ssid=%s pass=%s", + ssid_hex, pass_hex); + } else { + wpa_printf(MSG_INFO, + "DPP: Unsupported AP configuration for push button"); + str_clear_free(pass_hex); + hostapd_dpp_push_button_stop(hapd); + return; + } + str_clear_free(pass_hex); + + os_free(hapd->dpp_pkex_auth_cmd); + len = 30 + os_strlen(cmd); + hapd->dpp_pkex_auth_cmd = os_malloc(len); + if (hapd->dpp_pkex_auth_cmd) + os_snprintf(hapd->dpp_pkex_auth_cmd, len, " own=%d %s", + hapd->dpp_pkex_bi->id, cmd); + forced_memzero(cmd, sizeof(cmd)); + if (!hapd->dpp_pkex_auth_cmd) { + hostapd_dpp_push_button_stop(hapd); + return; + } + +send_frame: + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", MAC2STR(src), freq, + DPP_PA_PKEX_EXCHANGE_REQ); + hostapd_drv_send_action(hapd, pkex->freq, 0, src, + wpabuf_head(msg), wpabuf_len(msg)); + pkex->exch_req_wait_time = 2000; + pkex->exch_req_tries = 1; +} + + +static void +hostapd_dpp_rx_pb_presence_announcement(struct hostapd_data *hapd, + const u8 *src, const u8 *hdr, + const u8 *buf, size_t len, + unsigned int freq) +{ + struct hapd_interfaces *ifaces = hapd->iface->interfaces; + const u8 *r_hash; + u16 r_hash_len; + unsigned int i; + bool found = false; + struct dpp_pb_info *info, *tmp; + struct os_reltime now, age; + struct wpabuf *msg; + + if (!ifaces) + return; + + os_get_reltime(&now); + wpa_printf(MSG_DEBUG, "DPP: Push Button Presence Announcement from " + MACSTR, MAC2STR(src)); + + r_hash = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, + &r_hash_len); + if (!r_hash || r_hash_len != SHA256_MAC_LEN) { + wpa_printf(MSG_DEBUG, + "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute"); + return; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", + r_hash, r_hash_len); + + for (i = 0; i < DPP_PB_INFO_COUNT; i++) { + info = &ifaces->dpp_pb[i]; + if ((info->rx_time.sec == 0 && info->rx_time.usec == 0) || + os_memcmp(r_hash, info->hash, SHA256_MAC_LEN) != 0) + continue; + wpa_printf(MSG_DEBUG, + "DPP: Active push button Enrollee already known"); + found = true; + info->rx_time = now; + } + + if (!found) { + for (i = 0; i < DPP_PB_INFO_COUNT; i++) { + tmp = &ifaces->dpp_pb[i]; + if (tmp->rx_time.sec == 0 && tmp->rx_time.usec == 0) + continue; + + if (os_reltime_expired(&now, &tmp->rx_time, 120)) { + wpa_hexdump(MSG_DEBUG, + "DPP: Push button Enrollee hash expired", + tmp->hash, SHA256_MAC_LEN); + tmp->rx_time.sec = 0; + tmp->rx_time.usec = 0; + continue; + } + + wpa_hexdump(MSG_DEBUG, + "DPP: Push button session overlap with hash", + tmp->hash, SHA256_MAC_LEN); + if (!ifaces->dpp_pb_result_indicated && + hostapd_dpp_pb_active(hapd)) { + wpa_msg(hapd->msg_ctx, MSG_INFO, + DPP_EVENT_PB_RESULT "session-overlap"); + ifaces->dpp_pb_result_indicated = true; + } + hostapd_dpp_push_button_stop(hapd); + return; + } + + /* Replace the oldest entry */ + info = &ifaces->dpp_pb[0]; + for (i = 1; i < DPP_PB_INFO_COUNT; i++) { + tmp = &ifaces->dpp_pb[i]; + if (os_reltime_before(&tmp->rx_time, &info->rx_time)) + info = tmp; + } + wpa_printf(MSG_DEBUG, "DPP: New active push button Enrollee"); + os_memcpy(info->hash, r_hash, SHA256_MAC_LEN); + info->rx_time = now; + } + + if (!hostapd_dpp_pb_active(hapd)) { + wpa_printf(MSG_DEBUG, + "DPP: Discard message since own push button has not been pressed"); + return; + } + + if (ifaces->dpp_pb_announce_time.sec == 0 && + ifaces->dpp_pb_announce_time.usec == 0) { + /* Start a wait before allowing PKEX to be initiated */ + ifaces->dpp_pb_announce_time = now; + } + + if (!ifaces->dpp_pb_bi) { + int res; + + res = dpp_bootstrap_gen(ifaces->dpp, "type=pkex"); + if (res < 0) + return; + ifaces->dpp_pb_bi = dpp_bootstrap_get_id(ifaces->dpp, res); + if (!ifaces->dpp_pb_bi) + return; + + if (random_get_bytes(ifaces->dpp_pb_c_nonce, + ifaces->dpp_pb_bi->curve->nonce_len)) { + wpa_printf(MSG_ERROR, + "DPP: Failed to generate C-nonce"); + hostapd_dpp_push_button_stop(hapd); + return; + } + } + + /* Skip the response if one was sent within last 50 ms since the + * Enrollee is going to send out at least three announcement messages. + */ + os_reltime_sub(&now, &ifaces->dpp_pb_last_resp, &age); + if (age.sec == 0 && age.usec < 50000) { + wpa_printf(MSG_DEBUG, + "DPP: Skip Push Button Presence Announcement Response frame immediately after having sent one"); + return; + } + + msg = dpp_build_pb_announcement_resp( + ifaces->dpp_pb_bi, r_hash, ifaces->dpp_pb_c_nonce, + ifaces->dpp_pb_bi->curve->nonce_len); + if (!msg) { + hostapd_dpp_push_button_stop(hapd); + return; + } + + wpa_printf(MSG_DEBUG, + "DPP: Send Push Button Presence Announcement Response to " + MACSTR, MAC2STR(src)); + ifaces->dpp_pb_last_resp = now; + + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", MAC2STR(src), freq, + DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP); + hostapd_drv_send_action(hapd, freq, 0, src, + wpabuf_head(msg), wpabuf_len(msg)); + wpabuf_free(msg); + + if (os_reltime_expired(&now, &ifaces->dpp_pb_announce_time, 15)) + hostapd_dpp_pb_pkex_init(hapd, freq, src, r_hash); +} + + +static void +hostapd_dpp_rx_priv_peer_intro_query(struct hostapd_data *hapd, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len, + unsigned int freq) +{ + const u8 *trans_id, *version; + u16 trans_id_len, version_len; + struct wpabuf *msg; + u8 ver = DPP_VERSION; + int conn_ver; + + wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction Query from " + MACSTR, MAC2STR(src)); + + if (!hapd_dpp_connector_available(hapd)) + return; + + trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID, + &trans_id_len); + if (!trans_id || trans_id_len != 1) { + wpa_printf(MSG_DEBUG, + "DPP: Peer did not include Transaction ID"); + return; + } + + version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION, + &version_len); + if (!version || version_len != 1) { + wpa_printf(MSG_DEBUG, + "DPP: Peer did not include Protocol Version"); + return; + } + + wpa_printf(MSG_DEBUG, "DPP: Transaction ID %u, Version %u", + trans_id[0], version[0]); + + len = 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector); + msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_NOTIFY, len); + if (!msg) + return; + + /* Transaction ID */ + wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, trans_id[0]); + + /* Protocol Version */ + conn_ver = dpp_get_connector_version(hapd->conf->dpp_connector); + if (conn_ver > 0 && ver != conn_ver) { + wpa_printf(MSG_DEBUG, + "DPP: Use Connector version %d instead of current protocol version %d", + conn_ver, ver); + ver = conn_ver; + } + wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, ver); + + /* DPP Connector */ + wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); + wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector)); + wpabuf_put_str(msg, hapd->conf->dpp_connector); + + wpa_printf(MSG_DEBUG, "DPP: Send Private Peer Introduction Notify to " + MACSTR, MAC2STR(src)); + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", MAC2STR(src), freq, + DPP_PA_PRIV_PEER_INTRO_NOTIFY); + hostapd_drv_send_action(hapd, freq, 0, src, + wpabuf_head(msg), wpabuf_len(msg)); + wpabuf_free(msg); +} + + +static void +hostapd_dpp_rx_priv_peer_intro_update(struct hostapd_data *hapd, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len, + unsigned int freq) +{ + struct crypto_ec_key *own_key; + const struct dpp_curve_params *curve; + enum hpke_kem_id kem_id; + enum hpke_kdf_id kdf_id; + enum hpke_aead_id aead_id; + const u8 *aad = hdr; + size_t aad_len = DPP_HDR_LEN; + struct wpabuf *pt; + const u8 *trans_id, *wrapped, *version, *connector; + u16 trans_id_len, wrapped_len, version_len, connector_len; + struct os_time now; + struct dpp_introduction intro; + os_time_t expire; + int expiration; + enum dpp_status_error res; + u8 pkhash[SHA256_MAC_LEN]; + + os_memset(&intro, 0, sizeof(intro)); + + wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction Update from " + MACSTR, MAC2STR(src)); + + if (!hapd_dpp_connector_available(hapd)) + return; + + os_get_time(&now); + + if (hapd->conf->dpp_netaccesskey_expiry && + (os_time_t) hapd->conf->dpp_netaccesskey_expiry < now.sec) { + wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired"); + return; + } + + trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID, + &trans_id_len); + if (!trans_id || trans_id_len != 1) { + wpa_printf(MSG_DEBUG, + "DPP: Peer did not include Transaction ID"); + return; + } + + wrapped = dpp_get_attr(buf, len, DPP_ATTR_WRAPPED_DATA, + &wrapped_len); + if (!wrapped) { + wpa_printf(MSG_DEBUG, "DPP: Peer did not include Wrapped Data"); + return; + } + + own_key = dpp_set_keypair(&curve, + wpabuf_head(hapd->conf->dpp_netaccesskey), + wpabuf_len(hapd->conf->dpp_netaccesskey)); + if (!own_key) { + wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey"); + return; + } + + if (dpp_hpke_suite(curve->ike_group, &kem_id, &kdf_id, &aead_id) < 0) { + wpa_printf(MSG_ERROR, "DPP: Unsupported curve %d", + curve->ike_group); + crypto_ec_key_deinit(own_key); + return; + } + + pt = hpke_base_open(kem_id, kdf_id, aead_id, own_key, NULL, 0, + aad, aad_len, wrapped, wrapped_len); + crypto_ec_key_deinit(own_key); + if (!pt) { + wpa_printf(MSG_INFO, "DPP: Failed to decrypt Connector"); + return; + } + wpa_hexdump_buf(MSG_MSGDUMP, "DPP: HPKE-Decrypted Wrapped Data", pt); + + connector = dpp_get_attr(wpabuf_head(pt), wpabuf_len(pt), + DPP_ATTR_CONNECTOR, &connector_len); + if (!connector) { + wpa_printf(MSG_DEBUG, + "DPP: Peer did not include its Connector"); + goto done; + } + + version = dpp_get_attr(wpabuf_head(pt), wpabuf_len(pt), + DPP_ATTR_PROTOCOL_VERSION, &version_len); + if (!version || version_len < 1) { + wpa_printf(MSG_DEBUG, + "DPP: Peer did not include Protocol Version"); + goto done; + } + + res = dpp_peer_intro(&intro, hapd->conf->dpp_connector, + wpabuf_head(hapd->conf->dpp_netaccesskey), + wpabuf_len(hapd->conf->dpp_netaccesskey), + wpabuf_head(hapd->conf->dpp_csign), + wpabuf_len(hapd->conf->dpp_csign), + connector, connector_len, &expire, pkhash); + if (res == 255) { + wpa_printf(MSG_INFO, + "DPP: Network Introduction protocol resulted in internal failure (peer " + MACSTR ")", MAC2STR(src)); + goto done; + } + if (res != DPP_STATUS_OK) { + wpa_printf(MSG_INFO, + "DPP: Network Introduction protocol resulted in failure (peer " + MACSTR " status %d)", MAC2STR(src), res); + goto done; + } + + if (intro.peer_version && intro.peer_version >= 2) { + u8 attr_version = 1; + + if (version && version_len >= 1) + attr_version = version[0]; + if (attr_version != intro.peer_version) { + wpa_printf(MSG_INFO, + "DPP: Protocol version mismatch (Connector: %d Attribute: %d", + intro.peer_version, attr_version); + goto done; + } + } + + if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire) + expire = hapd->conf->dpp_netaccesskey_expiry; + if (expire) + expiration = expire - now.sec; + else + expiration = 0; + + if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len, + intro.pmkid, expiration, + WPA_KEY_MGMT_DPP, pkhash) < 0) { + wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry"); + goto done; + } + + wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction completed with " + MACSTR, MAC2STR(src)); + +done: + dpp_peer_intro_deinit(&intro); + wpabuf_free(pt); +} + +#endif /* CONFIG_DPP3 */ + + void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, const u8 *buf, size_t len, unsigned int freq) { @@ -1964,12 +3004,12 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, /* This is for PKEXv2, but for now, process only with * CONFIG_DPP3 to avoid issues with a capability that has not * been tested with other implementations. */ - hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq, + hostapd_dpp_rx_pkex_exchange_req(hapd, src, hdr, buf, len, freq, true); break; #endif /* CONFIG_DPP3 */ case DPP_PA_PKEX_V1_EXCHANGE_REQ: - hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq, + hostapd_dpp_rx_pkex_exchange_req(hapd, src, hdr, buf, len, freq, false); break; case DPP_PA_PKEX_EXCHANGE_RESP: @@ -2003,6 +3043,20 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, freq); break; #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + case DPP_PA_PB_PRESENCE_ANNOUNCEMENT: + hostapd_dpp_rx_pb_presence_announcement(hapd, src, hdr, + buf, len, freq); + break; + case DPP_PA_PRIV_PEER_INTRO_QUERY: + hostapd_dpp_rx_priv_peer_intro_query(hapd, src, hdr, + buf, len, freq); + break; + case DPP_PA_PRIV_PEER_INTRO_UPDATE: + hostapd_dpp_rx_priv_peer_intro_update(hapd, src, hdr, + buf, len, freq); + break; +#endif /* CONFIG_DPP3 */ default: wpa_printf(MSG_DEBUG, "DPP: Ignored unsupported frame subtype %d", type); @@ -2032,7 +3086,7 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa, wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR_SEC, MAC2STR_SEC(sa)); if (!auth || (!auth->auth_success && !auth->reconfig_success) || - os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) { + !ether_addr_equal(sa, auth->peer_mac_addr)) { #ifdef CONFIG_DPP2 if (dpp_relay_rx_gas_req(hapd->iface->interfaces->dpp, sa, data, data_len) == 0) { @@ -2051,9 +3105,15 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa, * from TX status handler, but since there was no such handler * call yet, simply send out the event message and proceed with * exchange. */ - wpa_msg(hapd->msg_ctx, MSG_INFO, - DPP_EVENT_AUTH_SUCCESS "init=1"); + dpp_notify_auth_success(hapd->dpp_auth, 1); hapd->dpp_auth_ok_on_ack = 0; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) { + wpa_printf(MSG_INFO, + "DPP: TESTING - stop at Authentication Confirm"); + return NULL; + } +#endif /* CONFIG_TESTING_OPTIONS */ } wpa_hexdump(MSG_DEBUG, @@ -2071,10 +3131,20 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa, void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok) { struct dpp_authentication *auth = hapd->dpp_auth; +#ifdef CONFIG_DPP3 + struct hapd_interfaces *ifaces = hapd->iface->interfaces; +#endif /* CONFIG_DPP3 */ if (!auth) return; +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key && ok) { + wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key"); + return; + } +#endif /* CONFIG_DPP3 */ + wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", ok); eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); @@ -2098,11 +3168,26 @@ void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok) hostapd_drv_send_action_cancel_wait(hapd); if (ok) - wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT); + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT + "conf_status=%d", auth->conf_resp_status); else wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); dpp_auth_deinit(hapd->dpp_auth); hapd->dpp_auth = NULL; +#ifdef CONFIG_DPP3 + if (!ifaces->dpp_pb_result_indicated && hostapd_dpp_pb_active(hapd)) { + if (ok) + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT + "success"); + else + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_RESULT + "could-not-connect"); + ifaces->dpp_pb_result_indicated = true; + if (ok) + hostapd_dpp_remove_pb_hash(hapd); + hostapd_dpp_push_button_stop(hapd); + } +#endif /* CONFIG_DPP3 */ } @@ -2135,6 +3220,34 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd) { struct dpp_bootstrap_info *own_bi; const char *pos, *end; +#ifdef CONFIG_DPP3 + enum dpp_pkex_ver ver = PKEX_VER_AUTO; +#else /* CONFIG_DPP3 */ + enum dpp_pkex_ver ver = PKEX_VER_ONLY_1; +#endif /* CONFIG_DPP3 */ + int tcp_port = DPP_TCP_PORT; + struct hostapd_ip_addr *ipaddr = NULL; +#ifdef CONFIG_DPP2 + struct hostapd_ip_addr ipaddr_buf; + char *addr; + + 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_buf); + os_free(addr); + if (res) + return -1; + ipaddr = &ipaddr_buf; + } +#endif /* CONFIG_DPP2 */ pos = os_strstr(cmd, " own="); if (!pos) @@ -2176,28 +3289,32 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd) hapd->dpp_pkex_code = os_strdup(pos + 6); if (!hapd->dpp_pkex_code) return -1; + hapd->dpp_pkex_code_len = os_strlen(hapd->dpp_pkex_code); - if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) { - struct wpabuf *msg; - bool v2 = os_strstr(cmd, " init=2") != NULL; + pos = os_strstr(cmd, " ver="); + if (pos) { + int v; - wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX"); - dpp_pkex_free(hapd->dpp_pkex); - hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi, - hapd->own_addr, - hapd->dpp_pkex_identifier, - hapd->dpp_pkex_code, v2); - if (!hapd->dpp_pkex) + pos += 5; + v = atoi(pos); + if (v == 1) + ver = PKEX_VER_ONLY_1; + else if (v == 2) + ver = PKEX_VER_ONLY_2; + else return -1; + } + hapd->dpp_pkex_ver = ver; - msg = hapd->dpp_pkex->exchange_req; - /* TODO: Which channel to use? */ - wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR - " freq=%u type=%d", MAC2STR(broadcast), 2437, - v2 ? DPP_PA_PKEX_EXCHANGE_REQ : - DPP_PA_PKEX_V1_EXCHANGE_REQ); - hostapd_drv_send_action(hapd, 2437, 0, broadcast, - wpabuf_head(msg), wpabuf_len(msg)); + if (os_strstr(cmd, " init=1")) { + if (hostapd_dpp_pkex_init(hapd, ver, ipaddr, tcp_port) < 0) + return -1; + } else { +#ifdef CONFIG_DPP2 + dpp_controller_pkex_add(hapd->iface->interfaces->dpp, own_bi, + hapd->dpp_pkex_code, + hapd->dpp_pkex_identifier); +#endif /* CONFIG_DPP2 */ } /* TODO: Support multiple PKEX info entries */ @@ -2221,7 +3338,7 @@ int hostapd_dpp_pkex_remove(struct hostapd_data *hapd, const char *id) return -1; } - if ((id_val != 0 && id_val != 1) || !hapd->dpp_pkex_code) + if ((id_val != 0 && id_val != 1)) return -1; /* TODO: Support multiple PKEX entries */ @@ -2245,6 +3362,9 @@ void hostapd_dpp_stop(struct hostapd_data *hapd) hapd->dpp_auth = NULL; dpp_pkex_free(hapd->dpp_pkex); hapd->dpp_pkex = NULL; +#ifdef CONFIG_DPP3 + hostapd_dpp_push_button_stop(hapd); +#endif /* CONFIG_DPP3 */ } @@ -2256,6 +3376,9 @@ static void hostapd_dpp_relay_tx(void *ctx, const u8 *addr, unsigned int freq, struct hostapd_data *hapd = ctx; u8 *buf; + if (freq == 0) + freq = hapd->iface->freq; + wpa_printf(MSG_DEBUG, "DPP: Send action frame dst=" MACSTR_SEC " freq=%u", MAC2STR_SEC(addr), freq); buf = os_malloc(2 + len); @@ -2275,7 +3398,7 @@ static void hostapd_dpp_relay_gas_resp_tx(void *ctx, const u8 *addr, { struct hostapd_data *hapd = ctx; - gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf); + gas_serv_req_dpp_processing(hapd, addr, dialog_token, prot, buf, 0); } #endif /* CONFIG_DPP2 */ @@ -2288,6 +3411,7 @@ static int hostapd_dpp_add_controllers(struct hostapd_data *hapd) struct dpp_relay_config config; os_memset(&config, 0, sizeof(config)); + config.msg_ctx = hapd->msg_ctx; config.cb_ctx = hapd; config.tx = hostapd_dpp_relay_tx; config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx; @@ -2298,12 +3422,76 @@ static int hostapd_dpp_add_controllers(struct hostapd_data *hapd) &config) < 0) return -1; } + + if (hapd->conf->dpp_relay_port) + dpp_relay_listen(hapd->iface->interfaces->dpp, + hapd->conf->dpp_relay_port, + &config); #endif /* CONFIG_DPP2 */ return 0; } +#ifdef CONFIG_DPP2 + +int hostapd_dpp_add_controller(struct hostapd_data *hapd, const char *cmd) +{ + struct dpp_relay_config config; + struct hostapd_ip_addr addr; + u8 pkhash[SHA256_MAC_LEN]; + char *pos, *tmp; + int ret = -1; + bool prev_state, new_state; + struct dpp_global *dpp = hapd->iface->interfaces->dpp; + + tmp = os_strdup(cmd); + if (!tmp) + goto fail; + pos = os_strchr(tmp, ' '); + if (!pos) + goto fail; + *pos++ = '\0'; + if (hostapd_parse_ip_addr(tmp, &addr) < 0 || + hexstr2bin(pos, pkhash, SHA256_MAC_LEN) < 0) + goto fail; + + os_memset(&config, 0, sizeof(config)); + config.msg_ctx = hapd->msg_ctx; + config.cb_ctx = hapd; + config.tx = hostapd_dpp_relay_tx; + config.gas_resp_tx = hostapd_dpp_relay_gas_resp_tx; + config.ipaddr = &addr; + config.pkhash = pkhash; + prev_state = dpp_relay_controller_available(dpp); + ret = dpp_relay_add_controller(dpp, &config); + new_state = dpp_relay_controller_available(dpp); + if (new_state != prev_state) + ieee802_11_update_beacons(hapd->iface); +fail: + os_free(tmp); + return ret; +} + + +void hostapd_dpp_remove_controller(struct hostapd_data *hapd, const char *cmd) +{ + struct hostapd_ip_addr addr; + bool prev_state, new_state; + struct dpp_global *dpp = hapd->iface->interfaces->dpp; + + if (hostapd_parse_ip_addr(cmd, &addr) < 0) + return; + prev_state = dpp_relay_controller_available(dpp); + dpp_relay_remove_controller(dpp, &addr); + new_state = dpp_relay_controller_available(dpp); + if (new_state != prev_state) + ieee802_11_update_beacons(hapd->iface); +} + +#endif /* CONFIG_DPP2 */ + + int hostapd_dpp_init(struct hostapd_data *hapd) { hapd->dpp_allowed_roles = DPP_CAPAB_CONFIGURATOR | DPP_CAPAB_ENROLLEE; @@ -2325,6 +3513,7 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd) #endif /* CONFIG_TESTING_OPTIONS */ if (!hapd->dpp_init_done) return; + eloop_cancel_timeout(hostapd_dpp_pkex_retry_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_init_timeout, hapd, NULL); @@ -2337,15 +3526,23 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd) eloop_cancel_timeout(hostapd_dpp_conn_status_result_wait_timeout, hapd, NULL); hostapd_dpp_chirp_stop(hapd); - if (hapd->iface->interfaces) + if (hapd->iface->interfaces) { + dpp_relay_stop_listen(hapd->iface->interfaces->dpp); dpp_controller_stop_for_ctx(hapd->iface->interfaces->dpp, hapd); + } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + eloop_cancel_timeout(hostapd_dpp_build_new_key, hapd, NULL); + hostapd_dpp_push_button_stop(hapd); +#endif /* CONFIG_DPP3 */ dpp_auth_deinit(hapd->dpp_auth); hapd->dpp_auth = NULL; hostapd_dpp_pkex_remove(hapd, "*"); hapd->dpp_pkex = NULL; os_free(hapd->dpp_configurator_params); hapd->dpp_configurator_params = NULL; + os_free(hapd->dpp_pkex_auth_cmd); + hapd->dpp_pkex_auth_cmd = NULL; } @@ -2718,3 +3915,99 @@ void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi) } #endif /* CONFIG_DPP2 */ + + +#ifdef CONFIG_DPP3 + +static void hostapd_dpp_push_button_expire(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + + wpa_printf(MSG_DEBUG, "DPP: Active push button mode expired"); + hostapd_dpp_push_button_stop(hapd); +} + + +int hostapd_dpp_push_button(struct hostapd_data *hapd, const char *cmd) +{ + struct hapd_interfaces *ifaces = hapd->iface->interfaces; + + if (!ifaces || !ifaces->dpp) + return -1; + os_get_reltime(&ifaces->dpp_pb_time); + ifaces->dpp_pb_announce_time.sec = 0; + ifaces->dpp_pb_announce_time.usec = 0; + str_clear_free(ifaces->dpp_pb_cmd); + ifaces->dpp_pb_cmd = NULL; + if (cmd) { + ifaces->dpp_pb_cmd = os_strdup(cmd); + if (!ifaces->dpp_pb_cmd) + return -1; + } + eloop_register_timeout(100, 0, hostapd_dpp_push_button_expire, + hapd, NULL); + + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_PB_STATUS "started"); + return 0; +} + + +void hostapd_dpp_push_button_stop(struct hostapd_data *hapd) +{ + struct hapd_interfaces *ifaces = hapd->iface->interfaces; + + if (!ifaces || !ifaces->dpp) + return; + eloop_cancel_timeout(hostapd_dpp_push_button_expire, hapd, NULL); + if (hostapd_dpp_pb_active(hapd)) { + wpa_printf(MSG_DEBUG, "DPP: Stop active push button mode"); + if (!ifaces->dpp_pb_result_indicated) + wpa_msg(hapd->msg_ctx, MSG_INFO, + DPP_EVENT_PB_RESULT "failed"); + } + ifaces->dpp_pb_time.sec = 0; + ifaces->dpp_pb_time.usec = 0; + dpp_pkex_free(hapd->dpp_pkex); + hapd->dpp_pkex = NULL; + hapd->dpp_pkex_bi = NULL; + os_free(hapd->dpp_pkex_auth_cmd); + hapd->dpp_pkex_auth_cmd = NULL; + + if (ifaces->dpp_pb_bi) { + char id[20]; + size_t i; + + for (i = 0; i < ifaces->count; i++) { + struct hostapd_iface *iface = ifaces->iface[i]; + size_t j; + + for (j = 0; iface && j < iface->num_bss; j++) { + struct hostapd_data *h = iface->bss[j]; + + if (h->dpp_pkex_bi == ifaces->dpp_pb_bi) + h->dpp_pkex_bi = NULL; + } + } + + os_snprintf(id, sizeof(id), "%u", ifaces->dpp_pb_bi->id); + dpp_bootstrap_remove(ifaces->dpp, id); + ifaces->dpp_pb_bi = NULL; + } + + ifaces->dpp_pb_result_indicated = false; + + str_clear_free(ifaces->dpp_pb_cmd); + ifaces->dpp_pb_cmd = NULL; +} + +#endif /* CONFIG_DPP3 */ + + +#ifdef CONFIG_DPP2 +bool hostapd_dpp_configurator_connectivity(struct hostapd_data *hapd) +{ + return hapd->conf->dpp_configurator_connectivity || + (hapd->iface->interfaces && + dpp_relay_controller_available(hapd->iface->interfaces->dpp)); +} +#endif /* CONFIG_DPP2 */ diff --git a/wpa_supplicant-2.9_standard/src/ap/dpp_hostapd.h b/wpa_supplicant-2.9_standard/src/ap/dpp_hostapd.h index 264d3e4c0166fb62b15cba2328c01a41b5f5a7a1..55f1fce22d1ac8839fa50a44aa0883537a5bcb93 100644 --- a/wpa_supplicant-2.9_standard/src/ap/dpp_hostapd.h +++ b/wpa_supplicant-2.9_standard/src/ap/dpp_hostapd.h @@ -45,5 +45,10 @@ int hostapd_dpp_controller_start(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_chirp(struct hostapd_data *hapd, const char *cmd); void hostapd_dpp_chirp_stop(struct hostapd_data *hapd); void hostapd_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi); +int hostapd_dpp_push_button(struct hostapd_data *hapd, const char *cmd); +void hostapd_dpp_push_button_stop(struct hostapd_data *hapd); +bool hostapd_dpp_configurator_connectivity(struct hostapd_data *hapd); +int hostapd_dpp_add_controller(struct hostapd_data *hapd, const char *cmd); +void hostapd_dpp_remove_controller(struct hostapd_data *hapd, const char *cmd); #endif /* DPP_HOSTAPD_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/drv_callbacks.c b/wpa_supplicant-2.9_standard/src/ap/drv_callbacks.c index 0f2761c2147f91a26270e0f00a736ad34fe7936f..ac6b492410406b12c4d9dbed61ebdb206b46c912 100755 --- a/wpa_supplicant-2.9_standard/src/ap/drv_callbacks.c +++ b/wpa_supplicant-2.9_standard/src/ap/drv_callbacks.c @@ -42,6 +42,7 @@ #include "dpp_hostapd.h" #include "fils_hlp.h" #include "neighbor_db.h" +#include "nan_usd_ap.h" #ifdef CONFIG_VENDOR_EXT #include "vendor_ext.h" #endif @@ -67,6 +68,7 @@ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd, struct ieee802_11_elems elems; u8 buf[IEEE80211_MAX_MMPDU_SIZE], *p = buf; int new_assoc; + bool updated; wpa_printf(MSG_DEBUG, "%s FILS: Finish association with " MACSTR_SEC, __func__, MAC2STR_SEC(sta->addr)); @@ -74,9 +76,10 @@ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd, if (!sta->fils_pending_assoc_req) return; - ieee802_11_parse_elems(sta->fils_pending_assoc_req, - sta->fils_pending_assoc_req_len, &elems, 0); - if (!elems.fils_session) { + if (ieee802_11_parse_elems(sta->fils_pending_assoc_req, + sta->fils_pending_assoc_req_len, &elems, + 0) == ParseFailed || + !elems.fils_session) { wpa_printf(MSG_DEBUG, "%s failed to find FILS Session element", __func__); return; @@ -90,11 +93,13 @@ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd, sta->fils_pending_assoc_is_reassoc, WLAN_STATUS_SUCCESS, buf, p - buf); - ap_sta_set_authorized(hapd, sta, 1); + updated = ap_sta_set_authorized_flag(hapd, sta, 1); new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; hostapd_set_sta_flags(hapd, sta); + if (updated) + ap_sta_set_authorized_event(hapd, sta, 1); wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); hostapd_new_assoc_sta(hapd, sta, !new_assoc); @@ -146,8 +151,122 @@ static bool check_sa_query_need(struct hostapd_data *hapd, struct sta_info *sta) } +#ifdef CONFIG_IEEE80211BE +static int hostapd_update_sta_links_status(struct hostapd_data *hapd, + struct sta_info *sta, + const u8 *resp_ies, + size_t resp_ies_len) +{ + struct mld_info *info = &sta->mld_info; + struct wpabuf *mlebuf; + const u8 *mle, *pos; + struct ieee802_11_elems elems; + size_t mle_len, rem_len; + int ret = 0; + + if (!resp_ies) { + wpa_printf(MSG_DEBUG, + "MLO: (Re)Association Response frame elements not available"); + return -1; + } + + if (ieee802_11_parse_elems(resp_ies, resp_ies_len, &elems, 0) == + ParseFailed) { + wpa_printf(MSG_DEBUG, + "MLO: Failed to parse (Re)Association Response frame elements"); + return -1; + } + + mlebuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true); + if (!mlebuf) { + wpa_printf(MSG_ERROR, + "MLO: Basic Multi-Link element not found in (Re)Association Response frame"); + return -1; + } + + mle = wpabuf_head(mlebuf); + mle_len = wpabuf_len(mlebuf); + if (mle_len < MULTI_LINK_CONTROL_LEN + 1 || + mle_len - MULTI_LINK_CONTROL_LEN < mle[MULTI_LINK_CONTROL_LEN]) { + wpa_printf(MSG_ERROR, + "MLO: Invalid Multi-Link element in (Re)Association Response frame"); + ret = -1; + goto out; + } + + /* Skip Common Info */ + pos = mle + MULTI_LINK_CONTROL_LEN + mle[MULTI_LINK_CONTROL_LEN]; + rem_len = mle_len - + (MULTI_LINK_CONTROL_LEN + mle[MULTI_LINK_CONTROL_LEN]); + + /* Parse Subelements */ + while (rem_len > 2) { + size_t ie_len = 2 + pos[1]; + + if (rem_len < ie_len) + break; + + if (pos[0] == MULTI_LINK_SUB_ELEM_ID_PER_STA_PROFILE) { + u8 link_id; + const u8 *sta_profile; + size_t sta_profile_len; + u16 sta_ctrl; + + if (pos[1] < BASIC_MLE_STA_CTRL_LEN + 1) { + wpa_printf(MSG_DEBUG, + "MLO: Invalid per-STA profile IE"); + goto next_subelem; + } + + sta_profile_len = pos[1]; + sta_profile = &pos[2]; + sta_ctrl = WPA_GET_LE16(sta_profile); + link_id = sta_ctrl & BASIC_MLE_STA_CTRL_LINK_ID_MASK; + if (link_id >= MAX_NUM_MLD_LINKS) { + wpa_printf(MSG_DEBUG, + "MLO: Invalid link ID in per-STA profile IE"); + goto next_subelem; + } + + /* Skip STA Control and STA Info */ + if (sta_profile_len - BASIC_MLE_STA_CTRL_LEN < + sta_profile[BASIC_MLE_STA_CTRL_LEN]) { + wpa_printf(MSG_DEBUG, + "MLO: Invalid STA info in per-STA profile IE"); + goto next_subelem; + } + + sta_profile_len = sta_profile_len - + (BASIC_MLE_STA_CTRL_LEN + + sta_profile[BASIC_MLE_STA_CTRL_LEN]); + sta_profile = sta_profile + BASIC_MLE_STA_CTRL_LEN + + sta_profile[BASIC_MLE_STA_CTRL_LEN]; + + /* Skip Capabilities Information field */ + if (sta_profile_len < 2) + goto next_subelem; + sta_profile_len -= 2; + sta_profile += 2; + + /* Get status of the link */ + info->links[link_id].status = WPA_GET_LE16(sta_profile); + } +next_subelem: + pos += ie_len; + rem_len -= ie_len; + } + +out: + wpabuf_free(mlebuf); + return ret; +} +#endif /* CONFIG_IEEE80211BE */ + + int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, - const u8 *req_ies, size_t req_ies_len, int reassoc) + const u8 *req_ies, size_t req_ies_len, + const u8 *resp_ies, size_t resp_ies_len, + const u8 *link_addr, int reassoc) { struct sta_info *sta; int new_assoc; @@ -160,6 +279,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, u16 reason = WLAN_REASON_UNSPECIFIED; int status = WLAN_STATUS_SUCCESS; const u8 *p2p_dev_addr = NULL; +#ifdef CONFIG_OWE + struct hostapd_iface *iface = hapd->iface; +#endif /* CONFIG_OWE */ + bool updated = false; if (addr == NULL) { /* @@ -181,7 +304,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, if (is_multicast_ether_addr(addr) || is_zero_ether_addr(addr) || - os_memcmp(addr, hapd->own_addr, ETH_ALEN) == 0) { + ether_addr_equal(addr, hapd->own_addr)) { /* Do not process any frames with unexpected/invalid SA so that * we do not add any state for unexpected STA addresses or end * up sending out frames to unexpected destination. */ @@ -204,7 +327,13 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, wpa_supplicant_upload_go_p2p_state(hapd, addr, P2P_INTERFACE_STATE_ASSOCIATING, P2P_CHR_DEFAULT_REASON_CODE); #endif - ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0); + + if (ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0) == + ParseFailed) { + wpa_printf(MSG_DEBUG, "%s: Could not parse elements", __func__); + return -1; + } + if (elems.wps_ie) { ie = elems.wps_ie - 2; ielen = elems.wps_ie_len + 2; @@ -248,6 +377,57 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, return -1; } } + + if (hapd->conf->wpa && 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); +#ifdef CONFIG_P2P_CHR + wpa_supplicant_upload_go_p2p_state(hapd, addr, + P2P_INTERFACE_STATE_DISCONNECTED, + DR_ASSOCIATING_REJECT_BY_GO); +#endif + return 0; + } + +#ifdef CONFIG_IEEE80211BE + if (link_addr) { + struct mld_info *info = &sta->mld_info; + int i, num_valid_links = 0; + u8 link_id = hapd->mld_link_id; + + ap_sta_set_mld(sta, true); + sta->mld_assoc_link_id = link_id; + os_memcpy(info->common_info.mld_addr, addr, ETH_ALEN); + info->links[link_id].valid = true; + os_memcpy(info->links[link_id].peer_addr, link_addr, ETH_ALEN); + os_memcpy(info->links[link_id].local_addr, hapd->own_addr, + ETH_ALEN); + + if (!elems.basic_mle || + hostapd_process_ml_assoc_req(hapd, &elems, sta) != + WLAN_STATUS_SUCCESS) { + reason = WLAN_REASON_UNSPECIFIED; + wpa_printf(MSG_DEBUG, + "Failed to get STA non-assoc links info"); + goto fail; + } + + for (i = 0 ; i < MAX_NUM_MLD_LINKS; i++) { + if (info->links[i].valid) + num_valid_links++; + } + if (num_valid_links > 1 && + hostapd_update_sta_links_status(hapd, sta, resp_ies, + resp_ies_len)) { + wpa_printf(MSG_DEBUG, + "Failed to get STA non-assoc links status info"); + reason = WLAN_REASON_UNSPECIFIED; + goto fail; + } + } +#endif /* CONFIG_IEEE80211BE */ + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); /* @@ -289,12 +469,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, } #endif /* NEED_AP_MLME */ -#ifdef CONFIG_INTERWORKING - if (elems.ext_capab && elems.ext_capab_len > 4) { - if (elems.ext_capab[4] & 0x01) - sta->qos_map_enabled = 1; - } -#endif /* CONFIG_INTERWORKING */ + check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len); #ifdef CONFIG_HS20 wpabuf_free(sta->hs20_ie); @@ -347,22 +522,6 @@ 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); -#ifdef CONFIG_P2P_CHR - wpa_supplicant_upload_go_p2p_state(hapd, addr, - P2P_INTERFACE_STATE_DISCONNECTED, - DR_ASSOCIATING_REJECT_BY_GO); -#endif - return 0; - } - sta->flags |= WLAN_STA_WPS; wps = ieee802_11_vendor_ie_concat(ie, ielen, WPS_IE_VENDOR_TYPE); @@ -392,13 +551,22 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, #endif return -1; } +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) { + wpa_printf(MSG_DEBUG, + "MLD: Set ML info in RSN Authenticator"); + wpa_auth_set_ml_info(sta->wpa_sm, + sta->mld_assoc_link_id, + &sta->mld_info); + } +#endif /* CONFIG_IEEE80211BE */ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, hapd->iface->freq, ie, ielen, elems.rsnxe ? elems.rsnxe - 2 : NULL, elems.rsnxe ? elems.rsnxe_len + 2 : 0, elems.mdie, elems.mdie_len, - elems.owe_dh, elems.owe_dh_len); + elems.owe_dh, elems.owe_dh_len, NULL); reason = WLAN_REASON_INVALID_IE; status = WLAN_STATUS_INVALID_IE; switch (res) { @@ -463,21 +631,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, goto fail; } - 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); -#ifdef CONFIG_P2P_CHR - wpa_supplicant_upload_go_p2p_state(hapd, addr, - P2P_INTERFACE_STATE_DISCONNECTED, - DR_ASSOCIATING_REJECT_BY_GO); -#endif - return 0; - } - if (wpa_auth_uses_mfp(sta->wpa_sm)) sta->flags |= WLAN_STA_MFP; else @@ -499,7 +652,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, } #endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_SAE - if (hapd->conf->sae_pwe == 2 && + if (hapd->conf->sae_pwe == SAE_PWE_BOTH && sta->auth_alg == WLAN_AUTH_SAE && sta->sae && !sta->sae->h2e && ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, @@ -691,6 +844,7 @@ skip_wpa_check: #ifdef CONFIG_OWE if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && + !(iface->drv_flags2 & WPA_DRIVER_FLAGS2_OWE_OFFLOAD_AP) && wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE && elems.owe_dh) { u8 *npos; @@ -765,18 +919,30 @@ skip_wpa_check: sta->auth_alg == WLAN_AUTH_FILS_SK || sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || sta->auth_alg == WLAN_AUTH_FILS_PK) - ap_sta_set_authorized(hapd, sta, 1); + updated = ap_sta_set_authorized_flag(hapd, sta, 1); #else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */ /* Keep compiler silent about unused variables */ if (status) { } #endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */ +#ifdef CONFIG_IEEE80211BE + if (hostapd_process_assoc_ml_info(hapd, sta, req_ies, req_ies_len, + !!reassoc, WLAN_STATUS_SUCCESS, + true)) { + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + reason = WLAN_REASON_UNSPECIFIED; + goto fail; + } +#endif /* CONFIG_IEEE80211BE */ + new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; hostapd_set_sta_flags(hapd, sta); + if (updated) + ap_sta_set_authorized_event(hapd, sta, 1); #ifdef CONFIG_VENDOR_EXT int result = wpa_vendor_ext_process_hostapd_assoc(hapd, req_ies, req_ies_len, sta); @@ -824,6 +990,54 @@ fail: } +static void hostapd_remove_sta(struct hostapd_data *hapd, struct sta_info *sta) +{ + ap_sta_set_authorized(hapd, sta, 0); + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); + hostapd_set_sta_flags(hapd, sta); + wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); + sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; + ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); + ap_free_sta(hapd, sta); +} + + +#ifdef CONFIG_IEEE80211BE +static void hostapd_notif_disassoc_mld(struct hostapd_data *assoc_hapd, + struct sta_info *sta, + const u8 *addr) +{ + unsigned int link_id, i; + struct hostapd_data *tmp_hapd; + struct hapd_interfaces *interfaces = assoc_hapd->iface->interfaces; + + /* Remove STA entry in non-assoc links */ + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sta->mld_info.links[link_id].valid) + continue; + + for (i = 0; i < interfaces->count; i++) { + struct sta_info *tmp_sta; + + tmp_hapd = interfaces->iface[i]->bss[0]; + + if (!tmp_hapd->conf->mld_ap || + assoc_hapd == tmp_hapd || + assoc_hapd->conf->mld_id != tmp_hapd->conf->mld_id) + continue; + + tmp_sta = ap_get_sta(tmp_hapd, addr); + if (tmp_sta) + ap_free_sta(tmp_hapd, tmp_sta); + } + } + + /* Remove STA in assoc link */ + hostapd_remove_sta(assoc_hapd, sta); +} +#endif /* CONFIG_IEEE80211BE */ + + void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) { struct sta_info *sta; @@ -845,6 +1059,50 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) HOSTAPD_LEVEL_INFO, "disassociated"); sta = ap_get_sta(hapd, addr); +#ifdef CONFIG_IEEE80211BE + if (hostapd_is_mld_ap(hapd)) { + struct hostapd_data *assoc_hapd; + unsigned int i; + + if (!sta) { + /* Find non-MLO cases from any of the affiliated AP + * links. */ + for (i = 0; i < hapd->iface->interfaces->count; ++i) { + struct hostapd_iface *h = + hapd->iface->interfaces->iface[i]; + struct hostapd_data *h_hapd = h->bss[0]; + struct hostapd_bss_config *hconf = h_hapd->conf; + + if (!hconf->mld_ap || + hconf->mld_id != hapd->conf->mld_id) + continue; + + sta = ap_get_sta(h_hapd, addr); + if (sta) { + if (!sta->mld_info.mld_sta) { + hapd = h_hapd; + goto legacy; + } + break; + } + } + } else if (!sta->mld_info.mld_sta) { + goto legacy; + } + if (!sta) { + wpa_printf(MSG_DEBUG, + "Disassociation notification for unknown STA " + MACSTR_SEC, MAC2STR_SEC(addr)); + return; + } + sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd); + if (sta) + hostapd_notif_disassoc_mld(assoc_hapd, sta, addr); + return; + } + +legacy: +#endif /* CONFIG_IEEE80211BE */ if (sta == NULL) { wpa_printf(MSG_DEBUG, "Disassociation notification for unknown STA " @@ -852,13 +1110,7 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) return; } - ap_sta_set_authorized(hapd, sta, 0); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); - hostapd_set_sta_flags(hapd, sta); - wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); - sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - ap_free_sta(hapd, sta); + hostapd_remove_sta(hapd, sta); } @@ -928,6 +1180,9 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr, case CHAN_WIDTH_160: txt = "160"; break; + case CHAN_WIDTH_320: + txt = "320"; + break; default: txt = NULL; break; @@ -946,21 +1201,24 @@ void hostapd_event_sta_opmode_changed(struct hostapd_data *hapd, const u8 *addr, void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, int offset, int width, int cf1, int cf2, - int finished) + u16 punct_bitmap, int finished) { #define VENDOR_EXT_CHANNEL_SWITCH 4 #ifdef NEED_AP_MLME - int channel, chwidth, is_dfs; - u8 seg0_idx = 0, seg1_idx = 0; + int channel, chwidth, is_dfs0, is_dfs; + u8 seg0_idx = 0, seg1_idx = 0, op_class, chan_no; size_t i; hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, - "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", + "driver %s channel switch: iface->freq=%d, freq=%d, ht=%d, vht_ch=0x%x, he_ch=0x%x, eht_ch=0x%x, offset=%d, width=%d (%s), cf1=%d, cf2=%d, puncturing_bitmap=0x%x", finished ? "had" : "starting", + hapd->iface->freq, freq, ht, hapd->iconf->ch_switch_vht_config, - hapd->iconf->ch_switch_he_config, offset, - width, channel_width_to_string(width), cf1, cf2); + hapd->iconf->ch_switch_he_config, + hapd->iconf->ch_switch_eht_config, offset, + width, channel_width_to_string(width), cf1, cf2, + punct_bitmap); if (!hapd->iface->current_mode) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, @@ -969,6 +1227,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, return; } + /* Check if any of configured channels require DFS */ + is_dfs0 = hostapd_is_dfs_required(hapd->iface); hapd->iface->freq = freq; channel = hostapd_hw_get_channel(hapd, freq); @@ -981,22 +1241,31 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, switch (width) { case CHAN_WIDTH_80: - chwidth = CHANWIDTH_80MHZ; + chwidth = CONF_OPER_CHWIDTH_80MHZ; break; case CHAN_WIDTH_80P80: - chwidth = CHANWIDTH_80P80MHZ; + chwidth = CONF_OPER_CHWIDTH_80P80MHZ; break; case CHAN_WIDTH_160: - chwidth = CHANWIDTH_160MHZ; + chwidth = CONF_OPER_CHWIDTH_160MHZ; + break; + case CHAN_WIDTH_320: + chwidth = CONF_OPER_CHWIDTH_320MHZ; break; case CHAN_WIDTH_20_NOHT: case CHAN_WIDTH_20: case CHAN_WIDTH_40: default: - chwidth = CHANWIDTH_USE_HT; + chwidth = CONF_OPER_CHWIDTH_USE_HT; break; } + /* The operating channel changed when CSA finished, so need to update + * hw_mode for all following operations to cover the cases where the + * driver changed the operating band. */ + if (finished && hostapd_csa_update_hwmode(hapd->iface)) + return; + switch (hapd->iface->current_mode->mode) { case HOSTAPD_MODE_IEEE80211A: if (cf1 == 5935) @@ -1021,9 +1290,9 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hapd->iconf->channel = channel; hapd->iconf->ieee80211n = ht; - if (!ht) { + if (!ht) hapd->iconf->ieee80211ac = 0; - } else if (hapd->iconf->ch_switch_vht_config) { + if (hapd->iconf->ch_switch_vht_config) { /* CHAN_SWITCH VHT config */ if (hapd->iconf->ch_switch_vht_config & CH_SWITCH_VHT_ENABLED) @@ -1031,34 +1300,65 @@ 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) { + } + if (hapd->iconf->ch_switch_he_config) { /* CHAN_SWITCH HE config */ if (hapd->iconf->ch_switch_he_config & - CH_SWITCH_HE_ENABLED) + CH_SWITCH_HE_ENABLED) { hapd->iconf->ieee80211ax = 1; + if (hapd->iface->freq > 4000 && + hapd->iface->freq < 5895) + hapd->iconf->ieee80211ac = 1; + } else if (hapd->iconf->ch_switch_he_config & CH_SWITCH_HE_DISABLED) hapd->iconf->ieee80211ax = 0; } +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ch_switch_eht_config) { + /* CHAN_SWITCH EHT config */ + if (hapd->iconf->ch_switch_eht_config & + CH_SWITCH_EHT_ENABLED) { + hapd->iconf->ieee80211be = 1; + hapd->iconf->ieee80211ax = 1; + if (!is_6ghz_freq(hapd->iface->freq) && + hapd->iface->freq > 4000) + hapd->iconf->ieee80211ac = 1; + } else if (hapd->iconf->ch_switch_eht_config & + CH_SWITCH_EHT_DISABLED) + hapd->iconf->ieee80211be = 0; + } +#endif /* CONFIG_IEEE80211BE */ hapd->iconf->ch_switch_vht_config = 0; hapd->iconf->ch_switch_he_config = 0; + hapd->iconf->ch_switch_eht_config = 0; if (width == CHAN_WIDTH_40 || width == CHAN_WIDTH_80 || - width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160) + width == CHAN_WIDTH_80P80 || width == CHAN_WIDTH_160 || + width == CHAN_WIDTH_320) hapd->iconf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; else if (width == CHAN_WIDTH_20 || width == CHAN_WIDTH_20_NOHT) hapd->iconf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; hapd->iconf->secondary_channel = offset; + if (ieee80211_freq_to_channel_ext(freq, offset, chwidth, + &op_class, &chan_no) != + NUM_HOSTAPD_MODES) + hapd->iconf->op_class = op_class; hostapd_set_oper_chwidth(hapd->iconf, chwidth); hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, seg0_idx); hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, seg1_idx); + /* Auto-detect new bw320_offset */ + hostapd_set_and_check_bw320_offset(hapd->iconf, 0); +#ifdef CONFIG_IEEE80211BE + hapd->iconf->punct_bitmap = punct_bitmap; +#endif /* CONFIG_IEEE80211BE */ if (hapd->iconf->ieee80211ac) { hapd->iconf->vht_capab &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK; - if (chwidth == CHANWIDTH_160MHZ) + if (chwidth == CONF_OPER_CHWIDTH_160MHZ) hapd->iconf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; - else if (chwidth == CHANWIDTH_80P80MHZ) + else if (chwidth == CONF_OPER_CHWIDTH_80P80MHZ) hapd->iconf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; } @@ -1067,11 +1367,11 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hapd->iface->num_hw_features); wpa_msg(hapd->msg_ctx, MSG_INFO, - "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d dfs=%d", + "%sfreq=%d ht_enabled=%d ch_offset=%d ch_width=%s cf1=%d cf2=%d is_dfs0=%d dfs=%d puncturing_bitmap=0x%04x", finished ? WPA_EVENT_CHANNEL_SWITCH : WPA_EVENT_CHANNEL_SWITCH_STARTED, freq, ht, offset, channel_width_to_string(width), - cf1, cf2, is_dfs); + cf1, cf2, is_dfs0, is_dfs, punct_bitmap); #ifdef CONFIG_LIBWPA_VENDOR if (finished) { struct WpaVendorExtInfo wpaVendorExtInfo; @@ -1107,6 +1407,14 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, } #endif } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { + /* Complete AP configuration for the first bring up. */ + if (is_dfs0 > 0 && + hostapd_is_dfs_required(hapd->iface) <= 0 && + hapd->iface->state != HAPD_IFACE_ENABLED) { + /* Fake a CAC start bit to skip setting channel */ + hapd->iface->cac_started = 1; + hostapd_setup_interface_complete(hapd->iface, 0); + } wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d dfs=%d", freq, is_dfs); #ifdef CONFIG_LIBWPA_VENDOR @@ -1133,7 +1441,9 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hostapd_neighbor_set_own_report(hapd->iface->bss[i]); #ifdef CONFIG_OCV - if (hapd->conf->ocv) { + if (hapd->conf->ocv && + !(hapd->iface->drv_flags2 & + WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP)) { struct sta_info *sta; bool check_sa_query = false; @@ -1192,6 +1502,18 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd, int err = 0; struct hostapd_channel_data *pri_chan; +#ifdef CONFIG_IEEE80211BE + if (acs_res->link_id != -1) { + hapd = hostapd_mld_get_link_bss(hapd, acs_res->link_id); + if (!hapd) { + wpa_printf(MSG_ERROR, + "MLD: Failed to get link BSS for EVENT_ACS_CHANNEL_SELECTED link_id=%d", + acs_res->link_id); + return; + } + } +#endif /* CONFIG_IEEE80211BE */ + if (hapd->iconf->channel) { wpa_printf(MSG_INFO, "ACS: Channel was already set to %d", hapd->iconf->channel); @@ -1265,7 +1587,7 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd, /* set defaults for backwards compatibility */ hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0); hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0); - hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT); + hostapd_set_oper_chwidth(hapd->iconf, CONF_OPER_CHWIDTH_USE_HT); if (acs_res->ch_width == 40) { if (is_6ghz_freq(acs_res->pri_freq)) hostapd_set_oper_centr_freq_seg0_idx( @@ -1275,22 +1597,36 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd, hostapd_set_oper_centr_freq_seg0_idx( hapd->iconf, acs_res->vht_seg0_center_ch); if (acs_res->vht_seg1_center_ch == 0) { - hostapd_set_oper_chwidth(hapd->iconf, - CHANWIDTH_80MHZ); + hostapd_set_oper_chwidth( + hapd->iconf, CONF_OPER_CHWIDTH_80MHZ); } else { - hostapd_set_oper_chwidth(hapd->iconf, - CHANWIDTH_80P80MHZ); + hostapd_set_oper_chwidth( + hapd->iconf, + CONF_OPER_CHWIDTH_80P80MHZ); hostapd_set_oper_centr_freq_seg1_idx( hapd->iconf, acs_res->vht_seg1_center_ch); } } else if (acs_res->ch_width == 160) { - hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ); + hostapd_set_oper_chwidth(hapd->iconf, + CONF_OPER_CHWIDTH_160MHZ); hostapd_set_oper_centr_freq_seg0_idx( hapd->iconf, acs_res->vht_seg1_center_ch); } } +#ifdef CONFIG_IEEE80211BE + if (hapd->iface->conf->ieee80211be && acs_res->ch_width == 320) { + hostapd_set_oper_chwidth(hapd->iconf, CONF_OPER_CHWIDTH_320MHZ); + hostapd_set_oper_centr_freq_seg0_idx( + hapd->iconf, acs_res->vht_seg1_center_ch); + hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0); + } + + if (hapd->iface->conf->ieee80211be && acs_res->puncture_bitmap) + hapd->iconf->punct_bitmap = acs_res->puncture_bitmap; +#endif /* CONFIG_IEEE80211BE */ + out: ret = hostapd_acs_completed(hapd->iface, err); if (ret) { @@ -1328,7 +1664,6 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, #ifdef CONFIG_IEEE80211R_AP static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst, - const u8 *bssid, u16 auth_transaction, u16 status, const u8 *ies, size_t ies_len) { @@ -1404,7 +1739,7 @@ static void hostapd_notif_auth(struct hostapd_data *hapd, status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } - wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid, + wpa_ft_process_auth(sta->wpa_sm, rx_auth->auth_transaction, rx_auth->ies, rx_auth->ies_len, hostapd_notify_auth_ft_finish, hapd); @@ -1484,6 +1819,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd, #endif /* CONFIG_FST */ #ifdef CONFIG_DPP if (plen >= 2 + 4 && + mgmt->u.action.category == WLAN_ACTION_PUBLIC && mgmt->u.action.u.vs_public_action.action == WLAN_PA_VENDOR_SPECIFIC && WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == @@ -1499,16 +1835,78 @@ static void hostapd_action_rx(struct hostapd_data *hapd, return; } #endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + if (mgmt->u.action.category == WLAN_ACTION_PUBLIC && plen >= 5 && + mgmt->u.action.u.vs_public_action.action == + WLAN_PA_VENDOR_SPECIFIC && + WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == + OUI_WFA && + mgmt->u.action.u.vs_public_action.variable[0] == NAN_OUI_TYPE) { + const u8 *pos, *end; + + pos = mgmt->u.action.u.vs_public_action.variable; + end = drv_mgmt->frame + drv_mgmt->frame_len; + pos++; + hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, drv_mgmt->freq, + pos, end - pos); + return; + } +#endif /* CONFIG_NAN_USD */ } #endif /* NEED_AP_MLME */ #ifdef NEED_AP_MLME +static struct hostapd_data * +switch_link_hapd(struct hostapd_data *hapd, int link_id) +{ +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap && link_id >= 0) { + struct hostapd_data *link_bss; + + link_bss = hostapd_mld_get_link_bss(hapd, link_id); + if (link_bss) + return link_bss; + } +#endif /* CONFIG_IEEE80211BE */ + + return hapd; +} + + +static struct hostapd_data * +switch_link_scan(struct hostapd_data *hapd, u64 scan_cookie) +{ +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap && scan_cookie != 0) { + unsigned int i; + + for (i = 0; i < hapd->iface->interfaces->count; i++) { + struct hostapd_iface *h; + struct hostapd_data *h_hapd; + + h = hapd->iface->interfaces->iface[i]; + h_hapd = h->bss[0]; + if (!hostapd_is_ml_partner(hapd, h_hapd)) + continue; + + if (h_hapd->scan_cookie == scan_cookie) { + h_hapd->scan_cookie = 0; + return h_hapd; + } + } + } +#endif /* CONFIG_IEEE80211BE */ + + return hapd; +} + + #define HAPD_BROADCAST ((struct hostapd_data *) -1) static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, - const u8 *bssid) + const u8 *bssid, int link_id) { size_t i; @@ -1519,8 +1917,35 @@ static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface, return HAPD_BROADCAST; for (i = 0; i < iface->num_bss; i++) { - if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) - return iface->bss[i]; + struct hostapd_data *hapd; +#ifdef CONFIG_IEEE80211BE + struct hostapd_data *p_hapd; +#endif /* CONFIG_IEEE80211BE */ + + hapd = iface->bss[i]; + if (ether_addr_equal(bssid, hapd->own_addr)) + return hapd; + +#ifdef CONFIG_IEEE80211BE + if (ether_addr_equal(bssid, hapd->own_addr) || + (hapd->conf->mld_ap && + ether_addr_equal(bssid, hapd->mld->mld_addr) && + link_id == hapd->mld_link_id)) + return hapd; + + if (!hapd->conf->mld_ap) + continue; + + for_each_mld_link(p_hapd, hapd) { + if (p_hapd == hapd) + continue; + + if (ether_addr_equal(bssid, p_hapd->own_addr) || + (ether_addr_equal(bssid, p_hapd->mld->mld_addr) && + link_id == p_hapd->mld_link_id)) + return p_hapd; + } +#endif /* CONFIG_IEEE80211BE */ } return NULL; @@ -1531,7 +1956,7 @@ static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, const u8 *bssid, const u8 *addr, int wds) { - hapd = get_hapd_bssid(hapd->iface, bssid); + hapd = get_hapd_bssid(hapd->iface, bssid, -1); if (hapd == NULL || hapd == HAPD_BROADCAST) return; @@ -1541,12 +1966,17 @@ static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) { - struct hostapd_iface *iface = hapd->iface; + struct hostapd_iface *iface; const struct ieee80211_hdr *hdr; const u8 *bssid; struct hostapd_frame_info fi; int ret; + if (rx_mgmt->ctx) + hapd = rx_mgmt->ctx; + hapd = switch_link_hapd(hapd, rx_mgmt->link_id); + iface = hapd->iface; + #ifdef CONFIG_TESTING_OPTIONS if (hapd->ext_mgmt_frame_handling) { size_t hex_len = 2 * rx_mgmt->frame_len + 1; @@ -1567,8 +1997,9 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) if (bssid == NULL) return 0; - hapd = get_hapd_bssid(iface, bssid); - if (hapd == NULL) { + hapd = get_hapd_bssid(iface, bssid, rx_mgmt->link_id); + + if (!hapd) { u16 fc = le_to_host16(hdr->frame_control); /* @@ -1613,20 +2044,33 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt) static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf, - size_t len, u16 stype, int ok) + size_t len, u16 stype, int ok, int link_id) { struct ieee80211_hdr *hdr; - struct hostapd_data *orig_hapd = hapd; + struct hostapd_data *orig_hapd, *tmp_hapd; + + orig_hapd = hapd; hdr = (struct ieee80211_hdr *) buf; - hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len)); - if (!hapd) + hapd = switch_link_hapd(hapd, link_id); + tmp_hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len), link_id); + if (tmp_hapd) { + hapd = tmp_hapd; +#ifdef CONFIG_IEEE80211BE + } else if (hapd->conf->mld_ap && + ether_addr_equal(hapd->mld->mld_addr, + get_hdr_bssid(hdr, len))) { + /* AP MLD address match - use hapd pointer as-is */ +#endif /* CONFIG_IEEE80211BE */ + } else { return; + } + if (hapd == HAPD_BROADCAST) { if (stype != WLAN_FC_STYPE_ACTION || len <= 25 || buf[24] != WLAN_ACTION_PUBLIC) return; - hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2); + hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2, link_id); if (!hapd || hapd == HAPD_BROADCAST) return; /* @@ -1662,22 +2106,76 @@ static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr) } -static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, - const u8 *data, size_t data_len) +static struct hostapd_data * hostapd_find_by_sta(struct hostapd_iface *iface, + const u8 *src, bool rsn, + struct sta_info **sta_ret) { - struct hostapd_iface *iface = hapd->iface; + struct hostapd_data *hapd; struct sta_info *sta; - size_t j; + unsigned int j; + + if (sta_ret) + *sta_ret = NULL; for (j = 0; j < iface->num_bss; j++) { - sta = ap_get_sta(iface->bss[j], src); - if (sta && sta->flags & WLAN_STA_ASSOC) { - hapd = iface->bss[j]; - break; + hapd = iface->bss[j]; + sta = ap_get_sta(hapd, src); + if (sta && (sta->flags & WLAN_STA_ASSOC) && + (!rsn || sta->wpa_sm)) { + if (sta_ret) + *sta_ret = sta; + return hapd; } +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) { + struct hostapd_data *p_hapd; + + for_each_mld_link(p_hapd, hapd) { + if (p_hapd == hapd) + continue; + + sta = ap_get_sta(p_hapd, src); + if (sta && (sta->flags & WLAN_STA_ASSOC) && + (!rsn || sta->wpa_sm)) { + if (sta_ret) + *sta_ret = sta; + return p_hapd; + } + } + } +#endif /* CONFIG_IEEE80211BE */ + } + + return NULL; +} + + +static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, + const u8 *data, size_t data_len, + enum frame_encryption encrypted, + int link_id) +{ + struct hostapd_data *orig_hapd = hapd; + +#ifdef CONFIG_IEEE80211BE + hapd = switch_link_hapd(hapd, link_id); + hapd = hostapd_find_by_sta(hapd->iface, src, true, NULL); +#else /* CONFIG_IEEE80211BE */ + hapd = hostapd_find_by_sta(hapd->iface, src, false, NULL); +#endif /* CONFIG_IEEE80211BE */ + + if (!hapd) { + /* WLAN cases need to have an existing association, but non-WLAN + * cases (mainly, wired IEEE 802.1X) need to be able to process + * EAPOL frames from new devices that do not yet have a STA + * entry and as such, do not get a match in + * hostapd_find_by_sta(). */ + wpa_printf(MSG_DEBUG, + "No STA-specific hostapd instance for EAPOL RX found - fall back to initial context"); + hapd = orig_hapd; } - ieee802_1x_receive(hapd, src, data, data_len); + ieee802_1x_receive(hapd, src, data, data_len, encrypted); } #endif /* HOSTAPD */ @@ -1910,7 +2408,7 @@ static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd, #ifdef CONFIG_OWE static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd, const u8 *peer, const u8 *ie, - size_t ie_len) + size_t ie_len, const u8 *link_addr) { u16 status; struct sta_info *sta; @@ -1960,24 +2458,89 @@ static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd, } sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); +#ifdef CONFIG_IEEE80211BE + if (link_addr) { + struct mld_info *info = &sta->mld_info; + u8 link_id = hapd->mld_link_id; + + ap_sta_set_mld(sta, true); + sta->mld_assoc_link_id = link_id; + os_memcpy(info->common_info.mld_addr, peer, ETH_ALEN); + info->links[link_id].valid = true; + os_memcpy(info->links[link_id].local_addr, hapd->own_addr, + ETH_ALEN); + os_memcpy(info->links[link_id].peer_addr, link_addr, ETH_ALEN); + } +#endif /* CONFIG_IEEE80211BE */ + status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie, elems.rsn_ie_len, elems.owe_dh, - elems.owe_dh_len); + elems.owe_dh_len, link_addr); if (status != WLAN_STATUS_SUCCESS) ap_free_sta(hapd, sta); return 0; err: - hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0); + hostapd_drv_update_dh_ie(hapd, link_addr ? link_addr : peer, status, + NULL, 0); return 0; } #endif /* CONFIG_OWE */ +#ifdef NEED_AP_MLME +static void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, + const u8 *data, size_t len, int ack, + int link_id) +{ + struct sta_info *sta; + + hapd = switch_link_hapd(hapd, link_id); + hapd = hostapd_find_by_sta(hapd->iface, dst, false, &sta); + + if (!sta) { + wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA " + MACSTR_SEC " that is not currently associated", + MAC2STR_SEC(dst)); + return; + } + + ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack); +} +#endif /* NEED_AP_MLME */ + + +#ifdef CONFIG_IEEE80211AX +static void hostapd_event_color_change(struct hostapd_data *hapd, bool success) +{ + struct hostapd_data *bss; + size_t i; + + for (i = 0; i < hapd->iface->num_bss; i++) { + bss = hapd->iface->bss[i]; + if (bss->cca_color == 0) + continue; + + if (success) + hapd->iface->conf->he_op.he_bss_color = bss->cca_color; + + bss->cca_in_progress = 0; + if (ieee802_11_set_beacon(bss)) { + wpa_printf(MSG_ERROR, "Failed to remove BCCA element"); + bss->cca_in_progress = 1; + } else { + hostapd_cleanup_cca_params(bss); + } + } +} +#endif /* CONFIG_IEEE80211AX */ + + void wpa_supplicant_event_hapd(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { struct hostapd_data *hapd = ctx; + struct sta_info *sta; #ifndef CONFIG_NO_STDOUT_DEBUG int level = MSG_DEBUG; @@ -2005,8 +2568,29 @@ void wpa_supplicant_event_hapd(void *ctx, enum wpa_event_type event, michael_mic_failure(hapd, data->michael_mic_failure.src, 1); break; case EVENT_SCAN_RESULTS: +#ifdef NEED_AP_MLME + if (data) + hapd = switch_link_scan(hapd, + data->scan_info.scan_cookie); +#endif /* NEED_AP_MLME */ if (hapd->iface->scan_cb) hapd->iface->scan_cb(hapd->iface); +#ifdef CONFIG_IEEE80211BE + if (!hapd->iface->scan_cb && hapd->conf->mld_ap) { + /* Other links may be waiting for HT scan result */ + unsigned int i; + + for (i = 0; i < hapd->iface->interfaces->count; i++) { + struct hostapd_iface *h = + hapd->iface->interfaces->iface[i]; + struct hostapd_data *h_hapd = h->bss[0]; + + if (hostapd_is_ml_partner(hapd, h_hapd) && + h_hapd->iface->scan_cb) + h_hapd->iface->scan_cb(h_hapd->iface); + } + } +#endif /* CONFIG_IEEE80211BE */ break; case EVENT_WPS_BUTTON_PUSHED: hostapd_wps_button_pushed(hapd, NULL); @@ -2018,7 +2602,8 @@ void wpa_supplicant_event_hapd(void *ctx, enum wpa_event_type event, hostapd_mgmt_tx_cb(hapd, data->tx_status.data, data->tx_status.data_len, data->tx_status.stype, - data->tx_status.ack); + data->tx_status.ack, + data->tx_status.link_id); break; case WLAN_FC_TYPE_DATA: hostapd_tx_status(hapd, data->tx_status.dst, @@ -2032,7 +2617,8 @@ void wpa_supplicant_event_hapd(void *ctx, enum wpa_event_type event, hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst, data->eapol_tx_status.data, data->eapol_tx_status.data_len, - data->eapol_tx_status.ack); + data->eapol_tx_status.ack, + data->eapol_tx_status.link_id); break; case EVENT_DRIVER_CLIENT_POLL_OK: hostapd_client_poll_ok(hapd, data->client_poll.addr); @@ -2069,23 +2655,61 @@ void wpa_supplicant_event_hapd(void *ctx, enum wpa_event_type event, case EVENT_EAPOL_RX: hostapd_event_eapol_rx(hapd, data->eapol_rx.src, data->eapol_rx.data, - data->eapol_rx.data_len); + data->eapol_rx.data_len, + data->eapol_rx.encrypted, + data->eapol_rx.link_id); break; case EVENT_ASSOC: if (!data) return; +#ifdef CONFIG_IEEE80211BE + if (data->assoc_info.assoc_link_id != -1) { + hapd = hostapd_mld_get_link_bss( + hapd, data->assoc_info.assoc_link_id); + if (!hapd) { + wpa_printf(MSG_ERROR, + "MLD: Failed to get link BSS for EVENT_ASSOC"); + return; + } + } +#endif /* CONFIG_IEEE80211BE */ hostapd_notif_assoc(hapd, data->assoc_info.addr, data->assoc_info.req_ies, data->assoc_info.req_ies_len, + data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len, + data->assoc_info.link_addr, data->assoc_info.reassoc); break; + case EVENT_PORT_AUTHORIZED: + /* Port authorized event for an associated STA */ + sta = ap_get_sta(hapd, data->port_authorized.sta_addr); + if (sta) + ap_sta_set_authorized(hapd, sta, 1); + else + wpa_printf(MSG_DEBUG, + "No STA info matching port authorized event found"); + break; #ifdef CONFIG_OWE case EVENT_UPDATE_DH: if (!data) return; +#ifdef CONFIG_IEEE80211BE + if (data->update_dh.assoc_link_id != -1) { + hapd = hostapd_mld_get_link_bss( + hapd, data->update_dh.assoc_link_id); + if (!hapd) { + wpa_printf(MSG_ERROR, + "MLD: Failed to get link BSS for EVENT_UPDATE_DH assoc_link_id=%d", + data->update_dh.assoc_link_id); + return; + } + } +#endif /* CONFIG_IEEE80211BE */ hostapd_notif_update_dh_ie(hapd, data->update_dh.peer, data->update_dh.ie, - data->update_dh.ie_len); + data->update_dh.ie_len, + data->update_dh.link_addr); break; #endif /* CONFIG_OWE */ case EVENT_DISASSOC: @@ -2108,12 +2732,25 @@ void wpa_supplicant_event_hapd(void *ctx, enum wpa_event_type event, case EVENT_CH_SWITCH: if (!data) break; +#ifdef CONFIG_IEEE80211BE + if (data->ch_switch.link_id != -1) { + hapd = hostapd_mld_get_link_bss( + hapd, data->ch_switch.link_id); + if (!hapd) { + wpa_printf(MSG_ERROR, + "MLD: Failed to get link (ID %d) BSS for EVENT_CH_SWITCH/EVENT_CH_SWITCH_STARTED", + data->ch_switch.link_id); + break; + } + } +#endif /* CONFIG_IEEE80211BE */ hostapd_event_ch_switch(hapd, data->ch_switch.freq, data->ch_switch.ht_enabled, data->ch_switch.ch_offset, data->ch_switch.ch_width, data->ch_switch.cf1, data->ch_switch.cf2, + data->ch_switch.punct_bitmap, event == EVENT_CH_SWITCH); break; case EVENT_CONNECT_FAILED_REASON: @@ -2133,26 +2770,31 @@ void wpa_supplicant_event_hapd(void *ctx, enum wpa_event_type event, case EVENT_DFS_RADAR_DETECTED: if (!data) break; + hapd = switch_link_hapd(hapd, data->dfs_event.link_id); hostapd_event_dfs_radar_detected(hapd, &data->dfs_event); break; case EVENT_DFS_PRE_CAC_EXPIRED: if (!data) break; + hapd = switch_link_hapd(hapd, data->dfs_event.link_id); hostapd_event_dfs_pre_cac_expired(hapd, &data->dfs_event); break; case EVENT_DFS_CAC_FINISHED: if (!data) break; + hapd = switch_link_hapd(hapd, data->dfs_event.link_id); hostapd_event_dfs_cac_finished(hapd, &data->dfs_event); break; case EVENT_DFS_CAC_ABORTED: if (!data) break; + hapd = switch_link_hapd(hapd, data->dfs_event.link_id); hostapd_event_dfs_cac_aborted(hapd, &data->dfs_event); break; case EVENT_DFS_NOP_FINISHED: if (!data) break; + hapd = switch_link_hapd(hapd, data->dfs_event.link_id); hostapd_event_dfs_nop_finished(hapd, &data->dfs_event); break; case EVENT_CHANNEL_LIST_CHANGED: @@ -2166,6 +2808,7 @@ void wpa_supplicant_event_hapd(void *ctx, enum wpa_event_type event, case EVENT_DFS_CAC_STARTED: if (!data) break; + hapd = switch_link_hapd(hapd, data->dfs_event.link_id); hostapd_event_dfs_cac_started(hapd, &data->dfs_event); break; #endif /* NEED_AP_MLME */ @@ -2213,6 +2856,39 @@ void wpa_supplicant_event_hapd(void *ctx, enum wpa_event_type event, data->wds_sta_interface.ifname, data->wds_sta_interface.sta_addr); break; +#ifdef CONFIG_IEEE80211AX + case EVENT_BSS_COLOR_COLLISION: + /* The BSS color is shared amongst all BBSs on a specific phy. + * Therefore we always start the color change on the primary + * BSS. */ + hapd = switch_link_hapd(hapd, + data->bss_color_collision.link_id); + wpa_printf(MSG_DEBUG, "BSS color collision on %s", + hapd->conf->iface); + hostapd_switch_color(hapd->iface->bss[0], + data->bss_color_collision.bitmap); + break; + case EVENT_CCA_STARTED_NOTIFY: + hapd = switch_link_hapd(hapd, + data->bss_color_collision.link_id); + wpa_printf(MSG_DEBUG, "CCA started on %s", + hapd->conf->iface); + break; + case EVENT_CCA_ABORTED_NOTIFY: + hapd = switch_link_hapd(hapd, + data->bss_color_collision.link_id); + wpa_printf(MSG_DEBUG, "CCA aborted on %s", + hapd->conf->iface); + hostapd_event_color_change(hapd, false); + break; + case EVENT_CCA_NOTIFY: + hapd = switch_link_hapd(hapd, + data->bss_color_collision.link_id); + wpa_printf(MSG_DEBUG, "CCA finished on %s", + hapd->conf->iface); + hostapd_event_color_change(hapd, true); + break; +#endif /* CONFIG_IEEE80211AX */ default: wpa_printf(MSG_DEBUG, "Unknown event %d", event); break; diff --git a/wpa_supplicant-2.9_standard/src/ap/fils_hlp.c b/wpa_supplicant-2.9_standard/src/ap/fils_hlp.c index 803f01512ad83e1b5efa66e4f62daf004ec446c1..8f369140545dc00d846ff38de457e422f1289351 100644 --- a/wpa_supplicant-2.9_standard/src/ap/fils_hlp.c +++ b/wpa_supplicant-2.9_standard/src/ap/fils_hlp.c @@ -530,9 +530,9 @@ static int fils_process_hlp_ip(struct hostapd_data *hapd, switch (iph->ip_p) { case 17: return fils_process_hlp_udp(hapd, sta, dst, pos, len); + default: + return 0; } - - return 0; } @@ -546,7 +546,7 @@ static int fils_process_hlp_req(struct hostapd_data *hapd, " src=" MACSTR_SEC " len=%u)", MAC2STR_SEC(sta->addr), MAC2STR_SEC(pos), MAC2STR_SEC(pos + ETH_ALEN), (unsigned int) len); - if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) { + if (!ether_addr_equal(sta->addr, pos + ETH_ALEN)) { wpa_printf(MSG_DEBUG, "FILS: Ignore HLP request with unexpected source address" MACSTR_SEC, MAC2STR_SEC(pos + ETH_ALEN)); @@ -567,9 +567,9 @@ static int fils_process_hlp_req(struct hostapd_data *hapd, case ETH_P_IP: return fils_process_hlp_ip(hapd, sta, pos, pkt + 2, end - pkt - 2); + default: + return 0; } - - return 0; } diff --git a/wpa_supplicant-2.9_standard/src/ap/gas_query_ap.c b/wpa_supplicant-2.9_standard/src/ap/gas_query_ap.c index 48c95ca50e93027c285baf3ec104923f07c0ed96..f044a346b31eea4166f131fc9d28342db8fe3c65 100644 --- a/wpa_supplicant-2.9_standard/src/ap/gas_query_ap.c +++ b/wpa_supplicant-2.9_standard/src/ap/gas_query_ap.c @@ -29,6 +29,8 @@ #define GAS_QUERY_WAIT_TIME_INITIAL 1000 #define GAS_QUERY_WAIT_TIME_COMEBACK 150 +#define GAS_QUERY_MAX_COMEBACK_DELAY 60000 + /** * struct gas_query_pending - Pending GAS query */ @@ -183,7 +185,7 @@ gas_query_get_pending(struct gas_query_ap *gas, const u8 *addr, u8 dialog_token) { struct gas_query_pending *q; dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { - if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 && + if (ether_addr_equal(q->addr, addr) && q->dialog_token == dialog_token) return q; } @@ -221,7 +223,7 @@ void gas_query_ap_tx_status(struct gas_query_ap *gas, const u8 *dst, wpa_printf(MSG_DEBUG, "GAS: TX status: dst=" MACSTR_SEC " ok=%d query=%p dialog_token=%u dur=%d ms", MAC2STR_SEC(dst), ok, query, query->dialog_token, dur); - if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(dst, query->addr)) { wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination"); return; } @@ -545,6 +547,8 @@ int gas_query_ap_rx(struct gas_query_ap *gas, const u8 *sa, u8 categ, if (pos + 2 > data + len) return 0; comeback_delay = WPA_GET_LE16(pos); + if (comeback_delay > GAS_QUERY_MAX_COMEBACK_DELAY) + comeback_delay = GAS_QUERY_MAX_COMEBACK_DELAY; pos += 2; /* Advertisement Protocol element */ @@ -614,7 +618,7 @@ static int gas_query_dialog_token_available(struct gas_query_ap *gas, { struct gas_query_pending *q; dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { - if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 && + if (ether_addr_equal(dst, q->addr) && dialog_token == q->dialog_token) return 0; } diff --git a/wpa_supplicant-2.9_standard/src/ap/gas_serv.c b/wpa_supplicant-2.9_standard/src/ap/gas_serv.c index 48513da208ad073c4027f3a67c8327f0accbb016..9c5ba209e07202fdfa2534e4a92e2f4e2a8331a0 100644 --- a/wpa_supplicant-2.9_standard/src/ap/gas_serv.c +++ b/wpa_supplicant-2.9_standard/src/ap/gas_serv.c @@ -1527,7 +1527,7 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd, #ifdef CONFIG_DPP void gas_serv_req_dpp_processing(struct hostapd_data *hapd, const u8 *sa, u8 dialog_token, - int prot, struct wpabuf *buf) + int prot, struct wpabuf *buf, int freq) { struct wpabuf *tx_buf; @@ -1546,8 +1546,8 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd, di = gas_dialog_create(hapd, sa, dialog_token); if (!di) { wpa_printf(MSG_INFO, "DPP: Could not create dialog for " - MACSTR_SEC " (dialog token %u)", - MAC2STR_SEC(sa), dialog_token); + MACSTR " (dialog token %u)", + MAC2STR(sa), dialog_token); wpabuf_free(buf); tx_buf = gas_build_initial_resp( dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE, @@ -1585,7 +1585,7 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd, return; if (prot) convert_to_protected_dual(tx_buf); - hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, + hostapd_drv_send_action(hapd, freq ? freq : hapd->iface->freq, 0, sa, wpabuf_head(tx_buf), wpabuf_len(tx_buf)); wpabuf_free(tx_buf); @@ -1596,7 +1596,7 @@ void gas_serv_req_dpp_processing(struct hostapd_data *hapd, static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, const u8 *sa, const u8 *data, size_t len, int prot, - int std_addr3) + int std_addr3, int freq) { const u8 *pos = data; const u8 *end = data + len; @@ -1693,7 +1693,8 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, data, len); if (!msg) return; - gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg); + gas_serv_req_dpp_processing(hapd, sa, dialog_token, prot, msg, + freq); return; } #endif /* CONFIG_DPP */ @@ -1879,7 +1880,7 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len, switch (data[0]) { case WLAN_PA_GAS_INITIAL_REQ: gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot, - std_addr3); + std_addr3, freq); break; case WLAN_PA_GAS_COMEBACK_REQ: gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot, diff --git a/wpa_supplicant-2.9_standard/src/ap/gas_serv.h b/wpa_supplicant-2.9_standard/src/ap/gas_serv.h index 1528af4afd91ceed320052ae9de2121f2cb6d608..7646a98a4e84d32390aa66b1cd0033edc80eeca2 100644 --- a/wpa_supplicant-2.9_standard/src/ap/gas_serv.h +++ b/wpa_supplicant-2.9_standard/src/ap/gas_serv.h @@ -90,6 +90,6 @@ void gas_serv_deinit(struct hostapd_data *hapd); void gas_serv_req_dpp_processing(struct hostapd_data *hapd, const u8 *sa, u8 dialog_token, - int prot, struct wpabuf *buf); + int prot, struct wpabuf *buf, int freq); #endif /* GAS_SERV_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/hostapd.c b/wpa_supplicant-2.9_standard/src/ap/hostapd.c index 78293c890d98440b214ce6ec797294b8fc436289..0d0aa6191fd1be49295d8365237623c3dbe350c0 100644 --- a/wpa_supplicant-2.9_standard/src/ap/hostapd.c +++ b/wpa_supplicant-2.9_standard/src/ap/hostapd.c @@ -35,6 +35,7 @@ #include "wpa_auth.h" #include "wps_hostapd.h" #include "dpp_hostapd.h" +#include "nan_usd_ap.h" #include "gas_query_ap.h" #include "hw_features.h" #include "wpa_auth_glue.h" @@ -55,6 +56,7 @@ #include "hs20.h" #include "airtime_policy.h" #include "wpa_auth_kay.h" +#include "hw_features.h" #ifdef CONFIG_LIBWPA_VENDOR #include "hostapd_client.h" #endif @@ -71,6 +73,10 @@ static int setup_interface2(struct hostapd_iface *iface); static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx); static void hostapd_interface_setup_failure_handler(void *eloop_ctx, void *timeout_ctx); +#ifdef CONFIG_IEEE80211AX +static void hostapd_switch_color_timeout_handler(void *eloop_data, + void *user_ctx); +#endif /* CONFIG_IEEE80211AX */ int hostapd_for_each_interface(struct hapd_interfaces *interfaces, @@ -92,6 +98,29 @@ int hostapd_for_each_interface(struct hapd_interfaces *interfaces, } +struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd) +{ + if (hapd->iconf->mbssid) + return hapd->iface->bss[0]; + + return hapd; +} + + +int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd) +{ + if (hapd->iconf->mbssid) { + size_t i; + + for (i = 1; i < hapd->iface->num_bss; i++) + if (hapd->iface->bss[i] == hapd) + return i; + } + + return 0; +} + + void hostapd_reconfig_encryption(struct hostapd_data *hapd) { if (hapd->wpa_auth) @@ -160,6 +189,8 @@ static void hostapd_reload_bss(struct hostapd_data *hapd) hostapd_set_generic_elem(hapd, (u8 *) "", 0); } + hostapd_neighbor_sync_own_report(hapd); + ieee802_11_set_beacon(hapd); hostapd_update_wps(hapd); @@ -173,27 +204,34 @@ static void hostapd_reload_bss(struct hostapd_data *hapd) } -static void hostapd_clear_old(struct hostapd_iface *iface) +static void hostapd_clear_old_bss(struct hostapd_data *bss) { - size_t j; + wpa_printf(MSG_DEBUG, "BSS %s changed - clear old state", + bss->conf->iface); /* * Deauthenticate all stations since the new configuration may not * allow them to use the BSS anymore. */ - for (j = 0; j < iface->num_bss; j++) { - hostapd_flush_old_stations(iface->bss[j], - WLAN_REASON_PREV_AUTH_NOT_VALID); + hostapd_flush_old_stations(bss, WLAN_REASON_PREV_AUTH_NOT_VALID); #ifdef CONFIG_WEP - hostapd_broadcast_wep_clear(iface->bss[j]); + hostapd_broadcast_wep_clear(bss); #endif /* CONFIG_WEP */ #ifndef CONFIG_NO_RADIUS - /* TODO: update dynamic data based on changed configuration - * items (e.g., open/close sockets, etc.) */ - radius_client_flush(iface->bss[j]->radius, 0); + /* TODO: update dynamic data based on changed configuration + * items (e.g., open/close sockets, etc.) */ + radius_client_flush(bss->radius, 0); #endif /* CONFIG_NO_RADIUS */ - } +} + + +static void hostapd_clear_old(struct hostapd_iface *iface) +{ + size_t j; + + for (j = 0; j < iface->num_bss; j++) + hostapd_clear_old_bss(iface->bss[j]); } @@ -237,13 +275,13 @@ int hostapd_reload_config(struct hostapd_iface *iface) if (newconf == NULL) return -1; - hostapd_clear_old(iface); - oldconf = hapd->iconf; if (hostapd_iface_conf_changed(newconf, oldconf)) { char *fname; int res; + hostapd_clear_old(iface); + wpa_printf(MSG_DEBUG, "Configuration changes include interface/BSS modification - force full disable+enable sequence"); fname = os_strdup(iface->config_fname); @@ -273,6 +311,10 @@ int hostapd_reload_config(struct hostapd_iface *iface) for (j = 0; j < iface->num_bss; j++) { hapd = iface->bss[j]; + if (!hapd->conf->config_id || !newconf->bss[j]->config_id || + os_strcmp(hapd->conf->config_id, + newconf->bss[j]->config_id) != 0) + hostapd_clear_old_bss(hapd); hapd->iconf = newconf; hapd->iconf->channel = oldconf->channel; hapd->iconf->acs = oldconf->acs; @@ -360,6 +402,62 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd) #endif /* CONFIG_WEP */ +#ifdef CONFIG_IEEE80211BE +#ifdef CONFIG_TESTING_OPTIONS + +#define TU_TO_USEC(_val) ((_val) * 1024) + +static void hostapd_link_remove_timeout_handler(void *eloop_data, + void *user_ctx) +{ + struct hostapd_data *hapd = (struct hostapd_data *) eloop_data; + + if (hapd->eht_mld_link_removal_count == 0) + return; + hapd->eht_mld_link_removal_count--; + + wpa_printf(MSG_DEBUG, "MLD: Remove link_id=%u in %u beacons", + hapd->mld_link_id, + hapd->eht_mld_link_removal_count); + + ieee802_11_set_beacon(hapd); + + if (!hapd->eht_mld_link_removal_count) { + hostapd_free_link_stas(hapd); + hostapd_disable_iface(hapd->iface); + return; + } + + eloop_register_timeout(0, TU_TO_USEC(hapd->iconf->beacon_int), + hostapd_link_remove_timeout_handler, + hapd, NULL); +} + + +int hostapd_link_remove(struct hostapd_data *hapd, u32 count) +{ + if (!hapd->conf->mld_ap) + return -1; + + wpa_printf(MSG_DEBUG, + "MLD: Remove link_id=%u in %u beacons", + hapd->mld_link_id, count); + + hapd->eht_mld_link_removal_count = count; + hapd->eht_mld_bss_param_change++; + + eloop_register_timeout(0, TU_TO_USEC(hapd->iconf->beacon_int), + hostapd_link_remove_timeout_handler, + hapd, NULL); + + ieee802_11_set_beacon(hapd); + return 0; +} + +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_IEEE80211BE */ + + void hostapd_free_hapd_data(struct hostapd_data *hapd) { os_free(hapd->probereq_cb); @@ -387,9 +485,31 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd) vlan_deinit(hapd); hostapd_acl_deinit(hapd); #ifndef CONFIG_NO_RADIUS - radius_client_deinit(hapd->radius); + if (hostapd_mld_is_first_bss(hapd)) { +#ifdef CONFIG_IEEE80211BE + struct hapd_interfaces *ifaces = hapd->iface->interfaces; + size_t i; + + for (i = 0; i < ifaces->count; i++) { + struct hostapd_iface *iface = ifaces->iface[i]; + size_t j; + + for (j = 0; iface && j < iface->num_bss; j++) { + struct hostapd_data *h = iface->bss[j]; + + if (hapd == h) + continue; + if (h->radius == hapd->radius) + h->radius = NULL; + if (h->radius_das == hapd->radius_das) + h->radius_das = NULL; + } + } +#endif /* CONFIG_IEEE80211BE */ + radius_client_deinit(hapd->radius); + radius_das_deinit(hapd->radius_das); + } hapd->radius = NULL; - radius_das_deinit(hapd->radius_das); hapd->radius_das = NULL; #endif /* CONFIG_NO_RADIUS */ @@ -400,6 +520,9 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd) gas_query_ap_deinit(hapd->gas); hapd->gas = NULL; #endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + hostapd_nan_usd_deinit(hapd); +#endif /* CONFIG_NAN_USD */ authsrv_deinit(hapd); @@ -420,6 +543,16 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd) } } +#ifdef CONFIG_IEEE80211BE + /* If the interface was not added as well as it is not the first BSS, + * at least the link should be removed here since deinit will take care + * of only the first BSS. */ + if (hapd->conf->mld_ap && !hapd->interface_added && + hapd->iface->bss[0] != hapd) + hostapd_if_link_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface, + hapd->mld_link_id); +#endif /* CONFIG_IEEE80211BE */ + wpabuf_free(hapd->time_adv); hapd->time_adv = NULL; @@ -447,7 +580,9 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd) hapd->setup_complete_cb = NULL; #endif /* CONFIG_MESH */ +#ifndef CONFIG_NO_RRM hostapd_clean_rrm(hapd); +#endif /* CONFIG_NO_RRM */ fils_hlp_deinit(hapd); #ifdef CONFIG_OCV @@ -467,6 +602,51 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd) } eloop_cancel_timeout(auth_sae_process_commit, hapd, NULL); #endif /* CONFIG_SAE */ + +#ifdef CONFIG_IEEE80211AX + eloop_cancel_timeout(hostapd_switch_color_timeout_handler, hapd, NULL); +#ifdef CONFIG_TESTING_OPTIONS +#ifdef CONFIG_IEEE80211BE + eloop_cancel_timeout(hostapd_link_remove_timeout_handler, hapd, NULL); +#endif /* CONFIG_IEEE80211BE */ +#endif /* CONFIG_TESTING_OPTIONS */ + +#endif /* CONFIG_IEEE80211AX */ +} + + +/* hostapd_bss_link_deinit - Per-BSS ML cleanup (deinitialization) + * @hapd: Pointer to BSS data + * + * This function is used to unlink the BSS from the AP MLD. + * If the BSS being removed is the first link, the next link becomes the first + * link. + */ +static void hostapd_bss_link_deinit(struct hostapd_data *hapd) +{ +#ifdef CONFIG_IEEE80211BE + if (!hapd->conf || !hapd->conf->mld_ap) + return; + + if (!hapd->mld->num_links) + return; + + /* If not started, not yet linked to the MLD. However, the first + * BSS is always linked since it is linked during driver_init(), and + * hence, need to remove it from the AP MLD. + */ + if (!hapd->started && hapd->iface->bss[0] != hapd) + return; + + /* The first BSS can also be only linked when at least driver_init() is + * executed. But if previous interface fails, it is not, and hence, + * safe to skip. + */ + if (hapd->iface->bss[0] == hapd && !hapd->drv_priv) + return; + + hostapd_mld_remove_link(hapd); +#endif /* CONFIG_IEEE80211BE */ } @@ -519,6 +699,7 @@ static void sta_track_deinit(struct hostapd_iface *iface) void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) { wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); + eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); #ifdef NEED_AP_MLME hostapd_stop_setup_timers(iface); #endif /* NEED_AP_MLME */ @@ -531,6 +712,7 @@ void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) iface->current_rates = NULL; os_free(iface->basic_rates); iface->basic_rates = NULL; + iface->cac_started = 0; ap_list_deinit(iface); sta_track_deinit(iface); airtime_policy_update_deinit(iface); @@ -547,7 +729,6 @@ void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) static void hostapd_cleanup_iface(struct hostapd_iface *iface) { wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); - eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface, NULL); @@ -731,8 +912,8 @@ static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface) } skip_mask_ext: - wpa_printf(MSG_EXCESSIVE, "BSS count %lu, BSSID mask " MACSTR_SEC " (%d bits)", - (unsigned long) iface->conf->num_bss, MAC2STR_SEC(mask), bits); + wpa_printf(MSG_EXCESSIVE, "BSS count %lu, BSSID mask " MACSTR " (%d bits)", + (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits); if (!auto_addr) return 0; @@ -1110,18 +1291,108 @@ static int db_table_create_radius_attributes(sqlite3 *db) #endif /* CONFIG_NO_RADIUS */ +static int hostapd_start_beacon(struct hostapd_data *hapd, + bool flush_old_stations) +{ + struct hostapd_bss_config *conf = hapd->conf; + + if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) + return -1; + + if (flush_old_stations && !conf->start_disabled && + conf->broadcast_deauth) { + u8 addr[ETH_ALEN]; + + /* Should any previously associated STA not have noticed that + * the AP had stopped and restarted, send one more + * deauthentication notification now that the AP is ready to + * operate. */ + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, + "Deauthenticate all stations at BSS start"); + os_memset(addr, 0xff, ETH_ALEN); + hostapd_drv_sta_deauth(hapd, addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + } + + if (hapd->driver && hapd->driver->set_operstate) + hapd->driver->set_operstate(hapd->drv_priv, 1); + + return 0; +} + + +#ifndef CONFIG_NO_RADIUS +static int hostapd_bss_radius_init(struct hostapd_data *hapd) +{ + struct hostapd_bss_config *conf; + + if (!hapd) + return -1; + + conf = hapd->conf; + + if (hapd->radius) { + wpa_printf(MSG_DEBUG, + "Skipping RADIUS client init (already done)"); + return 0; + } + + hapd->radius = radius_client_init(hapd, conf->radius); + if (!hapd->radius) { + wpa_printf(MSG_ERROR, + "RADIUS client initialization failed."); + return -1; + } + + if (conf->radius_das_port) { + struct radius_das_conf das_conf; + + os_memset(&das_conf, 0, sizeof(das_conf)); + das_conf.port = conf->radius_das_port; + das_conf.shared_secret = conf->radius_das_shared_secret; + das_conf.shared_secret_len = + conf->radius_das_shared_secret_len; + das_conf.client_addr = &conf->radius_das_client_addr; + das_conf.time_window = conf->radius_das_time_window; + das_conf.require_event_timestamp = + conf->radius_das_require_event_timestamp; + das_conf.require_message_authenticator = + conf->radius_das_require_message_authenticator; + das_conf.ctx = hapd; + das_conf.disconnect = hostapd_das_disconnect; + das_conf.coa = hostapd_das_coa; + hapd->radius_das = radius_das_init(&das_conf); + if (!hapd->radius_das) { + wpa_printf(MSG_ERROR, + "RADIUS DAS initialization failed."); + return -1; + } + } + + return 0; +} +#endif /* CONFIG_NO_RADIUS */ + + /** * hostapd_setup_bss - Per-BSS setup (initialization) * @hapd: Pointer to BSS data * @first: Whether this BSS is the first BSS of an interface; -1 = not first, * but interface may exist + * @start_beacon: Whether Beacon frame template should be configured and + * transmission of Beaconf rames started at this time. This is used when + * MBSSID element is enabled where the information regarding all BSSes + * should be retrieved before configuring the Beacon frame template. The + * calling functions are responsible for configuring the Beacon frame + * explicitly if this is set to false. * * This function is used to initialize all per-BSS data structures and * resources. This gets called in a loop for each BSS when an interface is * initialized. Most of the modules that are initialized here will be * deinitialized in hostapd_cleanup(). */ -static int hostapd_setup_bss(struct hostapd_data *hapd, int first) +static int hostapd_setup_bss(struct hostapd_data *hapd, int first, + bool start_beacon) { struct hostapd_bss_config *conf = hapd->conf; u8 ssid[SSID_MAX_LEN + 1]; @@ -1130,6 +1401,10 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) u8 if_addr[ETH_ALEN]; int flush_old_stations = 1; + if (!hostapd_mld_is_first_bss(hapd)) + wpa_printf(MSG_DEBUG, + "MLD: %s: Setting non-first BSS", __func__); + wpa_printf(MSG_EXCESSIVE, "%s(hapd=%p (%s), first=%d)", __func__, hapd, conf->iface, first); @@ -1171,6 +1446,23 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) } while (mac_in_conf(hapd->iconf, hapd->own_addr)); } +#ifdef CONFIG_IEEE80211BE + if (conf->mld_ap) { + struct hostapd_data *h_hapd; + + h_hapd = hostapd_mld_get_first_bss(hapd); + if (h_hapd) { + hapd->drv_priv = h_hapd->drv_priv; + hapd->interface_added = h_hapd->interface_added; + hostapd_mld_add_link(hapd); + wpa_printf(MSG_DEBUG, + "Setup of non first link (%d) BSS of MLD %s", + hapd->mld_link_id, hapd->conf->iface); + goto setup_mld; + } + } +#endif /* CONFIG_IEEE80211BE */ + hapd->interface_added = 1; if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, conf->iface, addr, hapd, @@ -1185,7 +1477,33 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) if (!addr) os_memcpy(hapd->own_addr, if_addr, ETH_ALEN); + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) { + wpa_printf(MSG_DEBUG, + "Setup of first link (%d) BSS of MLD %s", + hapd->mld_link_id, hapd->conf->iface); + os_memcpy(hapd->mld->mld_addr, hapd->own_addr, + ETH_ALEN); + hostapd_mld_add_link(hapd); + } +#endif /* CONFIG_IEEE80211BE */ + } + +#ifdef CONFIG_IEEE80211BE +setup_mld: + if (hapd->conf->mld_ap && !first) { + wpa_printf(MSG_DEBUG, + "MLD: Set link_id=%u, mld_addr=" MACSTR + ", own_addr=" MACSTR, + hapd->mld_link_id, MAC2STR(hapd->mld->mld_addr), + MAC2STR(hapd->own_addr)); + + if (hostapd_drv_link_add(hapd, hapd->mld_link_id, + hapd->own_addr)) + return -1; } +#endif /* CONFIG_IEEE80211BE */ if (conf->wmm_enabled < 0) conf->wmm_enabled = hapd->iconf->ieee80211n | @@ -1244,7 +1562,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) * Short SSID calculation is identical to FCS and it is defined in * IEEE P802.11-REVmd/D3.0, 9.4.2.170.3 (Calculating the Short-SSID). */ - conf->ssid.short_ssid = crc32(conf->ssid.ssid, conf->ssid.ssid_len); + conf->ssid.short_ssid = ieee80211_crc32(conf->ssid.ssid, + conf->ssid.ssid_len); if (!hostapd_drv_none(hapd)) { wpa_printf(MSG_DEBUG, "Using interface %s with hwaddr " MACSTR_SEC @@ -1287,34 +1606,30 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) } #endif /* CONFIG_SQLITE */ - hapd->radius = radius_client_init(hapd, conf->radius); - if (hapd->radius == NULL) { - wpa_printf(MSG_ERROR, "RADIUS client initialization failed."); - return -1; - } + if (hostapd_mld_is_first_bss(hapd)) { + if (hostapd_bss_radius_init(hapd)) + return -1; + } else { +#ifdef CONFIG_IEEE80211BE + struct hostapd_data *f_bss; - if (conf->radius_das_port) { - struct radius_das_conf das_conf; - os_memset(&das_conf, 0, sizeof(das_conf)); - das_conf.port = conf->radius_das_port; - das_conf.shared_secret = conf->radius_das_shared_secret; - das_conf.shared_secret_len = - conf->radius_das_shared_secret_len; - das_conf.client_addr = &conf->radius_das_client_addr; - das_conf.time_window = conf->radius_das_time_window; - das_conf.require_event_timestamp = - conf->radius_das_require_event_timestamp; - das_conf.require_message_authenticator = - conf->radius_das_require_message_authenticator; - das_conf.ctx = hapd; - das_conf.disconnect = hostapd_das_disconnect; - das_conf.coa = hostapd_das_coa; - hapd->radius_das = radius_das_init(&das_conf); - if (hapd->radius_das == NULL) { - wpa_printf(MSG_ERROR, "RADIUS DAS initialization " - "failed."); + f_bss = hostapd_mld_get_first_bss(hapd); + if (!f_bss) return -1; + + if (!f_bss->radius) { + wpa_printf(MSG_DEBUG, + "MLD: First BSS RADIUS client does not exist. Init on its behalf"); + + if (hostapd_bss_radius_init(f_bss)) + return -1; } + + wpa_printf(MSG_DEBUG, + "MLD: Using RADIUS client of the first BSS"); + hapd->radius = f_bss->radius; + hapd->radius_das = f_bss->radius_das; +#endif /* CONFIG_IEEE80211BE */ } #endif /* CONFIG_NO_RADIUS */ @@ -1333,6 +1648,11 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; #endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + if (hostapd_nan_usd_init(hapd) < 0) + return -1; +#endif /* CONFIG_NAN_USD */ + if (authsrv_init(hapd) < 0) return -1; @@ -1354,6 +1674,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) wpa_printf(MSG_ERROR, "GAS server initialization failed"); return -1; } +#endif /* CONFIG_INTERWORKING */ if (conf->qos_map_set_len && hostapd_drv_set_qos_map(hapd, conf->qos_map_set, @@ -1361,13 +1682,28 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) wpa_printf(MSG_ERROR, "Failed to initialize QoS Map"); return -1; } -#endif /* CONFIG_INTERWORKING */ if (conf->bss_load_update_period && bss_load_update_init(hapd)) { wpa_printf(MSG_ERROR, "BSS Load initialization failed"); return -1; } + if (conf->bridge[0]) { + /* Set explicitly configured bridge parameters that might have + * been lost if the interface has been removed out of the + * bridge. */ + + /* multicast to unicast on bridge ports */ + if (conf->bridge_multicast_to_unicast) + hostapd_drv_br_port_set_attr( + hapd, DRV_BR_PORT_ATTR_MCAST2UCAST, 1); + + /* hairpin mode */ + if (conf->bridge_hairpin) + hostapd_drv_br_port_set_attr( + hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 1); + } + if (conf->proxy_arp) { if (x_snoop_init(hapd)) { wpa_printf(MSG_ERROR, @@ -1393,30 +1729,12 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) + if (start_beacon && hostapd_start_beacon(hapd, flush_old_stations) < 0) return -1; - if (flush_old_stations && !conf->start_disabled && - conf->broadcast_deauth) { - u8 addr[ETH_ALEN]; - - /* Should any previously associated STA not have noticed that - * the AP had stopped and restarted, send one more - * deauthentication notification now that the AP is ready to - * operate. */ - wpa_dbg(hapd->msg_ctx, MSG_DEBUG, - "Deauthenticate all stations at BSS start"); - os_memset(addr, 0xff, ETH_ALEN); - hostapd_drv_sta_deauth(hapd, addr, - WLAN_REASON_PREV_AUTH_NOT_VALID); - } - if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) return -1; - if (hapd->driver && hapd->driver->set_operstate) - hapd->driver->set_operstate(hapd->drv_priv, 1); - return 0; } @@ -1472,14 +1790,14 @@ static int hostapd_set_acl_list(struct hostapd_data *hapd, } -static void hostapd_set_acl(struct hostapd_data *hapd) +int hostapd_set_acl(struct hostapd_data *hapd) { struct hostapd_config *conf = hapd->iconf; - int err; + int err = 0; u8 accept_acl; if (hapd->iface->drv_max_acl_mac_addrs == 0) - return; + return 0; if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) { accept_acl = 1; @@ -1488,7 +1806,7 @@ static void hostapd_set_acl(struct hostapd_data *hapd) accept_acl); if (err) { wpa_printf(MSG_DEBUG, "Failed to set accept acl"); - return; + return -1; } } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) { accept_acl = 0; @@ -1497,9 +1815,10 @@ static void hostapd_set_acl(struct hostapd_data *hapd) accept_acl); if (err) { wpa_printf(MSG_DEBUG, "Failed to set deny acl"); - return; + return -1; } } + return err; } @@ -1541,33 +1860,160 @@ static int start_ctrl_iface(struct hostapd_iface *iface) } -static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx) +/* When NO_IR flag is set and AP is stopped, clean up BSS parameters without + * deinitializing the driver and the control interfaces. A subsequent + * REG_CHANGE event can bring the AP back up. + */ +static void hostapd_no_ir_cleanup(struct hostapd_data *bss) { - struct hostapd_iface *iface = eloop_ctx; - - if (!iface->wait_channel_update) { - wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it"); - return; - } - - /* - * It is possible that the existing channel list is acceptable, so try - * to proceed. - */ - wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway"); - setup_interface2(iface); + hostapd_bss_deinit_no_free(bss); + hostapd_bss_link_deinit(bss); + hostapd_free_hapd_data(bss); + hostapd_cleanup_iface_partial(bss->iface); } -void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator) +static int hostapd_no_ir_channel_list_updated(struct hostapd_iface *iface, + void *ctx) { - if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER) - return; + bool all_no_ir, is_6ghz; + int i, j; + struct hostapd_hw_modes *mode = NULL; - wpa_printf(MSG_DEBUG, "Channel list updated - continue setup"); - eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); - setup_interface2(iface); -} + if (hostapd_get_hw_features(iface)) + return 0; + + all_no_ir = true; + is_6ghz = false; + + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + + if (mode->mode == iface->conf->hw_mode) { + if (iface->freq > 0 && + !hw_mode_get_channel(mode, iface->freq, NULL)) { + mode = NULL; + continue; + } + + for (j = 0; j < mode->num_channels; j++) { + if (!(mode->channels[j].flag & + HOSTAPD_CHAN_NO_IR)) + all_no_ir = false; + + if (is_6ghz_freq(mode->channels[j].freq)) + is_6ghz = true; + } + break; + } + } + + if (!mode || !is_6ghz) + return 0; + iface->current_mode = mode; + + if (iface->state == HAPD_IFACE_ENABLED) { + if (!all_no_ir) { + struct hostapd_channel_data *chan; + + chan = hw_get_channel_freq(iface->current_mode->mode, + iface->freq, NULL, + iface->hw_features, + iface->num_hw_features); + + if (!chan) { + wpa_printf(MSG_ERROR, + "NO_IR: Could not derive chan from freq"); + return 0; + } + + if (!(chan->flag & HOSTAPD_CHAN_NO_IR)) + return 0; + wpa_printf(MSG_DEBUG, + "NO_IR: The current channel has NO_IR flag now, stop AP."); + } else { + wpa_printf(MSG_DEBUG, + "NO_IR: All chan in new chanlist are NO_IR, stop AP."); + } + + hostapd_set_state(iface, HAPD_IFACE_NO_IR); + iface->is_no_ir = true; + hostapd_drv_stop_ap(iface->bss[0]); + hostapd_no_ir_cleanup(iface->bss[0]); + wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_NO_IR); + } else if (iface->state == HAPD_IFACE_NO_IR) { + if (all_no_ir) { + wpa_printf(MSG_DEBUG, + "NO_IR: AP in NO_IR and all chan in the new chanlist are NO_IR. Ignore"); + return 0; + } + + if (!iface->conf->acs) { + struct hostapd_channel_data *chan; + + chan = hw_get_channel_freq(iface->current_mode->mode, + iface->freq, NULL, + iface->hw_features, + iface->num_hw_features); + if (!chan) { + wpa_printf(MSG_ERROR, + "NO_IR: Could not derive chan from freq"); + return 0; + } + + /* If the last operating channel is NO_IR, trigger ACS. + */ + if (chan->flag & HOSTAPD_CHAN_NO_IR) { + iface->freq = 0; + iface->conf->channel = 0; + if (acs_init(iface) != HOSTAPD_CHAN_ACS) + wpa_printf(MSG_ERROR, + "NO_IR: Could not start ACS"); + return 0; + } + } + + setup_interface2(iface); + } + + return 0; +} + + +static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_iface *iface = eloop_ctx; + + if (!iface->wait_channel_update) { + wpa_printf(MSG_INFO, "Channel list update timeout, but interface was not waiting for it"); + return; + } + + /* + * It is possible that the existing channel list is acceptable, so try + * to proceed. + */ + wpa_printf(MSG_DEBUG, "Channel list update timeout - try to continue anyway"); + setup_interface2(iface); +} + + +void hostapd_channel_list_updated(struct hostapd_iface *iface, int initiator) +{ + if (initiator == REGDOM_SET_BY_DRIVER) { + hostapd_for_each_interface(iface->interfaces, + hostapd_no_ir_channel_list_updated, + NULL); + return; + } + + if (!iface->wait_channel_update || initiator != REGDOM_SET_BY_USER) + return; + + wpa_printf(MSG_DEBUG, "Channel list updated - continue setup"); + eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); + setup_interface2(iface); +} static int setup_interface(struct hostapd_iface *iface) @@ -1689,16 +2135,15 @@ static int configured_fixed_chan_to_freq(struct hostapd_iface *iface) static void hostapd_set_6ghz_sec_chan(struct hostapd_iface *iface) { - int bw, seg0; + int bw; if (!is_6ghz_op_class(iface->conf->op_class)) return; - seg0 = hostapd_get_oper_centr_freq_seg0_idx(iface->conf); - bw = center_idx_to_bw_6ghz(seg0); + bw = op_class_to_bandwidth(iface->conf->op_class); /* Assign the secondary channel if absent in config for * bandwidths > 20 MHz */ - if (bw > 20 && !iface->conf->secondary_channel) { + if (bw >= 40 && !iface->conf->secondary_channel) { if (((iface->conf->channel - 1) / 4) % 2) iface->conf->secondary_channel = -1; else @@ -1710,6 +2155,7 @@ static void hostapd_set_6ghz_sec_chan(struct hostapd_iface *iface) static int setup_interface2(struct hostapd_iface *iface) { iface->wait_channel_update = 0; + iface->is_no_ir = false; if (hostapd_get_hw_features(iface)) { /* Not all drivers support this yet, so continue without hw @@ -1717,12 +2163,18 @@ static int setup_interface2(struct hostapd_iface *iface) } else { int ret; + if (iface->conf->acs && !iface->is_ch_switch_dfs) { + iface->freq = 0; + iface->conf->channel = 0; + } + iface->is_ch_switch_dfs = false; + ret = configured_fixed_chan_to_freq(iface); if (ret < 0) goto fail; if (iface->conf->op_class) { - int ch_width; + enum oper_chan_width ch_width; ch_width = op_class_to_ch_width(iface->conf->op_class); hostapd_set_oper_chwidth(iface->conf, ch_width); @@ -1760,6 +2212,14 @@ static int setup_interface2(struct hostapd_iface *iface) return hostapd_setup_interface_complete(iface, 0); fail: + if (iface->is_no_ir) { + /* If AP is in NO_IR state, it can be reenabled by the driver + * regulatory update and EVENT_CHANNEL_LIST_CHANGED. */ + hostapd_set_state(iface, HAPD_IFACE_NO_IR); + wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_NO_IR); + return 0; + } + hostapd_set_state(iface, HAPD_IFACE_DISABLED); wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); #ifdef CONFIG_LIBWPA_VENDOR @@ -1797,6 +2257,16 @@ static void fst_hostapd_get_channel_info_cb(void *ctx, } +static int fst_hostapd_get_hw_modes_cb(void *ctx, + struct hostapd_hw_modes **modes) +{ + struct hostapd_data *hapd = ctx; + + *modes = hapd->iface->hw_features; + return hapd->iface->num_hw_features; +} + + static void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies) { struct hostapd_data *hapd = ctx; @@ -1889,9 +2359,11 @@ static const u8 * fst_hostapd_get_peer_next(void *ctx, void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd, struct fst_wpa_obj *iface_obj) { + os_memset(iface_obj, 0, sizeof(*iface_obj)); iface_obj->ctx = hapd; iface_obj->get_bssid = fst_hostapd_get_bssid_cb; iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb; + iface_obj->get_hw_modes = fst_hostapd_get_hw_modes_cb; iface_obj->set_ies = fst_hostapd_set_ies_cb; iface_obj->send_action = fst_hostapd_send_action_cb; iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb; @@ -2094,6 +2566,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, hapd->iconf->ieee80211n, hapd->iconf->ieee80211ac, hapd->iconf->ieee80211ax, + hapd->iconf->ieee80211be, hapd->iconf->secondary_channel, hostapd_get_oper_chwidth(hapd->iconf), hostapd_get_oper_centr_freq_seg0_idx( @@ -2139,7 +2612,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, hapd = iface->bss[j]; if (j) os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN); - if (hostapd_setup_bss(hapd, j == 0)) { + if (hostapd_setup_bss(hapd, j == 0, !iface->conf->mbssid)) { for (;;) { hapd = iface->bss[j]; hostapd_bss_deinit_no_free(hapd); @@ -2153,6 +2626,24 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, if (is_zero_ether_addr(hapd->conf->bssid)) prev_addr = hapd->own_addr; } + + if (hapd->iconf->mbssid) { + for (j = 0; hapd->iconf->mbssid && j < iface->num_bss; j++) { + hapd = iface->bss[j]; + if (hostapd_start_beacon(hapd, true)) { + for (;;) { + hapd = iface->bss[j]; + hostapd_bss_deinit_no_free(hapd); + hostapd_free_hapd_data(hapd); + if (j == 0) + break; + j--; + } + goto fail; + } + } + } + hapd = iface->bss[0]; hostapd_tx_queue_params(iface); @@ -2220,6 +2711,7 @@ dfs_offload: #endif 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"); @@ -2235,10 +2727,20 @@ dfs_offload: for (j = 0; j < iface->num_bss; j++) hostapd_neighbor_set_own_report(iface->bss[j]); + if (iface->interfaces && iface->interfaces->count > 1) + ieee802_11_set_beacons(iface); + return 0; fail: wpa_printf(MSG_ERROR, "Interface initialization failed"); + + if (iface->is_no_ir) { + hostapd_set_state(iface, HAPD_IFACE_NO_IR); + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_NO_IR); + return 0; + } + hostapd_set_state(iface, HAPD_IFACE_DISABLED); wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); #ifdef CONFIG_LIBWPA_VENDOR @@ -2292,8 +2794,15 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) if (err) { wpa_printf(MSG_ERROR, "Interface initialization failed"); - hostapd_set_state(iface, HAPD_IFACE_DISABLED); iface->need_to_start_in_sync = 0; + + if (iface->is_no_ir) { + hostapd_set_state(iface, HAPD_IFACE_NO_IR); + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_NO_IR); + return 0; + } + + hostapd_set_state(iface, HAPD_IFACE_DISABLED); wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); #ifdef CONFIG_LIBWPA_VENDOR struct HostapdApCbParm hostapdApCbParm = {}; @@ -2466,6 +2975,8 @@ static void hostapd_bss_deinit(struct hostapd_data *hapd) hapd->rad_attr_db = NULL; } #endif /* CONFIG_SQLITE */ + + hostapd_bss_link_deinit(hapd); hostapd_cleanup(hapd); } @@ -2482,6 +2993,7 @@ void hostapd_interface_deinit(struct hostapd_iface *iface) eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); iface->wait_channel_update = 0; + iface->is_no_ir = false; #ifdef CONFIG_FST if (iface->fst) { @@ -2503,6 +3015,40 @@ void hostapd_interface_deinit(struct hostapd_iface *iface) } +#ifdef CONFIG_IEEE80211BE + +static void hostapd_mld_ref_inc(struct hostapd_mld *mld) +{ + if (!mld) + return; + + if (mld->refcount == HOSTAPD_MLD_MAX_REF_COUNT) { + wpa_printf(MSG_ERROR, "AP MLD %s: Ref count overflow", + mld->name); + return; + } + + mld->refcount++; +} + + +static void hostapd_mld_ref_dec(struct hostapd_mld *mld) +{ + if (!mld) + return; + + if (!mld->refcount) { + wpa_printf(MSG_ERROR, "AP MLD %s: Ref count underflow", + mld->name); + return; + } + + mld->refcount--; +} + +#endif /* CONFIG_IEEE80211BE */ + + void hostapd_interface_free(struct hostapd_iface *iface) { size_t j; @@ -2510,6 +3056,10 @@ void hostapd_interface_free(struct hostapd_iface *iface) for (j = 0; j < iface->num_bss; j++) { if (!iface->bss) break; +#ifdef CONFIG_IEEE80211BE + if (iface->bss[j]) + hostapd_mld_ref_dec(iface->bss[j]->mld); +#endif /* CONFIG_IEEE80211BE */ wpa_printf(MSG_DEBUG, "%s: free hapd %p", __func__, iface->bss[j]); os_free(iface->bss[j]); @@ -2532,6 +3082,157 @@ struct hostapd_iface * hostapd_alloc_iface(void) } +#ifdef CONFIG_IEEE80211BE +static void hostapd_bss_alloc_link_id(struct hostapd_data *hapd) +{ + hapd->mld_link_id = hapd->mld->next_link_id++; + wpa_printf(MSG_DEBUG, "AP MLD: %s: Link ID %d assigned.", + hapd->mld->name, hapd->mld_link_id); +} +#endif /* CONFIG_IEEE80211BE */ + + +static void hostapd_bss_setup_multi_link(struct hostapd_data *hapd, + struct hapd_interfaces *interfaces) +{ +#ifdef CONFIG_IEEE80211BE + struct hostapd_mld *mld, **all_mld; + struct hostapd_bss_config *conf; + size_t i; + + conf = hapd->conf; + + if (!hapd->iconf || !hapd->iconf->ieee80211be || !conf->mld_ap || + conf->disable_11be) + return; + + for (i = 0; i < interfaces->mld_count; i++) { + mld = interfaces->mld[i]; + + if (!mld || os_strcmp(conf->iface, mld->name) != 0) + continue; + + hapd->mld = mld; + hostapd_mld_ref_inc(mld); + hostapd_bss_alloc_link_id(hapd); + break; + } + + if (hapd->mld) + return; + + mld = os_zalloc(sizeof(struct hostapd_mld)); + if (!mld) + goto fail; + + os_strlcpy(mld->name, conf->iface, sizeof(conf->iface)); + dl_list_init(&mld->links); + + wpa_printf(MSG_DEBUG, "AP MLD %s created", mld->name); + + hapd->mld = mld; + hostapd_mld_ref_inc(mld); + hostapd_bss_alloc_link_id(hapd); + + all_mld = os_realloc_array(interfaces->mld, interfaces->mld_count + 1, + sizeof(struct hostapd_mld *)); + if (!all_mld) + goto fail; + + interfaces->mld = all_mld; + interfaces->mld[interfaces->mld_count] = mld; + interfaces->mld_count++; + + return; +fail: + if (!mld) + return; + + wpa_printf(MSG_DEBUG, "AP MLD %s: free mld %p", mld->name, mld); + os_free(mld); + hapd->mld = NULL; +#endif /* CONFIG_IEEE80211BE */ +} + + +static void hostapd_cleanup_unused_mlds(struct hapd_interfaces *interfaces) +{ +#ifdef CONFIG_IEEE80211BE + struct hostapd_mld *mld, **all_mld; + size_t i, j, num_mlds; + bool forced_remove, remove; + + if (!interfaces->mld) + return; + + num_mlds = interfaces->mld_count; + + for (i = 0; i < interfaces->mld_count; i++) { + mld = interfaces->mld[i]; + if (!mld) + continue; + + remove = false; + forced_remove = false; + + if (!mld->refcount) + remove = true; + + /* If MLD is still being referenced but the number of interfaces + * is zero, it is safe to force its deletion. Normally, this + * should not happen but even if it does, let us free the + * memory. + */ + if (!remove && !interfaces->count) + forced_remove = true; + + if (!remove && !forced_remove) + continue; + + wpa_printf(MSG_DEBUG, "AP MLD %s: Freed%s", mld->name, + forced_remove ? " (forced)" : ""); + os_free(mld); + interfaces->mld[i] = NULL; + num_mlds--; + } + + if (!num_mlds) { + interfaces->mld_count = 0; + os_free(interfaces->mld); + interfaces->mld = NULL; + return; + } + + all_mld = os_zalloc(num_mlds * sizeof(struct hostapd_mld *)); + if (!all_mld) { + wpa_printf(MSG_ERROR, + "AP MLD: Failed to re-allocate the MLDs. Expect issues"); + return; + } + + for (i = 0, j = 0; i < interfaces->mld_count; i++) { + mld = interfaces->mld[i]; + if (!mld) + continue; + + all_mld[j++] = mld; + } + + /* This should not happen */ + if (j != num_mlds) { + wpa_printf(MSG_DEBUG, + "AP MLD: Some error occurred while reallocating MLDs. Expect issues."); + os_free(all_mld); + return; + } + + os_free(interfaces->mld); + interfaces->mld = all_mld; + interfaces->mld_count = num_mlds; +#endif /* CONFIG_IEEE80211BE */ +} + + /** * hostapd_init - Allocate and initialize per-interface data * @config_file: Path to the configuration file @@ -2575,8 +3276,10 @@ struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces, if (hapd == NULL) goto fail; hapd->msg_ctx = hapd; + hostapd_bss_setup_multi_link(hapd, interfaces); } + hapd_iface->is_ch_switch_dfs = false; return hapd_iface; fail: @@ -2696,6 +3399,8 @@ hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy, iface->conf->last_bss = bss; iface->bss[iface->num_bss] = hapd; hapd->msg_ctx = hapd; + hostapd_bss_setup_multi_link(hapd, interfaces); + bss_idx = iface->num_bss++; conf->num_bss--; @@ -2729,6 +3434,37 @@ hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy, } +static void hostapd_cleanup_driver(const struct wpa_driver_ops *driver, + void *drv_priv, struct hostapd_iface *iface) +{ + if (!driver || !driver->hapd_deinit || !drv_priv) + return; + +#ifdef CONFIG_IEEE80211BE + /* In case of non-ML operation, de-init. But if ML operation exist, + * even if that's the last BSS in the interface, the driver (drv) could + * be in use for a different AP MLD. Hence, need to check if drv is + * still being used by some other BSS before de-initiallizing. */ + if (!iface->bss[0]->conf->mld_ap) { + driver->hapd_deinit(drv_priv); + } else if (hostapd_mld_is_first_bss(iface->bss[0]) && + driver->is_drv_shared && + !driver->is_drv_shared(drv_priv, iface->bss[0])) { + driver->hapd_deinit(drv_priv); + } else if (hostapd_if_link_remove(iface->bss[0], + WPA_IF_AP_BSS, + iface->bss[0]->conf->iface, + iface->bss[0]->mld_link_id)) { + wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s", + iface->bss[0]->conf->iface); + } +#else /* CONFIG_IEEE80211BE */ + driver->hapd_deinit(drv_priv); +#endif /* CONFIG_IEEE80211BE */ + iface->bss[0]->drv_priv = NULL; +} + + void hostapd_interface_deinit_free(struct hostapd_iface *iface) { const struct wpa_driver_ops *driver; @@ -2745,10 +3481,7 @@ void hostapd_interface_deinit_free(struct hostapd_iface *iface) hostapd_interface_deinit(iface); wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", __func__, driver, drv_priv); - if (driver && driver->hapd_deinit && drv_priv) { - driver->hapd_deinit(drv_priv); - iface->bss[0]->drv_priv = NULL; - } + hostapd_cleanup_driver(driver, drv_priv, iface); hostapd_interface_free(iface); } @@ -2761,8 +3494,10 @@ static void hostapd_deinit_driver(const struct wpa_driver_ops *driver, wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", __func__, driver, drv_priv); + + hostapd_cleanup_driver(driver, drv_priv, hapd_iface); + if (driver && driver->hapd_deinit && drv_priv) { - driver->hapd_deinit(drv_priv); for (j = 0; j < hapd_iface->num_bss; j++) { wpa_printf(MSG_DEBUG, "%s:bss[%d]->drv_priv=%p", __func__, (int) j, @@ -2778,6 +3513,22 @@ static void hostapd_deinit_driver(const struct wpa_driver_ops *driver, } +static void hostapd_refresh_all_iface_beacons(struct hostapd_iface *hapd_iface) +{ + size_t j; + + if (!hapd_iface->interfaces || hapd_iface->interfaces->count <= 1) + return; + + for (j = 0; j < hapd_iface->interfaces->count; j++) { + if (hapd_iface->interfaces->iface[j] == hapd_iface) + continue; + + ieee802_11_update_beacons(hapd_iface->interfaces->iface[j]); + } +} + + int hostapd_enable_iface(struct hostapd_iface *hapd_iface) { size_t j; @@ -2819,6 +3570,8 @@ int hostapd_enable_iface(struct hostapd_iface *hapd_iface) return -1; } + hostapd_refresh_all_iface_beacons(hapd_iface); + return 0; } @@ -2843,6 +3596,21 @@ int hostapd_reload_iface(struct hostapd_iface *hapd_iface) } +int hostapd_reload_bss_only(struct hostapd_data *bss) +{ + + wpa_printf(MSG_DEBUG, "Reload BSS %s", bss->conf->iface); + hostapd_set_security_params(bss->conf, 1); + if (hostapd_config_check(bss->iconf, 1) < 0) { + wpa_printf(MSG_ERROR, "Updated BSS configuration is invalid"); + return -1; + } + hostapd_clear_old_bss(bss); + hostapd_reload_bss(bss); + return 0; +} + + int hostapd_disable_iface(struct hostapd_iface *hapd_iface) { size_t j; @@ -2887,6 +3655,7 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface) for (j = 0; j < hapd_iface->num_bss; j++) { struct hostapd_data *hapd = hapd_iface->bss[j]; hostapd_bss_deinit_no_free(hapd); + hostapd_bss_link_deinit(hapd); hostapd_free_hapd_data(hapd); } @@ -2900,6 +3669,7 @@ int hostapd_disable_iface(struct hostapd_iface *hapd_iface) wpa_printf(MSG_DEBUG, "Interface %s disabled", hapd_iface->bss[0]->conf->iface); hostapd_set_state(hapd_iface, HAPD_IFACE_DISABLED); + hostapd_refresh_all_iface_beacons(hapd_iface); return 0; } @@ -3008,6 +3778,7 @@ static int hostapd_data_alloc(struct hostapd_iface *hapd_iface, return -1; } hapd->msg_ctx = hapd; + hostapd_bss_setup_multi_link(hapd, hapd_iface->interfaces); } hapd_iface->conf = conf; @@ -3080,7 +3851,8 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf) if (start_ctrl_iface_bss(hapd) < 0 || (hapd_iface->state == HAPD_IFACE_ENABLED && - hostapd_setup_bss(hapd, -1))) { + hostapd_setup_bss(hapd, -1, true))) { + hostapd_bss_link_deinit(hapd); hostapd_cleanup(hapd); hapd_iface->bss[hapd_iface->num_bss - 1] = NULL; hapd_iface->conf->num_bss--; @@ -3089,6 +3861,9 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf) __func__, hapd, hapd->conf->iface); hostapd_config_free_bss(hapd->conf); hapd->conf = NULL; +#ifdef CONFIG_IEEE80211BE + hostapd_mld_ref_dec(hapd->mld); +#endif /* CONFIG_IEEE80211BE */ os_free(hapd); return -1; } @@ -3106,8 +3881,14 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf) conf_file = ptr + 7; for (i = 0; i < interfaces->count; i++) { + bool mld_ap = false; + +#ifdef CONFIG_IEEE80211BE + mld_ap = interfaces->iface[i]->conf->bss[0]->mld_ap; +#endif /* CONFIG_IEEE80211BE */ + if (!os_strcmp(interfaces->iface[i]->conf->bss[0]->iface, - buf)) { + buf) && !mld_ap) { wpa_printf(MSG_INFO, "Cannot add interface - it " "already exists"); return -1; @@ -3172,7 +3953,11 @@ fail: wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)", __func__, hapd_iface->bss[i], hapd->conf->iface); + hostapd_bss_link_deinit(hapd); hostapd_cleanup(hapd); +#ifdef CONFIG_IEEE80211BE + hostapd_mld_ref_dec(hapd->mld); +#endif /* CONFIG_IEEE80211BE */ os_free(hapd); hapd_iface->bss[i] = NULL; } @@ -3182,6 +3967,7 @@ fail: if (new_iface) { interfaces->count--; interfaces->iface[interfaces->count] = NULL; + hostapd_cleanup_unused_mlds(interfaces); } hostapd_cleanup_iface(hapd_iface); } @@ -3204,6 +3990,9 @@ static int hostapd_remove_bss(struct hostapd_iface *iface, unsigned int idx) __func__, hapd, hapd->conf->iface); hostapd_config_free_bss(hapd->conf); hapd->conf = NULL; +#ifdef CONFIG_IEEE80211BE + hostapd_mld_ref_dec(hapd->mld); +#endif /* CONFIG_IEEE80211BE */ os_free(hapd); iface->num_bss--; @@ -3246,6 +4035,8 @@ int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf) k++; } interfaces->count--; + hostapd_cleanup_unused_mlds(interfaces); + return 0; } @@ -3282,7 +4073,12 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, return; } - hostapd_prune_associations(hapd, sta->addr); +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta) && + sta->mld_assoc_link_id != hapd->mld_link_id) + return; +#endif /* CONFIG_IEEE80211BE */ + ap_sta_clear_disconnect_timeouts(hapd, sta); sta->post_csa_sa_query = 0; @@ -3319,8 +4115,12 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, sta->auth_alg != WLAN_AUTH_FILS_PK && !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH); - } else + } else if (!(hapd->iface->drv_flags2 & + WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK)) { + /* The 4-way handshake offloaded case will have this handled + * based on the port authorized event. */ wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm); + } if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) { if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) { @@ -3369,6 +4169,8 @@ const char * hostapd_state_text(enum hostapd_iface_state s) return "DFS"; case HAPD_IFACE_ENABLED: return "ENABLED"; + case HAPD_IFACE_NO_IR: + return "NO_IR"; } return "UNKNOWN"; @@ -3397,7 +4199,7 @@ int hostapd_csa_in_progress(struct hostapd_iface *iface) #ifdef NEED_AP_MLME -static void free_beacon_data(struct beacon_data *beacon) +void free_beacon_data(struct beacon_data *beacon) { os_free(beacon->head); beacon->head = NULL; @@ -3508,7 +4310,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, struct hostapd_freq_params *old_params) { int channel; - u8 seg0, seg1; + u8 seg0 = 0, seg1 = 0; struct hostapd_hw_modes *mode; if (!params->channel) { @@ -3520,6 +4322,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, if (!channel) return -1; + hostapd_determine_mode(hapd->iface); mode = hapd->iface->current_mode; /* if a pointer to old_params is provided we save previous state */ @@ -3529,13 +4332,16 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, conf->channel, conf->enable_edmg, conf->edmg_channel, conf->ieee80211n, conf->ieee80211ac, conf->ieee80211ax, - conf->secondary_channel, + conf->ieee80211be, conf->secondary_channel, hostapd_get_oper_chwidth(conf), hostapd_get_oper_centr_freq_seg0_idx(conf), hostapd_get_oper_centr_freq_seg1_idx(conf), conf->vht_capab, mode ? &mode->he_capab[IEEE80211_MODE_AP] : - NULL)) + NULL, + mode ? &mode->eht_capab[IEEE80211_MODE_AP] : + NULL, + hostapd_get_punct_bitmap(hapd))) return -1; switch (params->bandwidth) { @@ -3546,6 +4352,7 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, case 40: case 80: case 160: + case 320: conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; break; default: @@ -3556,16 +4363,21 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, case 0: case 20: case 40: - hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT); + hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_USE_HT); break; case 80: if (params->center_freq2) - hostapd_set_oper_chwidth(conf, CHANWIDTH_80P80MHZ); + hostapd_set_oper_chwidth(conf, + CONF_OPER_CHWIDTH_80P80MHZ); else - hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ); + hostapd_set_oper_chwidth(conf, + CONF_OPER_CHWIDTH_80MHZ); break; case 160: - hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ); + hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_160MHZ); + break; + case 320: + hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_320MHZ); break; default: return -1; @@ -3575,10 +4387,14 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, conf->ieee80211n = params->ht_enabled; conf->ieee80211ac = params->vht_enabled; conf->secondary_channel = params->sec_channel_offset; - ieee80211_freq_to_chan(params->center_freq1, - &seg0); - ieee80211_freq_to_chan(params->center_freq2, - &seg1); + if (params->center_freq1 && + ieee80211_freq_to_chan(params->center_freq1, &seg0) == + NUM_HOSTAPD_MODES) + return -1; + if (params->center_freq2 && + ieee80211_freq_to_chan(params->center_freq2, + &seg1) == NUM_HOSTAPD_MODES) + return -1; hostapd_set_oper_centr_freq_seg0_idx(conf, seg0); hostapd_set_oper_centr_freq_seg1_idx(conf, seg1); @@ -3594,6 +4410,9 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, struct hostapd_iface *iface = hapd->iface; struct hostapd_freq_params old_freq; int ret; +#ifdef CONFIG_IEEE80211BE + u16 old_punct_bitmap; +#endif /* CONFIG_IEEE80211BE */ u8 chan, bandwidth; os_memset(&old_freq, 0, sizeof(old_freq)); @@ -3603,15 +4422,18 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, switch (settings->freq_params.bandwidth) { case 80: if (settings->freq_params.center_freq2) - bandwidth = CHANWIDTH_80P80MHZ; + bandwidth = CONF_OPER_CHWIDTH_80P80MHZ; else - bandwidth = CHANWIDTH_80MHZ; + bandwidth = CONF_OPER_CHWIDTH_80MHZ; break; case 160: - bandwidth = CHANWIDTH_160MHZ; + bandwidth = CONF_OPER_CHWIDTH_160MHZ; + break; + case 320: + bandwidth = CONF_OPER_CHWIDTH_320MHZ; break; default: - bandwidth = CHANWIDTH_USE_HT; + bandwidth = CONF_OPER_CHWIDTH_USE_HT; break; } @@ -3622,11 +4444,12 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, &hapd->iface->cs_oper_class, &chan) == NUM_HOSTAPD_MODES) { wpa_printf(MSG_DEBUG, - "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)", + "invalid frequency for channel switch (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d)", settings->freq_params.freq, settings->freq_params.sec_channel_offset, settings->freq_params.vht_enabled, - settings->freq_params.he_enabled); + settings->freq_params.he_enabled, + settings->freq_params.eht_enabled); return -1; } @@ -3638,9 +4461,16 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, if (ret) return ret; +#ifdef CONFIG_IEEE80211BE + old_punct_bitmap = iface->conf->punct_bitmap; + iface->conf->punct_bitmap = settings->punct_bitmap; +#endif /* CONFIG_IEEE80211BE */ ret = hostapd_build_beacon_data(hapd, &settings->beacon_after); /* change back the configuration */ +#ifdef CONFIG_IEEE80211BE + iface->conf->punct_bitmap = old_punct_bitmap; +#endif /* CONFIG_IEEE80211BE */ hostapd_change_config_freq(iface->bss[0], iface->conf, &old_freq, NULL); @@ -3662,6 +4492,16 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd, settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp; settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon; settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp; + settings->link_id = -1; +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) + settings->link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ + +#ifdef CONFIG_IEEE80211AX + settings->ubpr.unsol_bcast_probe_resp_tmpl = + hostapd_unsol_bcast_probe_resp(hapd, &settings->ubpr); +#endif /* CONFIG_IEEE80211AX */ return 0; } @@ -3683,6 +4523,11 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd) void hostapd_chan_switch_config(struct hostapd_data *hapd, struct hostapd_freq_params *freq_params) { + if (freq_params->eht_enabled) + hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_ENABLED; + else + hapd->iconf->ch_switch_eht_config |= CH_SWITCH_EHT_DISABLED; + if (freq_params->he_enabled) hapd->iconf->ch_switch_he_config |= CH_SWITCH_HE_ENABLED; else @@ -3695,7 +4540,8 @@ void hostapd_chan_switch_config(struct hostapd_data *hapd, hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, - "CHAN_SWITCH HE config 0x%x VHT config 0x%x", + "CHAN_SWITCH EHT config 0x%x HE config 0x%x VHT config 0x%x", + hapd->iconf->ch_switch_eht_config, hapd->iconf->ch_switch_he_config, hapd->iconf->ch_switch_vht_config); } @@ -3718,6 +4564,9 @@ int hostapd_switch_channel(struct hostapd_data *hapd, ret = hostapd_drv_switch_channel(hapd, settings); free_beacon_data(&settings->beacon_csa); free_beacon_data(&settings->beacon_after); +#ifdef CONFIG_IEEE80211AX + os_free(settings->ubpr.unsol_bcast_probe_resp_tmpl); +#endif /* CONFIG_IEEE80211AX */ if (ret) { /* if we failed, clean cs parameters */ @@ -3734,29 +4583,38 @@ void hostapd_switch_channel_fallback(struct hostapd_iface *iface, const struct hostapd_freq_params *freq_params) { - int seg0_idx = 0, seg1_idx = 0, bw = CHANWIDTH_USE_HT; + u8 seg0_idx = 0, seg1_idx = 0; + enum oper_chan_width bw = CONF_OPER_CHWIDTH_USE_HT; + u8 op_class, chan = 0; wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes"); if (freq_params->center_freq1) - seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5; + ieee80211_freq_to_chan(freq_params->center_freq1, &seg0_idx); if (freq_params->center_freq2) - seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5; + ieee80211_freq_to_chan(freq_params->center_freq2, &seg1_idx); switch (freq_params->bandwidth) { case 0: case 20: case 40: - bw = CHANWIDTH_USE_HT; + bw = CONF_OPER_CHWIDTH_USE_HT; break; case 80: - if (freq_params->center_freq2) - bw = CHANWIDTH_80P80MHZ; - else - bw = CHANWIDTH_80MHZ; + if (freq_params->center_freq2) { + bw = CONF_OPER_CHWIDTH_80P80MHZ; + iface->conf->vht_capab |= + VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + } else { + bw = CONF_OPER_CHWIDTH_80MHZ; + } break; case 160: - bw = CHANWIDTH_160MHZ; + bw = CONF_OPER_CHWIDTH_160MHZ; + iface->conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + break; + case 320: + bw = CONF_OPER_CHWIDTH_320MHZ; break; default: wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d", @@ -3767,12 +4625,22 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface, iface->freq = freq_params->freq; iface->conf->channel = freq_params->channel; iface->conf->secondary_channel = freq_params->sec_channel_offset; + if (ieee80211_freq_to_channel_ext(freq_params->freq, + freq_params->sec_channel_offset, bw, + &op_class, &chan) == + NUM_HOSTAPD_MODES || + chan != freq_params->channel) + wpa_printf(MSG_INFO, "CSA: Channel mismatch: %d -> %d", + freq_params->channel, chan); + + iface->conf->op_class = op_class; hostapd_set_oper_centr_freq_seg0_idx(iface->conf, seg0_idx); hostapd_set_oper_centr_freq_seg1_idx(iface->conf, seg1_idx); hostapd_set_oper_chwidth(iface->conf, bw); iface->conf->ieee80211n = freq_params->ht_enabled; iface->conf->ieee80211ac = freq_params->vht_enabled; iface->conf->ieee80211ax = freq_params->he_enabled; + iface->conf->ieee80211be = freq_params->eht_enabled; /* * cs_params must not be cleared earlier because the freq_params @@ -3783,6 +4651,149 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface, hostapd_enable_iface(iface); } + +#ifdef CONFIG_IEEE80211AX + +void hostapd_cleanup_cca_params(struct hostapd_data *hapd) +{ + hapd->cca_count = 0; + hapd->cca_color = 0; + hapd->cca_c_off_beacon = 0; + hapd->cca_c_off_proberesp = 0; + hapd->cca_in_progress = false; +} + + +int hostapd_fill_cca_settings(struct hostapd_data *hapd, + struct cca_settings *settings) +{ + struct hostapd_iface *iface = hapd->iface; + u8 old_color; + int ret; + + if (!iface || iface->conf->he_op.he_bss_color_disabled) + return -1; + + settings->link_id = -1; +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) + settings->link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ + + old_color = iface->conf->he_op.he_bss_color; + iface->conf->he_op.he_bss_color = hapd->cca_color; + ret = hostapd_build_beacon_data(hapd, &settings->beacon_after); + if (ret) + return ret; + + iface->conf->he_op.he_bss_color = old_color; + + settings->cca_count = hapd->cca_count; + settings->cca_color = hapd->cca_color, + hapd->cca_in_progress = true; + + ret = hostapd_build_beacon_data(hapd, &settings->beacon_cca); + if (ret) { + free_beacon_data(&settings->beacon_after); + return ret; + } + + settings->ubpr.unsol_bcast_probe_resp_tmpl = + hostapd_unsol_bcast_probe_resp(hapd, &settings->ubpr); + + settings->counter_offset_beacon = hapd->cca_c_off_beacon; + settings->counter_offset_presp = hapd->cca_c_off_proberesp; + + return 0; +} + + +static void hostapd_switch_color_timeout_handler(void *eloop_data, + void *user_ctx) +{ + struct hostapd_data *hapd = (struct hostapd_data *) eloop_data; + os_time_t delta_t; + unsigned int b; + int i, r; + + /* CCA can be triggered once the handler constantly receives + * color collision events to for at least + * DOT11BSS_COLOR_COLLISION_AP_PERIOD (50 s by default). */ + delta_t = hapd->last_color_collision.sec - + hapd->first_color_collision.sec; + if (delta_t < DOT11BSS_COLOR_COLLISION_AP_PERIOD) + return; + + r = os_random() % HE_OPERATION_BSS_COLOR_MAX; + for (i = 0; i < HE_OPERATION_BSS_COLOR_MAX; i++) { + if (r && !(hapd->color_collision_bitmap & (1ULL << r))) + break; + + r = (r + 1) % HE_OPERATION_BSS_COLOR_MAX; + } + + if (i == HE_OPERATION_BSS_COLOR_MAX) { + /* There are no free colors so turn BSS coloring off */ + wpa_printf(MSG_INFO, + "No free colors left, turning off BSS coloring"); + hapd->iface->conf->he_op.he_bss_color_disabled = 1; + hapd->iface->conf->he_op.he_bss_color = os_random() % 63 + 1; + for (b = 0; b < hapd->iface->num_bss; b++) + ieee802_11_set_beacon(hapd->iface->bss[b]); + return; + } + + for (b = 0; b < hapd->iface->num_bss; b++) { + struct hostapd_data *bss = hapd->iface->bss[b]; + struct cca_settings settings; + int ret; + + hostapd_cleanup_cca_params(bss); + bss->cca_color = r; + bss->cca_count = 10; + + if (hostapd_fill_cca_settings(bss, &settings)) { + hostapd_cleanup_cca_params(bss); + continue; + } + + ret = hostapd_drv_switch_color(bss, &settings); + if (ret) + hostapd_cleanup_cca_params(bss); + + free_beacon_data(&settings.beacon_cca); + free_beacon_data(&settings.beacon_after); + os_free(settings.ubpr.unsol_bcast_probe_resp_tmpl); + } +} + + +void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap) +{ + struct os_reltime now; + + if (hapd->cca_in_progress) + return; + + if (os_get_reltime(&now)) + return; + + hapd->color_collision_bitmap = bitmap; + hapd->last_color_collision = now; + + if (eloop_is_timeout_registered(hostapd_switch_color_timeout_handler, + hapd, NULL)) + return; + + hapd->first_color_collision = now; + /* 10 s window as margin for persistent color collision reporting */ + eloop_register_timeout(DOT11BSS_COLOR_COLLISION_AP_PERIOD + 10, 0, + hostapd_switch_color_timeout_handler, + hapd, NULL); +} + +#endif /* CONFIG_IEEE80211AX */ + #endif /* NEED_AP_MLME */ @@ -3845,3 +4856,174 @@ void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx) } } #endif /* CONFIG_OCV */ + + +#ifdef CONFIG_IEEE80211BE + +struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd, + u8 link_id) +{ + struct hostapd_iface *iface; + struct hostapd_data *bss; + unsigned int i, j; + + for (i = 0; i < hapd->iface->interfaces->count; i++) { + iface = hapd->iface->interfaces->iface[i]; + if (!iface) + continue; + + for (j = 0; j < iface->num_bss; j++) { + bss = iface->bss[j]; + + if (!bss->conf->mld_ap || + !hostapd_is_ml_partner(hapd, bss)) + continue; + + if (!bss->drv_priv) + continue; + + if (bss->mld_link_id == link_id) + return bss; + } + } + + return NULL; +} + + +bool hostapd_is_ml_partner(struct hostapd_data *hapd1, + struct hostapd_data *hapd2) +{ + if (!hapd1->conf->mld_ap || !hapd2->conf->mld_ap) + return false; + + return !os_strcmp(hapd1->conf->iface, hapd2->conf->iface); +} + + +u8 hostapd_get_mld_id(struct hostapd_data *hapd) +{ + if (!hapd->conf->mld_ap) + return 255; + + /* MLD ID 0 represents self */ + return 0; + + /* TODO: MLD ID for Multiple BSS cases */ +} + + +int hostapd_mld_add_link(struct hostapd_data *hapd) +{ + struct hostapd_mld *mld = hapd->mld; + + if (!hapd->conf->mld_ap) + return 0; + + /* Should not happen */ + if (!mld) + return -1; + + dl_list_add_tail(&mld->links, &hapd->link); + mld->num_links++; + + wpa_printf(MSG_DEBUG, "AP MLD %s: Link ID %d added. num_links: %d", + mld->name, hapd->mld_link_id, mld->num_links); + + if (mld->fbss) + return 0; + + mld->fbss = hapd; + wpa_printf(MSG_DEBUG, "AP MLD %s: First link BSS set to %p", + mld->name, mld->fbss); + return 0; +} + + +int hostapd_mld_remove_link(struct hostapd_data *hapd) +{ + struct hostapd_mld *mld = hapd->mld; + struct hostapd_data *next_fbss; + + if (!hapd->conf->mld_ap) + return 0; + + /* Should not happen */ + if (!mld) + return -1; + + dl_list_del(&hapd->link); + mld->num_links--; + + wpa_printf(MSG_DEBUG, "AP MLD %s: Link ID %d removed. num_links: %d", + mld->name, hapd->mld_link_id, mld->num_links); + + if (mld->fbss != hapd) + return 0; + + /* If the list is empty, all links are removed */ + if (dl_list_empty(&mld->links)) { + mld->fbss = NULL; + } else { + next_fbss = dl_list_entry(mld->links.next, struct hostapd_data, + link); + mld->fbss = next_fbss; + } + + wpa_printf(MSG_DEBUG, "AP MLD %s: First link BSS set to %p", + mld->name, mld->fbss); + return 0; +} + + +bool hostapd_mld_is_first_bss(struct hostapd_data *hapd) +{ + struct hostapd_mld *mld = hapd->mld; + + if (!hapd->conf->mld_ap) + return true; + + /* Should not happen */ + if (!mld) + return false; + + /* If fbss is not set, it is safe to assume the caller is the first BSS. + */ + if (!mld->fbss) + return true; + + return hapd == mld->fbss; +} + + +struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd) +{ + struct hostapd_mld *mld = hapd->mld; + + if (!hapd->conf->mld_ap) + return NULL; + + /* Should not happen */ + if (!mld) + return NULL; + + return mld->fbss; +} + +#endif /* CONFIG_IEEE80211BE */ + + +u16 hostapd_get_punct_bitmap(struct hostapd_data *hapd) +{ + u16 punct_bitmap = 0; + +#ifdef CONFIG_IEEE80211BE + punct_bitmap = hapd->iconf->punct_bitmap; +#ifdef CONFIG_TESTING_OPTIONS + if (!punct_bitmap) + punct_bitmap = hapd->conf->eht_oper_puncturing_override; +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_IEEE80211BE */ + + return punct_bitmap; +} diff --git a/wpa_supplicant-2.9_standard/src/ap/hostapd.h b/wpa_supplicant-2.9_standard/src/ap/hostapd.h index f3ca7529ac96a41528d209172443c2164dcbe405..dcf395ca5ee8802f171911cee761da4c5cdf50d0 100644 --- a/wpa_supplicant-2.9_standard/src/ap/hostapd.h +++ b/wpa_supplicant-2.9_standard/src/ap/hostapd.h @@ -14,6 +14,7 @@ #endif /* CONFIG_SQLITE */ #include "common/defs.h" +#include "common/dpp.h" #include "utils/list.h" #include "ap_config.h" #include "drivers/driver.h" @@ -43,6 +44,7 @@ struct mesh_conf; #endif /* CONFIG_CTRL_IFACE_UDP */ struct hostapd_iface; +struct hostapd_mld; struct hapd_interfaces { int (*reload_config)(struct hostapd_iface *iface); @@ -75,18 +77,34 @@ struct hapd_interfaces { #ifdef CONFIG_DPP struct dpp_global *dpp; +#ifdef CONFIG_DPP3 + struct os_reltime dpp_pb_time; + struct os_reltime dpp_pb_announce_time; + struct dpp_pb_info dpp_pb[DPP_PB_INFO_COUNT]; + struct dpp_bootstrap_info *dpp_pb_bi; + u8 dpp_pb_c_nonce[DPP_MAX_NONCE_LEN]; + u8 dpp_pb_resp_hash[SHA256_MAC_LEN]; + struct os_reltime dpp_pb_last_resp; + bool dpp_pb_result_indicated; + char *dpp_pb_cmd; +#endif /* CONFIG_DPP3 */ #endif /* CONFIG_DPP */ #ifdef CONFIG_CTRL_IFACE_UDP unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN]; #endif /* CONFIG_CTRL_IFACE_UDP */ +#ifdef CONFIG_IEEE80211BE + struct hostapd_mld **mld; + size_t mld_count; +#endif /* CONFIG_IEEE80211BE */ }; enum hostapd_chan_status { HOSTAPD_CHAN_VALID = 0, /* channel is ready */ HOSTAPD_CHAN_INVALID = 1, /* no usable channel found */ HOSTAPD_CHAN_ACS = 2, /* ACS work being performed */ + HOSTAPD_CHAN_INVALID_NO_IR = 3, /* channel invalid due to AFC NO IR */ }; struct hostapd_probereq_cb { @@ -207,6 +225,7 @@ struct hostapd_data { void *ssl_ctx; void *eap_sim_db_priv; + struct crypto_rsa_key *imsi_privacy_key; struct radius_server_data *radius_srv; struct dl_list erp_keys; /* struct eap_server_erp_key */ @@ -273,7 +292,8 @@ struct hostapd_data { void *wps_event_cb_ctx; void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr, - int authorized, const u8 *p2p_dev_addr); + int authorized, const u8 *p2p_dev_addr, + const u8 *ip); void *sta_authorized_cb_ctx; void (*setup_complete_cb)(void *ctx); @@ -294,6 +314,17 @@ struct hostapd_data { unsigned int cs_c_off_ecsa_beacon; unsigned int cs_c_off_ecsa_proberesp; +#ifdef CONFIG_IEEE80211AX + bool cca_in_progress; + u8 cca_count; + u8 cca_color; + unsigned int cca_c_off_beacon; + unsigned int cca_c_off_proberesp; + struct os_reltime first_color_collision; + struct os_reltime last_color_collision; + u64 color_collision_bitmap; +#endif /* CONFIG_IEEE80211AX */ + #ifdef CONFIG_P2P struct p2p_data *p2p; struct p2p_group *p2p_group; @@ -311,6 +342,7 @@ struct hostapd_data { #ifdef CONFIG_PROXYARP struct l2_packet_data *sock_dhcp; struct l2_packet_data *sock_ndisc; + bool x_snoop_initialized; #endif /* CONFIG_PROXYARP */ #ifdef CONFIG_MESH int num_plinks; @@ -327,11 +359,15 @@ struct hostapd_data { #endif /* CONFIG_SQLITE */ #ifdef CONFIG_SAE + +#define COMEBACK_KEY_SIZE 8 +#define COMEBACK_PENDING_IDX_SIZE 256 + /** Key used for generating SAE anti-clogging tokens */ - u8 comeback_key[8]; + u8 comeback_key[COMEBACK_KEY_SIZE]; struct os_reltime last_comeback_key_update; u16 comeback_idx; - u16 comeback_pending_idx[256]; + u16 comeback_pending_idx[COMEBACK_PENDING_IDX_SIZE]; int dot11RSNASAERetransPeriod; /* msec */ struct dl_list sae_commit_queue; /* struct hostapd_sae_commit_queue */ #endif /* CONFIG_SAE */ @@ -369,8 +405,10 @@ struct hostapd_data { u8 beacon_req_token; u8 lci_req_token; u8 range_req_token; + u8 link_measurement_req_token; unsigned int lci_req_active:1; unsigned int range_req_active:1; + unsigned int link_mesr_req_active:1; int dhcp_sock; /* UDP socket used with the DHCP server */ @@ -387,7 +425,9 @@ struct hostapd_data { struct dpp_pkex *dpp_pkex; struct dpp_bootstrap_info *dpp_pkex_bi; char *dpp_pkex_code; + size_t dpp_pkex_code_len; char *dpp_pkex_identifier; + enum dpp_pkex_ver dpp_pkex_ver; char *dpp_pkex_auth_cmd; char *dpp_configurator_params; struct os_reltime dpp_last_init; @@ -406,6 +446,7 @@ struct hostapd_data { int dpp_chirp_round; int dpp_chirp_scan_done; int dpp_chirp_listen; + struct os_reltime dpp_relay_last_needs_ctrl; #endif /* CONFIG_DPP2 */ #ifdef CONFIG_TESTING_OPTIONS char *dpp_config_obj_override; @@ -429,6 +470,23 @@ struct hostapd_data { #ifdef CONFIG_CTRL_IFACE_UDP unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN]; #endif /* CONFIG_CTRL_IFACE_UDP */ + +#ifdef CONFIG_IEEE80211BE + u8 eht_mld_bss_param_change; + struct hostapd_mld *mld; + struct dl_list link; + u8 mld_link_id; +#ifdef CONFIG_TESTING_OPTIONS + u8 eht_mld_link_removal_count; +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_IEEE80211BE */ + +#ifdef CONFIG_NAN_USD + struct nan_de *nan_de; +#endif /* CONFIG_NAN_USD */ + + u64 scan_cookie; /* Scan instance identifier for the ongoing HT40 scan + */ }; @@ -442,6 +500,29 @@ struct hostapd_sta_info { #endif /* CONFIG_TAXONOMY */ }; +#ifdef CONFIG_IEEE80211BE +/** + * struct hostapd_mld - hostapd per-mld data structure + */ +struct hostapd_mld { + char name[IFNAMSIZ + 1]; + u8 mld_addr[ETH_ALEN]; + u8 next_link_id; + u8 num_links; + /* Number of hostapd_data (hapd) referencing this. num_links cannot be + * used since num_links can go to 0 even when a BSS is disabled and + * when it is re-enabled, the MLD should exist and hence it cannot be + * freed when num_links is 0. + */ + u8 refcount; + + struct hostapd_data *fbss; + struct dl_list links; /* List head of all affiliated links */ +}; + +#define HOSTAPD_MLD_MAX_REF_COUNT 0xFF +#endif /* CONFIG_IEEE80211BE */ + /** * struct hostapd_iface - hostapd per-interface data structure */ @@ -459,6 +540,7 @@ struct hostapd_iface { HAPD_IFACE_ACS, HAPD_IFACE_HT_SCAN, HAPD_IFACE_DFS, + HAPD_IFACE_NO_IR, HAPD_IFACE_ENABLED } state; @@ -497,6 +579,7 @@ struct hostapd_iface { u64 drv_flags; u64 drv_flags2; + unsigned int drv_rrm_flags; /* * A bitmap of supported protocols for probe response offload. See @@ -508,6 +591,8 @@ struct hostapd_iface { const u8 *extended_capa, *extended_capa_mask; unsigned int extended_capa_len; + u16 mld_eml_capa, mld_mld_capa; + unsigned int drv_max_acl_mac_addrs; struct hostapd_hw_modes *hw_features; @@ -520,6 +605,23 @@ struct hostapd_iface { int *basic_rates; int freq; + bool radar_detected; + + /* Background radar configuration */ + struct { + int channel; + int secondary_channel; + int freq; + int centr_freq_seg0_idx; + int centr_freq_seg1_idx; + /* Main chain is on temporary channel during + * CAC detection on radar offchain. + */ + unsigned int temp_ch:1; + /* CAC started on radar offchain */ + unsigned int cac_started:1; + } radar_background; + u16 hw_flags; /* Number of associated Non-ERP stations (i.e., stations using 802.11b @@ -580,6 +682,7 @@ struct hostapd_iface { #ifdef CONFIG_ACS unsigned int acs_num_completed_scans; + unsigned int acs_num_retries; #endif /* CONFIG_ACS */ void (*scan_cb)(struct hostapd_iface *iface); @@ -596,8 +699,18 @@ struct hostapd_iface { /* Previous WMM element information */ struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM]; + /* Maximum number of interfaces supported for MBSSID advertisement */ + unsigned int mbssid_max_interfaces; + /* Maximum profile periodicity for enhanced MBSSID advertisement */ + unsigned int ema_max_periodicity; + int (*enable_iface_cb)(struct hostapd_iface *iface); int (*disable_iface_cb)(struct hostapd_iface *iface); + + /* Configured freq of interface is NO_IR */ + bool is_no_ir; + + bool is_ch_switch_dfs; /* Channel switch from ACS to DFS */ }; /* hostapd.c */ @@ -625,6 +738,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, void hostapd_interface_deinit_free(struct hostapd_iface *iface); int hostapd_enable_iface(struct hostapd_iface *hapd_iface); int hostapd_reload_iface(struct hostapd_iface *hapd_iface); +int hostapd_reload_bss_only(struct hostapd_data *bss); int hostapd_disable_iface(struct hostapd_iface *hapd_iface); void hostapd_bss_deinit_no_free(struct hostapd_data *hapd); void hostapd_free_hapd_data(struct hostapd_data *hapd); @@ -647,6 +761,9 @@ void hostapd_periodic_iface(struct hostapd_iface *iface); int hostapd_owe_trans_get_info(struct hostapd_data *hapd); void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx); +void hostapd_switch_color(struct hostapd_data *hapd, u64 bitmap); +void hostapd_cleanup_cca_params(struct hostapd_data *hapd); + /* utils.c */ int hostapd_register_probereq_cb(struct hostapd_data *hapd, int (*cb)(void *ctx, const u8 *sa, @@ -654,13 +771,15 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd, const u8 *ie, size_t ie_len, int ssi_signal), void *ctx); -void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr); +void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr, + int mld_assoc_link_id); /* drv_callbacks.c (TODO: move to somewhere else?) */ void hostapd_notify_assoc_fils_finish(struct hostapd_data *hapd, struct sta_info *sta); int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, - const u8 *ie, size_t ielen, int reassoc); + const u8 *req_ie, size_t req_ielen, const u8 *resp_ie, + size_t resp_ielen, const u8 *link_addr, int reassoc); void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr); void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr); void hostapd_event_connect_failed_reason(struct hostapd_data *hapd, @@ -670,7 +789,7 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da, int ssi_signal); void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, int offset, int width, int cf1, int cf2, - int finished); + u16 punct_bitmap, int finished); struct survey_results; void hostapd_event_get_survey(struct hostapd_iface *iface, struct survey_results *survey_results); @@ -692,4 +811,42 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd, struct fst_wpa_obj *iface_obj); #endif /* CONFIG_FST */ +int hostapd_set_acl(struct hostapd_data *hapd); +struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd); +int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd); +struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd, + u8 link_id); +int hostapd_link_remove(struct hostapd_data *hapd, u32 count); +bool hostapd_is_ml_partner(struct hostapd_data *hapd1, + struct hostapd_data *hapd2); +u8 hostapd_get_mld_id(struct hostapd_data *hapd); +int hostapd_mld_add_link(struct hostapd_data *hapd); +int hostapd_mld_remove_link(struct hostapd_data *hapd); +struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd); + +void free_beacon_data(struct beacon_data *beacon); +int hostapd_fill_cca_settings(struct hostapd_data *hapd, + struct cca_settings *settings); + +#ifdef CONFIG_IEEE80211BE + +bool hostapd_mld_is_first_bss(struct hostapd_data *hapd); + +#define for_each_mld_link(partner, self) \ + dl_list_for_each(partner, &self->mld->links, struct hostapd_data, link) + +#else /* CONFIG_IEEE80211BE */ + +static inline bool hostapd_mld_is_first_bss(struct hostapd_data *hapd) +{ + return true; +} + +#define for_each_mld_link(partner, self) \ + if (false) + +#endif /* CONFIG_IEEE80211BE */ + +u16 hostapd_get_punct_bitmap(struct hostapd_data *hapd); + #endif /* HOSTAPD_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/hw_features.c b/wpa_supplicant-2.9_standard/src/ap/hw_features.c index 67aface85c9ed3dbaf86cd1ff2ecfa32d35eddd0..e3a85113cb13dcf6cd0ede318d311a13aba0db4a 100644 --- a/wpa_supplicant-2.9_standard/src/ap/hw_features.c +++ b/wpa_supplicant-2.9_standard/src/ap/hw_features.c @@ -79,6 +79,9 @@ int hostapd_get_hw_features(struct hostapd_iface *iface) u16 num_modes, flags; struct hostapd_hw_modes *modes; u8 dfs_domain; + enum hostapd_hw_mode mode = HOSTAPD_MODE_IEEE80211ANY; + bool is_6ghz = false; + bool orig_mode_valid = false; if (hostapd_drv_none(hapd)) return -1; @@ -95,6 +98,18 @@ int hostapd_get_hw_features(struct hostapd_iface *iface) iface->hw_flags = flags; iface->dfs_domain = dfs_domain; + if (iface->current_mode) { + /* + * Received driver event CHANNEL_LIST_CHANGED when the current + * hw mode is valid. Clear iface->current_mode temporarily as + * the mode instance will be replaced with a new instance and + * the current pointer would be pointing to freed memory. + */ + orig_mode_valid = true; + mode = iface->current_mode->mode; + is_6ghz = iface->current_mode->is_6ghz; + iface->current_mode = NULL; + } hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); iface->hw_features = modes; iface->num_hw_features = num_modes; @@ -104,6 +119,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface) int dfs_enabled = hapd->iconf->ieee80211h && (iface->drv_flags & WPA_DRIVER_FLAGS_RADAR); + /* Restore orignal mode if possible */ + if (orig_mode_valid && feature->mode == mode && + feature->num_channels > 0 && + is_6ghz == is_6ghz_freq(feature->channels[0].freq)) + iface->current_mode = feature; + /* set flag for channels we can use in current regulatory * domain */ for (j = 0; j < feature->num_channels; j++) { @@ -141,6 +162,12 @@ int hostapd_get_hw_features(struct hostapd_iface *iface) } } + if (orig_mode_valid && !iface->current_mode) { + wpa_printf(MSG_ERROR, + "%s: Could not update iface->current_mode", + __func__); + } + return 0; } @@ -376,7 +403,7 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface) iface->conf->secondary_channel = 0; hostapd_set_oper_centr_freq_seg0_idx(iface->conf, 0); hostapd_set_oper_centr_freq_seg1_idx(iface->conf, 0); - hostapd_set_oper_chwidth(iface->conf, CHANWIDTH_USE_HT); + hostapd_set_oper_chwidth(iface->conf, CONF_OPER_CHWIDTH_USE_HT); res = 1; wpa_printf(MSG_INFO, "Fallback to 20 MHz"); } @@ -484,6 +511,12 @@ static void ap_ht40_scan_retry(void *eloop_data, void *user_data) else ieee80211n_scan_channels_5g(iface, ¶ms); + params.link_id = -1; +#ifdef CONFIG_IEEE80211BE + if (iface->bss[0]->conf->mld_ap) + params.link_id = iface->bss[0]->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ + ret = hostapd_driver_scan(iface->bss[0], ¶ms); iface->num_ht40_scan_tries++; os_free(params.freqs); @@ -499,6 +532,7 @@ static void ap_ht40_scan_retry(void *eloop_data, void *user_data) if (ret == 0) { iface->scan_cb = ieee80211n_check_scan; + iface->bss[0]->scan_cookie = params.scan_cookie; return; } @@ -534,6 +568,11 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface) else ieee80211n_scan_channels_5g(iface, ¶ms); + params.link_id = -1; +#ifdef CONFIG_IEEE80211BE + if (iface->bss[0]->conf->mld_ap) + params.link_id = iface->bss[0]->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ ret = hostapd_driver_scan(iface->bss[0], ¶ms); os_free(params.freqs); @@ -555,6 +594,7 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface) } iface->scan_cb = ieee80211n_check_scan; + iface->bss[0]->scan_cookie = params.scan_cookie; return 1; } @@ -799,6 +839,11 @@ int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface) } +/* Returns: + * 1 = usable + * 0 = not usable + * -1 = not currently usable due to 6 GHz NO-IR + */ static int hostapd_is_usable_chan(struct hostapd_iface *iface, int frequency, int primary) { @@ -821,6 +866,10 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface, chan->flag, chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "", chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : ""); + + if (is_6ghz_freq(chan->freq) && (chan->flag & HOSTAPD_CHAN_NO_IR)) + return -1; + return 0; } @@ -830,6 +879,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface) int i, contiguous = 0; int num_of_enabled = 0; int max_contiguous = 0; + int err; struct ieee80211_edmg_config edmg; struct hostapd_channel_data *pri_chan; @@ -869,8 +919,9 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface) if (num_of_enabled > 4) return 0; - if (!hostapd_is_usable_chan(iface, freq, 1)) - return 0; + err = hostapd_is_usable_chan(iface, freq, 1); + if (err <= 0) + return err; if (contiguous > max_contiguous) max_contiguous = contiguous; @@ -897,10 +948,75 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface) } +static bool hostapd_is_usable_punct_bitmap(struct hostapd_iface *iface) +{ +#ifdef CONFIG_IEEE80211BE + struct hostapd_config *conf = iface->conf; + u16 bw; + u8 start_chan; + + if (!conf->punct_bitmap) + return true; + + if (!conf->ieee80211be) { + wpa_printf(MSG_ERROR, + "Currently RU puncturing is supported only if ieee80211be is enabled"); + return false; + } + + if (iface->freq >= 2412 && iface->freq <= 2484) { + wpa_printf(MSG_ERROR, + "RU puncturing not supported in 2.4 GHz"); + return false; + } + + /* + * In the 6 GHz band, eht_oper_chwidth is ignored. Use operating class + * to determine channel width. + */ + if (conf->op_class == 137) { + bw = 320; + start_chan = conf->eht_oper_centr_freq_seg0_idx - 30; + } else { + switch (conf->eht_oper_chwidth) { + case 0: + wpa_printf(MSG_ERROR, + "RU puncturing is supported only in 80 MHz and 160 MHz"); + return false; + case 1: + bw = 80; + start_chan = conf->eht_oper_centr_freq_seg0_idx - 6; + break; + case 2: + bw = 160; + start_chan = conf->eht_oper_centr_freq_seg0_idx - 14; + break; + default: + return false; + } + } + + if (!is_punct_bitmap_valid(bw, (conf->channel - start_chan) / 4, + conf->punct_bitmap)) { + wpa_printf(MSG_ERROR, "Invalid puncturing bitmap"); + return false; + } +#endif /* CONFIG_IEEE80211BE */ + + return true; +} + + +/* Returns: + * 1 = usable + * 0 = not usable + * -1 = not currently usable due to 6 GHz NO-IR + */ static int hostapd_is_usable_chans(struct hostapd_iface *iface) { int secondary_freq; struct hostapd_channel_data *pri_chan; + int err, err2; if (!iface->current_mode) return 0; @@ -912,18 +1028,25 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface) wpa_printf(MSG_ERROR, "Primary frequency not present"); return 0; } - if (!hostapd_is_usable_chan(iface, pri_chan->freq, 1)) { + + err = hostapd_is_usable_chan(iface, pri_chan->freq, 1); + if (err <= 0) { wpa_printf(MSG_ERROR, "Primary frequency not allowed"); - return 0; + return err; } - if (!hostapd_is_usable_edmg(iface)) + err = hostapd_is_usable_edmg(iface); + if (err <= 0) + return err; + + if (!hostapd_is_usable_punct_bitmap(iface)) return 0; if (!iface->conf->secondary_channel) return 1; - if (hostapd_is_usable_chan(iface, iface->freq + - iface->conf->secondary_channel * 20, 0)) { + err = hostapd_is_usable_chan(iface, iface->freq + + iface->conf->secondary_channel * 20, 0); + if (err > 0) { if (iface->conf->secondary_channel == 1 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) return 1; @@ -932,35 +1055,51 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface) return 1; } if (!iface->conf->ht40_plus_minus_allowed) - return 0; + return err; /* Both HT40+ and HT40- are set, pick a valid secondary channel */ secondary_freq = iface->freq + 20; - if (hostapd_is_usable_chan(iface, secondary_freq, 0) && - (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) { + err2 = hostapd_is_usable_chan(iface, secondary_freq, 0); + if (err2 > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P)) { iface->conf->secondary_channel = 1; return 1; } secondary_freq = iface->freq - 20; - if (hostapd_is_usable_chan(iface, secondary_freq, 0) && - (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) { + err2 = hostapd_is_usable_chan(iface, secondary_freq, 0); + if (err2 > 0 && (pri_chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40M)) { iface->conf->secondary_channel = -1; return 1; } - return 0; + return err; +} + + +static bool skip_mode(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode) +{ + int chan; + + if (iface->freq > 0 && !hw_mode_get_channel(mode, iface->freq, &chan)) + return true; + + if (is_6ghz_op_class(iface->conf->op_class) && iface->freq == 0 && + !mode->is_6ghz) + return true; + + return false; } -static void hostapd_determine_mode(struct hostapd_iface *iface) +int hostapd_determine_mode(struct hostapd_iface *iface) { int i; enum hostapd_hw_mode target_mode; if (iface->current_mode || iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY) - return; + return 0; if (iface->freq < 4000) target_mode = HOSTAPD_MODE_IEEE80211G; @@ -974,14 +1113,20 @@ static void hostapd_determine_mode(struct hostapd_iface *iface) mode = &iface->hw_features[i]; if (mode->mode == target_mode) { + if (skip_mode(iface, mode)) + continue; + iface->current_mode = mode; iface->conf->hw_mode = mode->mode; break; } } - if (!iface->current_mode) - wpa_printf(MSG_ERROR, "ACS: Cannot decide mode"); + if (!iface->current_mode) { + wpa_printf(MSG_ERROR, "ACS/CSA: Cannot decide mode"); + return -1; + } + return 0; } @@ -989,11 +1134,17 @@ static enum hostapd_chan_status hostapd_check_chans(struct hostapd_iface *iface) { if (iface->freq) { + int err; + hostapd_determine_mode(iface); - if (hostapd_is_usable_chans(iface)) - return HOSTAPD_CHAN_VALID; - else - return HOSTAPD_CHAN_INVALID; + + err = hostapd_is_usable_chans(iface); + if (err <= 0) { + if (!err) + return HOSTAPD_CHAN_INVALID; + return HOSTAPD_CHAN_INVALID_NO_IR; + } + return HOSTAPD_CHAN_VALID; } /* @@ -1004,6 +1155,8 @@ hostapd_check_chans(struct hostapd_iface *iface) switch (acs_init(iface)) { case HOSTAPD_CHAN_ACS: return HOSTAPD_CHAN_ACS; + case HOSTAPD_CHAN_INVALID_NO_IR: + return HOSTAPD_CHAN_INVALID_NO_IR; case HOSTAPD_CHAN_VALID: case HOSTAPD_CHAN_INVALID: default: @@ -1043,6 +1196,7 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err) switch (hostapd_check_chans(iface)) { case HOSTAPD_CHAN_VALID: + iface->is_no_ir = false; wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_COMPLETED "freq=%d channel=%d", iface->freq, iface->conf->channel); @@ -1052,6 +1206,9 @@ int hostapd_acs_completed(struct hostapd_iface *iface, int err) wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, ACS_EVENT_FAILED); hostapd_notify_bad_chans(iface); goto out; + case HOSTAPD_CHAN_INVALID_NO_IR: + iface->is_no_ir = true; + __attribute__((fallthrough)); case HOSTAPD_CHAN_INVALID: default: wpa_printf(MSG_ERROR, "ACS picked unusable channels"); @@ -1074,6 +1231,25 @@ out: } +/** + * hostapd_csa_update_hwmode - Update hardware mode + * @iface: Pointer to interface data. + * Returns: 0 on success, < 0 on failure + * + * Update hardware mode when the operating channel changed because of CSA. + */ +int hostapd_csa_update_hwmode(struct hostapd_iface *iface) +{ + if (!iface || !iface->conf) + return -1; + + iface->current_mode = NULL; + iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY; + + return hostapd_determine_mode(iface); +} + + /** * hostapd_select_hw_mode - Select the hardware mode * @iface: Pointer to interface data. @@ -1091,23 +1267,22 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) if ((iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211G || iface->conf->ieee80211n || iface->conf->ieee80211ac || - iface->conf->ieee80211ax) && + iface->conf->ieee80211ax || iface->conf->ieee80211be) && iface->conf->channel == 14) { - wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE on channel 14"); + wpa_printf(MSG_INFO, "Disable OFDM/HT/VHT/HE/EHT on channel 14"); iface->conf->hw_mode = HOSTAPD_MODE_IEEE80211B; iface->conf->ieee80211n = 0; iface->conf->ieee80211ac = 0; iface->conf->ieee80211ax = 0; + iface->conf->ieee80211be = 0; } iface->current_mode = NULL; for (i = 0; i < iface->num_hw_features; i++) { struct hostapd_hw_modes *mode = &iface->hw_features[i]; - int chan; if (mode->mode == iface->conf->hw_mode) { - if (iface->freq > 0 && - !hw_mode_get_channel(mode, iface->freq, &chan)) + if (skip_mode(iface, mode)) continue; iface->current_mode = mode; @@ -1138,9 +1313,13 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) switch (hostapd_check_chans(iface)) { case HOSTAPD_CHAN_VALID: + iface->is_no_ir = false; return 0; case HOSTAPD_CHAN_ACS: /* ACS will run and later complete */ return 1; + case HOSTAPD_CHAN_INVALID_NO_IR: + iface->is_no_ir = true; + __attribute__((fallthrough)); case HOSTAPD_CHAN_INVALID: default: hostapd_notify_bad_chans(iface); diff --git a/wpa_supplicant-2.9_standard/src/ap/hw_features.h b/wpa_supplicant-2.9_standard/src/ap/hw_features.h index ad0ddf7ff3864a0214452c4ffcd4b25a4ee9b02b..c682c6d20b817c6ba68be348c1b3c46e5f9be7ce 100644 --- a/wpa_supplicant-2.9_standard/src/ap/hw_features.h +++ b/wpa_supplicant-2.9_standard/src/ap/hw_features.h @@ -15,6 +15,7 @@ void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, size_t num_hw_features); int hostapd_get_hw_features(struct hostapd_iface *iface); +int hostapd_csa_update_hwmode(struct hostapd_iface *iface); int hostapd_acs_completed(struct hostapd_iface *iface, int err); int hostapd_select_hw_mode(struct hostapd_iface *iface); const char * hostapd_hw_mode_txt(int mode); @@ -28,6 +29,7 @@ int hostapd_prepare_rates(struct hostapd_iface *iface, void hostapd_stop_setup_timers(struct hostapd_iface *iface); int hostapd_hw_skip_mode(struct hostapd_iface *iface, struct hostapd_hw_modes *mode); +int hostapd_determine_mode(struct hostapd_iface *iface); #else /* NEED_AP_MLME */ static inline void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, @@ -40,6 +42,11 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface) return -1; } +static inline int hostapd_csa_update_hwmode(struct hostapd_iface *iface) +{ + return 0; +} + static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err) { return -1; @@ -91,6 +98,11 @@ static inline int hostapd_check_he_6ghz_capab(struct hostapd_iface *iface) return 0; } +static inline int hostapd_determine_mode(struct hostapd_iface *iface) +{ + return 0; +} + #endif /* NEED_AP_MLME */ #endif /* HW_FEATURES_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_11.c b/wpa_supplicant-2.9_standard/src/ap/ieee802_11.c index b5a11903c2648ffb409fedba9cbb78a2c635c52b..9e192cda74c1874cab997c43942f5ce83515d576 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ieee802_11.c +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_11.c @@ -55,6 +55,9 @@ #include "fils_hlp.h" #include "dpp_hostapd.h" #include "gas_query_ap.h" +#include "comeback_token.h" +#include "nan_usd_ap.h" +#include "pasn/pasn_common.h" #ifdef CONFIG_FILS @@ -68,11 +71,6 @@ prepare_auth_resp_fils(struct hostapd_data *hapd, #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, @@ -86,20 +84,35 @@ static void pasn_fils_auth_resp(struct hostapd_data *hapd, static void handle_auth(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int rssi, int from_queue); +static int add_associated_sta(struct hostapd_data *hapd, + struct sta_info *sta, int reassoc); -u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid) +static u8 * hostapd_eid_multi_ap(struct hostapd_data *hapd, u8 *eid, size_t len) { - u8 multi_ap_val = 0; + struct multi_ap_params multi_ap = { 0 }; if (!hapd->conf->multi_ap) return eid; + if (hapd->conf->multi_ap & BACKHAUL_BSS) - multi_ap_val |= MULTI_AP_BACKHAUL_BSS; + multi_ap.capability |= MULTI_AP_BACKHAUL_BSS; if (hapd->conf->multi_ap & FRONTHAUL_BSS) - multi_ap_val |= MULTI_AP_FRONTHAUL_BSS; + multi_ap.capability |= MULTI_AP_FRONTHAUL_BSS; - return eid + add_multi_ap_ie(eid, 9, multi_ap_val); + if (hapd->conf->multi_ap_client_disallow & + PROFILE1_CLIENT_ASSOC_DISALLOW) + multi_ap.capability |= + MULTI_AP_PROFILE1_BACKHAUL_STA_DISALLOWED; + if (hapd->conf->multi_ap_client_disallow & + PROFILE2_CLIENT_ASSOC_DISALLOW) + multi_ap.capability |= + MULTI_AP_PROFILE2_BACKHAUL_STA_DISALLOWED; + + multi_ap.profile = hapd->conf->multi_ap_profile; + multi_ap.vlanid = hapd->conf->multi_ap_vlanid; + + return eid + add_multi_ap_ie(eid, len, &multi_ap); } @@ -118,9 +131,13 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) num++; if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) num++; - h2e_required = (hapd->conf->sae_pwe == 1 || +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax && hapd->iconf->require_he) + num++; +#endif /* CONFIG_IEEE80211AX */ + h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || hostapd_sae_pw_id_in_use(hapd->conf) == 2) && - hapd->conf->sae_pwe != 3 && + hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt); if (h2e_required) num++; @@ -150,6 +167,13 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; } +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax && hapd->iconf->require_he && count < 8) { + count++; + *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY; + } +#endif /* CONFIG_IEEE80211AX */ + if (h2e_required && count < 8) { count++; *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY; @@ -165,6 +189,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) int i, num, count; int h2e_required; + hapd->conf->xrates_supported = false; if (hapd->iface->current_rates == NULL) return eid; @@ -173,9 +198,13 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) num++; if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) num++; - h2e_required = (hapd->conf->sae_pwe == 1 || +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax && hapd->iconf->require_he) + num++; +#endif /* CONFIG_IEEE80211AX */ + h2e_required = (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || hostapd_sae_pw_id_in_use(hapd->conf) == 2) && - hapd->conf->sae_pwe != 3 && + hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt); if (h2e_required) num++; @@ -208,12 +237,21 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; } +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax && hapd->iconf->require_he) { + count++; + if (count > 8) + *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HE_PHY; + } +#endif /* CONFIG_IEEE80211AX */ + if (h2e_required) { count++; if (count > 8) *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY; } + hapd->conf->xrates_supported = true; return pos; } @@ -366,7 +404,7 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *dst, const u8 *bssid, + const u8 *dst, u16 auth_alg, u16 auth_transaction, u16 resp, const u8 *ies, size_t ies_len, const char *dbg) { @@ -374,18 +412,32 @@ static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta, u8 *buf; size_t rlen; int reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE; + const u8 *sa = hapd->own_addr; + struct wpabuf *ml_resp = NULL; + +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) { + ml_resp = hostapd_ml_auth_resp(hapd); + if (!ml_resp) + return -1; + } +#endif /* CONFIG_IEEE80211BE */ rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len; + if (ml_resp) + rlen += wpabuf_len(ml_resp); buf = os_zalloc(rlen); - if (buf == NULL) + if (!buf) { + wpabuf_free(ml_resp); return -1; + } reply = (struct ieee80211_mgmt *) buf; reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_AUTH); os_memcpy(reply->da, dst, ETH_ALEN); - os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(reply->bssid, bssid, ETH_ALEN); + os_memcpy(reply->sa, sa, ETH_ALEN); + os_memcpy(reply->bssid, sa, ETH_ALEN); reply->u.auth.auth_alg = host_to_le16(auth_alg); reply->u.auth.auth_transaction = host_to_le16(auth_transaction); @@ -394,6 +446,14 @@ static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta, if (ies && ies_len) os_memcpy(reply->u.auth.variable, ies, ies_len); +#ifdef CONFIG_IEEE80211BE + if (ml_resp) + os_memcpy(reply->u.auth.variable + ies_len, + wpabuf_head(ml_resp), wpabuf_len(ml_resp)); + + wpabuf_free(ml_resp); +#endif /* CONFIG_IEEE80211BE */ + wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR_SEC " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)", MAC2STR_SEC(dst), auth_alg, auth_transaction, @@ -441,7 +501,7 @@ static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_IEEE80211R_AP -static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, +static void handle_auth_ft_finish(void *ctx, const u8 *dst, u16 auth_transaction, u16 status, const u8 *ies, size_t ies_len) { @@ -449,7 +509,7 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, struct sta_info *sta; int reply_res; - reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT, + reply_res = send_auth_reply(hapd, NULL, dst, WLAN_AUTH_FT, auth_transaction, status, ies, ies_len, "auth-ft-finish"); @@ -487,21 +547,23 @@ static void sae_set_state(struct sta_info *sta, enum sae_state state, } -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) +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) { const char *password = NULL; struct sae_password_entry *pw; struct sae_pt *pt = NULL; const struct sae_pk *pk = NULL; + struct hostapd_sta_wpa_psk_short *psk = NULL; for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) { if (!is_broadcast_ether_addr(pw->peer_addr) && - os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0) + (!sta || + !ether_addr_equal(pw->peer_addr, sta->addr))) continue; if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier)) continue; @@ -519,6 +581,15 @@ static const char * sae_get_password(struct hostapd_data *hapd, pt = hapd->conf->ssid.pt; } + if (!password && sta) { + for (psk = sta->psk; psk; psk = psk->next) { + if (psk->is_passphrase) { + password = psk->passphrase; + break; + } + } + } + if (pw_entry) *pw_entry = pw; if (s_pt) @@ -541,17 +612,23 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, int use_pt = 0; struct sae_pt *pt = NULL; const struct sae_pk *pk = NULL; + const u8 *own_addr = hapd->own_addr; + +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) + own_addr = hapd->mld->mld_addr; +#endif /* CONFIG_IEEE80211BE */ 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->own_addr, 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) + if (rx_id && hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) use_pt = 1; else if (status_code == WLAN_STATUS_SUCCESS) use_pt = 0; @@ -566,12 +643,12 @@ 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, + sae_prepare_commit_pt(sta->sae, pt, own_addr, sta->addr, NULL, pk) < 0) return NULL; if (update && !use_pt && - sae_prepare_commit(hapd->own_addr, sta->addr, + sae_prepare_commit(own_addr, sta->addr, (u8 *) password, os_strlen(password), sta->sae) < 0) { wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE"); @@ -628,7 +705,7 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd, static int auth_sae_send_commit(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *bssid, int update, int status_code) + int update, int status_code) { struct wpabuf *data; int reply_res; @@ -655,7 +732,7 @@ static int auth_sae_send_commit(struct hostapd_data *hapd, status = hapd->conf->sae_commit_status; } #endif /* CONFIG_TESTING_OPTIONS */ - reply_res = send_auth_reply(hapd, sta, sta->addr, bssid, + reply_res = send_auth_reply(hapd, sta, sta->addr, WLAN_AUTH_SAE, 1, status, wpabuf_head(data), wpabuf_len(data), "sae-send-commit"); @@ -667,8 +744,7 @@ static int auth_sae_send_commit(struct hostapd_data *hapd, static int auth_sae_send_confirm(struct hostapd_data *hapd, - struct sta_info *sta, - const u8 *bssid) + struct sta_info *sta) { struct wpabuf *data; int reply_res; @@ -677,7 +753,7 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd, if (data == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; - reply_res = send_auth_reply(hapd, sta, sta->addr, bssid, + reply_res = send_auth_reply(hapd, sta, sta->addr, WLAN_AUTH_SAE, 2, WLAN_STATUS_SUCCESS, wpabuf_head(data), wpabuf_len(data), "sae-send-confirm"); @@ -727,137 +803,48 @@ static int use_anti_clogging(struct hostapd_data *hapd) return 0; } +#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */ -static int comeback_token_hash(struct hostapd_data *hapd, const u8 *addr, - u8 *idx) -{ - u8 hash[SHA256_MAC_LEN]; - - if (hmac_sha256(hapd->comeback_key, sizeof(hapd->comeback_key), - addr, ETH_ALEN, hash) < 0) - return -1; - *idx = hash[0]; - return 0; -} +#ifdef CONFIG_SAE -static int check_comeback_token(struct hostapd_data *hapd, const u8 *addr, - const u8 *token, size_t token_len) +static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta) { - u8 mac[SHA256_MAC_LEN]; - const u8 *addrs[2]; - size_t len[2]; - u16 token_idx; - u8 idx; - - if (token_len != SHA256_MAC_LEN || - comeback_token_hash(hapd, addr, &idx) < 0) - return -1; - token_idx = hapd->comeback_pending_idx[idx]; - if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) { - wpa_printf(MSG_DEBUG, - "Comeback: Invalid anti-clogging token from " - MACSTR_SEC " - token_idx 0x%04x, expected 0x%04x", - MAC2STR_SEC(addr), WPA_GET_BE16(token), token_idx); + if (sta->sae->sync > hapd->conf->sae_sync) { + sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync"); + sta->sae->sync = 0; + if (sta->sae->tmp) { + /* Disable this SAE instance for 10 seconds to avoid + * unnecessary flood of multiple SAE commits in + * unexpected mesh cases. */ + if (os_get_reltime(&sta->sae->tmp->disabled_until) == 0) + sta->sae->tmp->disabled_until.sec += 10; + } return -1; } - - addrs[0] = addr; - len[0] = ETH_ALEN; - addrs[1] = token; - len[1] = 2; - if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key), - 2, addrs, len, mac) < 0 || - os_memcmp_const(token + 2, &mac[2], SHA256_MAC_LEN - 2) != 0) - return -1; - - hapd->comeback_pending_idx[idx] = 0; /* invalidate used token */ - return 0; } -static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd, - int group, const u8 *addr, int h2e) +static bool sae_proto_instance_disabled(struct sta_info *sta) { - struct wpabuf *buf; - u8 *token; - struct os_reltime now; - u8 idx[2]; - const u8 *addrs[2]; - size_t len[2]; - u8 p_idx; - u16 token_idx; - - os_get_reltime(&now); - if (!os_reltime_initialized(&hapd->last_comeback_key_update) || - os_reltime_expired(&now, &hapd->last_comeback_key_update, 60) || - hapd->comeback_idx == 0xffff) { - if (random_get_bytes(hapd->comeback_key, - sizeof(hapd->comeback_key)) < 0) - return NULL; - wpa_hexdump(MSG_DEBUG, "Comeback: Updated token key", - hapd->comeback_key, sizeof(hapd->comeback_key)); - hapd->last_comeback_key_update = now; - hapd->comeback_idx = 0; - os_memset(hapd->comeback_pending_idx, 0, - sizeof(hapd->comeback_pending_idx)); - } - - buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN); - if (buf == NULL) - return NULL; + struct sae_temporary_data *tmp; - if (group) - wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ - - if (h2e) { - /* Encapsulate Anti-clogging Token field in a container IE */ - wpabuf_put_u8(buf, WLAN_EID_EXTENSION); - wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN); - wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN); - } + if (!sta->sae) + return false; + tmp = sta->sae->tmp; + if (!tmp) + return false; - if (comeback_token_hash(hapd, addr, &p_idx) < 0) { - wpabuf_free(buf); - return NULL; - } + if (os_reltime_initialized(&tmp->disabled_until)) { + struct os_reltime now; - token_idx = hapd->comeback_pending_idx[p_idx]; - if (!token_idx) { - hapd->comeback_idx++; - token_idx = hapd->comeback_idx; - hapd->comeback_pending_idx[p_idx] = token_idx; - } - WPA_PUT_BE16(idx, token_idx); - token = wpabuf_put(buf, SHA256_MAC_LEN); - addrs[0] = addr; - len[0] = ETH_ALEN; - addrs[1] = idx; - len[1] = sizeof(idx); - if (hmac_sha256_vector(hapd->comeback_key, sizeof(hapd->comeback_key), - 2, addrs, len, token) < 0) { - wpabuf_free(buf); - return NULL; + os_get_reltime(&now); + if (os_reltime_before(&now, &tmp->disabled_until)) + return true; } - WPA_PUT_BE16(token, token_idx); - - return buf; -} - -#endif /* defined(CONFIG_SAE) || defined(CONFIG_PASN) */ - - -#ifdef CONFIG_SAE -static int sae_check_big_sync(struct hostapd_data *hapd, struct sta_info *sta) -{ - if (sta->sae->sync > hapd->conf->sae_sync) { - sae_set_state(sta, SAE_NOTHING, "Sync > dot11RSNASAESync"); - sta->sae->sync = 0; - return -1; - } - return 0; + return false; } @@ -877,13 +864,13 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data) switch (sta->sae->state) { case SAE_COMMITTED: - ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1); + ret = auth_sae_send_commit(hapd, sta, 0, -1); eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000, auth_sae_retransmit_timer, hapd, sta); break; case SAE_CONFIRMED: - ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr); + ret = auth_sae_send_confirm(hapd, sta); eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000, auth_sae_retransmit_timer, hapd, sta); @@ -923,7 +910,15 @@ static void sae_sme_send_external_auth_status(struct hostapd_data *hapd, os_memset(¶ms, 0, sizeof(params)); params.status = status; - params.bssid = sta->addr; + +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) + params.bssid = + sta->mld_info.links[sta->mld_assoc_link_id].peer_addr; +#endif /* CONFIG_IEEE80211BE */ + if (!params.bssid) + params.bssid = sta->addr; + if (status == WLAN_STATUS_SUCCESS && sta->sae && !hapd->conf->disable_pmksa_caching) params.pmkid = sta->sae->pmkid; @@ -942,23 +937,27 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta) " to VLAN ID %d", MAC2STR_SEC(sta->addr), sta->sae->tmp->vlan_id); - os_memset(&vlan_desc, 0, sizeof(vlan_desc)); - vlan_desc.notempty = 1; - vlan_desc.untagged = sta->sae->tmp->vlan_id; - if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { - wpa_printf(MSG_INFO, - "Invalid VLAN ID %d in sae_password", - sta->sae->tmp->vlan_id); - return; - } + if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) { + os_memset(&vlan_desc, 0, sizeof(vlan_desc)); + vlan_desc.notempty = 1; + vlan_desc.untagged = sta->sae->tmp->vlan_id; + if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { + wpa_printf(MSG_INFO, + "Invalid VLAN ID %d in sae_password", + sta->sae->tmp->vlan_id); + return; + } - if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 || - ap_sta_bind_vlan(hapd, sta) < 0) { - wpa_printf(MSG_INFO, - "Failed to assign VLAN ID %d from sae_password to " - MACSTR_SEC, sta->sae->tmp->vlan_id, - MAC2STR_SEC(sta->addr)); - return; + if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0 || + ap_sta_bind_vlan(hapd, sta) < 0) { + wpa_printf(MSG_INFO, + "Failed to assign VLAN ID %d from sae_password to " + MACSTR_SEC, sta->sae->tmp->vlan_id, + MAC2STR_SEC(sta->addr)); + return; + } + } else { + sta->vlan_id = sta->sae->tmp->vlan_id; } } #endif /* CONFIG_NO_VLAN */ @@ -979,7 +978,7 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta) static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *bssid, u16 auth_transaction, u16 status_code, + u16 auth_transaction, u16 status_code, int allow_reuse, int *sta_removed) { int ret; @@ -992,6 +991,13 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, wpa_printf(MSG_DEBUG, "SAE: Peer " MACSTR_SEC " state=%s auth_trans=%u", MAC2STR_SEC(sta->addr), sae_state_txt(sta->sae->state), auth_transaction); + + if (auth_transaction == 1 && sae_proto_instance_disabled(sta)) { + wpa_printf(MSG_DEBUG, + "SAE: Protocol instance temporarily disabled - discard received SAE commit"); + return WLAN_STATUS_SUCCESS; + } + switch (sta->sae->state) { case SAE_NOTHING: if (auth_transaction == 1) { @@ -1003,7 +1009,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, sta->sae->pk = status_code == WLAN_STATUS_SAE_PK; } - ret = auth_sae_send_commit(hapd, sta, bssid, + ret = auth_sae_send_commit(hapd, sta, !allow_reuse, status_code); if (ret) return ret; @@ -1029,7 +1035,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, * based on SAE finite state machine * Nothing -> Confirm transition. */ - ret = auth_sae_send_confirm(hapd, sta, bssid); + ret = auth_sae_send_confirm(hapd, sta); if (ret) return ret; sae_set_state(sta, SAE_CONFIRMED, @@ -1059,7 +1065,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, if (sae_process_commit(sta->sae) < 0) return WLAN_STATUS_UNSPECIFIED_FAILURE; - ret = auth_sae_send_confirm(hapd, sta, bssid); + ret = auth_sae_send_confirm(hapd, sta); if (ret) return ret; sae_set_state(sta, SAE_CONFIRMED, "Sent Confirm"); @@ -1074,8 +1080,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_SUCCESS; sta->sae->sync++; - ret = auth_sae_send_commit(hapd, sta, bssid, 0, - status_code); + ret = auth_sae_send_commit(hapd, sta, 0, status_code); if (ret) return ret; @@ -1086,7 +1091,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, * Nothing -> Confirmed transition that was reduced to * Nothing -> Committed above. */ - ret = auth_sae_send_confirm(hapd, sta, bssid); + ret = auth_sae_send_confirm(hapd, sta); if (ret) return ret; @@ -1097,7 +1102,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, * step to get to Accepted without waiting for * additional events. */ - return sae_sm_step(hapd, sta, bssid, auth_transaction, + return sae_sm_step(hapd, sta, auth_transaction, WLAN_STATUS_SUCCESS, 0, sta_removed); } break; @@ -1108,15 +1113,14 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_SUCCESS; sta->sae->sync++; - ret = auth_sae_send_commit(hapd, sta, bssid, 1, - status_code); + ret = auth_sae_send_commit(hapd, sta, 1, status_code); if (ret) return ret; if (sae_process_commit(sta->sae) < 0) return WLAN_STATUS_UNSPECIFIED_FAILURE; - ret = auth_sae_send_confirm(hapd, sta, bssid); + ret = auth_sae_send_confirm(hapd, sta); if (ret) return ret; @@ -1137,8 +1141,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, *sta_removed = 1; } else if (auth_transaction == 1) { wpa_printf(MSG_DEBUG, "SAE: Start reauthentication"); - ret = auth_sae_send_commit(hapd, sta, bssid, 1, - status_code); + ret = auth_sae_send_commit(hapd, sta, 1, status_code); if (ret) return ret; sae_set_state(sta, SAE_COMMITTED, "Sent Commit"); @@ -1152,7 +1155,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_SUCCESS; sta->sae->sync++; - ret = auth_sae_send_confirm(hapd, sta, bssid); + ret = auth_sae_send_confirm(hapd, sta); sae_clear_temp_data(sta->sae); if (ret) return ret; @@ -1210,30 +1213,32 @@ static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta) static int sae_status_success(struct hostapd_data *hapd, u16 status_code) { - int sae_pwe = hapd->conf->sae_pwe; + enum sae_pwe 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; + if (id_in_use == 2 && sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) + sae_pwe = SAE_PWE_HASH_TO_ELEMENT; + else if (id_in_use == 1 && sae_pwe == SAE_PWE_HUNT_AND_PECK) + sae_pwe = SAE_PWE_BOTH; #ifdef CONFIG_SAE_PK sae_pk = hostapd_sae_pk_in_use(hapd->conf); - if (sae_pwe == 0 && sae_pk) - sae_pwe = 2; + if (sae_pwe == SAE_PWE_HUNT_AND_PECK && sae_pk) + sae_pwe = SAE_PWE_BOTH; #endif /* CONFIG_SAE_PK */ if (sae_pwe == SAE_PWE_HUNT_AND_PECK && - (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY)) + (hapd->conf->wpa_key_mgmt & + (WPA_KEY_MGMT_SAE_EXT_KEY | WPA_KEY_MGMT_FT_SAE_EXT_KEY))) sae_pwe = SAE_PWE_BOTH; - return ((sae_pwe == 0 || sae_pwe == 3) && + return ((sae_pwe == SAE_PWE_HUNT_AND_PECK || + sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) && status_code == WLAN_STATUS_SUCCESS) || - (sae_pwe == 1 && + (sae_pwe == SAE_PWE_HASH_TO_ELEMENT && (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT || (sae_pk && status_code == WLAN_STATUS_SAE_PK))) || - (sae_pwe == 2 && + (sae_pwe == SAE_PWE_BOTH && (status_code == WLAN_STATUS_SUCCESS || status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT || (sae_pk && status_code == WLAN_STATUS_SAE_PK))); @@ -1262,7 +1267,7 @@ static int check_sae_rejected_groups(struct hostapd_data *hapd, struct sae_data *sae) { const struct wpabuf *groups; - size_t i, count; + size_t i, count, len; const u8 *pos; if (!sae->tmp) @@ -1272,7 +1277,15 @@ static int check_sae_rejected_groups(struct hostapd_data *hapd, return 0; pos = wpabuf_head(groups); - count = wpabuf_len(groups) / 2; + len = wpabuf_len(groups); + if (len & 1) { + wpa_printf(MSG_DEBUG, + "SAE: Invalid length of the Rejected Groups element payload: %zu", + len); + return 1; + } + + count = len / 2; for (i = 0; i < count; i++) { int enabled; u16 group; @@ -1311,7 +1324,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, 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, + send_auth_reply(hapd, sta, sta->addr, + WLAN_AUTH_SAE, auth_transaction, resp, pos, end - pos, "auth-sae-reflection-attack"); goto remove_sta; @@ -1319,7 +1333,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, if (hapd->conf->sae_commit_override && auth_transaction == 1) { wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override"); - send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, + send_auth_reply(hapd, sta, sta->addr, + WLAN_AUTH_SAE, auth_transaction, resp, wpabuf_head(hapd->conf->sae_commit_override), wpabuf_len(hapd->conf->sae_commit_override), @@ -1398,8 +1413,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, * Authentication frame, and the commit-scalar and * COMMIT-ELEMENT previously sent. */ - resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0, - status_code); + resp = auth_sae_send_commit(hapd, sta, 0, status_code); if (resp != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_ERROR, "SAE: Failed to send commit message"); @@ -1425,6 +1439,12 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, if (!sae_status_success(hapd, status_code)) goto remove_sta; + if (sae_proto_instance_disabled(sta)) { + wpa_printf(MSG_DEBUG, + "SAE: Protocol instance temporarily disabled - discard received SAE commit"); + return; + } + if (!(hapd->conf->mesh & MESH_ENABLED) && sta->sae->state == SAE_COMMITTED) { /* This is needed in the infrastructure BSS case to @@ -1457,12 +1477,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, mgmt->u.auth.variable, &token, &token_len, groups, status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT || - status_code == WLAN_STATUS_SAE_PK -#ifdef CONFIG_MLD_PATCH - , NULL -#endif - ); - + status_code == WLAN_STATUS_SAE_PK, + NULL); if (resp == SAE_SILENTLY_DISCARD) { wpa_printf(MSG_DEBUG, "SAE: Drop commit message from " MACSTR_SEC " due to reflection attack", @@ -1481,7 +1497,9 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, } if (token && - check_comeback_token(hapd, sta->addr, token, token_len) + check_comeback_token(hapd->comeback_key, + hapd->comeback_pending_idx, sta->addr, + token, token_len) < 0) { wpa_printf(MSG_DEBUG, "SAE: Drop commit message with " "incorrect token from " MACSTR_SEC, @@ -1509,8 +1527,14 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, 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); + data = auth_build_token_req( + &hapd->last_comeback_key_update, + hapd->comeback_key, + hapd->comeback_idx, + hapd->comeback_pending_idx, + sizeof(hapd->comeback_pending_idx), + sta->sae->group, + sta->addr, h2e); resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ; if (hapd->conf->mesh & MESH_ENABLED) sae_set_state(sta, SAE_NOTHING, @@ -1518,7 +1542,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, goto reply; } - resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, + resp = sae_sm_step(hapd, sta, auth_transaction, status_code, allow_reuse, &sta_removed); } else if (auth_transaction == 2) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, @@ -1554,17 +1578,14 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, return; } - if (sae_check_confirm(sta->sae, var, var_len -#ifdef CONFIG_MLD_PATCH - , NULL -#endif - ) < 0) { - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + if (sae_check_confirm(sta->sae, var, var_len, + NULL) < 0) { + resp = WLAN_STATUS_CHALLENGE_FAIL; goto reply; } sta->sae->rc = peer_send_confirm; } - resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, + resp = sae_sm_step(hapd, sta, auth_transaction, status_code, 0, &sta_removed); } else { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, @@ -1589,10 +1610,19 @@ reply: data = wpabuf_alloc_copy(pos, 2); sae_sme_send_external_auth_status(hapd, sta, resp); - send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, + send_auth_reply(hapd, sta, sta->addr, + WLAN_AUTH_SAE, auth_transaction, resp, data ? wpabuf_head(data) : (u8 *) "", data ? wpabuf_len(data) : 0, "auth-sae"); + if (sta->sae && sta->sae->tmp && sta->sae->tmp->pw_id && + resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER && + auth_transaction == 1) { + wpa_printf(MSG_DEBUG, + "SAE: Clear stored password identifier since this SAE commit was not accepted"); + os_free(sta->sae->tmp->pw_id); + sta->sae->tmp->pw_id = NULL; + } } remove_sta: @@ -1629,7 +1659,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta) if (sta->sae->state != SAE_NOTHING) return -1; - ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1); + ret = auth_sae_send_commit(hapd, sta, 0, -1); if (ret) return -1; @@ -1701,7 +1731,7 @@ static void auth_sae_queue(struct hostapd_data *hapd, dl_list_for_each(q2, &hapd->sae_commit_queue, struct hostapd_sae_commit_queue, list) { mgmt2 = (const struct ieee80211_mgmt *) q2->msg; - if (os_memcmp(mgmt->sa, mgmt2->sa, ETH_ALEN) == 0 && + if (ether_addr_equal(mgmt->sa, mgmt2->sa) && mgmt->u.auth.auth_transaction == mgmt2->u.auth.auth_transaction) { wpa_printf(MSG_DEBUG, @@ -1732,7 +1762,7 @@ static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr) dl_list_for_each(q, &hapd->sae_commit_queue, struct hostapd_sae_commit_queue, list) { mgmt = (const struct ieee80211_mgmt *) q->msg; - if (os_memcmp(addr, mgmt->sa, ETH_ALEN) == 0) + if (ether_addr_equal(addr, mgmt->sa)) return 1; } @@ -1910,7 +1940,7 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta, elems.rsn_ie - 2, elems.rsn_ie_len + 2, elems.rsnxe ? elems.rsnxe - 2 : NULL, elems.rsnxe ? elems.rsnxe_len + 2 : 0, - elems.mdie, elems.mdie_len, NULL, 0); + elems.mdie, elems.mdie_len, NULL, 0, NULL); resp = wpa_res_to_status_code(res); if (resp != WLAN_STATUS_SUCCESS) goto fail; @@ -2058,7 +2088,7 @@ prepare_auth_resp_fils(struct hostapd_data *hapd, } os_memcpy(ie_buf, ie, ielen); - if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) { + if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid, true) < 0) { *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } @@ -2108,10 +2138,8 @@ prepare_auth_resp_fils(struct hostapd_data *hapd, if (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm))) { /* FTE[R1KH-ID,R0KH-ID] when using FILS+FT */ int res; - int use_sha384 = wpa_key_mgmt_sha384( - wpa_auth_sta_key_mgmt(sta->wpa_sm)); - res = wpa_auth_write_fte(hapd->wpa_auth, use_sha384, + res = wpa_auth_write_fte(hapd->wpa_auth, sta->wpa_sm, wpabuf_put(data, 0), wpabuf_tailroom(data)); if (res < 0) { @@ -2188,7 +2216,8 @@ prepare_auth_resp_fils(struct hostapd_data *hapd, pmk, pmk_len, sta->fils_erp_pmkid, session_timeout, - wpa_auth_sta_key_mgmt(sta->wpa_sm)) < 0) { + wpa_auth_sta_key_mgmt(sta->wpa_sm), + NULL) < 0) { wpa_printf(MSG_ERROR, "FILS: Failed to add PMKSA cache entry based on ERP"); } @@ -2243,7 +2272,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd, auth_alg = (pub || resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK; - send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp, + send_auth_reply(hapd, sta, sta->addr, auth_alg, 2, resp, data ? wpabuf_head(data) : (u8 *) "", data ? wpabuf_len(data) : 0, "auth-fils-finish"); wpabuf_free(data); @@ -2328,9 +2357,8 @@ static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr, } -static int -ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, - int res, struct radius_sta *info) +int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, + int res, struct radius_sta *info) { u32 session_timeout = info->session_timeout; u32 acct_interim_interval = info->acct_interim_interval; @@ -2389,109 +2417,119 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_PASN -#ifdef CONFIG_SAE +#ifdef CONFIG_FILS -static int pasn_wd_handle_sae_commit(struct hostapd_data *hapd, - struct sta_info *sta, - struct wpabuf *wd) +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; - const char *password; - const u8 *data; - size_t buf_len; - u16 res, alg, seq, status; - int groups[] = { pasn->group, 0 }; - struct sae_pt *pt = NULL; + struct pasn_fils *fils = &pasn->fils; + u8 pmk[PMK_LEN_MAX]; + size_t pmk_len; int ret; - if (!wd) - return -1; + wpa_printf(MSG_DEBUG, "PASN: FILS: Handle AS response - status=%u", + status); - data = wpabuf_head_u8(wd); - buf_len = wpabuf_len(wd); + if (status != WLAN_STATUS_SUCCESS) + goto fail; - if (buf_len < 6) { - wpa_printf(MSG_DEBUG, "PASN: SAE buffer too short. len=%zu", - buf_len); - return -1; + if (!pasn->secret) { + wpa_printf(MSG_DEBUG, "PASN: FILS: Missing secret"); + goto fail; } - 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); - - if (alg != WLAN_AUTH_SAE || seq != 1 || - status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) { - wpa_printf(MSG_DEBUG, "PASN: Dropping peer SAE commit"); - return -1; + if (random_get_bytes(fils->anonce, FILS_NONCE_LEN) < 0) { + wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to get ANonce"); + goto fail; } - sae_clear_data(&pasn->sae); - pasn->sae.state = SAE_NOTHING; + wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS ANonce", + fils->anonce, FILS_NONCE_LEN); - ret = sae_set_group(&pasn->sae, pasn->group); + ret = fils_rmsk_to_pmk(pasn_get_akmp(pasn), msk, msk_len, fils->nonce, + fils->anonce, NULL, 0, pmk, &pmk_len); if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group"); - return -1; - } - - password = sae_get_password(hapd, sta, NULL, NULL, &pt, NULL); - if (!password || !pt) { - wpa_printf(MSG_DEBUG, "PASN: No SAE PT found"); - return -1; + wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK"); + goto fail; } - ret = sae_prepare_commit_pt(&pasn->sae, pt, hapd->own_addr, sta->addr, - NULL, NULL); + ret = pasn_pmk_to_ptk(pmk, pmk_len, sta->addr, hapd->own_addr, + wpabuf_head(pasn->secret), + wpabuf_len(pasn->secret), + pasn_get_ptk(sta->pasn), pasn_get_akmp(sta->pasn), + pasn_get_cipher(sta->pasn), sta->pasn->kdk_len); if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to prepare SAE commit"); - return -1; + wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK"); + goto fail; } - res = sae_parse_commit(&pasn->sae, data + 6, buf_len - 6, NULL, 0, - groups, 0 -#ifdef CONFIG_MLD_PATCH - , NULL -#endif - ); - if (res != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_DEBUG, "PASN: Failed parsing SAE commit"); - return -1; + if (pasn->secure_ltf) { + ret = wpa_ltf_keyseed(pasn_get_ptk(pasn), pasn_get_akmp(pasn), + pasn_get_cipher(pasn)); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: FILS: Failed to derive LTF keyseed"); + goto fail; + } } - /* Process the commit message and derive the PMK */ - ret = sae_process_commit(&pasn->sae); + 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(sta->pasn, hapd->own_addr, sta->addr, NULL, + WLAN_STATUS_SUCCESS); + fils->erp_resp = NULL; + if (ret) { - wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit"); - return -1; + wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to send response"); + goto fail; } - pasn->sae.state = SAE_COMMITTED; - - return 0; + fils->state = PASN_FILS_STATE_COMPLETE; + return; +fail: + ap_free_sta(hapd, sta); } -static int pasn_wd_handle_sae_confirm(struct hostapd_data *hapd, - struct sta_info *sta, - struct wpabuf *wd) +static int pasn_wd_handle_fils(struct hostapd_data *hapd, struct sta_info *sta, + struct wpabuf *wd) { +#ifdef CONFIG_NO_RADIUS + wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail"); + return -1; +#else /* CONFIG_NO_RADIUS */ struct pasn_data *pasn = sta->pasn; + struct pasn_fils *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 res, alg, seq, status; + u16 alg, seq, status; + int ret; - if (!wd) + 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: SAE buffer too short. len=%zu", + wpa_printf(MSG_DEBUG, "PASN: FILS: Buffer too short. len=%zu", buf_len); return -1; } @@ -2500,915 +2538,185 @@ static int pasn_wd_handle_sae_confirm(struct hostapd_data *hapd, 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", + wpa_printf(MSG_DEBUG, "PASN: FILS: 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"); + if (alg != WLAN_AUTH_FILS_SK || seq != 1 || + status != WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, + "PASN: FILS: Dropping peer authentication"); return -1; } - res = sae_check_confirm(&pasn->sae, data + 6, buf_len - 6 -#ifdef CONFIG_MLD_PATCH - , NULL -#endif - ); - if (res != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_DEBUG, "PASN: SAE failed checking confirm"); + 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; } - 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.pmk_len, - pasn->sae.pmkid, pasn->sae.akmp); - return 0; -} - + if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce || + !elems.wrapped_data || !elems.fils_session) { + wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs"); + return -1; + } -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; + 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 RSNE"); + return -1; + } - /* 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; + ret = wpa_pasn_validate_rsne(&rsne_data); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: FILS: Failed validating RSNE"); + return -1; } - /* 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_SAE_HASH_TO_ELEMENT); + if (rsne_data.num_pmkid) { + wpa_printf(MSG_DEBUG, + "PASN: FILS: Not expecting PMKID in RSNE"); + return -1; + } - /* 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, sta->pasn->kdk_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) -{ -#ifdef CONFIG_NO_RADIUS - wpa_printf(MSG_DEBUG, "PASN: FILS: RADIUS is not configured. Fail"); - return -1; -#else /* CONFIG_NO_RADIUS */ - 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=%zu", - 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); - - 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_NO_RADIUS */ -} - -#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, sta->pasn->kdk_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 void handle_auth_pasn_comeback(struct hostapd_data *hapd, - struct sta_info *sta, u16 group) -{ - struct wpabuf *buf, *comeback; - int ret; - - wpa_printf(MSG_DEBUG, - "PASN: Building comeback frame 2. Comeback after=%u", - hapd->conf->pasn_comeback_after); - - buf = wpabuf_alloc(1500); - if (!buf) - return; - - wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr, - sta->addr, 2, - WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY); - - /* - * Do not include the group as a part of the token since it is not going - * to be used. - */ - comeback = auth_build_token_req(hapd, 0, sta->addr, 0); - if (!comeback) { - wpa_printf(MSG_DEBUG, - "PASN: Failed sending auth with comeback"); - wpabuf_free(buf); - return; - } - - wpa_pasn_add_parameter_ie(buf, group, - WPA_PASN_WRAPPED_DATA_NO, - NULL, 0, comeback, - hapd->conf->pasn_comeback_after); - wpabuf_free(comeback); - - wpa_printf(MSG_DEBUG, - "PASN: comeback: STA=" MACSTR_SEC, MAC2STR_SEC(sta->addr)); - - ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0, - NULL, 0, 0); - if (ret) - wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2"); - - wpabuf_free(buf); -} - - -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; - u8 *ptr; - const u8 *frame, *data, *rsn_ie, *rsnxe_ie; - u8 *data_buf = NULL; - size_t rsn_ie_len, frame_len, data_len; - int ret; - const u8 *pmkid = NULL; - - 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 (pmksa) { - pmkid = pmksa->pmkid; -#ifdef CONFIG_SAE - } else if (sta->pasn->akmp == WPA_KEY_MGMT_SAE) { - wpa_printf(MSG_DEBUG, "PASN: Use SAE PMKID"); - pmkid = sta->pasn->sae.pmkid; -#endif /* CONFIG_SAE */ -#ifdef CONFIG_FILS - } else if (sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 || - sta->pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) { - wpa_printf(MSG_DEBUG, "PASN: Use FILS ERP PMKID"); - pmkid = sta->pasn->fils.erp_pmkid; -#endif /* CONFIG_FILS */ - } - - if (wpa_pasn_add_rsne(buf, pmkid, - 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, true, 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; - } - -#ifdef CONFIG_TESTING_OPTIONS - if (hapd->conf->pasn_corrupt_mic) { - wpa_printf(MSG_DEBUG, "PASN: frame 2: Corrupt MIC"); - mic[0] = ~mic[0]; - } -#endif /* CONFIG_TESTING_OPTIONS */ - - os_memcpy(ptr, mic, mic_len); - -done: - wpa_printf(MSG_DEBUG, - "PASN: Building frame 2: success; resp STA=" MACSTR_SEC, - MAC2STR_SEC(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, inc_y; - 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 (hapd->conf->force_kdk_derivation || - ((hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) && - ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, - WLAN_RSNX_CAPAB_SECURE_LTF))) - sta->pasn->kdk_len = WPA_KDK_MAX_LEN; - else - sta->pasn->kdk_len = 0; - wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", sta->pasn->kdk_len); - - 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; - } + wpa_hexdump(MSG_DEBUG, "PASN: FILS: Nonce", elems.fils_nonce, + FILS_NONCE_LEN); + os_memcpy(fils->nonce, elems.fils_nonce, FILS_NONCE_LEN); - for (i = 0; groups[i] > 0 && groups[i] != pasn_params.group; i++) - ; + wpa_hexdump(MSG_DEBUG, "PASN: FILS: Session", elems.fils_session, + FILS_SESSION_LEN); + os_memcpy(fils->session, elems.fils_session, FILS_SESSION_LEN); - 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; - } + fils_wd = ieee802_11_defrag(elems.wrapped_data, elems.wrapped_data_len, + true); - if (!pasn_params.pubkey || !pasn_params.pubkey_len) { - wpa_printf(MSG_DEBUG, "PASN: Invalid public key"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; + if (!fils_wd) { + wpa_printf(MSG_DEBUG, "PASN: FILS: Missing wrapped data"); + return -1; } - if (pasn_params.comeback) { - wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token"); + if (!sta->eapol_sm) + sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); - ret = check_comeback_token(hapd, sta->addr, - pasn_params.comeback, - pasn_params.comeback_len); + wpa_printf(MSG_DEBUG, + "PASN: FILS: Forward EAP-Initiate/Re-auth to AS"); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } - } else if (use_anti_clogging(hapd)) { - wpa_printf(MSG_DEBUG, "PASN: Respond with comeback"); - handle_auth_pasn_comeback(hapd, sta, pasn_params.group); - ap_free_sta(hapd, sta); - return; - } + ieee802_1x_encapsulate_radius(hapd, sta, wpabuf_head(fils_wd), + wpabuf_len(fils_wd)); - 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->flags |= WLAN_STA_PENDING_PASN_FILS_ERP; - sta->pasn->group = pasn_params.group; + fils->state = PASN_FILS_STATE_PENDING_AS; - if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) { - inc_y = 1; - } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 || - pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) { - inc_y = 0; - } else { - wpa_printf(MSG_DEBUG, - "PASN: Invalid first octet in pubkey=0x%x", - pasn_params.pubkey[0]); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } + /* + * Calculate pending PMKID here so that we do not need to maintain a + * copy of the EAP-Initiate/Reautt message. + */ + fils_pmkid_erp(pasn_get_akmp(pasn), + wpabuf_head(fils_wd), wpabuf_len(fils_wd), + fils->erp_pmkid); - secret = crypto_ecdh_set_peerkey(sta->pasn->ecdh, inc_y, - pasn_params.pubkey + 1, - pasn_params.pubkey_len - 1); - if (!secret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret"); - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - goto send_resp; - } + wpabuf_free(fils_wd); + return 0; +#endif /* CONFIG_NO_RADIUS */ +} - 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; - } +#endif /* CONFIG_FILS */ -#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"); +static int hapd_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len, + int noack, unsigned int freq, unsigned int wait) +{ + struct hostapd_data *hapd = ctx; - /* - * With PASN/FILS, keys can be derived only after a - * response from the AS is processed. - */ - derive_keys = false; - } -#endif /* CONFIG_FILS */ - } + return hostapd_drv_send_mlme(hapd, data, data_len, 0, NULL, 0, 0); +} - 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; - } +static void hapd_initialize_pasn(struct hostapd_data *hapd, + struct sta_info *sta) +{ + struct pasn_data *pasn = sta->pasn; - if (!derive_keys) { - wpa_printf(MSG_DEBUG, "PASN: Storing secret"); - sta->pasn->secret = secret; - wpabuf_free(wrapped_data); - return; - } + pasn_register_callbacks(pasn, hapd, hapd_pasn_send_mlme, NULL); + pasn_set_bssid(pasn, hapd->own_addr); + pasn_set_own_addr(pasn, hapd->own_addr); + pasn_set_peer_addr(pasn, sta->addr); + pasn_set_wpa_key_mgmt(pasn, hapd->conf->wpa_key_mgmt); + pasn_set_rsn_pairwise(pasn, hapd->conf->rsn_pairwise); + pasn->pasn_groups = hapd->conf->pasn_groups; + pasn->noauth = hapd->conf->pasn_noauth; + if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP) + pasn_enable_kdk_derivation(pasn); - 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"); +#ifdef CONFIG_TESTING_OPTIONS + pasn->corrupt_mic = hapd->conf->pasn_corrupt_mic; + if (hapd->conf->force_kdk_derivation) + pasn_enable_kdk_derivation(pasn); +#endif /* CONFIG_TESTING_OPTIONS */ + pasn->use_anti_clogging = use_anti_clogging(hapd); + pasn_set_password(pasn, sae_get_password(hapd, sta, NULL, NULL, + &pasn->pt, NULL)); + pasn->rsn_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &pasn->rsn_ie_len); + pasn_set_rsnxe_ie(pasn, hostapd_wpa_ie(hapd, WLAN_EID_RSNX)); + pasn->disable_pmksa_caching = hapd->conf->disable_pmksa_caching; + pasn_set_responder_pmksa(pasn, + wpa_auth_get_pmksa_cache(hapd->wpa_auth)); + + pasn->comeback_after = hapd->conf->pasn_comeback_after; + pasn->comeback_idx = hapd->comeback_idx; + pasn->comeback_key = hapd->comeback_key; + pasn->comeback_pending_idx = hapd->comeback_pending_idx; +} - 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; - } +static int pasn_set_keys_from_cache(struct hostapd_data *hapd, + const u8 *own_addr, const u8 *sta_addr, + int cipher, int akmp) +{ + struct ptksa_cache_entry *entry; - 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; + entry = ptksa_cache_get(hapd->ptksa, sta_addr, cipher); + if (!entry) { + wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR + " not present in PTKSA cache", MAC2STR(sta_addr)); + return -1; } -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 { + if (!ether_addr_equal(entry->own_addr, own_addr)) { wpa_printf(MSG_DEBUG, - "PASN: Success handling transaction == 1"); + "PASN: own addr " MACSTR " and PTKSA entry own addr " + MACSTR " differ", + MAC2STR(own_addr), MAC2STR(entry->own_addr)); + return -1; } - wpabuf_free(secret); - wpabuf_free(wrapped_data); + wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache", + MAC2STR(sta_addr)); + hostapd_drv_set_secure_ranging_ctx(hapd, own_addr, sta_addr, cipher, + entry->ptk.tk_len, entry->ptk.tk, + entry->ptk.ltf_keyseed_len, + entry->ptk.ltf_keyseed, 0); - if (status != WLAN_STATUS_SUCCESS) - ap_free_sta(hapd, sta); + return 0; } -static void handle_auth_pasn_3(struct hostapd_data *hapd, struct sta_info *sta, - const struct ieee80211_mgmt *mgmt, size_t len) +static void hapd_pasn_update_params(struct hostapd_data *hapd, + struct sta_info *sta, + const struct ieee80211_mgmt *mgmt, + size_t len) { + struct pasn_data *pasn = sta->pasn; struct ieee802_11_elems elems; + struct wpa_ie_data rsn_data; +#ifdef CONFIG_FILS 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; +#endif /* CONFIG_FILS */ + int akmp; if (ieee802_11_parse_elems(mgmt->u.auth.variable, len - offsetof(struct ieee80211_mgmt, @@ -3416,98 +2724,72 @@ static void handle_auth_pasn_3(struct hostapd_data *hapd, struct sta_info *sta, &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); + return; } - if (!elems.pasn_params || !elems.pasn_params_len) { - wpa_printf(MSG_DEBUG, - "PASN: No PASN Parameters element found"); - goto fail; + if (!elems.rsn_ie || + wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2, elems.rsn_ie_len + 2, + &rsn_data)) { + wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE"); + return; } - 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 (!(rsn_data.key_mgmt & pasn->wpa_key_mgmt) || + !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) { + wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher"); + return; } - if (pasn_params.pubkey || pasn_params.pubkey_len) { - wpa_printf(MSG_DEBUG, - "PASN: Public key should not be included"); - goto fail; - } + pasn_set_akmp(pasn, rsn_data.key_mgmt); + pasn_set_cipher(pasn, rsn_data.pairwise_cipher); - /* 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); + if (pasn->derive_kdk && + !ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, + WLAN_RSNX_CAPAB_SECURE_LTF)) + pasn_disable_kdk_derivation(pasn); +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->conf->force_kdk_derivation) + pasn_enable_kdk_derivation(pasn); +#endif /* CONFIG_TESTING_OPTIONS */ + akmp = pasn_get_akmp(pasn); - 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 (wpa_key_mgmt_ft(akmp) && rsn_data.num_pmkid) { +#ifdef CONFIG_IEEE80211R_AP + pasn->pmk_r1_len = 0; + wpa_ft_fetch_pmk_r1(hapd->wpa_auth, sta->addr, + rsn_data.pmkid, + pasn->pmk_r1, &pasn->pmk_r1_len, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL); +#endif /* CONFIG_IEEE80211R_AP */ + } +#ifdef CONFIG_FILS + if (akmp != WPA_KEY_MGMT_FILS_SHA256 && + akmp != WPA_KEY_MGMT_FILS_SHA384) + return; + if (!elems.pasn_params || + wpa_pasn_parse_parameter_ie(elems.pasn_params - 3, + elems.pasn_params_len + 3, + false, &pasn_params)) { + wpa_printf(MSG_DEBUG, + "PASN: Failed validation of PASN Parameters element"); + return; } - 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); - + wrapped_data = ieee802_11_defrag(elems.wrapped_data, + elems.wrapped_data_len, true); 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"); - } + return; } -#endif /* CONFIG_FILS */ - wpabuf_free(wrapped_data); + if (pasn_wd_handle_fils(hapd, sta, wrapped_data)) + wpa_printf(MSG_DEBUG, + "PASN: Failed processing FILS wrapped data"); + else + pasn->fils_wd_valid = true; } - - 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); + wpabuf_free(wrapped_data); +#endif /* CONFIG_FILS */ } @@ -3536,14 +2818,19 @@ static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta, return; } - sta->pasn = os_zalloc(sizeof(*sta->pasn)); + sta->pasn = pasn_data_init(); if (!sta->pasn) { wpa_printf(MSG_DEBUG, "PASN: Failed to allocate PASN context"); return; } - handle_auth_pasn_1(hapd, sta, mgmt, len); + hapd_initialize_pasn(hapd, sta); + + hapd_pasn_update_params(hapd, sta, mgmt, len); + if (handle_auth_pasn_1(sta->pasn, hapd->own_addr, + sta->addr, mgmt, len) < 0) + ap_free_sta(hapd, sta); } else if (trans_seq == 3) { if (!sta->pasn) { wpa_printf(MSG_DEBUG, @@ -3558,7 +2845,19 @@ static void handle_auth_pasn(struct hostapd_data *hapd, struct sta_info *sta, return; } - handle_auth_pasn_3(hapd, sta, mgmt, len); + if (handle_auth_pasn_3(sta->pasn, hapd->own_addr, + sta->addr, mgmt, len) == 0) { + ptksa_cache_add(hapd->ptksa, hapd->own_addr, sta->addr, + pasn_get_cipher(sta->pasn), 43200, + pasn_get_ptk(sta->pasn), NULL, NULL, + pasn_get_akmp(sta->pasn)); + + pasn_set_keys_from_cache(hapd, hapd->own_addr, + sta->addr, + pasn_get_cipher(sta->pasn), + pasn_get_akmp(sta->pasn)); + } + ap_free_sta(hapd, sta); } else { wpa_printf(MSG_DEBUG, "PASN: Invalid transaction %u - ignore", trans_seq); @@ -3582,6 +2881,10 @@ static void handle_auth(struct hostapd_data *hapd, size_t resp_ies_len = 0; u16 seq_ctrl; struct radius_sta rad_info; + const u8 *dst, *sa; +#ifdef CONFIG_IEEE80211BE + bool mld_sta = false; +#endif /* CONFIG_IEEE80211BE */ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)", @@ -3599,6 +2902,20 @@ static void handle_auth(struct hostapd_data *hapd, } #endif /* CONFIG_TESTING_OPTIONS */ + sa = mgmt->sa; +#ifdef CONFIG_IEEE80211BE + /* + * Handle MLO authentication before the station is added to hostapd and + * the driver so that the station MLD MAC address would be used in both + * hostapd and the driver. + */ + sa = hostapd_process_ml_auth(hapd, mgmt, len); + if (sa) + mld_sta = true; + else + sa = mgmt->sa; +#endif /* CONFIG_IEEE80211BE */ + 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); @@ -3614,7 +2931,7 @@ static void handle_auth(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR_SEC " auth_alg=%d " "auth_transaction=%d status_code=%d wep=%d%s " "seq_ctrl=0x%x%s%s", - MAC2STR_SEC(mgmt->sa), auth_alg, auth_transaction, + MAC2STR_SEC(sa), auth_alg, auth_transaction, status_code, !!(fc & WLAN_FC_ISWEP), challenge ? " challenge" : "", seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "", @@ -3678,17 +2995,29 @@ static void handle_auth(struct hostapd_data *hapd, goto fail; } - if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) { + if (ether_addr_equal(mgmt->sa, hapd->own_addr)) { wpa_printf(MSG_INFO, "Station " MACSTR_SEC " not allowed to authenticate", - MAC2STR_SEC(mgmt->sa)); + MAC2STR_SEC(sa)); + resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto fail; + } + +#ifdef CONFIG_IEEE80211BE + if (mld_sta && + (ether_addr_equal(sa, hapd->own_addr) || + ether_addr_equal(sa, hapd->mld->mld_addr))) { + wpa_printf(MSG_INFO, + "Station " MACSTR " not allowed to authenticate", + MAC2STR(sa)); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } +#endif /* CONFIG_IEEE80211BE */ if (hapd->conf->no_auth_if_seen_on) { struct hostapd_data *other; - other = sta_track_seen_on(hapd->iface, mgmt->sa, + other = sta_track_seen_on(hapd->iface, sa, hapd->conf->no_auth_if_seen_on); if (other) { u8 *pos; @@ -3697,7 +3026,7 @@ static void handle_auth(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "%s: Reject authentication from " MACSTR_SEC " since STA has been seen on %s", - hapd->conf->iface, MAC2STR_SEC(mgmt->sa), + hapd->conf->iface, MAC2STR_SEC(sa), hapd->conf->no_auth_if_seen_on); resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION; @@ -3740,12 +3069,12 @@ static void handle_auth(struct hostapd_data *hapd, } } - res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len, + res = ieee802_11_allowed_address(hapd, sa, (const u8 *) mgmt, len, &rad_info); if (res == HOSTAPD_ACL_REJECT) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Ignore Authentication frame from " MACSTR - " due to ACL reject", MAC2STR(mgmt->sa)); + " due to ACL reject", MAC2STR(sa)); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } @@ -3755,7 +3084,7 @@ static void handle_auth(struct hostapd_data *hapd, #ifdef CONFIG_SAE if (auth_alg == WLAN_AUTH_SAE && !from_queue && (auth_transaction == 1 || - (auth_transaction == 2 && auth_sae_queued_addr(hapd, mgmt->sa)))) { + (auth_transaction == 2 && auth_sae_queued_addr(hapd, sa)))) { /* Handle SAE Authentication commit message through a queue to * provide more control for postponing the needed heavy * processing under a possible DoS attack scenario. In addition, @@ -3768,7 +3097,7 @@ static void handle_auth(struct hostapd_data *hapd, } #endif /* CONFIG_SAE */ - sta = ap_get_sta(hapd, mgmt->sa); + sta = ap_get_sta(hapd, sa); if (sta) { sta->flags &= ~WLAN_STA_PENDING_FILS_ERP; sta->ft_over_ds = 0; @@ -3783,15 +3112,6 @@ static void handle_auth(struct hostapd_data *hapd, seq_ctrl); return; } -#ifdef CONFIG_MESH - if ((hapd->conf->mesh & MESH_ENABLED) && - sta->plink_state == PLINK_BLOCKED) { - wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR_SEC - " is blocked - drop Authentication frame", - MAC2STR_SEC(mgmt->sa)); - return; - } -#endif /* CONFIG_MESH */ #ifdef CONFIG_PASN if (auth_alg == WLAN_AUTH_PASN && (sta->flags & WLAN_STA_ASSOC)) { @@ -3808,7 +3128,7 @@ static void handle_auth(struct hostapd_data *hapd, */ wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR_SEC " not yet known - drop Authentication frame", - MAC2STR_SEC(mgmt->sa)); + MAC2STR_SEC(sa)); /* * Save a copy of the frame so that it can be processed * if a new peer entry is added shortly after this. @@ -3820,13 +3140,44 @@ static void handle_auth(struct hostapd_data *hapd, } #endif /* CONFIG_MESH */ - sta = ap_sta_add(hapd, mgmt->sa); + sta = ap_sta_add(hapd, sa); if (!sta) { wpa_printf(MSG_DEBUG, "ap_sta_add() failed"); resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; goto fail; } } + +#ifdef CONFIG_IEEE80211BE + /* Set the non-AP MLD information based on the initial Authentication + * frame. Once the STA entry has been added to the driver, the driver + * will translate addresses in the frame and we need to avoid overriding + * peer_addr based on mgmt->sa which would have been translated to the + * MLD MAC address. */ + if (!sta->added_unassoc && auth_transaction == 1) { + ap_sta_free_sta_profile(&sta->mld_info); + os_memset(&sta->mld_info, 0, sizeof(sta->mld_info)); + + if (mld_sta) { + u8 link_id = hapd->mld_link_id; + + ap_sta_set_mld(sta, true); + sta->mld_assoc_link_id = link_id; + + /* + * Set the MLD address as the station address and the + * station addresses. + */ + os_memcpy(sta->mld_info.common_info.mld_addr, sa, + ETH_ALEN); + os_memcpy(sta->mld_info.links[link_id].peer_addr, + mgmt->sa, ETH_ALEN); + os_memcpy(sta->mld_info.links[link_id].local_addr, + hapd->own_addr, ETH_ALEN); + } + } +#endif /* CONFIG_IEEE80211BE */ + sta->last_seq_ctrl = seq_ctrl; sta->last_subtype = WLAN_FC_STYPE_AUTH; #ifdef CONFIG_MBO @@ -3917,7 +3268,7 @@ static void handle_auth(struct hostapd_data *hapd, resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } - wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid, + wpa_ft_process_auth(sta->wpa_sm, auth_transaction, mgmt->u.auth.variable, len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth), @@ -3964,7 +3315,14 @@ static void handle_auth(struct hostapd_data *hapd, } fail: - reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg, + dst = mgmt->sa; + +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) + dst = sta->addr; +#endif /* CONFIG_IEEE80211BE */ + + reply_res = send_auth_reply(hapd, sta, dst, auth_alg, auth_alg == WLAN_AUTH_SAE ? auth_transaction : auth_transaction + 1, resp, resp_ies, resp_ies_len, @@ -3978,10 +3336,68 @@ static void handle_auth(struct hostapd_data *hapd, } +static u8 hostapd_max_bssid_indicator(struct hostapd_data *hapd) +{ + size_t num_bss_nontx; + u8 max_bssid_ind = 0; + + if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1) + return 0; + + num_bss_nontx = hapd->iface->num_bss - 1; + while (num_bss_nontx > 0) { + max_bssid_ind++; + num_bss_nontx >>= 1; + } + return max_bssid_ind; +} + + +static u32 hostapd_get_aid_word(struct hostapd_data *hapd, + struct sta_info *sta, int i) +{ +#ifdef CONFIG_IEEE80211BE + u32 aid_word = 0; + + /* Do not assign an AID that is in use on any of the affiliated links + * when finding an AID for a non-AP MLD. */ + if (hapd->conf->mld_ap && sta->mld_info.mld_sta) { + int j; + + for (j = 0; j < MAX_NUM_MLD_LINKS; j++) { + struct hostapd_data *link_bss; + + if (!sta->mld_info.links[j].valid) + continue; + + link_bss = hostapd_mld_get_link_bss(hapd, j); + if (!link_bss) { + /* This shouldn't happen, just skip */ + wpa_printf(MSG_ERROR, + "MLD: Failed to get link BSS for AID"); + continue; + } + + aid_word |= link_bss->sta_aid[i]; + } + + return aid_word; + } +#endif /* CONFIG_IEEE80211BE */ + + return hapd->sta_aid[i]; +} + + int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) { int i, j = 32, aid; + /* Transmitted and non-transmitted BSSIDs share the same AID pool, so + * use the shared storage in the transmitted BSS to find the next + * available value. */ + hapd = hostapd_mbssid_get_tx_bss(hapd); + /* get a unique AID */ if (sta->aid > 0) { wpa_printf(MSG_DEBUG, " old AID %d", sta->aid); @@ -3992,10 +3408,12 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) return -1; for (i = 0; i < AID_WORDS; i++) { - if (hapd->sta_aid[i] == (u32) -1) + u32 aid_word = hostapd_get_aid_word(hapd, sta, i); + + if (aid_word == (u32) -1) continue; for (j = 0; j < 32; j++) { - if (!(hapd->sta_aid[i] & BIT(j))) + if (!(aid_word & BIT(j))) break; } if (j < 32) @@ -4003,7 +3421,7 @@ int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) } if (j == 32) return -1; - aid = i * 32 + j + 1; + aid = i * 32 + j + (1 << hostapd_max_bssid_indicator(hapd)); if (aid > 2007) return -1; @@ -4062,37 +3480,58 @@ static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta, static u16 check_multi_ap(struct hostapd_data *hapd, struct sta_info *sta, const u8 *multi_ap_ie, size_t multi_ap_len) { - u8 multi_ap_value = 0; + struct multi_ap_params multi_ap; + u16 status; sta->flags &= ~WLAN_STA_MULTI_AP; if (!hapd->conf->multi_ap) return WLAN_STATUS_SUCCESS; - if (multi_ap_ie) { - const u8 *multi_ap_subelem; - - multi_ap_subelem = get_ie(multi_ap_ie + 4, - multi_ap_len - 4, - MULTI_AP_SUB_ELEM_TYPE); - if (multi_ap_subelem && multi_ap_subelem[1] == 1) { - multi_ap_value = multi_ap_subelem[2]; - } else { + if (!multi_ap_ie) { + if (!(hapd->conf->multi_ap & FRONTHAUL_BSS)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, - "Multi-AP IE has missing or invalid Multi-AP subelement"); - return WLAN_STATUS_INVALID_IE; + "Non-Multi-AP STA tries to associate with backhaul-only BSS"); + return WLAN_STATUS_ASSOC_DENIED_UNSPEC; } + + return WLAN_STATUS_SUCCESS; } - if (multi_ap_value && multi_ap_value != MULTI_AP_BACKHAUL_STA) + status = check_multi_ap_ie(multi_ap_ie + 4, multi_ap_len - 4, + &multi_ap); + if (status != WLAN_STATUS_SUCCESS) + return status; + + if (multi_ap.capability && multi_ap.capability != MULTI_AP_BACKHAUL_STA) hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "Multi-AP IE with unexpected value 0x%02x", - multi_ap_value); + multi_ap.capability); + + if (multi_ap.profile == MULTI_AP_PROFILE_1 && + (hapd->conf->multi_ap_client_disallow & + PROFILE1_CLIENT_ASSOC_DISALLOW)) { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "Multi-AP Profile-1 clients not allowed"); + return WLAN_STATUS_ASSOC_DENIED_UNSPEC; + } + + if (multi_ap.profile >= MULTI_AP_PROFILE_2 && + (hapd->conf->multi_ap_client_disallow & + PROFILE2_CLIENT_ASSOC_DISALLOW)) { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "Multi-AP Profile-2 clients not allowed"); + return WLAN_STATUS_ASSOC_DENIED_UNSPEC; + } - if (!(multi_ap_value & MULTI_AP_BACKHAUL_STA)) { + if (!(multi_ap.capability & MULTI_AP_BACKHAUL_STA)) { if (hapd->conf->multi_ap & FRONTHAUL_BSS) return WLAN_STATUS_SUCCESS; @@ -4147,32 +3586,6 @@ static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta, } -static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *ext_capab_ie, size_t ext_capab_ie_len) -{ -#ifdef CONFIG_INTERWORKING - /* check for QoS Map support */ - if (ext_capab_ie_len >= 5) { - if (ext_capab_ie[4] & 0x01) - sta->qos_map_enabled = 1; - } -#endif /* CONFIG_INTERWORKING */ - - if (ext_capab_ie_len > 0) { - sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2)); - os_free(sta->ext_capability); - sta->ext_capability = os_malloc(1 + ext_capab_ie_len); - if (sta->ext_capability) { - sta->ext_capability[0] = ext_capab_ie_len; - os_memcpy(sta->ext_capability + 1, ext_capab_ie, - ext_capab_ie_len); - } - } - - return WLAN_STATUS_SUCCESS; -} - - #ifdef CONFIG_OWE static int owe_group_supported(struct hostapd_data *hapd, u16 group) @@ -4227,8 +3640,21 @@ static u16 owe_process_assoc_req(struct hostapd_data *hapd, else return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; - crypto_ecdh_deinit(sta->owe_ecdh); - sta->owe_ecdh = crypto_ecdh_init(group); + if (sta->owe_group == group && sta->owe_ecdh) { + /* This is a workaround for mac80211 behavior of retransmitting + * the Association Request frames multiple times if the link + * layer retries (i.e., seq# remains same) fail. The mac80211 + * initiated retransmission will use a different seq# and as + * such, will go through duplicate detection. If we were to + * change our DH key for that attempt, there would be two + * different DH shared secrets and the STA would likely select + * the wrong one. */ + wpa_printf(MSG_DEBUG, + "OWE: Try to reuse own previous DH key since the STA tried to go through OWE association again"); + } else { + crypto_ecdh_deinit(sta->owe_ecdh); + sta->owe_ecdh = crypto_ecdh_init(group); + } if (!sta->owe_ecdh) return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; sta->owe_group = group; @@ -4332,7 +3758,7 @@ static u16 owe_process_assoc_req(struct hostapd_data *hapd, wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sta->owe_pmk, sta->owe_pmk_len); wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, PMKID_LEN); wpa_auth_pmksa_add2(hapd->wpa_auth, sta->addr, sta->owe_pmk, - sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE); + sta->owe_pmk_len, pmkid, 0, WPA_KEY_MGMT_OWE, NULL); return WLAN_STATUS_SUCCESS; } @@ -4380,7 +3806,8 @@ u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer, u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta, const u8 *rsn_ie, size_t rsn_ie_len, - const u8 *owe_dh, size_t owe_dh_len) + const u8 *owe_dh, size_t owe_dh_len, + const u8 *link_addr) { u16 status; u8 *owe_buf, ie[256 * 2]; @@ -4402,11 +3829,16 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd, status = WLAN_STATUS_UNSPECIFIED_FAILURE; goto end; } +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) + wpa_auth_set_ml_info(sta->wpa_sm, + sta->mld_assoc_link_id, &sta->mld_info); +#endif /* CONFIG_IEEE80211BE */ rsn_ie -= 2; rsn_ie_len += 2; res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, hapd->iface->freq, rsn_ie, rsn_ie_len, - NULL, 0, NULL, 0, owe_dh, owe_dh_len); + NULL, 0, NULL, 0, owe_dh, owe_dh_len, NULL); status = wpa_res_to_status_code(res); if (status != WLAN_STATUS_SUCCESS) goto end; @@ -4446,8 +3878,9 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd, end: wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer " MACSTR_SEC, status, (unsigned int) ie_len, - MAC2STR_SEC(sta->addr)); - hostapd_drv_update_dh_ie(hapd, sta->addr, status, + MAC2STR_SEC(link_addr ? link_addr : sta->addr)); + hostapd_drv_update_dh_ie(hapd, link_addr ? link_addr : sta->addr, + status, status == WLAN_STATUS_SUCCESS ? ie : NULL, ie_len); @@ -4485,40 +3918,37 @@ static bool check_sa_query(struct hostapd_data *hapd, struct sta_info *sta, } -static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, - const u8 *ies, size_t ies_len, int reassoc) +static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *ies, size_t ies_len, + struct ieee802_11_elems *elems, int reassoc, + bool link) { - struct ieee802_11_elems elems; int resp; const u8 *wpa_ie; size_t wpa_ie_len; const u8 *p2p_dev_addr = NULL; + struct hostapd_data *assoc_hapd; + struct sta_info *assoc_sta = NULL; - if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "Station sent an invalid " - "association request"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - - resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len); + resp = check_ssid(hapd, sta, elems->ssid, elems->ssid_len); if (resp != WLAN_STATUS_SUCCESS) return resp; - resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len); + resp = check_wmm(hapd, sta, elems->wmm, elems->wmm_len); if (resp != WLAN_STATUS_SUCCESS) return resp; - resp = check_ext_capab(hapd, sta, elems.ext_capab, elems.ext_capab_len); + resp = check_ext_capab(hapd, sta, elems->ext_capab, + elems->ext_capab_len); if (resp != WLAN_STATUS_SUCCESS) return resp; - resp = copy_supp_rates(hapd, sta, &elems); + resp = copy_supp_rates(hapd, sta, elems); if (resp != WLAN_STATUS_SUCCESS) return resp; - resp = check_multi_ap(hapd, sta, elems.multi_ap, elems.multi_ap_len); + resp = check_multi_ap(hapd, sta, elems->multi_ap, elems->multi_ap_len); if (resp != WLAN_STATUS_SUCCESS) return resp; - resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities); + resp = copy_sta_ht_capab(hapd, sta, elems->ht_capabilities); if (resp != WLAN_STATUS_SUCCESS) return resp; if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && @@ -4531,11 +3961,11 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_IEEE80211AC if (hapd->iconf->ieee80211ac) { - resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities); + resp = copy_sta_vht_capab(hapd, sta, elems->vht_capabilities); if (resp != WLAN_STATUS_SUCCESS) return resp; - resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif); + resp = set_sta_vht_opmode(hapd, sta, elems->opmode_notif); if (resp != WLAN_STATUS_SUCCESS) return resp; } @@ -4548,9 +3978,9 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_ASSOC_DENIED_NO_VHT; } - if (hapd->conf->vendor_vht && !elems.vht_capabilities) { - resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht, - elems.vendor_vht_len); + if (hapd->conf->vendor_vht && !elems->vht_capabilities) { + resp = copy_sta_vendor_vht(hapd, sta, elems->vendor_vht, + elems->vendor_vht_len); if (resp != WLAN_STATUS_SUCCESS) return resp; } @@ -4558,10 +3988,19 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_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); + elems->he_capabilities, + elems->he_capabilities_len); if (resp != WLAN_STATUS_SUCCESS) return resp; + + if (hapd->iconf->require_he && !(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; + } + if (is_6ghz_op_class(hapd->iconf->op_class)) { if (!(sta->flags & WLAN_STA_HE)) { hostapd_logger(hapd, sta->addr, @@ -4571,15 +4010,32 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_DENIED_HE_NOT_SUPPORTED; } resp = copy_sta_he_6ghz_capab(hapd, sta, - elems.he_6ghz_band_cap); + elems->he_6ghz_band_cap); if (resp != WLAN_STATUS_SUCCESS) return resp; } } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + resp = copy_sta_eht_capab(hapd, sta, IEEE80211_MODE_AP, + elems->he_capabilities, + elems->he_capabilities_len, + elems->eht_capabilities, + elems->eht_capabilities_len); + if (resp != WLAN_STATUS_SUCCESS) + return resp; + + if (!link) { + resp = hostapd_process_ml_assoc_req(hapd, elems, sta); + if (resp != WLAN_STATUS_SUCCESS) + return resp; + } + } +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_P2P - if (elems.p2p) { + if (elems->p2p && ies && ies_len) { wpabuf_free(sta->p2p_ie); sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len, P2P_IE_VENDOR_TYPE); @@ -4591,13 +4047,13 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } #endif /* CONFIG_P2P */ - if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) { - wpa_ie = elems.rsn_ie; - wpa_ie_len = elems.rsn_ie_len; + if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems->rsn_ie) { + wpa_ie = elems->rsn_ie; + wpa_ie_len = elems->rsn_ie_len; } else if ((hapd->conf->wpa & WPA_PROTO_WPA) && - elems.wpa_ie) { - wpa_ie = elems.wpa_ie; - wpa_ie_len = elems.wpa_ie_len; + elems->wpa_ie) { + wpa_ie = elems->wpa_ie; + wpa_ie_len = elems->wpa_ie_len; } else { wpa_ie = NULL; wpa_ie_len = 0; @@ -4605,11 +4061,9 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_WPS sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2); - if (hapd->conf->wps_state && elems.wps_ie) { + if (hapd->conf->wps_state && elems->wps_ie && ies && ies_len) { 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, @@ -4640,33 +4094,56 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, if (hapd->conf->wpa && wpa_ie) { enum wpa_validate_result res; +#ifdef CONFIG_IEEE80211BE + struct mld_info *info = &sta->mld_info; + bool init = !sta->wpa_sm; +#endif /* CONFIG_IEEE80211BE */ wpa_ie -= 2; wpa_ie_len += 2; - if (sta->wpa_sm == NULL) + + if (!sta->wpa_sm) { + if (!link) + assoc_sta = hostapd_ml_get_assoc_sta( + hapd, sta, &assoc_hapd); + sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, p2p_dev_addr); - if (sta->wpa_sm == NULL) { - wpa_printf(MSG_WARNING, "Failed to initialize WPA " - "state machine"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + + if (!sta->wpa_sm) { + wpa_printf(MSG_WARNING, + "Failed to initialize RSN state machine"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + } + +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) { + wpa_printf(MSG_DEBUG, + "MLD: %s ML info in RSN Authenticator", + init ? "Set" : "Reset"); + wpa_auth_set_ml_info(sta->wpa_sm, + sta->mld_assoc_link_id, + info); } +#endif /* CONFIG_IEEE80211BE */ + wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg); res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, hapd->iface->freq, wpa_ie, wpa_ie_len, - elems.rsnxe ? elems.rsnxe - 2 : NULL, - elems.rsnxe ? elems.rsnxe_len + 2 : 0, - elems.mdie, elems.mdie_len, - elems.owe_dh, elems.owe_dh_len); + elems->rsnxe ? elems->rsnxe - 2 : + NULL, + elems->rsnxe ? elems->rsnxe_len + 2 : + 0, + elems->mdie, elems->mdie_len, + elems->owe_dh, elems->owe_dh_len, + assoc_sta ? assoc_sta->wpa_sm : NULL); resp = wpa_res_to_status_code(res); if (resp != WLAN_STATUS_SUCCESS) return resp; - 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; else @@ -4689,6 +4166,8 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } #endif /* CONFIG_IEEE80211R_AP */ + if (link) + goto skip_sae_owe; #ifdef CONFIG_SAE if (wpa_auth_uses_sae(sta->wpa_sm) && sta->sae && sta->sae->state == SAE_ACCEPTED) @@ -4716,10 +4195,10 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; } - if (hapd->conf->sae_pwe == 2 && + if (hapd->conf->sae_pwe == SAE_PWE_BOTH && sta->auth_alg == WLAN_AUTH_SAE && sta->sae && !sta->sae->h2e && - ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, + ieee802_11_rsnx_capab_len(elems->rsnxe, elems->rsnxe_len, WLAN_RSNX_CAPAB_SAE_H2E)) { wpa_printf(MSG_INFO, "SAE: " MACSTR_SEC " indicates support for SAE H2E, but did not use it", @@ -4731,13 +4210,14 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_OWE if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_OWE && - elems.owe_dh) { - resp = owe_process_assoc_req(hapd, sta, elems.owe_dh, - elems.owe_dh_len); + elems->owe_dh) { + resp = owe_process_assoc_req(hapd, sta, elems->owe_dh, + elems->owe_dh_len); if (resp != WLAN_STATUS_SUCCESS) return resp; } #endif /* CONFIG_OWE */ + skip_sae_owe: #ifdef CONFIG_DPP2 dpp_pfs_free(sta->dpp_pfs); @@ -4747,7 +4227,7 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) && hapd->conf->dpp_netaccesskey && sta->wpa_sm && wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_DPP && - elems.owe_dh) { + elems->owe_dh) { sta->dpp_pfs = dpp_pfs_init( wpabuf_head(hapd->conf->dpp_netaccesskey), wpabuf_len(hapd->conf->dpp_netaccesskey)); @@ -4758,8 +4238,8 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, goto pfs_fail; } - if (dpp_pfs_process(sta->dpp_pfs, elems.owe_dh, - elems.owe_dh_len) < 0) { + if (dpp_pfs_process(sta->dpp_pfs, elems->owe_dh, + elems->owe_dh_len) < 0) { dpp_pfs_free(sta->dpp_pfs); sta->dpp_pfs = NULL; return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -4780,9 +4260,16 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, "association"); return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; } + + wpa_auth_set_ssid_protection( + sta->wpa_sm, + hapd->conf->ssid_protection && + ieee802_11_rsnx_capab_len( + elems->rsnxe, elems->rsnxe_len, + WLAN_RSNX_CAPAB_SSID_PROTECTION)); #ifdef CONFIG_HS20 } else if (hapd->conf->osen) { - if (elems.osen == NULL) { + if (!elems->osen) { hostapd_logger( hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, @@ -4800,7 +4287,7 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_UNSPECIFIED_FAILURE; } if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm, - elems.osen - 2, elems.osen_len + 2) < 0) + elems->osen - 2, elems->osen_len + 2) < 0) return WLAN_STATUS_INVALID_IE; #endif /* CONFIG_HS20 */ } else @@ -4812,12 +4299,12 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_HS20 wpabuf_free(sta->hs20_ie); - if (elems.hs20 && elems.hs20_len > 4) { + if (elems->hs20 && elems->hs20_len > 4) { int release; - sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4, - elems.hs20_len - 4); - release = ((elems.hs20[4] >> 4) & 0x0f) + 1; + sta->hs20_ie = wpabuf_alloc_copy(elems->hs20 + 4, + elems->hs20_len - 4); + release = ((elems->hs20[4] >> 4) & 0x0f) + 1; if (release >= 2 && !wpa_auth_uses_mfp(sta->wpa_sm) && hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { wpa_printf(MSG_DEBUG, @@ -4830,10 +4317,10 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } wpabuf_free(sta->roaming_consortium); - if (elems.roaming_cons_sel) + if (elems->roaming_cons_sel) sta->roaming_consortium = wpabuf_alloc_copy( - elems.roaming_cons_sel + 4, - elems.roaming_cons_sel_len - 4); + elems->roaming_cons_sel + 4, + elems->roaming_cons_sel_len - 4); else sta->roaming_consortium = NULL; #endif /* CONFIG_HS20 */ @@ -4841,16 +4328,16 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, #ifdef CONFIG_FST wpabuf_free(sta->mb_ies); if (hapd->iface->fst) - sta->mb_ies = mb_ies_by_info(&elems.mb_ies); + sta->mb_ies = mb_ies_by_info(&elems->mb_ies); else sta->mb_ies = NULL; #endif /* CONFIG_FST */ #ifdef CONFIG_MBO - mbo_ap_check_sta_assoc(hapd, sta, &elems); + mbo_ap_check_sta_assoc(hapd, sta, elems); if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) && - elems.mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) && + elems->mbo && sta->cell_capa && !(sta->flags & WLAN_STA_MFP) && hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { wpa_printf(MSG_INFO, "MBO: Reject WPA2 association without PMF"); @@ -4880,7 +4367,7 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, &tx_seg1_idx) < 0) return WLAN_STATUS_UNSPECIFIED_FAILURE; - res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci, + 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) { @@ -4899,27 +4386,315 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } #endif /* CONFIG_FILS && CONFIG_OCV */ - ap_copy_sta_supp_op_classes(sta, elems.supp_op_classes, - elems.supp_op_classes_len); + ap_copy_sta_supp_op_classes(sta, elems->supp_op_classes, + elems->supp_op_classes_len); if ((sta->capability & WLAN_CAPABILITY_RADIO_MEASUREMENT) && - elems.rrm_enabled && - elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa)) - os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled, + elems->rrm_enabled && + elems->rrm_enabled_len >= sizeof(sta->rrm_enabled_capa)) + os_memcpy(sta->rrm_enabled_capa, elems->rrm_enabled, sizeof(sta->rrm_enabled_capa)); - if (elems.power_capab) { - sta->min_tx_power = elems.power_capab[0]; - sta->max_tx_power = elems.power_capab[1]; + if (elems->power_capab) { + sta->min_tx_power = elems->power_capab[0]; + sta->max_tx_power = elems->power_capab[1]; sta->power_capab = 1; } else { sta->power_capab = 0; } + if (elems->bss_max_idle_period && + hapd->conf->max_acceptable_idle_period) { + u16 req; + + req = WPA_GET_LE16(elems->bss_max_idle_period); + if (req <= hapd->conf->max_acceptable_idle_period) + sta->max_idle_period = req; + else if (hapd->conf->max_acceptable_idle_period > + hapd->conf->ap_max_inactivity) + sta->max_idle_period = + hapd->conf->max_acceptable_idle_period; + } + return WLAN_STATUS_SUCCESS; } +static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *ies, size_t ies_len, int reassoc) +{ + struct ieee802_11_elems elems; + + if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "Station sent an invalid association request"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + return __check_assoc_ies(hapd, sta, ies, ies_len, &elems, reassoc, + false); +} + + +#ifdef CONFIG_IEEE80211BE + +static void ieee80211_ml_build_assoc_resp(struct hostapd_data *hapd, + struct mld_link_info *link) +{ + u8 buf[EHT_ML_MAX_STA_PROF_LEN]; + u8 *p = buf; + size_t buflen = sizeof(buf); + + /* Capability Info */ + WPA_PUT_LE16(p, hostapd_own_capab_info(hapd)); + p += 2; + + /* Status Code */ + WPA_PUT_LE16(p, link->status); + p += 2; + + if (link->status != WLAN_STATUS_SUCCESS) + goto out; + + /* AID is not included */ + p = hostapd_eid_supp_rates(hapd, p); + p = hostapd_eid_ext_supp_rates(hapd, p); + p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p); + p = hostapd_eid_ht_capabilities(hapd, p); + p = hostapd_eid_ht_operation(hapd, p); + + if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) { + p = hostapd_eid_vht_capabilities(hapd, p, 0); + p = hostapd_eid_vht_operation(hapd, p); + } + + 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); + p = hostapd_eid_he_mu_edca_parameter_set(hapd, p); + p = hostapd_eid_he_6ghz_band_cap(hapd, p); + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP); + p = hostapd_eid_eht_operation(hapd, p); + } + } + + p = hostapd_eid_ext_capab(hapd, p, false); + p = hostapd_eid_mbo(hapd, p, buf + buflen - p); + p = hostapd_eid_wmm(hapd, p); + + if (hapd->conf->assocresp_elements && + (size_t) (buf + buflen - p) >= + wpabuf_len(hapd->conf->assocresp_elements)) { + os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements), + wpabuf_len(hapd->conf->assocresp_elements)); + p += wpabuf_len(hapd->conf->assocresp_elements); + } + +out: + os_free(link->resp_sta_profile); + link->resp_sta_profile = os_memdup(buf, p - buf); + link->resp_sta_profile_len = link->resp_sta_profile ? p - buf : 0; +} + + +static int ieee80211_ml_process_link(struct hostapd_data *hapd, + struct sta_info *origin_sta, + struct mld_link_info *link, + const u8 *ies, size_t ies_len, + bool reassoc, bool offload) +{ + struct ieee802_11_elems elems; + struct wpabuf *mlbuf = NULL; + struct sta_info *sta = NULL; + u16 status = WLAN_STATUS_SUCCESS; + int i; + + wpa_printf(MSG_DEBUG, "MLD: link: link_id=%u, peer=" MACSTR, + hapd->mld_link_id, MAC2STR(link->peer_addr)); + + if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) { + wpa_printf(MSG_DEBUG, "MLD: link: Element parsing failed"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; + } + + sta = ap_get_sta(hapd, origin_sta->addr); + if (sta) { + wpa_printf(MSG_INFO, "MLD: link: Station already exists"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + sta = NULL; + goto out; + } + + sta = ap_sta_add(hapd, origin_sta->addr); + if (!sta) { + wpa_printf(MSG_DEBUG, "MLD: link: ap_sta_add() failed"); + status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + goto out; + } + + mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true); + if (!mlbuf) + goto out; + + if (ieee802_11_parse_link_assoc_req(ies, ies_len, &elems, mlbuf, + hapd->mld_link_id, true) == + ParseFailed) { + wpa_printf(MSG_DEBUG, + "MLD: link: Failed to parse association request Multi-Link element"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; + } + + sta->flags |= origin_sta->flags | WLAN_STA_ASSOC_REQ_OK; + sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id; + + status = __check_assoc_ies(hapd, sta, NULL, 0, &elems, reassoc, true); + if (status != WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, "MLD: link: Element check failed"); + goto out; + } + + ap_sta_set_mld(sta, true); + + os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info)); + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + struct mld_link_info *li = &sta->mld_info.links[i]; + + li->resp_sta_profile = NULL; + li->resp_sta_profile_len = 0; + } + + if (!offload) { + /* + * Get the AID from the station on which the association was + * performed, and mark it as used. + */ + sta->aid = origin_sta->aid; + if (sta->aid == 0) { + wpa_printf(MSG_DEBUG, "MLD: link: No AID assigned"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; + } + hapd->sta_aid[(sta->aid - 1) / 32] |= BIT((sta->aid - 1) % 32); + sta->listen_interval = origin_sta->listen_interval; + if (update_ht_state(hapd, sta) > 0) + ieee802_11_update_beacons(hapd->iface); + } + + /* Maintain state machine reference on all link STAs, this is needed + * during group rekey handling. + */ + wpa_auth_sta_deinit(sta->wpa_sm); + sta->wpa_sm = origin_sta->wpa_sm; + + /* + * Do not initialize the EAPOL state machine. + * TODO: Maybe it is needed? + */ + sta->eapol_sm = NULL; + + wpa_printf(MSG_DEBUG, "MLD: link=%u, association OK (aid=%u)", + hapd->mld_link_id, sta->aid); + + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC_REQ_OK; + + /* TODO: What other processing is required? */ + + if (!offload && add_associated_sta(hapd, sta, reassoc)) + status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; +out: + wpabuf_free(mlbuf); + link->status = status; + + if (!offload) + ieee80211_ml_build_assoc_resp(hapd, link); + + wpa_printf(MSG_DEBUG, "MLD: link: status=%u", status); + if (status != WLAN_STATUS_SUCCESS) { + if (sta) + ap_free_sta(hapd, sta); + return -1; + } + + return 0; +} + + +bool hostapd_is_mld_ap(struct hostapd_data *hapd) +{ + if (!hapd->conf->mld_ap) + return false; + + if (!hapd->iface || !hapd->iface->interfaces || + hapd->iface->interfaces->count <= 1) + return false; + + return true; +} + +#endif /* CONFIG_IEEE80211BE */ + + +int hostapd_process_assoc_ml_info(struct hostapd_data *hapd, + struct sta_info *sta, + const u8 *ies, size_t ies_len, + bool reassoc, int tx_link_status, + bool offload) +{ +#ifdef CONFIG_IEEE80211BE + unsigned int i; + + if (!hostapd_is_mld_ap(hapd)) + return 0; + + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + struct hostapd_data *bss = NULL; + struct mld_link_info *link = &sta->mld_info.links[i]; + bool link_bss_found = false; + + if (!link->valid || i == sta->mld_assoc_link_id) + continue; + + for_each_mld_link(bss, hapd) { + if (bss == hapd) + continue; + + if (bss->mld_link_id != i) + continue; + + link_bss_found = true; + break; + } + + if (!link_bss_found || TEST_FAIL()) { + wpa_printf(MSG_DEBUG, + "MLD: No link match for link_id=%u", i); + + link->status = WLAN_STATUS_UNSPECIFIED_FAILURE; + if (!offload) + ieee80211_ml_build_assoc_resp(hapd, link); + } else if (tx_link_status != WLAN_STATUS_SUCCESS) { + /* TX link rejected the connection */ + link->status = WLAN_STATUS_DENIED_TX_LINK_NOT_ACCEPTED; + if (!offload) + ieee80211_ml_build_assoc_resp(hapd, link); + } else { + if (ieee80211_ml_process_link(bss, sta, link, + ies, ies_len, reassoc, + offload)) + return -1; + } + } +#endif /* CONFIG_IEEE80211BE */ + + return 0; +} + + static void send_deauth(struct hostapd_data *hapd, const u8 *addr, u16 reason_code) { @@ -4948,7 +4723,22 @@ static int add_associated_sta(struct hostapd_data *hapd, struct ieee80211_ht_capabilities ht_cap; struct ieee80211_vht_capabilities vht_cap; struct ieee80211_he_capabilities he_cap; + struct ieee80211_eht_capabilities eht_cap; int set = 1; + const u8 *mld_link_addr = NULL; + bool mld_link_sta = false; + +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) { + u8 mld_link_id = hapd->mld_link_id; + + mld_link_sta = sta->mld_assoc_link_id != mld_link_id; + mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr; + + if (hapd->mld_link_id != sta->mld_assoc_link_id) + set = 0; + } +#endif /* CONFIG_IEEE80211BE */ /* * Remove the STA entry to ensure the STA PS state gets cleared and @@ -4977,7 +4767,7 @@ static int add_associated_sta(struct hostapd_data *hapd, wpa_auth_sta_ft_tk_already_set(sta->wpa_sm), wpa_auth_sta_fils_tk_already_set(sta->wpa_sm)); - if (!sta->added_unassoc && + if (!mld_link_sta && !sta->added_unassoc && (!(sta->flags & WLAN_STA_AUTHORIZED) || (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) || (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) && @@ -5004,6 +4794,11 @@ static int add_associated_sta(struct hostapd_data *hapd, sta->he_capab_len); } #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + if (sta->flags & WLAN_STA_EHT) + hostapd_get_eht_capab(hapd, sta->eht_capab, &eht_cap, + sta->eht_capab_len); +#endif /* CONFIG_IEEE80211BE */ /* * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags @@ -5017,10 +4812,12 @@ static int add_associated_sta(struct hostapd_data *hapd, sta->flags & WLAN_STA_VHT ? &vht_cap : NULL, sta->flags & WLAN_STA_HE ? &he_cap : NULL, sta->flags & WLAN_STA_HE ? sta->he_capab_len : 0, + sta->flags & WLAN_STA_EHT ? &eht_cap : NULL, + sta->flags & WLAN_STA_EHT ? sta->eht_capab_len : 0, sta->he_6ghz_capab, sta->flags | WLAN_STA_ASSOC, sta->qosinfo, sta->vht_opmode, sta->p2p_ie ? 1 : 0, - set)) { + set, mld_link_addr, mld_link_sta)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, "Could not %s STA to kernel driver", @@ -5043,7 +4840,7 @@ static int add_associated_sta(struct hostapd_data *hapd, static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, const u8 *addr, u16 status_code, int reassoc, const u8 *ies, size_t ies_len, int rssi, - int omit_rsnxe) + int omit_rsnxe, bool allow_mld_addr_trans) { int send_len; u8 *buf; @@ -5067,6 +4864,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, if (sta && sta->dpp_pfs) buflen += 5 + sta->dpp_pfs->curve->prime_len; #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + buflen += hostapd_eid_eht_capab_len(hapd, IEEE80211_MODE_AP); + buflen += 3 + sizeof(struct ieee80211_eht_operation); + if (hapd->iconf->punct_bitmap) + buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE; + } +#endif /* CONFIG_IEEE80211BE */ + buf = os_zalloc(buflen); if (!buf) { res = WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -5077,6 +4883,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, IEEE80211_FC(WLAN_FC_TYPE_MGMT, (reassoc ? WLAN_FC_STYPE_REASSOC_RESP : WLAN_FC_STYPE_ASSOC_RESP)); + os_memcpy(reply->da, addr, ETH_ALEN); os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN); @@ -5175,14 +4982,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, 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_cca(hapd, p); p = hostapd_eid_spatial_reuse(hapd, p); p = hostapd_eid_he_mu_edca_parameter_set(hapd, p); p = hostapd_eid_he_6ghz_band_cap(hapd, p); } #endif /* CONFIG_IEEE80211AX */ - p = hostapd_eid_ext_capab(hapd, p); - p = hostapd_eid_bss_max_idle_period(hapd, p); + p = hostapd_eid_ext_capab(hapd, p, false); + p = hostapd_eid_bss_max_idle_period(hapd, p, sta->max_idle_period); if (sta && sta->qos_map_enabled) p = hostapd_eid_qos_map_set(hapd, p); @@ -5212,6 +5020,15 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, rsnxe_done: #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_IEEE80211BE + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + if (hapd->conf->mld_ap) + p = hostapd_eid_eht_ml_assoc(hapd, sta, p); + p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP); + p = hostapd_eid_eht_operation(hapd, p); + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_OWE if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS && @@ -5268,7 +5085,7 @@ rsnxe_done: #endif /* CONFIG_WPS */ if (sta && (sta->flags & WLAN_STA_MULTI_AP)) - p = hostapd_eid_multi_ap(hapd, p); + p = hostapd_eid_multi_ap(hapd, p, buf + buflen - p); #ifdef CONFIG_P2P if (sta && sta->p2p_ie && hapd->p2p_group) { @@ -5429,7 +5246,8 @@ void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta) reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS, sta->fils_pending_assoc_is_reassoc, sta->fils_pending_assoc_req, - sta->fils_pending_assoc_req_len, 0, 0); + sta->fils_pending_assoc_req_len, 0, 0, + true); os_free(sta->fils_pending_assoc_req); sta->fils_pending_assoc_req = NULL; sta->fils_pending_assoc_req_len = 0; @@ -5447,21 +5265,63 @@ void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta) } -void fils_hlp_timeout(void *eloop_ctx, void *eloop_data) -{ - struct hostapd_data *hapd = eloop_ctx; - struct sta_info *sta = eloop_data; +void fils_hlp_timeout(void *eloop_ctx, void *eloop_data) +{ + struct hostapd_data *hapd = eloop_ctx; + struct sta_info *sta = eloop_data; + + wpa_printf(MSG_DEBUG, + "FILS: HLP response timeout - continue with association response for " + MACSTR_SEC, MAC2STR_SEC(sta->addr)); + if (sta->fils_drv_assoc_finish) + hostapd_notify_assoc_fils_finish(hapd, sta); + else + fils_hlp_finish_assoc(hapd, sta); +} + +#endif /* CONFIG_FILS */ + + +#ifdef CONFIG_IEEE80211BE +static struct sta_info * handle_mlo_translate(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len, bool reassoc, + struct hostapd_data **assoc_hapd) +{ + struct sta_info *sta; + struct ieee802_11_elems elems; + u8 mld_addr[ETH_ALEN]; + const u8 *pos; + + if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be) + return NULL; + + if (reassoc) { + len -= IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req); + pos = mgmt->u.reassoc_req.variable; + } else { + len -= IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req); + pos = mgmt->u.assoc_req.variable; + } + + if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed) + return NULL; + + if (hostapd_process_ml_assoc_req_addr(hapd, elems.basic_mle, + elems.basic_mle_len, + mld_addr)) + return NULL; + + sta = ap_get_sta(hapd, mld_addr); + if (!sta) + return NULL; - wpa_printf(MSG_DEBUG, - "FILS: HLP response timeout - continue with association response for " - MACSTR_SEC, MAC2STR_SEC(sta->addr)); - if (sta->fils_drv_assoc_finish) - hostapd_notify_assoc_fils_finish(hapd, sta); - else - fils_hlp_finish_assoc(hapd, sta); -} + wpa_printf(MSG_DEBUG, "MLD: assoc: mld=" MACSTR ", link=" MACSTR, + MAC2STR(mld_addr), MAC2STR(mgmt->sa)); -#endif /* CONFIG_FILS */ + return hostapd_ml_get_assoc_sta(hapd, sta, assoc_hapd); +} +#endif /* CONFIG_IEEE80211BE */ static void handle_assoc(struct hostapd_data *hapd, @@ -5479,6 +5339,8 @@ static void handle_assoc(struct hostapd_data *hapd, int delay_assoc = 0; #endif /* CONFIG_FILS */ int omit_rsnxe = 0; + bool set_beacon = false; + bool mld_addrs_not_translated = false; if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : sizeof(mgmt->u.assoc_req))) { @@ -5536,6 +5398,28 @@ static void handle_assoc(struct hostapd_data *hapd, } sta = ap_get_sta(hapd, mgmt->sa); + +#ifdef CONFIG_IEEE80211BE + /* + * It is possible that the association frame is from an associated + * non-AP MLD station, that tries to re-associate using different link + * addresses. In such a case, try to find the station based on the AP + * MLD MAC address. + */ + if (!sta) { + struct hostapd_data *assoc_hapd; + + sta = handle_mlo_translate(hapd, mgmt, len, reassoc, + &assoc_hapd); + if (sta) { + wpa_printf(MSG_DEBUG, + "MLD: Switching to assoc hapd/station"); + hapd = assoc_hapd; + mld_addrs_not_translated = true; + } + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_IEEE80211R_AP if (sta && sta->auth_alg == WLAN_AUTH_FT && (sta->flags & WLAN_STA_AUTH) == 0) { @@ -5654,6 +5538,11 @@ static void handle_assoc(struct hostapd_data *hapd, } #endif /* CONFIG_MBO */ + if (hapd->conf->wpa && check_sa_query(hapd, sta, reassoc)) { + resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; + goto fail; + } + /* * sta->capability is used in check_assoc_ies() for RRM enabled * capability element. @@ -5715,7 +5604,7 @@ static void handle_assoc(struct hostapd_data *hapd, sta->nonerp_set = 1; hapd->iface->num_sta_non_erp++; if (hapd->iface->num_sta_non_erp == 1) - ieee802_11_set_beacons(hapd->iface); + set_beacon = true; } if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) && @@ -5726,7 +5615,7 @@ static void handle_assoc(struct hostapd_data *hapd, hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->iface->num_sta_no_short_slot_time == 1) - ieee802_11_set_beacons(hapd->iface); + set_beacon = true; } if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) @@ -5741,10 +5630,11 @@ static void handle_assoc(struct hostapd_data *hapd, if (hapd->iface->current_mode && hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->iface->num_sta_no_short_preamble == 1) - ieee802_11_set_beacons(hapd->iface); + set_beacon = true; } - update_ht_state(hapd, sta); + if (update_ht_state(hapd, sta) > 0) + set_beacon = true; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, @@ -5783,6 +5673,9 @@ static void handle_assoc(struct hostapd_data *hapd, } #endif /* CONFIG_FILS */ + if (set_beacon) + ieee802_11_update_beacons(hapd->iface); + fail: /* @@ -5803,6 +5696,10 @@ static void handle_assoc(struct hostapd_data *hapd, * issues with processing other non-Data Class 3 frames during this * window. */ + if (sta) + hostapd_process_assoc_ml_info(hapd, sta, pos, left, reassoc, + resp, false); + if (resp == WLAN_STATUS_SUCCESS && sta && add_associated_sta(hapd, sta, reassoc)) resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; @@ -5845,8 +5742,12 @@ static void handle_assoc(struct hostapd_data *hapd, #endif /* CONFIG_FILS */ if (resp >= 0) - reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, - pos, left, rssi, omit_rsnxe); + reply_res = send_assoc_resp(hapd, + mld_addrs_not_translated ? + NULL : sta, + mgmt->sa, resp, reassoc, + pos, left, rssi, omit_rsnxe, + !mld_addrs_not_translated); os_free(tmp); /* @@ -5862,27 +5763,37 @@ static void handle_assoc(struct hostapd_data *hapd, } -static void handle_disassoc(struct hostapd_data *hapd, - const struct ieee80211_mgmt *mgmt, size_t len) +static void hostapd_deauth_sta(struct hostapd_data *hapd, + struct sta_info *sta, + const struct ieee80211_mgmt *mgmt) { - struct sta_info *sta; + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "deauthentication: STA=" MACSTR " reason_code=%d", + MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); - if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { - wpa_printf(MSG_INFO, "handle_disassoc - too short payload (len=%lu)", - (unsigned long) len); - return; - } + ap_sta_set_authorized(hapd, sta, 0); + sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | + WLAN_STA_ASSOC_REQ_OK); + hostapd_set_sta_flags(hapd, sta); + wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "deauthenticated"); + mlme_deauthenticate_indication( + hapd, sta, le_to_host16(mgmt->u.deauth.reason_code)); + sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; + ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); + ap_free_sta(hapd, sta); +} - wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR_SEC " reason_code=%d", - MAC2STR_SEC(mgmt->sa), - le_to_host16(mgmt->u.disassoc.reason_code)); - sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL) { - wpa_printf(MSG_INFO, "Station " MACSTR_SEC " trying to disassociate, but it is not associated", - MAC2STR_SEC(mgmt->sa)); - return; - } +static void hostapd_disassoc_sta(struct hostapd_data *hapd, + struct sta_info *sta, + const struct ieee80211_mgmt *mgmt) +{ + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "disassocation: STA=" MACSTR " reason_code=%d", + MAC2STR(mgmt->sa), le_to_host16(mgmt->u.disassoc.reason_code)); ap_sta_set_authorized(hapd, sta, 0); sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; @@ -5927,14 +5838,98 @@ static void handle_disassoc(struct hostapd_data *hapd, } +static bool hostapd_ml_handle_disconnect(struct hostapd_data *hapd, + struct sta_info *sta, + const struct ieee80211_mgmt *mgmt, + bool disassoc) +{ +#ifdef CONFIG_IEEE80211BE + struct hostapd_data *assoc_hapd, *tmp_hapd; + struct sta_info *assoc_sta; + struct sta_info *tmp_sta; + + if (!hostapd_is_mld_ap(hapd)) + return false; + + /* + * Get the station on which the association was performed, as it holds + * the information about all the other links. + */ + assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd); + if (!assoc_sta) + return false; + + for_each_mld_link(tmp_hapd, assoc_hapd) { + if (tmp_hapd == assoc_hapd) + continue; + + if (!assoc_sta->mld_info.links[tmp_hapd->mld_link_id].valid) + continue; + + for (tmp_sta = tmp_hapd->sta_list; tmp_sta; + tmp_sta = tmp_sta->next) { + if (tmp_sta->mld_assoc_link_id != + assoc_sta->mld_assoc_link_id || + tmp_sta->aid != assoc_sta->aid) + continue; + + if (!disassoc) + hostapd_deauth_sta(tmp_hapd, tmp_sta, mgmt); + else + hostapd_disassoc_sta(tmp_hapd, tmp_sta, mgmt); + break; + } + } + + /* Remove the station on which the association was performed. */ + if (!disassoc) + hostapd_deauth_sta(assoc_hapd, assoc_sta, mgmt); + else + hostapd_disassoc_sta(assoc_hapd, assoc_sta, mgmt); + + return true; +#else /* CONFIG_IEEE80211BE */ + return false; +#endif /* CONFIG_IEEE80211BE */ +} + + +static void handle_disassoc(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, size_t len) +{ + struct sta_info *sta; + + if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "handle_disassoc - too short payload (len=%lu)", + (unsigned long) len); + return; + } + + sta = ap_get_sta(hapd, mgmt->sa); + if (!sta) { + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR_SEC + " trying to disassociate, but it is not associated", + MAC2STR_SEC(mgmt->sa)); + return; + } + + if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, true)) + return; + + hostapd_disassoc_sta(hapd, sta, mgmt); +} + + static void handle_deauth(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short " - "payload (len=%lu)", (unsigned long) len); + wpa_msg(hapd->msg_ctx, MSG_DEBUG, + "handle_deauth - too short payload (len=%lu)", + (unsigned long) len); return; } @@ -5944,31 +5939,22 @@ static void handle_deauth(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "deauthentication: STA=" MACSTR_SEC " reason_code=%d", MAC2STR_SEC(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); - + /* Clear the PTKSA cache entries for PASN */ ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE); sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " - "to deauthenticate, but it is not authenticated", + if (!sta) { + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR + " trying to deauthenticate, but it is not authenticated", MAC2STR(mgmt->sa)); return; } - ap_sta_set_authorized(hapd, sta, 0); - sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | - WLAN_STA_ASSOC_REQ_OK); - hostapd_set_sta_flags(hapd, sta); - wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "deauthenticated"); - mlme_deauthenticate_indication( - hapd, sta, le_to_host16(mgmt->u.deauth.reason_code)); - sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; - ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - ap_free_sta(hapd, sta); + if (hostapd_ml_handle_disconnect(hapd, sta, mgmt, false)) + return; + + hostapd_deauth_sta(hapd, sta, mgmt); } @@ -6123,21 +6109,38 @@ static int handle_action(struct hostapd_data *hapd, pos = &mgmt->u.action.u.public_action.action; end = ((const u8 *) mgmt) + len; - gas_query_ap_rx(hapd->gas, mgmt->sa, - mgmt->u.action.category, - pos, end - pos, hapd->iface->freq); - return 1; + if (gas_query_ap_rx(hapd->gas, mgmt->sa, + mgmt->u.action.category, + pos, end - pos, freq) == 0) + return 1; } #endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + if (mgmt->u.action.category == WLAN_ACTION_PUBLIC && + len >= IEEE80211_HDRLEN + 5 && + mgmt->u.action.u.vs_public_action.action == + WLAN_PA_VENDOR_SPECIFIC && + WPA_GET_BE24(mgmt->u.action.u.vs_public_action.oui) == + OUI_WFA && + mgmt->u.action.u.vs_public_action.variable[0] == + NAN_OUI_TYPE) { + const u8 *pos, *end; + + pos = mgmt->u.action.u.vs_public_action.variable; + end = ((const u8 *) mgmt) + len; + pos++; + hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, freq, + pos, end - pos); + return 1; + } +#endif /* CONFIG_NAN_USD */ if (hapd->public_action_cb) { hapd->public_action_cb(hapd->public_action_cb_ctx, - (u8 *) mgmt, len, - hapd->iface->freq); + (u8 *) mgmt, len, freq); } if (hapd->public_action_cb2) { hapd->public_action_cb2(hapd->public_action_cb2_ctx, - (u8 *) mgmt, len, - hapd->iface->freq); + (u8 *) mgmt, len, freq); } if (hapd->public_action_cb || hapd->public_action_cb2) return 1; @@ -6145,14 +6148,15 @@ static int handle_action(struct hostapd_data *hapd, case WLAN_ACTION_VENDOR_SPECIFIC: if (hapd->vendor_action_cb) { if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx, - (u8 *) mgmt, len, - hapd->iface->freq) == 0) + (u8 *) mgmt, len, freq) == 0) return 1; } break; +#ifndef CONFIG_NO_RRM case WLAN_ACTION_RADIO_MEASUREMENT: hostapd_handle_radio_measurement(hapd, (const u8 *) mgmt, len); return 1; +#endif /* CONFIG_NO_RRM */ } hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -6237,6 +6241,10 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, int ret = 0; unsigned int freq; int ssi_signal = fi ? fi->ssi_signal : 0; +#ifdef CONFIG_NAN_USD + static const u8 nan_network_id[ETH_ALEN] = + { 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 }; +#endif /* CONFIG_NAN_USD */ if (len < 24) return 0; @@ -6252,7 +6260,7 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, if (is_multicast_ether_addr(mgmt->sa) || is_zero_ether_addr(mgmt->sa) || - os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) { + ether_addr_equal(mgmt->sa, hapd->own_addr)) { /* Do not process any frames with unexpected/invalid SA so that * we do not add any state for unexpected STA addresses or end * up sending out frames to unexpected destination. */ @@ -6276,7 +6284,11 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, #ifdef CONFIG_MESH !(hapd->conf->mesh & MESH_ENABLED) && #endif /* CONFIG_MESH */ - os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) { +#ifdef CONFIG_IEEE80211BE + !(hapd->conf->mld_ap && + ether_addr_equal(hapd->mld->mld_addr, mgmt->bssid)) && +#endif /* CONFIG_IEEE80211BE */ + !ether_addr_equal(mgmt->bssid, hapd->own_addr)) { wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR_SEC " not our address", MAC2STR_SEC(mgmt->bssid)); return 0; @@ -6295,7 +6307,14 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, if ((!is_broadcast_ether_addr(mgmt->da) || stype != WLAN_FC_STYPE_ACTION) && - os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) { +#ifdef CONFIG_IEEE80211BE + !(hapd->conf->mld_ap && + ether_addr_equal(hapd->mld->mld_addr, mgmt->bssid)) && +#endif /* CONFIG_IEEE80211BE */ +#ifdef CONFIG_NAN_USD + !ether_addr_equal(mgmt->da, nan_network_id) && +#endif /* CONFIG_NAN_USD */ + !ether_addr_equal(mgmt->da, hapd->own_addr)) { hostapd_logger_only_for_cb(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "MGMT: DA=" MACSTR " not our address", @@ -6441,6 +6460,88 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd, } +#ifdef CONFIG_IEEE80211BE +static void ieee80211_ml_link_sta_assoc_cb(struct hostapd_data *hapd, + struct sta_info *sta, + struct mld_link_info *link, + bool ok) +{ + bool updated = false; + + if (!ok) { + hostapd_logger(hapd, link->peer_addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "did not acknowledge association response"); + sta->flags &= ~WLAN_STA_ASSOC_REQ_OK; + + /* The STA is added only in case of SUCCESS */ + if (link->status == WLAN_STATUS_SUCCESS) + hostapd_drv_sta_remove(hapd, sta->addr); + + return; + } + + if (link->status != WLAN_STATUS_SUCCESS) + return; + + sta->flags |= WLAN_STA_ASSOC; + sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; + + if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) + updated = ap_sta_set_authorized_flag(hapd, sta, 1); + + hostapd_set_sta_flags(hapd, sta); + if (updated) + ap_sta_set_authorized_event(hapd, sta, 1); + + /* + * TODOs: + * - IEEE 802.1X port enablement is not needed as done on the station + * doing the connection. + * - Not handling accounting + * - Need to handle VLAN configuration + */ +} +#endif /* CONFIG_IEEE80211BE */ + + +static void hostapd_ml_handle_assoc_cb(struct hostapd_data *hapd, + struct sta_info *sta, bool ok) +{ +#ifdef CONFIG_IEEE80211BE + struct hostapd_data *tmp_hapd; + + if (!hostapd_is_mld_ap(hapd)) + return; + + for_each_mld_link(tmp_hapd, hapd) { + struct mld_link_info *link; + struct sta_info *tmp_sta; + + if (tmp_hapd == hapd) + continue; + + link = &sta->mld_info.links[tmp_hapd->mld_link_id]; + if (!link->valid) + continue; + + for (tmp_sta = tmp_hapd->sta_list; tmp_sta; + tmp_sta = tmp_sta->next) { + if (tmp_sta == sta || + tmp_sta->mld_assoc_link_id != + sta->mld_assoc_link_id || + tmp_sta->aid != sta->aid) + continue; + + ieee80211_ml_link_sta_assoc_cb(tmp_hapd, tmp_sta, link, + ok); + break; + } + } +#endif /* CONFIG_IEEE80211BE */ +} + + static void handle_assoc_cb(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int reassoc, int ok) @@ -6456,6 +6557,17 @@ static void handle_assoc_cb(struct hostapd_data *hapd, return; } +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta) && + hapd->mld_link_id != sta->mld_assoc_link_id) { + /* See ieee80211_ml_link_sta_assoc_cb() for the MLD case */ + wpa_printf(MSG_DEBUG, + "%s: MLD: ignore on link station (%d != %d)", + __func__, hapd->mld_link_id, sta->mld_assoc_link_id); + return; + } +#endif /* CONFIG_IEEE80211BE */ + if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) : sizeof(mgmt->u.assoc_resp))) { wpa_printf(MSG_INFO, @@ -6479,11 +6591,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd, if (status == WLAN_STATUS_SUCCESS) hostapd_drv_sta_remove(hapd, sta->addr); - return; + goto handle_ml; } if (status != WLAN_STATUS_SUCCESS) - return; + goto handle_ml; /* Stop previous accounting session, if one is started, and allocate * new session id for the new session. */ @@ -6525,11 +6637,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd, * interface selection is not going to change anymore. */ if (ap_sta_bind_vlan(hapd, sta) < 0) - return; + goto handle_ml; } else if (sta->vlan_id) { /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */ if (ap_sta_bind_vlan(hapd, sta) < 0) - return; + goto handle_ml; } hostapd_set_sta_flags(hapd, sta); @@ -6542,7 +6654,12 @@ static void handle_assoc_cb(struct hostapd_data *hapd, sta->flags |= WLAN_STA_WDS; } - if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) { + /* WPS not supported on backhaul BSS. Disable 4addr mode on fronthaul */ + if ((sta->flags & WLAN_STA_WDS) || + (sta->flags & WLAN_STA_MULTI_AP && + (hapd->conf->multi_ap & BACKHAUL_BSS) && + hapd->conf->wds_sta && + !(sta->flags & WLAN_STA_WPS))) { int ret; char ifname_wds[IFNAMSIZ + 1]; @@ -6586,12 +6703,16 @@ static void handle_assoc_cb(struct hostapd_data *hapd, ieee802_1x_receive( hapd, mgmt->da, wpabuf_head(sta->pending_eapol_rx->buf), - wpabuf_len(sta->pending_eapol_rx->buf)); + wpabuf_len(sta->pending_eapol_rx->buf), + sta->pending_eapol_rx->encrypted); } wpabuf_free(sta->pending_eapol_rx->buf); os_free(sta->pending_eapol_rx); sta->pending_eapol_rx = NULL; } + +handle_ml: + hostapd_ml_handle_assoc_cb(hapd, sta, ok); } @@ -6648,10 +6769,10 @@ static void handle_action_cb(struct hostapd_data *hapd, size_t len, int ok) { struct sta_info *sta; +#ifndef CONFIG_NO_RRM const struct rrm_measurement_report_element *report; +#endif /* CONFIG_NO_RRM */ - if (is_multicast_ether_addr(mgmt->da)) - return; #ifdef CONFIG_DPP if (len >= IEEE80211_HDRLEN + 6 && mgmt->u.action.category == WLAN_ACTION_PUBLIC && @@ -6682,6 +6803,8 @@ static void handle_action_cb(struct hostapd_data *hapd, return; } #endif /* CONFIG_DPP */ + if (is_multicast_ether_addr(mgmt->da)) + return; sta = ap_get_sta(hapd, mgmt->da); if (!sta) { wpa_printf(MSG_DEBUG, "handle_action_cb: STA " MACSTR_SEC @@ -6689,6 +6812,20 @@ static void handle_action_cb(struct hostapd_data *hapd, return; } +#ifdef CONFIG_HS20 + if (ok && len >= IEEE80211_HDRLEN + 2 && + mgmt->u.action.category == WLAN_ACTION_WNM && + mgmt->u.action.u.vs_public_action.action == WNM_NOTIFICATION_REQ && + sta->hs20_deauth_on_ack) { + wpa_printf(MSG_DEBUG, "HS 2.0: Deauthenticate STA " MACSTR_SEC + " on acknowledging the WNM-Notification", + MAC2STR_SEC(sta->addr)); + ap_sta_session_timeout(hapd, sta, 0); + return; + } +#endif /* CONFIG_HS20 */ + +#ifndef CONFIG_NO_RRM if (len < 24 + 5 + sizeof(*report)) return; report = (const struct rrm_measurement_report_element *) @@ -6699,6 +6836,7 @@ static void handle_action_cb(struct hostapd_data *hapd, report->len >= 3 && report->type == MEASURE_TYPE_BEACON) hostapd_rrm_beacon_req_tx_status(hapd, mgmt, len, ok); +#endif /* CONFIG_NO_RRM */ } @@ -6813,33 +6951,6 @@ void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, } -void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, - const u8 *data, size_t len, int ack) -{ - struct sta_info *sta; - struct hostapd_iface *iface = hapd->iface; - - sta = ap_get_sta(hapd, dst); - if (sta == NULL && iface->num_bss > 1) { - size_t j; - for (j = 0; j < iface->num_bss; j++) { - hapd = iface->bss[j]; - sta = ap_get_sta(hapd, dst); - if (sta) - break; - } - } - if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { - wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA " - MACSTR_SEC " that is not currently associated", - MAC2STR_SEC(dst)); - return; - } - - ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack); -} - - void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr) { struct sta_info *sta; @@ -6910,7 +7021,7 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA " MACSTR_SEC, MAC2STR_SEC(src)); if (is_multicast_ether_addr(src) || is_zero_ether_addr(src) || - os_memcmp(src, hapd->own_addr, ETH_ALEN) == 0) { + ether_addr_equal(src, hapd->own_addr)) { /* Broadcast bit set in SA or unexpected SA?! Ignore the frame * silently. */ return; @@ -6935,6 +7046,38 @@ void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, } +static u8 * hostapd_add_tpe_info(u8 *eid, u8 tx_pwr_count, + enum max_tx_pwr_interpretation tx_pwr_intrpn, + u8 tx_pwr_cat, u8 tx_pwr) +{ + int i; + + *eid++ = WLAN_EID_TRANSMIT_POWER_ENVELOPE; /* Element ID */ + *eid++ = 2 + tx_pwr_count; /* Length */ + + /* + * Transmit Power Information field + * bits 0-2 : Maximum Transmit Power Count + * bits 3-5 : Maximum Transmit Power Interpretation + * bits 6-7 : Maximum Transmit Power Category + */ + *eid++ = tx_pwr_count | (tx_pwr_intrpn << 3) | (tx_pwr_cat << 6); + + /* Maximum Transmit Power field */ + for (i = 0; i <= tx_pwr_count; i++) + *eid++ = tx_pwr; + + return eid; +} + + +/* + * TODO: Extract power limits from channel data after 6G regulatory + * support. + */ +#define REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT (-1) /* dBm/MHz */ +#define REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT 5 /* dBm/MHz */ + u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid) { struct hostapd_iface *iface = hapd->iface; @@ -6946,21 +7089,72 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid) int max_tx_power; u8 tx_pwr; - if (!mode) - return eid; + 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; + +#ifdef CONFIG_IEEE80211AX + /* IEEE Std 802.11ax-2021, Annex E.2.7 (6 GHz band in the United + * States): An AP that is an Indoor Access Point per regulatory rules + * shall send at least two Transmit Power Envelope elements in Beacon + * and Probe Response frames as follows: + * - Maximum Transmit Power Category subfield = Default; + * Unit interpretation = Regulatory client EIRP PSD + * - Maximum Transmit Power Category subfield = Subordinate Device; + * Unit interpretation = Regulatory client EIRP PSD + */ + if (is_6ghz_op_class(iconf->op_class)) { + enum max_tx_pwr_interpretation tx_pwr_intrpn; + + /* Same Maximum Transmit Power for all 20 MHz bands */ + tx_pwr_count = 0; + tx_pwr_intrpn = REGULATORY_CLIENT_EIRP_PSD; + + /* Default Transmit Power Envelope for Global Operating Class */ + if (hapd->iconf->reg_def_cli_eirp_psd != -1) + tx_pwr = hapd->iconf->reg_def_cli_eirp_psd; + else + tx_pwr = REG_PSD_MAX_TXPOWER_FOR_DEFAULT_CLIENT * 2; + + eid = hostapd_add_tpe_info(eid, tx_pwr_count, tx_pwr_intrpn, + REG_DEFAULT_CLIENT, tx_pwr); + + /* Indoor Access Point must include an additional TPE for + * subordinate devices */ + if (he_reg_is_indoor(iconf->he_6ghz_reg_pwr_type)) { + /* TODO: Extract PSD limits from channel data */ + if (hapd->iconf->reg_sub_cli_eirp_psd != -1) + tx_pwr = hapd->iconf->reg_sub_cli_eirp_psd; + else + tx_pwr = REG_PSD_MAX_TXPOWER_FOR_SUBORDINATE_CLIENT * 2; + eid = hostapd_add_tpe_info(eid, tx_pwr_count, + tx_pwr_intrpn, + REG_SUBORDINATE_CLIENT, + tx_pwr); + } + + if (iconf->reg_def_cli_eirp != -1 && + he_reg_is_sp(iconf->he_6ghz_reg_pwr_type)) + eid = hostapd_add_tpe_info( + eid, tx_pwr_count, REGULATORY_CLIENT_EIRP, + REG_DEFAULT_CLIENT, + hapd->iconf->reg_def_cli_eirp); - 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; +#endif /* CONFIG_IEEE80211AX */ switch (hostapd_get_oper_chwidth(iconf)) { - case CHANWIDTH_USE_HT: + case CONF_OPER_CHWIDTH_USE_HT: if (iconf->secondary_channel == 0) { /* Max Transmit Power count = 0 (20 MHz) */ tx_pwr_count = 0; @@ -6969,12 +7163,12 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid) tx_pwr_count = 1; } break; - case CHANWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: /* Max Transmit Power count = 2 (20, 40, and 80 MHz) */ tx_pwr_count = 2; break; - case CHANWIDTH_80P80MHZ: - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_160MHZ: /* Max Transmit Power count = 3 (20, 40, 80, 160/80+80 MHz) */ tx_pwr_count = 3; break; @@ -7031,46 +7225,37 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid) 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; + return hostapd_add_tpe_info(eid, tx_pwr_count, LOCAL_EIRP, + 0 /* Reserved for bands other than 6 GHz */, + tx_pwr); } u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid) { - u8 bw, chan1, chan2 = 0; + u8 bw, chan1 = 0, chan2 = 0; int freq1; if (!hapd->cs_freq_params.channel || (!hapd->cs_freq_params.vht_enabled && - !hapd->cs_freq_params.he_enabled)) + !hapd->cs_freq_params.he_enabled && + !hapd->cs_freq_params.eht_enabled)) return eid; - /* bandwidth: 0: 40, 1: 80, 2: 160, 3: 80+80 */ + /* bandwidth: 0: 40, 1: 80, 160, 80+80, 4: 320 as per + * IEEE P802.11-REVme/D4.0, 9.4.2.159 and Table 9-314. */ 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; + bw = 1; break; case 160: - bw = 2; + bw = 1; + break; + case 320: + bw = 4; break; default: /* not valid VHT bandwidth or not in CSA */ @@ -7089,11 +7274,26 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid) &chan2) != HOSTAPD_MODE_IEEE80211A) return eid; - *eid++ = WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER; + *eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER; *eid++ = 5; /* Length of Channel Switch Wrapper */ - *eid++ = WLAN_EID_VHT_WIDE_BW_CHSWITCH; + *eid++ = WLAN_EID_WIDE_BW_CHSWITCH; *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */ *eid++ = bw; /* New Channel Width */ + if (hapd->cs_freq_params.bandwidth == 160) { + /* Update the CCFS0 and CCFS1 values in the element based on + * IEEE P802.11-REVme/D4.0, Table 9-314 */ + + /* CCFS1 - The channel center frequency index of the 160 MHz + * channel. */ + chan2 = chan1; + + /* CCFS0 - The channel center frequency index of the 80 MHz + * channel segment that contains the primary channel. */ + if (hapd->cs_freq_params.channel < chan1) + chan1 -= 8; + else + chan1 += 8; + } *eid++ = chan1; /* New Channel Center Frequency Segment 0 */ *eid++ = chan2; /* New Channel Center Frequency Segment 1 */ @@ -7131,19 +7331,70 @@ static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd, } -static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd, - struct hostapd_data *reporting_hapd, - size_t *current_len) +struct mbssid_ie_profiles { + u8 start; + u8 end; +}; + +static bool hostapd_skip_rnr(size_t i, struct mbssid_ie_profiles *skip_profiles, + bool ap_mld, u8 tbtt_info_len, bool mld_update, + struct hostapd_data *reporting_hapd, + struct hostapd_data *bss) +{ + if (skip_profiles && + i >= skip_profiles->start && i < skip_profiles->end) + return true; + + /* No need to report if length is for normal TBTT and the BSS is + * affiliated with an AP MLD. MLD TBTT will include this. */ + if (tbtt_info_len == RNR_TBTT_INFO_LEN && ap_mld) + return true; + + /* No need to report if length is for MLD TBTT and the BSS is not + * affiliated with an aP MLD. Normal TBTT will include this. */ + if (tbtt_info_len == RNR_TBTT_INFO_MLD_LEN && !ap_mld) + return true; + +#ifdef CONFIG_IEEE80211BE + /* If building for co-location and they are ML partners, no need to + * include since the ML RNR will carry this. */ + if (!mld_update && hostapd_is_ml_partner(reporting_hapd, bss)) + return true; + + /* If building for ML RNR and they are not ML partners, don't include. + */ + if (mld_update && !hostapd_is_ml_partner(reporting_hapd, bss)) + return true; +#endif /* CONFIG_IEEE80211BE */ + + return false; +} + + +static size_t +hostapd_eid_rnr_iface_len(struct hostapd_data *hapd, + struct hostapd_data *reporting_hapd, + size_t *current_len, + struct mbssid_ie_profiles *skip_profiles, + bool mld_update) { size_t total_len = 0, len = *current_len; - int tbtt_count = 0; - size_t i, start = 0; + int tbtt_count, total_tbtt_count = 0; + size_t i, start; + u8 tbtt_info_len = mld_update ? RNR_TBTT_INFO_MLD_LEN : + RNR_TBTT_INFO_LEN; + +repeat_rnr_len: + start = 0; + tbtt_count = 0; while (start < hapd->iface->num_bss) { if (!len || - len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) { + len + RNR_TBTT_HEADER_LEN + tbtt_info_len > 255 || + tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) { len = RNR_HEADER_LEN; total_len += RNR_HEADER_LEN; + tbtt_count = 0; } len += RNR_TBTT_HEADER_LEN; @@ -7151,26 +7402,61 @@ static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd, for (i = start; i < hapd->iface->num_bss; i++) { struct hostapd_data *bss = hapd->iface->bss[i]; + bool ap_mld = false; if (!bss || !bss->conf || !bss->started) continue; +#ifdef CONFIG_IEEE80211BE + ap_mld = bss->conf->mld_ap; +#endif /* CONFIG_IEEE80211BE */ + if (bss == reporting_hapd || bss->conf->ignore_broadcast_ssid) continue; - if (len + RNR_TBTT_INFO_LEN > 255 || + if (hostapd_skip_rnr(i, skip_profiles, ap_mld, + tbtt_info_len, mld_update, + reporting_hapd, bss)) + continue; + + if (len + tbtt_info_len > 255 || tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) break; - len += RNR_TBTT_INFO_LEN; - total_len += RNR_TBTT_INFO_LEN; + len += tbtt_info_len; + total_len += tbtt_info_len; tbtt_count++; } start = i; } - if (!tbtt_count) + total_tbtt_count += tbtt_count; + + /* If building for co-location, re-build again but this time include + * ML TBTTs. + */ + if (!mld_update && tbtt_info_len == RNR_TBTT_INFO_LEN) { + tbtt_info_len = RNR_TBTT_INFO_MLD_LEN; + + /* If no TBTT was found, adjust the len and total_len since it + * would have incremented before we checked all BSSs. */ + if (!tbtt_count) { + len -= RNR_TBTT_HEADER_LEN; + total_len -= RNR_TBTT_HEADER_LEN; + } + + goto repeat_rnr_len; + } + + /* This is possible when in the re-built case and no suitable TBTT was + * found. Adjust the length accordingly. */ + if (!tbtt_count && total_tbtt_count) { + len -= RNR_TBTT_HEADER_LEN; + total_len -= RNR_TBTT_HEADER_LEN; + } + + if (!total_tbtt_count) total_len = 0; else *current_len = len; @@ -7232,19 +7518,52 @@ static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd, for (i = 0; i < hapd->iface->interfaces->count; i++) { iface = hapd->iface->interfaces->iface[i]; - if (iface == hapd->iface || + if (!iface || iface == hapd->iface || + iface->state != HAPD_IFACE_ENABLED || !is_6ghz_op_class(iface->conf->op_class)) continue; len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd, - current_len); + current_len, NULL, false); + } + + return len; +} + + +static size_t hostapd_eid_rnr_mlo_len(struct hostapd_data *hapd, u32 type, + size_t *current_len) +{ + size_t len = 0; +#ifdef CONFIG_IEEE80211BE + struct hostapd_iface *iface; + size_t i; + + if (!hapd->iface || !hapd->iface->interfaces || !hapd->conf->mld_ap) + return 0; + + /* TODO: Allow for FILS/Action as well */ + if (type != WLAN_FC_STYPE_BEACON && type != WLAN_FC_STYPE_PROBE_RESP) + return 0; + + for (i = 0; i < hapd->iface->interfaces->count; i++) { + iface = hapd->iface->interfaces->iface[i]; + + if (!iface || iface == hapd->iface || + hapd->iface->freq == iface->freq) + continue; + + len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd, + current_len, NULL, true); } +#endif /* CONFIG_IEEE80211BE */ return len; } -size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type) +size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type, + bool include_mld_params) { size_t total_len = 0, current_len = 0; enum colocation_mode mode = get_colocation_mode(hapd); @@ -7254,27 +7573,33 @@ size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type) if (hapd->conf->rnr) total_len += hostapd_eid_nr_db_len(hapd, ¤t_len); /* fallthrough */ - case WLAN_FC_STYPE_PROBE_RESP: if (mode == COLOCATED_LOWER_BAND) - total_len += hostapd_eid_rnr_colocation_len( - hapd, ¤t_len); + total_len += + hostapd_eid_rnr_colocation_len(hapd, + ¤t_len); - if (hapd->conf->rnr && hapd->iface->num_bss > 1) + if (hapd->conf->rnr && hapd->iface->num_bss > 1 && + !hapd->iconf->mbssid) total_len += hostapd_eid_rnr_iface_len(hapd, hapd, - ¤t_len); + ¤t_len, + NULL, false); break; - case WLAN_FC_STYPE_ACTION: if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ) total_len += hostapd_eid_rnr_iface_len(hapd, hapd, - ¤t_len); - break; - - default: + ¤t_len, + NULL, false); break; } + /* For EMA Beacons, MLD neighbor repoting is added as part of + * MBSSID RNR. */ + if (include_mld_params && + (type != WLAN_FC_STYPE_BEACON || + hapd->iconf->mbssid != ENHANCED_MBSSID_ENABLED)) + total_len += hostapd_eid_rnr_mlo_len(hapd, type, ¤t_len); + return total_len; } @@ -7324,7 +7649,7 @@ static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid, /* BSS parameters */ *eid++ = nr->bss_parameters; /* 20 MHz PSD */ - *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1; + *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER; len += RNR_TBTT_INFO_LEN; *size_offset = (eid - size_offset) - 1; } @@ -7334,16 +7659,117 @@ static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid, } +static bool hostapd_eid_rnr_bss(struct hostapd_data *hapd, + struct hostapd_data *reporting_hapd, + struct mbssid_ie_profiles *skip_profiles, + size_t i, u8 *tbtt_count, size_t *len, + u8 **pos, u8 **tbtt_count_pos, u8 tbtt_info_len, + u8 op_class, bool mld_update) +{ + struct hostapd_iface *iface = hapd->iface; + struct hostapd_data *bss = iface->bss[i]; + u8 bss_param = 0; + bool ap_mld = false; + u8 *eid = *pos; + +#ifdef CONFIG_IEEE80211BE + ap_mld = !!hapd->conf->mld_ap; +#endif /* CONFIG_IEEE80211BE */ + + if (!bss || !bss->conf || !bss->started || + bss == reporting_hapd || bss->conf->ignore_broadcast_ssid) + return false; + + if (hostapd_skip_rnr(i, skip_profiles, ap_mld, tbtt_info_len, + mld_update, reporting_hapd, bss)) + return false; + + if (*len + RNR_TBTT_INFO_LEN > 255 || + *tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) + return true; + + if (!(*tbtt_count)) { + /* Add neighbor report header info only if there is at least + * one TBTT info available. */ + *tbtt_count_pos = eid++; + *eid++ = tbtt_info_len; + *eid++ = op_class; + *eid++ = bss->iconf->channel; + *len += RNR_TBTT_HEADER_LEN; + } + + *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN; + os_memcpy(eid, bss->own_addr, ETH_ALEN); + eid += ETH_ALEN; + os_memcpy(eid, &bss->conf->ssid.short_ssid, 4); + eid += 4; + if (bss->conf->ssid.short_ssid == reporting_hapd->conf->ssid.short_ssid) + bss_param |= RNR_BSS_PARAM_SAME_SSID; + + if (iface->conf->mbssid != MBSSID_DISABLED && iface->num_bss > 1) { + bss_param |= RNR_BSS_PARAM_MULTIPLE_BSSID; + if (bss == hostapd_mbssid_get_tx_bss(hapd)) + bss_param |= RNR_BSS_PARAM_TRANSMITTED_BSSID; + } + + if (is_6ghz_op_class(hapd->iconf->op_class) && + bss->conf->unsol_bcast_probe_resp_interval) + bss_param |= RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE; + + bss_param |= RNR_BSS_PARAM_CO_LOCATED; + + *eid++ = bss_param; + *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER; + +#ifdef CONFIG_IEEE80211BE + if (ap_mld) { + u8 param_ch = bss->eht_mld_bss_param_change; + bool is_partner; + + /* If BSS is not a partner of the reporting_hapd + * a) MLD ID advertised shall be 255. + * b) Link ID advertised shall be 15. + * c) BPCC advertised shall be 255 */ + is_partner = hostapd_is_ml_partner(bss, reporting_hapd); + /* MLD ID */ + *eid++ = is_partner ? hostapd_get_mld_id(bss) : 0xFF; + /* Link ID (Bit 3 to Bit 0) + * BPCC (Bit 4 to Bit 7) */ + *eid++ = is_partner ? + bss->mld_link_id | ((param_ch & 0xF) << 4) : + (MAX_NUM_MLD_LINKS | 0xF0); + /* BPCC (Bit 3 to Bit 0) */ + *eid = is_partner ? ((param_ch & 0xF0) >> 4) : 0x0F; +#ifdef CONFIG_TESTING_OPTIONS + if (bss->conf->mld_indicate_disabled) + *eid |= RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED; +#endif /* CONFIG_TESTING_OPTIONS */ + eid++; + } +#endif /* CONFIG_IEEE80211BE */ + + *len += tbtt_info_len; + (*tbtt_count)++; + *pos = eid; + + return false; +} + + static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd, struct hostapd_data *reporting_hapd, - u8 *eid, size_t *current_len) + u8 *eid, size_t *current_len, + struct mbssid_ie_profiles *skip_profiles, + bool mld_update) { - struct hostapd_data *bss; struct hostapd_iface *iface = hapd->iface; - size_t i, start = 0; + size_t i, start; size_t len = *current_len; - u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1; - u8 tbtt_count = 0, op_class, channel, bss_param; + u8 *eid_start = eid, *size_offset = (eid - len) + 1; + u8 *tbtt_count_pos = size_offset + 1; + u8 tbtt_count, total_tbtt_count = 0, op_class, channel; + u8 tbtt_info_len = mld_update ? RNR_TBTT_INFO_MLD_LEN : + RNR_TBTT_INFO_LEN; if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq) return eid; @@ -7355,9 +7781,13 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd, NUM_HOSTAPD_MODES) return eid; +repeat_rnr: + start = 0; + tbtt_count = 0; while (start < iface->num_bss) { if (!len || - len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) { + len + RNR_TBTT_HEADER_LEN + tbtt_info_len > 255 || + tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) { eid_start = eid; *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT; size_offset = eid++; @@ -7365,54 +7795,34 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd, tbtt_count = 0; } - tbtt_count_pos = eid++; - *eid++ = RNR_TBTT_INFO_LEN; - *eid++ = op_class; - *eid++ = hapd->iconf->channel; - len += RNR_TBTT_HEADER_LEN; - for (i = start; i < iface->num_bss; i++) { - bss_param = 0; - bss = iface->bss[i]; - if (!bss || !bss->conf || !bss->started) - continue; - - if (bss == reporting_hapd || - bss->conf->ignore_broadcast_ssid) - continue; - - if (len + RNR_TBTT_INFO_LEN > 255 || - tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) + if (hostapd_eid_rnr_bss(hapd, reporting_hapd, + skip_profiles, i, + &tbtt_count, &len, &eid, + &tbtt_count_pos, tbtt_info_len, + op_class, mld_update)) break; + } - *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN; - os_memcpy(eid, bss->conf->bssid, ETH_ALEN); - eid += ETH_ALEN; - os_memcpy(eid, &bss->conf->ssid.short_ssid, 4); - eid += 4; - if (bss->conf->ssid.short_ssid == - reporting_hapd->conf->ssid.short_ssid) - bss_param |= RNR_BSS_PARAM_SAME_SSID; - - if (is_6ghz_op_class(hapd->iconf->op_class) && - bss->conf->unsol_bcast_probe_resp_interval) - bss_param |= - RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE; - - bss_param |= RNR_BSS_PARAM_CO_LOCATED; + start = i; - *eid++ = bss_param; - *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1; - len += RNR_TBTT_INFO_LEN; - tbtt_count += 1; + if (tbtt_count) { + *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1); + *size_offset = (eid - size_offset) - 1; } + } - start = i; - *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1); - *size_offset = (eid - size_offset) - 1; + total_tbtt_count += tbtt_count; + + /* If building for co-location, re-build again but this time include + * ML TBTTs. + */ + if (!mld_update && tbtt_info_len == RNR_TBTT_INFO_LEN) { + tbtt_info_len = RNR_TBTT_INFO_MLD_LEN; + goto repeat_rnr; } - if (tbtt_count == 0) + if (!total_tbtt_count) return eid_start; *current_len = len; @@ -7420,8 +7830,8 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd, } -static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid, - size_t *current_len) +u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid, + size_t *current_len) { struct hostapd_iface *iface; size_t i; @@ -7432,19 +7842,51 @@ static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid, for (i = 0; i < hapd->iface->interfaces->count; i++) { iface = hapd->iface->interfaces->iface[i]; - if (iface == hapd->iface || + if (!iface || iface == hapd->iface || + iface->state != HAPD_IFACE_ENABLED || !is_6ghz_op_class(iface->conf->op_class)) continue; eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid, - current_len); + current_len, NULL, false); + } + + return eid; +} + + +u8 * hostapd_eid_rnr_mlo(struct hostapd_data *hapd, u32 type, + u8 *eid, size_t *current_len) +{ +#ifdef CONFIG_IEEE80211BE + struct hostapd_iface *iface; + size_t i; + + if (!hapd->iface || !hapd->iface->interfaces || !hapd->conf->mld_ap) + return eid; + + /* TODO: Allow for FILS/Action as well */ + if (type != WLAN_FC_STYPE_BEACON && type != WLAN_FC_STYPE_PROBE_RESP) + return eid; + + for (i = 0; i < hapd->iface->interfaces->count; i++) { + iface = hapd->iface->interfaces->iface[i]; + + if (!iface || iface == hapd->iface || + hapd->iface->freq == iface->freq) + continue; + + eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid, + current_len, NULL, true); } +#endif /* CONFIG_IEEE80211BE */ return eid; } -u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type) +u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type, + bool include_mld_params) { u8 *eid_start = eid; size_t current_len = 0; @@ -7455,31 +7897,393 @@ u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type) if (hapd->conf->rnr) eid = hostapd_eid_nr_db(hapd, eid, ¤t_len); /* fallthrough */ - case WLAN_FC_STYPE_PROBE_RESP: if (mode == COLOCATED_LOWER_BAND) eid = hostapd_eid_rnr_colocation(hapd, eid, ¤t_len); - if (hapd->conf->rnr && hapd->iface->num_bss > 1) + if (hapd->conf->rnr && hapd->iface->num_bss > 1 && + !hapd->iconf->mbssid) eid = hostapd_eid_rnr_iface(hapd, hapd, eid, - ¤t_len); + ¤t_len, NULL, false); break; - case WLAN_FC_STYPE_ACTION: if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ) - eid = hostapd_eid_rnr_iface(hapd, hapd, eid, - ¤t_len); + eid = hostapd_eid_rnr_iface(hapd, hapd, eid, + ¤t_len, NULL, false); break; - default: return eid_start; } + /* For EMA Beacons, MLD neighbor repoting is added as part of + * MBSSID RNR. */ + if (include_mld_params && + (type != WLAN_FC_STYPE_BEACON || + hapd->iconf->mbssid != ENHANCED_MBSSID_ENABLED)) + eid = hostapd_eid_rnr_mlo(hapd, type, eid, ¤t_len); + if (eid == eid_start + 2) return eid_start; return eid; } + +static bool mbssid_known_bss(unsigned int i, const u8 *known_bss, + size_t known_bss_len) +{ + if (!known_bss || known_bss_len <= i / 8) + return false; + known_bss = &known_bss[i / 8]; + return *known_bss & (u8) (BIT(i % 8)); +} + + +static size_t hostapd_mbssid_ext_capa(struct hostapd_data *bss, + struct hostapd_data *tx_bss, u8 *buf) +{ + u8 ext_capa_tx[20], *ext_capa_tx_end, ext_capa[20], *ext_capa_end; + size_t ext_capa_len, ext_capa_tx_len; + + ext_capa_tx_end = hostapd_eid_ext_capab(tx_bss, ext_capa_tx, + true); + ext_capa_tx_len = ext_capa_tx_end - ext_capa_tx; + ext_capa_end = hostapd_eid_ext_capab(bss, ext_capa, true); + ext_capa_len = ext_capa_end - ext_capa; + if (ext_capa_tx_len != ext_capa_len || + os_memcmp(ext_capa_tx, ext_capa, ext_capa_len) != 0) { + os_memcpy(buf, ext_capa, ext_capa_len); + return ext_capa_len; + } + + return 0; +} + + +static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd, + u32 frame_type, size_t *bss_index, + const u8 *known_bss, + size_t known_bss_len) +{ + struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd); + size_t len, i; + u8 ext_capa[20]; + + /* Element ID: 1 octet + * Length: 1 octet + * MaxBSSID Indicator: 1 octet + * Optional Subelements: vatiable + * + * Total fixed length: 3 octets + * + * 1 octet in len for the MaxBSSID Indicator field. + */ + len = 1; + + for (i = *bss_index; i < hapd->iface->num_bss; i++) { + struct hostapd_data *bss = hapd->iface->bss[i]; + const u8 *auth, *rsn = NULL, *rsnx = NULL; + size_t nontx_profile_len, auth_len; + u8 ie_count = 0; + + if (!bss || !bss->conf || !bss->started || + mbssid_known_bss(i, known_bss, known_bss_len)) + continue; + + /* + * Sublement ID: 1 octet + * Length: 1 octet + * Nontransmitted capabilities: 4 octets + * SSID element: 2 + variable + * Multiple BSSID Index Element: 3 octets (+2 octets in beacons) + * Fixed length = 1 + 1 + 4 + 2 + 3 = 11 + */ + nontx_profile_len = 11 + bss->conf->ssid.ssid_len; + + if (frame_type == WLAN_FC_STYPE_BEACON) + nontx_profile_len += 2; + + auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len); + if (auth) { + rsn = get_ie(auth, auth_len, WLAN_EID_RSN); + if (rsn) + nontx_profile_len += 2 + rsn[1]; + + rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX); + if (rsnx) + nontx_profile_len += 2 + rsnx[1]; + } + + nontx_profile_len += hostapd_mbssid_ext_capa(bss, tx_bss, + ext_capa); + + if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN)) + ie_count++; + if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX)) + ie_count++; + if (bss->conf->xrates_supported) + nontx_profile_len += 8; + else if (hapd->conf->xrates_supported) + ie_count++; + if (ie_count) + nontx_profile_len += 4 + ie_count; + + if (len + nontx_profile_len > 255) + break; + + len += nontx_profile_len; + } + + *bss_index = i; + + /* Add 2 octets to get the full size of the element */ + return len + 2; +} + + +size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, + u8 *elem_count, const u8 *known_bss, + size_t known_bss_len, size_t *rnr_len) +{ + size_t len = 0, bss_index = 1; + bool ap_mld = false; + +#ifdef CONFIG_IEEE80211BE + ap_mld = hapd->conf->mld_ap; +#endif /* CONFIG_IEEE80211BE */ + + if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 || + (frame_type != WLAN_FC_STYPE_BEACON && + frame_type != WLAN_FC_STYPE_PROBE_RESP)) + return 0; + + if (frame_type == WLAN_FC_STYPE_BEACON) { + if (!elem_count) { + wpa_printf(MSG_INFO, + "MBSSID: Insufficient data for Beacon frames"); + return 0; + } + *elem_count = 0; + } + + while (bss_index < hapd->iface->num_bss) { + size_t rnr_count = bss_index; + + len += hostapd_eid_mbssid_elem_len(hapd, frame_type, + &bss_index, known_bss, + known_bss_len); + + if (frame_type == WLAN_FC_STYPE_BEACON) + *elem_count += 1; + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) { + size_t rnr_cur_len = 0; + struct mbssid_ie_profiles skip_profiles = { + rnr_count, bss_index + }; + + *rnr_len += hostapd_eid_rnr_iface_len( + hapd, hostapd_mbssid_get_tx_bss(hapd), + &rnr_cur_len, &skip_profiles, ap_mld); + } + } + + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) + *rnr_len += hostapd_eid_rnr_len(hapd, frame_type, false); + + return len; +} + + +static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end, + u32 frame_type, u8 max_bssid_indicator, + size_t *bss_index, u8 elem_count, + const u8 *known_bss, size_t known_bss_len) +{ + struct hostapd_data *tx_bss = hostapd_mbssid_get_tx_bss(hapd); + size_t i; + u8 *eid_len_offset, *max_bssid_indicator_offset; + + *eid++ = WLAN_EID_MULTIPLE_BSSID; + eid_len_offset = eid++; + max_bssid_indicator_offset = eid++; + + for (i = *bss_index; i < hapd->iface->num_bss; i++) { + struct hostapd_data *bss = hapd->iface->bss[i]; + struct hostapd_bss_config *conf; + u8 *eid_len_pos, *nontx_bss_start = eid; + const u8 *auth, *rsn = NULL, *rsnx = NULL; + u8 ie_count = 0, non_inherit_ie[3]; + size_t auth_len = 0; + u16 capab_info; + + if (!bss || !bss->conf || !bss->started || + mbssid_known_bss(i, known_bss, known_bss_len)) + continue; + conf = bss->conf; + + *eid++ = WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE; + eid_len_pos = eid++; + + capab_info = hostapd_own_capab_info(bss); + *eid++ = WLAN_EID_NONTRANSMITTED_BSSID_CAPA; + *eid++ = sizeof(capab_info); + WPA_PUT_LE16(eid, capab_info); + eid += sizeof(capab_info); + + *eid++ = WLAN_EID_SSID; + *eid++ = conf->ssid.ssid_len; + os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len); + eid += conf->ssid.ssid_len; + + *eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX; + if (frame_type == WLAN_FC_STYPE_BEACON) { + *eid++ = 3; + *eid++ = i; /* BSSID Index */ + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && + (conf->dtim_period % elem_count)) + conf->dtim_period = elem_count; + *eid++ = conf->dtim_period; + /* The driver is expected to update the DTIM Count + * field for each BSS that corresponds to a + * nontransmitted BSSID. The value is initialized to + * 0 here so that the DTIM count would be somewhat + * functional even if the driver were not to update + * this. */ + *eid++ = 0; /* DTIM Count */ + } else { + /* Probe Request frame does not include DTIM Period and + * DTIM Count fields. */ + *eid++ = 1; + *eid++ = i; /* BSSID Index */ + } + + auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len); + if (auth) { + rsn = get_ie(auth, auth_len, WLAN_EID_RSN); + if (rsn) { + os_memcpy(eid, rsn, 2 + rsn[1]); + eid += 2 + rsn[1]; + } + + rsnx = get_ie(auth, auth_len, WLAN_EID_RSNX); + if (rsnx) { + os_memcpy(eid, rsnx, 2 + rsnx[1]); + eid += 2 + rsnx[1]; + } + } + + eid += hostapd_mbssid_ext_capa(bss, tx_bss, eid); + + /* List of Element ID values in increasing order */ + if (!rsn && hostapd_wpa_ie(tx_bss, WLAN_EID_RSN)) + non_inherit_ie[ie_count++] = WLAN_EID_RSN; + if (hapd->conf->xrates_supported && + !bss->conf->xrates_supported) + non_inherit_ie[ie_count++] = WLAN_EID_EXT_SUPP_RATES; + if (!rsnx && hostapd_wpa_ie(tx_bss, WLAN_EID_RSNX)) + non_inherit_ie[ie_count++] = WLAN_EID_RSNX; + if (ie_count) { + *eid++ = WLAN_EID_EXTENSION; + *eid++ = 2 + ie_count + 1; + *eid++ = WLAN_EID_EXT_NON_INHERITANCE; + *eid++ = ie_count; + os_memcpy(eid, non_inherit_ie, ie_count); + eid += ie_count; + *eid++ = 0; /* No Element ID Extension List */ + } + + *eid_len_pos = (eid - eid_len_pos) - 1; + + if (((eid - eid_len_offset) - 1) > 255) { + eid = nontx_bss_start; + break; + } + } + + *bss_index = i; + *max_bssid_indicator_offset = max_bssid_indicator; + if (*max_bssid_indicator_offset < 1) + *max_bssid_indicator_offset = 1; + *eid_len_offset = (eid - eid_len_offset) - 1; + return eid; +} + + +u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, + unsigned int frame_stype, u8 elem_count, + u8 **elem_offset, + const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid, + u8 *rnr_count, u8 **rnr_offset, size_t rnr_len) +{ + size_t bss_index = 1, cur_len = 0; + u8 elem_index = 0, *rnr_start_eid = rnr_eid; + bool add_rnr, ap_mld = false; + +#ifdef CONFIG_IEEE80211BE + ap_mld = hapd->conf->mld_ap; +#endif /* CONFIG_IEEE80211BE */ + + if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 || + (frame_stype != WLAN_FC_STYPE_BEACON && + frame_stype != WLAN_FC_STYPE_PROBE_RESP)) + return eid; + + if (frame_stype == WLAN_FC_STYPE_BEACON && !elem_offset) { + wpa_printf(MSG_INFO, + "MBSSID: Insufficient data for Beacon frames"); + return eid; + } + + add_rnr = hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && + frame_stype == WLAN_FC_STYPE_BEACON && + rnr_eid && rnr_count && rnr_offset && rnr_len; + + while (bss_index < hapd->iface->num_bss) { + unsigned int rnr_start_count = bss_index; + + if (frame_stype == WLAN_FC_STYPE_BEACON) { + if (elem_index == elem_count) { + wpa_printf(MSG_WARNING, + "MBSSID: Larger number of elements than there is room in the provided array"); + break; + } + + elem_offset[elem_index] = eid; + elem_index = elem_index + 1; + } + eid = hostapd_eid_mbssid_elem(hapd, eid, end, frame_stype, + hostapd_max_bssid_indicator(hapd), + &bss_index, elem_count, + known_bss, known_bss_len); + + if (add_rnr) { + struct mbssid_ie_profiles skip_profiles = { + rnr_start_count, bss_index + }; + + rnr_offset[*rnr_count] = rnr_eid; + *rnr_count = *rnr_count + 1; + cur_len = 0; + rnr_eid = hostapd_eid_rnr_iface( + hapd, hostapd_mbssid_get_tx_bss(hapd), + rnr_eid, &cur_len, &skip_profiles, ap_mld); + } + } + + if (add_rnr && (size_t) (rnr_eid - rnr_start_eid) < rnr_len) { + rnr_offset[*rnr_count] = rnr_eid; + *rnr_count = *rnr_count + 1; + cur_len = 0; + + if (hapd->conf->rnr) + rnr_eid = hostapd_eid_nr_db(hapd, rnr_eid, &cur_len); + if (get_colocation_mode(hapd) == COLOCATED_LOWER_BAND) + rnr_eid = hostapd_eid_rnr_colocation(hapd, rnr_eid, + &cur_len); + } + + return eid; +} + #endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_11.h b/wpa_supplicant-2.9_standard/src/ap/ieee802_11.h index c59ad5e38e920210bdcb47d755e7873fce60a0f2..dd4995f3f31a66d285657b46f7a716458eaad202 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ieee802_11.h +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_11.h @@ -18,6 +18,12 @@ struct ieee80211_vht_capabilities; struct ieee80211_mgmt; struct radius_sta; enum ieee80211_op_mode; +enum oper_chan_width; +struct ieee802_11_elems; +struct sae_pk; +struct sae_pt; +struct sae_password_entry; +struct mld_info; int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, struct hostapd_frame_info *fi); @@ -45,7 +51,8 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd, #endif /* NEED_AP_MLME */ u16 hostapd_own_capab_info(struct hostapd_data *hapd); void ap_ht2040_timeout(void *eloop_data, void *user_data); -u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid, + bool mbssid_complete); u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid); @@ -78,13 +85,35 @@ void hostapd_get_he_capab(struct hostapd_data *hapd, const struct ieee80211_he_capabilities *he_cap, struct ieee80211_he_capabilities *neg_he_cap, size_t he_capab_len); +void hostapd_get_eht_capab(struct hostapd_data *hapd, + const struct ieee80211_eht_capabilities *src, + struct ieee80211_eht_capabilities *dest, + size_t len); +u8 * hostapd_eid_eht_ml_beacon(struct hostapd_data *hapd, + struct mld_info *mld_info, + u8 *eid, bool include_mld_id); +u8 * hostapd_eid_eht_ml_assoc(struct hostapd_data *hapd, struct sta_info *info, + u8 *eid); +size_t hostapd_eid_eht_ml_beacon_len(struct hostapd_data *hapd, + struct mld_info *info, + bool include_mld_id); +struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd); +const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len); +u16 hostapd_process_ml_assoc_req(struct hostapd_data *hapd, + struct ieee802_11_elems *elems, + struct sta_info *sta); +int hostapd_process_ml_assoc_req_addr(struct hostapd_data *hapd, + const u8 *basic_mle, size_t basic_mle_len, + u8 *mld_addr); int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta); u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *ht_capab); u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta, const u8 *ie, size_t len); -void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta); +int update_ht_state(struct hostapd_data *hapd, struct sta_info *sta); void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta); void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta); u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, @@ -100,10 +129,10 @@ u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *he_6ghz_capab); int hostapd_get_he_twt_responder(struct hostapd_data *hapd, enum ieee80211_op_mode mode); +bool hostapd_get_ht_vht_twt_responder(struct hostapd_data *hapd); +u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid); void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, const u8 *buf, size_t len, int ack); -void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, - const u8 *data, size_t len, int ack); void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, int wds); u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, @@ -118,7 +147,8 @@ u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid); int hostapd_update_time_adv(struct hostapd_data *hapd); void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr); -u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid, + u16 value); int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta); #ifdef CONFIG_SAE @@ -170,7 +200,8 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta, u8 *owe_buf, size_t owe_buf_len, u16 *status); u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta, const u8 *rsn_ie, size_t rsn_ie_len, - const u8 *owe_dh, size_t owe_dh_len); + const u8 *owe_dh, size_t owe_dh_len, + const u8 *link_addr); u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer, const u8 *rsn_ie, size_t rsn_ie_len, const u8 *owe_dh, size_t owe_dh_len); @@ -194,7 +225,43 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth, void auth_sae_process_commit(void *eloop_ctx, void *user_ctx); u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len); -size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type); -u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type); +u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *ext_capab_ie, size_t ext_capab_ie_len); +size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type, + bool include_mld_params); +u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type, + bool include_mld_params); +int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, + int res, struct radius_sta *info); +size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd, + enum ieee80211_op_mode opmode); +u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid, + enum ieee80211_op_mode opmode); +u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid); +u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta, + enum ieee80211_op_mode opmode, + const u8 *he_capab, size_t he_capab_len, + const u8 *eht_capab, size_t eht_capab_len); +size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, + u8 *elem_count, const u8 *known_bss, + size_t known_bss_len, size_t *rnr_len); +u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, + unsigned int frame_stype, u8 elem_count, + u8 **elem_offset, + const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid, + u8 *rnr_count, u8 **rnr_offset, size_t rnr_len); +bool hostapd_is_mld_ap(struct hostapd_data *hapd); +const char * sae_get_password(struct hostapd_data *hapd, + struct sta_info *sta, const char *rx_id, + struct sae_password_entry **pw_entry, + struct sae_pt **s_pt, const struct sae_pk **s_pk); +struct sta_info * hostapd_ml_get_assoc_sta(struct hostapd_data *hapd, + struct sta_info *sta, + struct hostapd_data **assoc_hapd); +int hostapd_process_assoc_ml_info(struct hostapd_data *hapd, + struct sta_info *sta, + const u8 *ies, size_t ies_len, + bool reassoc, int tx_link_status, + bool offload); #endif /* IEEE802_11_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_auth.c b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_auth.c index 106496a16937d2eb3aa786c2ae246ec298ecfd7e..47650c05633fee00d85d7e5fd861f003969f5a58 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_auth.c +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_auth.c @@ -1,6 +1,6 @@ /* * hostapd / IEEE 802.11 authentication (ACL) - * Copyright (c) 2003-2012, Jouni Malinen + * Copyright (c) 2003-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -20,6 +20,8 @@ #include "hostapd.h" #include "ap_config.h" #include "ap_drv_ops.h" +#include "sta_info.h" +#include "wpa_auth.h" #include "ieee802_11.h" #include "ieee802_1x.h" #include "ieee802_11_auth.h" @@ -43,6 +45,11 @@ struct hostapd_acl_query_data { u8 *auth_msg; /* IEEE 802.11 authentication frame from station */ size_t auth_msg_len; struct hostapd_acl_query_data *next; + bool radius_psk; + int akm; + u8 *anonce; + u8 *eapol; + size_t eapol_len; }; @@ -77,7 +84,7 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, os_get_reltime(&now); for (entry = hapd->acl_cache; entry; entry = entry->next) { - if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0) + if (!ether_addr_equal(entry->addr, addr)) continue; if (os_reltime_expired(&now, &entry->timestamp, @@ -95,9 +102,11 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, static void hostapd_acl_query_free(struct hostapd_acl_query_data *query) { - if (query == NULL) + if (!query) return; os_free(query->auth_msg); + os_free(query->anonce); + os_free(query->eapol); os_free(query); } @@ -111,7 +120,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, query->radius_id = radius_client_get_id(hapd->radius); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id); - if (msg == NULL) + if (!msg) return -1; if (radius_msg_make_authenticator(msg) < 0) { @@ -119,6 +128,9 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, goto fail; } + if (!radius_msg_add_msg_auth(msg)) + goto fail; + os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf, os_strlen(buf))) { @@ -153,6 +165,31 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, goto fail; } + if (query->akm && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE, + wpa_akm_to_suite(query->akm))) { + wpa_printf(MSG_DEBUG, "Could not add WLAN-AKM-Suite"); + goto fail; + } + + if (query->anonce && + !radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, + RADIUS_VENDOR_ID_FREERADIUS, + RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE, + query->anonce, WPA_NONCE_LEN)) { + wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-Anonce"); + goto fail; + } + + if (query->eapol && + !radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, + RADIUS_VENDOR_ID_FREERADIUS, + RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG, + query->eapol, query->eapol_len)) { + wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-EAPoL-Key-Msg"); + goto fail; + } + if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0) goto fail; return 0; @@ -247,7 +284,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, query = hapd->acl_queries; while (query) { - if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) { + if (ether_addr_equal(query->addr, addr)) { /* pending query in RADIUS retransmit queue; * do not generate a new one */ return HOSTAPD_ACL_PENDING; @@ -260,23 +297,23 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, /* No entry in the cache - query external RADIUS server */ query = os_zalloc(sizeof(*query)); - if (query == NULL) { + if (!query) { wpa_printf(MSG_ERROR, "malloc for query data failed"); return HOSTAPD_ACL_REJECT; } os_get_reltime(&query->timestamp); os_memcpy(query->addr, addr, ETH_ALEN); if (hostapd_radius_acl_query(hapd, addr, query)) { - wpa_printf(MSG_DEBUG, "Failed to send Access-Request " - "for ACL query."); + wpa_printf(MSG_DEBUG, + "Failed to send Access-Request for ACL query."); hostapd_acl_query_free(query); return HOSTAPD_ACL_REJECT; } query->auth_msg = os_memdup(msg, len); - if (query->auth_msg == NULL) { - wpa_printf(MSG_ERROR, "Failed to allocate memory for " - "auth frame."); + if (!query->auth_msg) { + wpa_printf(MSG_ERROR, + "Failed to allocate memory for auth frame."); hostapd_acl_query_free(query); return HOSTAPD_ACL_REJECT; } @@ -392,7 +429,7 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd, * Passphrase is NULL iff there is no i-th Tunnel-Password * attribute in msg. */ - if (passphrase == NULL) + if (!passphrase) break; /* @@ -464,28 +501,32 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, prev = query; query = query->next; } - if (query == NULL) + if (!query) return RADIUS_RX_UNKNOWN; - wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS " - "message (id=%d)", query->radius_id); + wpa_printf(MSG_DEBUG, + "Found matching Access-Request for RADIUS message (id=%d)", + query->radius_id); - if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { - wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have " - "correct authenticator - dropped\n"); + if (radius_msg_verify( + msg, shared_secret, shared_secret_len, req, + hapd->conf->radius_require_message_authenticator)) { + wpa_printf(MSG_INFO, + "Incoming RADIUS packet did not have correct authenticator - dropped"); return RADIUS_RX_INVALID_AUTHENTICATOR; } if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && hdr->code != RADIUS_CODE_ACCESS_REJECT) { - wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL " - "query", hdr->code); + wpa_printf(MSG_DEBUG, + "Unknown RADIUS message code %d to ACL query", + hdr->code); return RADIUS_RX_UNKNOWN; } /* Insert Accept/Reject info into ACL cache */ cache = os_zalloc(sizeof(*cache)); - if (cache == NULL) { + if (!cache) { wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); goto done; } @@ -506,8 +547,9 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, &info->acct_interim_interval) == 0 && info->acct_interim_interval < 60) { - wpa_printf(MSG_DEBUG, "Ignored too small " - "Acct-Interim-Interval %d for STA " MACSTR_SEC, + wpa_printf(MSG_DEBUG, + "Ignored too small Acct-Interim-Interval %d for STA " + MACSTR_SEC, info->acct_interim_interval, MAC2STR_SEC(query->addr)); info->acct_interim_interval = 0; @@ -557,20 +599,44 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, cache->next = hapd->acl_cache; hapd->acl_cache = cache; + if (query->radius_psk) { + struct sta_info *sta; + bool success = cache->accepted == HOSTAPD_ACL_ACCEPT || + cache->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT; + + sta = ap_get_sta(hapd, query->addr); + if (!sta || !sta->wpa_sm) { + wpa_printf(MSG_DEBUG, + "No STA/SM entry found for the RADIUS PSK response"); + goto done; + } +#ifdef NEED_AP_MLME + if (success && + (ieee802_11_set_radius_info(hapd, sta, cache->accepted, + info) < 0 || + ap_sta_bind_vlan(hapd, sta) < 0)) + success = false; +#endif /* NEED_AP_MLME */ + wpa_auth_sta_radius_psk_resp(sta->wpa_sm, success); + } else { #ifdef CONFIG_DRIVER_RADIUS_ACL - hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted, - info->session_timeout); + hostapd_drv_set_radius_acl_auth(hapd, query->addr, + cache->accepted, + info->session_timeout); #else /* CONFIG_DRIVER_RADIUS_ACL */ #ifdef NEED_AP_MLME - /* Re-send original authentication frame for 802.11 processing */ - wpa_printf(MSG_DEBUG, "Re-sending authentication frame after " - "successful RADIUS ACL query"); - ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL); + /* Re-send original authentication frame for 802.11 processing + */ + wpa_printf(MSG_DEBUG, + "Re-sending authentication frame after successful RADIUS ACL query"); + ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, + NULL); #endif /* NEED_AP_MLME */ #endif /* CONFIG_DRIVER_RADIUS_ACL */ + } done: - if (prev == NULL) + if (!prev) hapd->acl_queries = query->next; else prev->next = query->next; @@ -646,6 +712,40 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk) while (psk) { struct hostapd_sta_wpa_psk_short *prev = psk; psk = psk->next; - os_free(prev); + bin_clear_free(prev, sizeof(*prev)); } } + + +#ifndef CONFIG_NO_RADIUS +void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr, + int key_mgmt, const u8 *anonce, + const u8 *eapol, size_t eapol_len) +{ + struct hostapd_acl_query_data *query; + + query = os_zalloc(sizeof(*query)); + if (!query) + return; + + query->radius_psk = true; + query->akm = key_mgmt; + os_get_reltime(&query->timestamp); + os_memcpy(query->addr, addr, ETH_ALEN); + if (anonce) + query->anonce = os_memdup(anonce, WPA_NONCE_LEN); + if (eapol) { + query->eapol = os_memdup(eapol, eapol_len); + query->eapol_len = eapol_len; + } + if (hostapd_radius_acl_query(hapd, addr, query)) { + wpa_printf(MSG_DEBUG, + "Failed to send Access-Request for RADIUS PSK/ACL query"); + hostapd_acl_query_free(query); + return; + } + + query->next = hapd->acl_queries; + hapd->acl_queries = query; +} +#endif /* CONFIG_NO_RADIUS */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_auth.h b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_auth.h index 9410f55c5807fa7d3dab98e22182a1a6467628c8..22ae1a9d3dbab1167d649b7dc915c25082e5c7e0 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_auth.h +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_auth.h @@ -1,6 +1,6 @@ /* * hostapd / IEEE 802.11 authentication (ACL) - * Copyright (c) 2003-2005, Jouni Malinen + * Copyright (c) 2003-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -36,5 +36,8 @@ void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk); void hostapd_acl_expire(struct hostapd_data *hapd); void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk, struct hostapd_sta_wpa_psk_short *src); +void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr, + int key_mgmt, const u8 *anonce, + const u8 *eapol, size_t eapol_len); #endif /* IEEE802_11_AUTH_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_eht.c b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_eht.c new file mode 100644 index 0000000000000000000000000000000000000000..9d13f168d31abbbaa6ce1ce625241e500a1537c3 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_eht.c @@ -0,0 +1,1405 @@ +/* + * hostapd / IEEE 802.11be EHT + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" +#include "utils/common.h" +#include "crypto/crypto.h" +#include "crypto/dh_groups.h" +#include "hostapd.h" +#include "sta_info.h" +#include "ieee802_11.h" + + +static u16 ieee80211_eht_ppet_size(u16 ppe_thres_hdr, const u8 *phy_cap_info) +{ + u8 ru; + u16 sz = 0; + + if ((phy_cap_info[EHT_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] & + EHT_PHYCAP_PPE_THRESHOLD_PRESENT) == 0) + return 0; + + ru = (ppe_thres_hdr & + EHT_PPE_THRES_RU_INDEX_MASK) >> EHT_PPE_THRES_RU_INDEX_SHIFT; + while (ru) { + if (ru & 0x1) + sz++; + ru >>= 1; + } + + sz = sz * (1 + ((ppe_thres_hdr & EHT_PPE_THRES_NSS_MASK) >> + EHT_PPE_THRES_NSS_SHIFT)); + sz = (sz * 6) + 9; + if (sz % 8) + sz += 8; + sz /= 8; + + return sz; +} + + +static u8 ieee80211_eht_mcs_set_size(enum hostapd_hw_mode mode, u8 opclass, + int he_oper_chwidth, const u8 *he_phy_cap, + const u8 *eht_phy_cap) +{ + u8 sz = EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS; + bool band24, band5, band6; + u8 he_phy_cap_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK; + u8 cap_chwidth; + + switch (he_oper_chwidth) { + case CONF_OPER_CHWIDTH_80P80MHZ: + he_phy_cap_chwidth |= + HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G; + __attribute__((fallthrough)); + case CONF_OPER_CHWIDTH_160MHZ: + he_phy_cap_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + __attribute__((fallthrough)); + case CONF_OPER_CHWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_USE_HT: + he_phy_cap_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; + break; + } + + cap_chwidth = he_phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX]; + if (he_oper_chwidth != -1) + he_phy_cap_chwidth &= cap_chwidth; + else + he_phy_cap_chwidth = cap_chwidth; + + band24 = mode == HOSTAPD_MODE_IEEE80211B || + mode == HOSTAPD_MODE_IEEE80211G || + mode == NUM_HOSTAPD_MODES; + band5 = mode == HOSTAPD_MODE_IEEE80211A || + mode == NUM_HOSTAPD_MODES; + band6 = is_6ghz_op_class(opclass); + + if (band24 && + (he_phy_cap_chwidth & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G) == 0) + return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY; + + if (band5 && + (he_phy_cap_chwidth & + (HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) == 0) + return EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY; + + if (band5 && + (he_phy_cap_chwidth & + (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G | + HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))) + sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS; + + if (band6 && + (eht_phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] & + EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) + sz += EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS; + + return sz; +} + + +size_t hostapd_eid_eht_capab_len(struct hostapd_data *hapd, + enum ieee80211_op_mode opmode) +{ + struct hostapd_hw_modes *mode; + struct eht_capabilities *eht_cap; + size_t len = 3 + 2 + EHT_PHY_CAPAB_LEN; + + mode = hapd->iface->current_mode; + if (!mode) + return 0; + + eht_cap = &mode->eht_capab[opmode]; + if (!eht_cap->eht_supported) + return 0; + + len += ieee80211_eht_mcs_set_size(mode->mode, hapd->iconf->op_class, + hapd->iconf->he_oper_chwidth, + mode->he_capab[opmode].phy_cap, + eht_cap->phy_cap); + len += ieee80211_eht_ppet_size(WPA_GET_LE16(&eht_cap->ppet[0]), + eht_cap->phy_cap); + + return len; +} + + +u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid, + enum ieee80211_op_mode opmode) +{ + struct hostapd_hw_modes *mode; + struct eht_capabilities *eht_cap; + struct ieee80211_eht_capabilities *cap; + size_t mcs_nss_len, ppe_thresh_len; + u8 *pos = eid, *length_pos; + + mode = hapd->iface->current_mode; + if (!mode) + return eid; + + eht_cap = &mode->eht_capab[opmode]; + if (!eht_cap->eht_supported) + return eid; + + *pos++ = WLAN_EID_EXTENSION; + length_pos = pos++; + *pos++ = WLAN_EID_EXT_EHT_CAPABILITIES; + + cap = (struct ieee80211_eht_capabilities *) pos; + os_memset(cap, 0, sizeof(*cap)); + cap->mac_cap = host_to_le16(eht_cap->mac_cap); + os_memcpy(cap->phy_cap, eht_cap->phy_cap, EHT_PHY_CAPAB_LEN); + + if (!is_6ghz_op_class(hapd->iconf->op_class)) + cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &= + ~EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK; + if (!hapd->iface->conf->eht_phy_capab.su_beamformer) + cap->phy_cap[EHT_PHYCAP_SU_BEAMFORMER_IDX] &= + ~EHT_PHYCAP_SU_BEAMFORMER; + + if (!hapd->iface->conf->eht_phy_capab.su_beamformee) + cap->phy_cap[EHT_PHYCAP_SU_BEAMFORMEE_IDX] &= + ~EHT_PHYCAP_SU_BEAMFORMEE; + + if (!hapd->iface->conf->eht_phy_capab.mu_beamformer) + cap->phy_cap[EHT_PHYCAP_MU_BEAMFORMER_IDX] &= + ~EHT_PHYCAP_MU_BEAMFORMER_MASK; + + pos = cap->optional; + + mcs_nss_len = ieee80211_eht_mcs_set_size(mode->mode, + hapd->iconf->op_class, + hapd->iconf->he_oper_chwidth, + mode->he_capab[opmode].phy_cap, + eht_cap->phy_cap); + if (mcs_nss_len) { + os_memcpy(pos, eht_cap->mcs, mcs_nss_len); + pos += mcs_nss_len; + } + + ppe_thresh_len = ieee80211_eht_ppet_size( + WPA_GET_LE16(&eht_cap->ppet[0]), + eht_cap->phy_cap); + if (ppe_thresh_len) { + os_memcpy(pos, eht_cap->ppet, ppe_thresh_len); + pos += ppe_thresh_len; + } + + *length_pos = pos - (eid + 2); + return pos; +} + + +u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid) +{ + struct hostapd_config *conf = hapd->iconf; + struct ieee80211_eht_operation *oper; + u8 *pos = eid, seg0 = 0, seg1 = 0; + enum oper_chan_width chwidth; + size_t elen = 1 + 4; + bool eht_oper_info_present; + u16 punct_bitmap = hostapd_get_punct_bitmap(hapd); + + if (!hapd->iface->current_mode) + return eid; + + if (is_6ghz_op_class(conf->op_class)) + chwidth = op_class_to_ch_width(conf->op_class); + else + chwidth = conf->eht_oper_chwidth; + + eht_oper_info_present = chwidth == CONF_OPER_CHWIDTH_320MHZ || + punct_bitmap; + + if (eht_oper_info_present) + elen += 3; + + if (punct_bitmap) + elen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE; + + *pos++ = WLAN_EID_EXTENSION; + *pos++ = 1 + elen; + *pos++ = WLAN_EID_EXT_EHT_OPERATION; + + oper = (struct ieee80211_eht_operation *) pos; + oper->oper_params = 0; + + if (hapd->iconf->eht_default_pe_duration) + oper->oper_params |= EHT_OPER_DEFAULT_PE_DURATION; + + /* TODO: Fill in appropriate EHT-MCS max Nss information */ + oper->basic_eht_mcs_nss_set[0] = 0x11; + oper->basic_eht_mcs_nss_set[1] = 0x00; + oper->basic_eht_mcs_nss_set[2] = 0x00; + oper->basic_eht_mcs_nss_set[3] = 0x00; + + if (!eht_oper_info_present) + return pos + elen; + + oper->oper_params |= EHT_OPER_INFO_PRESENT; + seg0 = hostapd_get_oper_centr_freq_seg0_idx(conf); + + switch (chwidth) { + case CONF_OPER_CHWIDTH_320MHZ: + oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_320MHZ; + seg1 = seg0; + if (hapd->iconf->channel < seg0) + seg0 -= 16; + else + seg0 += 16; + break; + case CONF_OPER_CHWIDTH_160MHZ: + oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_160MHZ; + seg1 = seg0; + if (hapd->iconf->channel < seg0) + seg0 -= 8; + else + seg0 += 8; + break; + case CONF_OPER_CHWIDTH_80MHZ: + oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_80MHZ; + break; + case CONF_OPER_CHWIDTH_USE_HT: + if (seg0) + oper->oper_info.control |= EHT_OPER_CHANNEL_WIDTH_40MHZ; + break; + default: + return eid; + } + + oper->oper_info.ccfs0 = seg0 ? seg0 : hapd->iconf->channel; + oper->oper_info.ccfs1 = seg1; + + if (punct_bitmap) { + oper->oper_params |= EHT_OPER_DISABLED_SUBCHAN_BITMAP_PRESENT; + oper->oper_info.disabled_chan_bitmap = + host_to_le16(punct_bitmap); + } + + return pos + elen; +} + + +static bool check_valid_eht_mcs_nss(struct hostapd_data *hapd, const u8 *ap_mcs, + const u8 *sta_mcs, u8 mcs_count, u8 map_len) +{ + unsigned int i, j; + + for (i = 0; i < mcs_count; i++) { + ap_mcs += i * 3; + sta_mcs += i * 3; + + for (j = 0; j < map_len; j++) { + if (((ap_mcs[j] >> 4) & 0xFF) == 0) + continue; + + if ((sta_mcs[j] & 0xFF) == 0) + continue; + + return true; + } + } + + wpa_printf(MSG_DEBUG, + "No matching EHT MCS found between AP TX and STA RX"); + return false; +} + + +static bool check_valid_eht_mcs(struct hostapd_data *hapd, + const u8 *sta_eht_capab, + enum ieee80211_op_mode opmode) +{ + struct hostapd_hw_modes *mode; + const struct ieee80211_eht_capabilities *capab; + const u8 *ap_mcs, *sta_mcs; + u8 mcs_count = 1; + + mode = hapd->iface->current_mode; + if (!mode) + return true; + + ap_mcs = mode->eht_capab[opmode].mcs; + capab = (const struct ieee80211_eht_capabilities *) sta_eht_capab; + sta_mcs = capab->optional; + + if (ieee80211_eht_mcs_set_size(mode->mode, hapd->iconf->op_class, + hapd->iconf->he_oper_chwidth, + mode->he_capab[opmode].phy_cap, + mode->eht_capab[opmode].phy_cap) == + EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY) + return check_valid_eht_mcs_nss( + hapd, ap_mcs, sta_mcs, 1, + EHT_PHYCAP_MCS_NSS_LEN_20MHZ_ONLY); + + switch (hapd->iface->conf->eht_oper_chwidth) { + case CONF_OPER_CHWIDTH_320MHZ: + mcs_count++; + __attribute__((fallthrough)); + case CONF_OPER_CHWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_160MHZ: + mcs_count++; + break; + default: + break; + } + + return check_valid_eht_mcs_nss(hapd, ap_mcs, sta_mcs, mcs_count, + EHT_PHYCAP_MCS_NSS_LEN_20MHZ_PLUS); +} + + +static bool ieee80211_invalid_eht_cap_size(enum hostapd_hw_mode mode, + u8 opclass, const u8 *he_cap, + const u8 *eht_cap, size_t len) +{ + const struct ieee80211_he_capabilities *he_capab; + struct ieee80211_eht_capabilities *cap; + const u8 *he_phy_cap; + size_t cap_len; + u16 ppe_thres_hdr; + + he_capab = (const struct ieee80211_he_capabilities *) he_cap; + he_phy_cap = he_capab->he_phy_capab_info; + cap = (struct ieee80211_eht_capabilities *) eht_cap; + cap_len = sizeof(*cap) - sizeof(cap->optional); + if (len < cap_len) + return true; + + cap_len += ieee80211_eht_mcs_set_size(mode, opclass, -1, he_phy_cap, + cap->phy_cap); + if (len < cap_len) + return true; + + ppe_thres_hdr = len > cap_len + 1 ? + WPA_GET_LE16(&eht_cap[cap_len]) : 0x01ff; + cap_len += ieee80211_eht_ppet_size(ppe_thres_hdr, cap->phy_cap); + + return len < cap_len; +} + + +u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta, + enum ieee80211_op_mode opmode, + const u8 *he_capab, size_t he_capab_len, + const u8 *eht_capab, size_t eht_capab_len) +{ + struct hostapd_hw_modes *c_mode = hapd->iface->current_mode; + enum hostapd_hw_mode mode = c_mode ? c_mode->mode : NUM_HOSTAPD_MODES; + + if (!hapd->iconf->ieee80211be || hapd->conf->disable_11be || + !he_capab || he_capab_len < IEEE80211_HE_CAPAB_MIN_LEN || + !eht_capab || + ieee80211_invalid_eht_cap_size(mode, hapd->iconf->op_class, + he_capab, eht_capab, + eht_capab_len) || + !check_valid_eht_mcs(hapd, eht_capab, opmode)) { + sta->flags &= ~WLAN_STA_EHT; + os_free(sta->eht_capab); + sta->eht_capab = NULL; + return WLAN_STATUS_SUCCESS; + } + + os_free(sta->eht_capab); + sta->eht_capab = os_memdup(eht_capab, eht_capab_len); + if (!sta->eht_capab) { + sta->eht_capab_len = 0; + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + sta->flags |= WLAN_STA_EHT; + sta->eht_capab_len = eht_capab_len; + + return WLAN_STATUS_SUCCESS; +} + + +void hostapd_get_eht_capab(struct hostapd_data *hapd, + const struct ieee80211_eht_capabilities *src, + struct ieee80211_eht_capabilities *dest, + size_t len) +{ + if (!src || !dest) + return; + + if (len > sizeof(*dest)) + len = sizeof(*dest); + /* TODO: mask out unsupported features */ + + os_memset(dest, 0, sizeof(*dest)); + os_memcpy(dest, src, len); +} + + +static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd, + u8 *eid, struct mld_info *mld_info, + bool include_mld_id) +{ + struct wpabuf *buf; + u16 control; + u8 *pos = eid; + const u8 *ptr; + size_t len, slice_len; + u8 link_id; + u8 common_info_len; + u16 mld_cap; + u8 max_simul_links, active_links; + + /* + * As the Multi-Link element can exceed the size of 255 bytes need to + * first build it and then handle fragmentation. + */ + buf = wpabuf_alloc(1024); + if (!buf) + return pos; + + /* Multi-Link Control field */ + control = MULTI_LINK_CONTROL_TYPE_BASIC | + BASIC_MULTI_LINK_CTRL_PRES_LINK_ID | + BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT | + BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA | + BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA; + + /* + * Set the basic Multi-Link common information. Hard code the common + * info length to 13 based on the length of the present fields: + * Length (1) + MLD address (6) + Link ID (1) + + * BSS Parameters Change Count (1) + EML Capabilities (2) + + * MLD Capabilities and Operations (2) + */ +#define EHT_ML_COMMON_INFO_LEN 13 + common_info_len = EHT_ML_COMMON_INFO_LEN; + + if (include_mld_id) { + /* AP MLD ID */ + control |= BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID; + common_info_len++; + } + + wpabuf_put_le16(buf, control); + + wpabuf_put_u8(buf, common_info_len); + + /* Own MLD MAC Address */ + wpabuf_put_data(buf, hapd->mld->mld_addr, ETH_ALEN); + + /* Own Link ID */ + wpabuf_put_u8(buf, hapd->mld_link_id); + + /* Currently hard code the BSS Parameters Change Count to 0x1 */ + wpabuf_put_u8(buf, 0x1); + + wpa_printf(MSG_DEBUG, "MLD: EML Capabilities=0x%x", + hapd->iface->mld_eml_capa); + wpabuf_put_le16(buf, hapd->iface->mld_eml_capa); + + mld_cap = hapd->iface->mld_mld_capa; + max_simul_links = mld_cap & EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK; + active_links = hapd->mld->num_links - 1; + + if (active_links > max_simul_links) { + wpa_printf(MSG_ERROR, + "MLD: Error in max simultaneous links, advertised: 0x%x current: 0x%x", + max_simul_links, active_links); + active_links = max_simul_links; + } + + mld_cap &= ~EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK; + mld_cap |= active_links & EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK; + + /* TODO: Advertise T2LM based on driver support as well */ + mld_cap &= ~EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_NEG_SUPP_MSK; + + wpa_printf(MSG_DEBUG, "MLD: MLD Capabilities and Operations=0x%x", + mld_cap); + wpabuf_put_le16(buf, mld_cap); + + if (include_mld_id) { + wpa_printf(MSG_DEBUG, "MLD: AP MLD ID=0x%x", + hostapd_get_mld_id(hapd)); + wpabuf_put_u8(buf, hostapd_get_mld_id(hapd)); + } + + if (!mld_info) + goto out; + + /* Add link info for the other links */ + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + struct mld_link_info *link = &mld_info->links[link_id]; + struct hostapd_data *link_bss; + + /* + * control (2) + station info length (1) + MAC address (6) + + * beacon interval (2) + TSF offset (8) + DTIM info (2) + BSS + * parameters change counter (1) + station profile length. + */ +#define EHT_ML_STA_INFO_LEN 22 + size_t total_len = EHT_ML_STA_INFO_LEN + + link->resp_sta_profile_len; + + /* Skip the local one */ + if (link_id == hapd->mld_link_id || !link->valid) + continue; + + link_bss = hostapd_mld_get_link_bss(hapd, link_id); + if (!link_bss) { + wpa_printf(MSG_ERROR, + "MLD: Couldn't find link BSS - skip it"); + continue; + } + + /* Per-STA Profile subelement */ + wpabuf_put_u8(buf, EHT_ML_SUB_ELEM_PER_STA_PROFILE); + + if (total_len <= 255) + wpabuf_put_u8(buf, total_len); + else + wpabuf_put_u8(buf, 255); + + /* STA Control */ + control = (link_id & 0xf) | + EHT_PER_STA_CTRL_MAC_ADDR_PRESENT_MSK | + EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK | + EHT_PER_STA_CTRL_TSF_OFFSET_PRESENT_MSK | + EHT_PER_STA_CTRL_BEACON_INTERVAL_PRESENT_MSK | + EHT_PER_STA_CTRL_DTIM_INFO_PRESENT_MSK | + EHT_PER_STA_CTRL_BSS_PARAM_CNT_PRESENT_MSK; + wpabuf_put_le16(buf, control); + + /* STA Info */ + + /* STA Info Length */ + wpabuf_put_u8(buf, EHT_ML_STA_INFO_LEN - 2); + wpabuf_put_data(buf, link->local_addr, ETH_ALEN); + wpabuf_put_le16(buf, link_bss->iconf->beacon_int); + + /* TSF Offset */ + /* + * TODO: Currently setting TSF offset to zero. However, this + * information needs to come from the driver. + */ + wpabuf_put_le64(buf, 0); + + /* DTIM Info */ + wpabuf_put_u8(buf, 0); /* DTIM Count */ + wpabuf_put_u8(buf, link_bss->conf->dtim_period); + + /* BSS Parameters Change Count */ + wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change); + + if (!link->resp_sta_profile) + continue; + + /* Fragment the sub element if needed */ + if (total_len <= 255) { + wpabuf_put_data(buf, link->resp_sta_profile, + link->resp_sta_profile_len); + } else { + ptr = link->resp_sta_profile; + len = link->resp_sta_profile_len; + + slice_len = 255 - EHT_ML_STA_INFO_LEN; + + wpabuf_put_data(buf, ptr, slice_len); + len -= slice_len; + ptr += slice_len; + + while (len) { + if (len <= 255) + slice_len = len; + else + slice_len = 255; + + wpabuf_put_u8(buf, EHT_ML_SUB_ELEM_FRAGMENT); + wpabuf_put_u8(buf, slice_len); + wpabuf_put_data(buf, ptr, slice_len); + + len -= slice_len; + ptr += slice_len; + } + } + } + +out: + /* Fragment the Multi-Link element, if needed */ + len = wpabuf_len(buf); + ptr = wpabuf_head(buf); + + if (len <= 254) + slice_len = len; + else + slice_len = 254; + + *pos++ = WLAN_EID_EXTENSION; + *pos++ = slice_len + 1; + *pos++ = WLAN_EID_EXT_MULTI_LINK; + os_memcpy(pos, ptr, slice_len); + + ptr += slice_len; + pos += slice_len; + len -= slice_len; + + while (len) { + if (len <= 255) + slice_len = len; + else + slice_len = 255; + + *pos++ = WLAN_EID_FRAGMENT; + *pos++ = slice_len; + os_memcpy(pos, ptr, slice_len); + + ptr += slice_len; + pos += slice_len; + len -= slice_len; + } + + wpabuf_free(buf); + return pos; +} + + +static u8 * hostapd_eid_eht_reconf_ml(struct hostapd_data *hapd, u8 *eid) +{ +#ifdef CONFIG_TESTING_OPTIONS + struct hostapd_data *other_hapd; + u16 control; + u8 *pos = eid; + unsigned int i; + + wpa_printf(MSG_DEBUG, "MLD: Reconfiguration ML"); + + /* First check if the element needs to be added */ + for (i = 0; i < hapd->iface->interfaces->count; i++) { + other_hapd = hapd->iface->interfaces->iface[i]->bss[0]; + + wpa_printf(MSG_DEBUG, "MLD: Reconfiguration ML: %u", + other_hapd->eht_mld_link_removal_count); + + if (other_hapd->eht_mld_link_removal_count) + break; + } + + /* No link is going to be removed */ + if (i == hapd->iface->interfaces->count) + return eid; + + wpa_printf(MSG_DEBUG, "MLD: Reconfiguration ML: Adding element"); + + /* The length will be set at the end */ + *pos++ = WLAN_EID_EXTENSION; + *pos++ = 0; + *pos++ = WLAN_EID_EXT_MULTI_LINK; + + /* Set the Multi-Link Control field */ + control = MULTI_LINK_CONTROL_TYPE_RECONF; + WPA_PUT_LE16(pos, control); + pos += 2; + + /* Common Info doesn't include any information */ + *pos++ = 1; + + /* Add the per station profiles */ + for (i = 0; i < hapd->iface->interfaces->count; i++) { + other_hapd = hapd->iface->interfaces->iface[i]->bss[0]; + if (!other_hapd->eht_mld_link_removal_count) + continue; + + /* Subelement ID is 0 */ + *pos++ = 0; + *pos++ = 5; + + control = other_hapd->mld_link_id | + EHT_PER_STA_RECONF_CTRL_AP_REMOVAL_TIMER; + + WPA_PUT_LE16(pos, control); + pos += 2; + + /* STA profile length */ + *pos++ = 3; + + WPA_PUT_LE16(pos, other_hapd->eht_mld_link_removal_count); + pos += 2; + } + + eid[1] = pos - eid - 2; + + wpa_hexdump(MSG_DEBUG, "MLD: Reconfiguration ML", eid, eid[1] + 2); + return pos; +#else /* CONFIG_TESTING_OPTIONS */ + return eid; +#endif /* CONFIG_TESTING_OPTIONS */ +} + + +static size_t hostapd_eid_eht_ml_len(struct mld_info *info, + bool include_mld_id) +{ + size_t len = 0; + size_t eht_ml_len = 2 + EHT_ML_COMMON_INFO_LEN; + u8 link_id; + + if (include_mld_id) + eht_ml_len++; + + for (link_id = 0; info && link_id < ARRAY_SIZE(info->links); + link_id++) { + struct mld_link_info *link; + size_t sta_len = EHT_ML_STA_INFO_LEN; + + link = &info->links[link_id]; + if (!link->valid) + continue; + + sta_len += link->resp_sta_profile_len; + + /* Element data and (fragmentation) headers */ + eht_ml_len += sta_len; + eht_ml_len += 2 + sta_len / 255 * 2; + } + + /* Element data */ + len += eht_ml_len; + + /* First header (254 bytes of data) */ + len += 3; + + /* Fragmentation headers; +1 for shorter first chunk */ + len += (eht_ml_len + 1) / 255 * 2; + + return len; +} +#undef EHT_ML_COMMON_INFO_LEN +#undef EHT_ML_STA_INFO_LEN + + +u8 * hostapd_eid_eht_ml_beacon(struct hostapd_data *hapd, + struct mld_info *info, + u8 *eid, bool include_mld_id) +{ + eid = hostapd_eid_eht_basic_ml_common(hapd, eid, info, include_mld_id); + return hostapd_eid_eht_reconf_ml(hapd, eid); +} + + + +u8 * hostapd_eid_eht_ml_assoc(struct hostapd_data *hapd, struct sta_info *info, + u8 *eid) +{ + if (!ap_sta_is_mld(hapd, info)) + return eid; + + eid = hostapd_eid_eht_basic_ml_common(hapd, eid, &info->mld_info, + false); + ap_sta_free_sta_profile(&info->mld_info); + return hostapd_eid_eht_reconf_ml(hapd, eid); +} + + +size_t hostapd_eid_eht_ml_beacon_len(struct hostapd_data *hapd, + struct mld_info *info, + bool include_mld_id) +{ + return hostapd_eid_eht_ml_len(info, include_mld_id); +} + + +struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd) +{ + struct wpabuf *buf = wpabuf_alloc(12); + + if (!buf) + return NULL; + + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(buf, 10); + wpabuf_put_u8(buf, WLAN_EID_EXT_MULTI_LINK); + wpabuf_put_le16(buf, MULTI_LINK_CONTROL_TYPE_BASIC); + wpabuf_put_u8(buf, ETH_ALEN + 1); + wpabuf_put_data(buf, hapd->mld->mld_addr, ETH_ALEN); + + return buf; +} + + +#ifdef CONFIG_SAE + +static const u8 * +sae_commit_skip_fixed_fields(const struct ieee80211_mgmt *mgmt, size_t len, + const u8 *pos, u16 status_code) +{ + u16 group; + size_t prime_len; + struct crypto_ec *ec; + + if (status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT) + return pos; + + /* SAE H2E commit message (group, scalar, FFE) */ + if (len < 2) { + wpa_printf(MSG_DEBUG, + "EHT: SAE Group is not present"); + return NULL; + } + + group = WPA_GET_LE16(pos); + pos += 2; + + /* TODO: How to parse when the group is unknown? */ + ec = crypto_ec_init(group); + if (!ec) { + const struct dh_group *dh = dh_groups_get(group); + + if (!dh) { + wpa_printf(MSG_DEBUG, "EHT: Unknown SAE group %u", + group); + return NULL; + } + + prime_len = dh->prime_len; + } else { + prime_len = crypto_ec_prime_len(ec); + } + + wpa_printf(MSG_DEBUG, "EHT: SAE scalar length is %zu", prime_len); + + /* scalar */ + pos += prime_len; + + if (ec) { + pos += prime_len * 2; + crypto_ec_deinit(ec); + } else { + pos += prime_len; + } + + if (pos - mgmt->u.auth.variable > (int) len) { + wpa_printf(MSG_DEBUG, + "EHT: Too short SAE commit Authentication frame"); + return NULL; + } + + wpa_hexdump(MSG_DEBUG, "EHT: SAE: Authentication frame elements", + pos, (int) len - (pos - mgmt->u.auth.variable)); + + return pos; +} + + +static const u8 * +sae_confirm_skip_fixed_fields(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, size_t len, + const u8 *pos, u16 status_code) +{ + struct sta_info *sta; + + if (status_code == WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION) + return pos; + + /* send confirm integer */ + pos += 2; + + /* + * At this stage we should already have an MLD station and actually SA + * will be replaced with the MLD MAC address by the driver. + */ + sta = ap_get_sta(hapd, mgmt->sa); + if (!sta) { + wpa_printf(MSG_DEBUG, "SAE: No MLD STA for SAE confirm"); + return NULL; + } + + if (!sta->sae || sta->sae->state < SAE_COMMITTED || !sta->sae->tmp) { + if (sta->sae) + wpa_printf(MSG_DEBUG, "SAE: Invalid state=%u", + sta->sae->state); + else + wpa_printf(MSG_DEBUG, "SAE: No SAE context"); + return NULL; + } + + wpa_printf(MSG_DEBUG, "SAE: confirm: kck_len=%zu", + sta->sae->tmp->kck_len); + + pos += sta->sae->tmp->kck_len; + + if (pos - mgmt->u.auth.variable > (int) len) { + wpa_printf(MSG_DEBUG, + "EHT: Too short SAE confirm Authentication frame"); + return NULL; + } + + return pos; +} + +#endif /* CONFIG_SAE */ + + +static const u8 * auth_skip_fixed_fields(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len) +{ + u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg); +#ifdef CONFIG_SAE + u16 auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); + u16 status_code = le_to_host16(mgmt->u.auth.status_code); +#endif /* CONFIG_SAE */ + const u8 *pos = mgmt->u.auth.variable; + + /* Skip fixed fields as based on IEE P802.11-REVme/D3.0, Table 9-69 + * (Presence of fields and elements in Authentications frames) */ + switch (auth_alg) { + case WLAN_AUTH_OPEN: + return pos; +#ifdef CONFIG_SAE + case WLAN_AUTH_SAE: + if (auth_transaction == 1) { + if (status_code == WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, + "EHT: SAE H2E is mandatory for MLD"); + goto out; + } + + return sae_commit_skip_fixed_fields(mgmt, len, pos, + status_code); + } else if (auth_transaction == 2) { + return sae_confirm_skip_fixed_fields(hapd, mgmt, len, + pos, status_code); + } + + return pos; +#endif /* CONFIG_SAE */ + /* TODO: Support additional algorithms that can be used for MLO */ + case WLAN_AUTH_FT: + case WLAN_AUTH_FILS_SK: + case WLAN_AUTH_FILS_SK_PFS: + case WLAN_AUTH_FILS_PK: + case WLAN_AUTH_PASN: + default: + break; + } + +#ifdef CONFIG_SAE +out: +#endif /* CONFIG_SAE */ + wpa_printf(MSG_DEBUG, + "TODO: Authentication algorithm %u not supported with MLD", + auth_alg); + return NULL; +} + + +const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd, + const struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct ieee802_11_elems elems; + const u8 *pos; + + if (!hapd->conf->mld_ap) + return NULL; + + len -= offsetof(struct ieee80211_mgmt, u.auth.variable); + + pos = auth_skip_fixed_fields(hapd, mgmt, len); + if (!pos) + return NULL; + + if (ieee802_11_parse_elems(pos, + (int)len - (pos - mgmt->u.auth.variable), + &elems, 0) == ParseFailed) { + wpa_printf(MSG_DEBUG, + "MLD: Failed parsing Authentication frame"); + } + + if (!elems.basic_mle || !elems.basic_mle_len) + return NULL; + + return get_basic_mle_mld_addr(elems.basic_mle, elems.basic_mle_len); +} + + +static int hostapd_mld_validate_assoc_info(struct hostapd_data *hapd, + struct sta_info *sta) +{ + u8 link_id; + struct mld_info *info = &sta->mld_info; + + if (!ap_sta_is_mld(hapd, sta)) { + wpa_printf(MSG_DEBUG, "MLD: Not a non-AP MLD"); + return 0; + } + + /* + * Iterate over the links negotiated in the (Re)Association Request + * frame and validate that they are indeed valid links in the local AP + * MLD. + * + * While at it, also update the local address for the links in the + * mld_info, so it could be easily available for later flows, e.g., for + * the RSN Authenticator, etc. + */ + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + struct hostapd_data *other_hapd; + + if (!info->links[link_id].valid || link_id == hapd->mld_link_id) + continue; + + other_hapd = hostapd_mld_get_link_bss(hapd, link_id); + if (!other_hapd) { + wpa_printf(MSG_DEBUG, "MLD: Invalid link ID=%u", + link_id); + return -1; + } + + os_memcpy(info->links[link_id].local_addr, other_hapd->own_addr, + ETH_ALEN); + } + + return 0; +} + + +int hostapd_process_ml_assoc_req_addr(struct hostapd_data *hapd, + const u8 *basic_mle, size_t basic_mle_len, + u8 *mld_addr) +{ + struct wpabuf *mlbuf = ieee802_11_defrag(basic_mle, basic_mle_len, + true); + struct ieee80211_eht_ml *ml; + struct eht_ml_basic_common_info *common_info; + size_t ml_len, common_info_len; + int ret = -1; + u16 ml_control; + + if (!mlbuf) + return WLAN_STATUS_SUCCESS; + + ml = (struct ieee80211_eht_ml *) wpabuf_head(mlbuf); + ml_len = wpabuf_len(mlbuf); + + if (ml_len < sizeof(*ml)) + goto out; + + ml_control = le_to_host16(ml->ml_control); + if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) != + MULTI_LINK_CONTROL_TYPE_BASIC) { + wpa_printf(MSG_DEBUG, "MLD: Invalid ML type=%u", + ml_control & MULTI_LINK_CONTROL_TYPE_MASK); + goto out; + } + + /* Common Info Length and MLD MAC Address must always be present */ + common_info_len = 1 + ETH_ALEN; + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID) { + wpa_printf(MSG_DEBUG, "MLD: Link ID Info not expected"); + goto out; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT) { + wpa_printf(MSG_DEBUG, + "MLD: BSS Parameters Change Count not expected"); + goto out; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) { + wpa_printf(MSG_DEBUG, + "MLD: Medium Synchronization Delay Information not expected"); + goto out; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) + common_info_len += 2; + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA) + common_info_len += 2; + + if (sizeof(*ml) + common_info_len > ml_len) { + wpa_printf(MSG_DEBUG, "MLD: Not enough bytes for common info"); + goto out; + } + + common_info = (struct eht_ml_basic_common_info *) ml->variable; + + /* Common information length includes the length octet */ + if (common_info->len != common_info_len) { + wpa_printf(MSG_DEBUG, + "MLD: Invalid common info len=%u", common_info->len); + goto out; + } + + /* Get the MLD MAC Address */ + os_memcpy(mld_addr, common_info->mld_addr, ETH_ALEN); + ret = 0; + +out: + wpabuf_free(mlbuf); + return ret; +} + + +u16 hostapd_process_ml_assoc_req(struct hostapd_data *hapd, + struct ieee802_11_elems *elems, + struct sta_info *sta) +{ + struct wpabuf *mlbuf; + const struct ieee80211_eht_ml *ml; + const struct eht_ml_basic_common_info *common_info; + size_t ml_len, common_info_len; + struct mld_link_info *link_info; + struct mld_info *info = &sta->mld_info; + const u8 *pos; + int ret = -1; + u16 ml_control; + + mlbuf = ieee802_11_defrag(elems->basic_mle, elems->basic_mle_len, true); + if (!mlbuf) + return WLAN_STATUS_SUCCESS; + + ml = wpabuf_head(mlbuf); + ml_len = wpabuf_len(mlbuf); + + ml_control = le_to_host16(ml->ml_control); + if ((ml_control & MULTI_LINK_CONTROL_TYPE_MASK) != + MULTI_LINK_CONTROL_TYPE_BASIC) { + wpa_printf(MSG_DEBUG, "MLD: Invalid ML type=%u", + ml_control & MULTI_LINK_CONTROL_TYPE_MASK); + goto out; + } + + /* Common Info length and MLD MAC address must always be present */ + common_info_len = 1 + ETH_ALEN; + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID) { + wpa_printf(MSG_DEBUG, "MLD: Link ID info not expected"); + goto out; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT) { + wpa_printf(MSG_DEBUG, "MLD: BSS params change not expected"); + goto out; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) { + wpa_printf(MSG_DEBUG, "MLD: Sync delay not expected"); + goto out; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) { + common_info_len += 2; + } else { + wpa_printf(MSG_DEBUG, "MLD: EML capabilities not present"); + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA) { + common_info_len += 2; + + } else { + wpa_printf(MSG_DEBUG, "MLD: MLD capabilities not present"); + goto out; + } + + wpa_printf(MSG_DEBUG, "MLD: expected_common_info_len=%zu", + common_info_len); + + if (sizeof(*ml) + common_info_len > ml_len) { + wpa_printf(MSG_DEBUG, "MLD: Not enough bytes for common info"); + goto out; + } + + common_info = (const struct eht_ml_basic_common_info *) ml->variable; + + /* Common information length includes the length octet */ + if (common_info->len != common_info_len) { + wpa_printf(MSG_DEBUG, + "MLD: Invalid common info len=%u (expected %zu)", + common_info->len, common_info_len); + goto out; + } + + pos = common_info->variable; + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) { + info->common_info.eml_capa = WPA_GET_LE16(pos); + pos += 2; + } else { + info->common_info.eml_capa = 0; + } + + info->common_info.mld_capa = WPA_GET_LE16(pos); + pos += 2; + + wpa_printf(MSG_DEBUG, "MLD: addr=" MACSTR ", eml=0x%x, mld=0x%x", + MAC2STR(info->common_info.mld_addr), + info->common_info.eml_capa, info->common_info.mld_capa); + + /* Check the MLD MAC Address */ + if (!ether_addr_equal(info->common_info.mld_addr, + common_info->mld_addr)) { + wpa_printf(MSG_DEBUG, + "MLD: MLD address mismatch between authentication (" + MACSTR ") and association (" MACSTR ")", + MAC2STR(info->common_info.mld_addr), + MAC2STR(common_info->mld_addr)); + goto out; + } + + info->links[hapd->mld_link_id].valid = 1; + + /* Parse the link info field */ + ml_len -= sizeof(*ml) + common_info_len; + + while (ml_len > 2) { + size_t sub_elem_len = *(pos + 1); + size_t sta_info_len; + u16 control; + + wpa_printf(MSG_DEBUG, "MLD: sub element len=%zu", + sub_elem_len); + + if (2 + sub_elem_len > ml_len) { + wpa_printf(MSG_DEBUG, + "MLD: Invalid link info len: %zu %zu", + 2 + sub_elem_len, ml_len); + goto out; + } + + if (*pos == MULTI_LINK_SUB_ELEM_ID_VENDOR) { + wpa_printf(MSG_DEBUG, + "MLD: Skip vendor specific subelement"); + + pos += 2 + sub_elem_len; + ml_len -= 2 + sub_elem_len; + continue; + } + + if (*pos != MULTI_LINK_SUB_ELEM_ID_PER_STA_PROFILE) { + wpa_printf(MSG_DEBUG, + "MLD: Skip unknown Multi-Link element subelement ID=%u", + *pos); + pos += 2 + sub_elem_len; + ml_len -= 2 + sub_elem_len; + continue; + } + + /* Skip the subelement ID and the length */ + pos += 2; + ml_len -= 2; + + /* Get the station control field */ + if (sub_elem_len < 2) { + wpa_printf(MSG_DEBUG, + "MLD: Too short Per-STA Profile subelement"); + goto out; + } + control = WPA_GET_LE16(pos); + link_info = &info->links[control & + EHT_PER_STA_CTRL_LINK_ID_MSK]; + pos += 2; + ml_len -= 2; + sub_elem_len -= 2; + + if (!(control & EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK)) { + wpa_printf(MSG_DEBUG, + "MLD: Per-STA complete profile expected"); + goto out; + } + + if (!(control & EHT_PER_STA_CTRL_MAC_ADDR_PRESENT_MSK)) { + wpa_printf(MSG_DEBUG, + "MLD: Per-STA MAC address not present"); + goto out; + } + + if ((control & (EHT_PER_STA_CTRL_BEACON_INTERVAL_PRESENT_MSK | + EHT_PER_STA_CTRL_DTIM_INFO_PRESENT_MSK))) { + wpa_printf(MSG_DEBUG, + "MLD: Beacon/DTIM interval not expected"); + goto out; + } + + /* The length octet and the MAC address must be present */ + sta_info_len = 1 + ETH_ALEN; + + if (control & EHT_PER_STA_CTRL_NSTR_LINK_PAIR_PRESENT_MSK) { + if (control & EHT_PER_STA_CTRL_NSTR_BM_SIZE_MSK) + link_info->nstr_bitmap_len = 2; + else + link_info->nstr_bitmap_len = 1; + } + + sta_info_len += link_info->nstr_bitmap_len; + + if (sta_info_len > ml_len || sta_info_len != *pos || + sta_info_len > sub_elem_len) { + wpa_printf(MSG_DEBUG, "MLD: Invalid STA Info length"); + goto out; + } + + /* skip the length */ + pos++; + ml_len--; + + /* get the link address */ + os_memcpy(link_info->peer_addr, pos, ETH_ALEN); + wpa_printf(MSG_DEBUG, + "MLD: assoc: link id=%u, addr=" MACSTR, + control & EHT_PER_STA_CTRL_LINK_ID_MSK, + MAC2STR(link_info->peer_addr)); + + pos += ETH_ALEN; + ml_len -= ETH_ALEN; + + /* Get the NSTR bitmap */ + if (link_info->nstr_bitmap_len) { + os_memcpy(link_info->nstr_bitmap, pos, + link_info->nstr_bitmap_len); + pos += link_info->nstr_bitmap_len; + ml_len -= link_info->nstr_bitmap_len; + } + + sub_elem_len -= sta_info_len; + + wpa_printf(MSG_DEBUG, "MLD: STA Profile len=%zu", sub_elem_len); + if (sub_elem_len > ml_len) + goto out; + + if (sub_elem_len > 2) + link_info->capability = WPA_GET_LE16(pos); + + pos += sub_elem_len; + ml_len -= sub_elem_len; + + wpa_printf(MSG_DEBUG, "MLD: link ctrl=0x%x, " MACSTR + ", nstr bitmap len=%u", + control, MAC2STR(link_info->peer_addr), + link_info->nstr_bitmap_len); + + link_info->valid = true; + } + + if (ml_len) { + wpa_printf(MSG_DEBUG, "MLD: %zu bytes left after parsing. fail", + ml_len); + goto out; + } + + ret = hostapd_mld_validate_assoc_info(hapd, sta); +out: + wpabuf_free(mlbuf); + if (ret) { + os_memset(info, 0, sizeof(*info)); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + return WLAN_STATUS_SUCCESS; +} diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_he.c b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_he.c index 6cd6c90dcf021808b23e6749edd72520d0b899ac..70af59be8e2bbd83bb9e5db763499b7fec23627d 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_he.c +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_he.c @@ -12,6 +12,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "common/hw_features_common.h" #include "hostapd.h" #include "ap_config.h" #include "beacon.h" @@ -29,17 +30,19 @@ static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) & HE_PPE_THRES_RU_INDEX_BITMASK_MASK; + /* Count the number of 1 bits in RU Index Bitmask */ while (ru) { if (ru & 0x1) sz++; ru >>= 1; } + /* fixed header of 3 (NSTS) + 4 (RU Index Bitmask) = 7 bits */ + /* 6 * (NSTS + 1) bits for bit 1 in RU Index Bitmask */ sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK); sz = (sz * 6) + 7; - if (sz % 8) - sz += 8; - sz /= 8; + /* PPE Pad to count the number of needed full octets */ + sz = (sz + 7) / 8; return sz; } @@ -64,6 +67,7 @@ static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len) { struct ieee80211_he_capabilities *cap; size_t cap_len; + u8 ppe_thres_hdr; cap = (struct ieee80211_he_capabilities *) buf; cap_len = sizeof(*cap) - sizeof(cap->optional); @@ -74,9 +78,11 @@ static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len) if (len < cap_len) return 1; - cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info); + ppe_thres_hdr = len > cap_len ? buf[cap_len] : 0xff; + cap_len += ieee80211_he_ppet_size(ppe_thres_hdr, + cap->he_phy_capab_info); - return len != cap_len; + return len < cap_len; } @@ -97,20 +103,22 @@ u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid, mode->he_capab[opmode].phy_cap); switch (hapd->iface->conf->he_oper_chwidth) { - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G; mcs_nss_size += 4; - /* fall through */ - case CHANWIDTH_160MHZ: + __attribute__((fallthrough)); + case CONF_OPER_CHWIDTH_160MHZ: he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G; mcs_nss_size += 4; - /* fall through */ - case CHANWIDTH_80MHZ: - case CHANWIDTH_USE_HT: + __attribute__((fallthrough)); + case CONF_OPER_CHWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_USE_HT: he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G | HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; break; + default: + break; } ie_size += mcs_nss_size + ppet_size; @@ -195,7 +203,8 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) if (hapd->iface->conf->he_op.he_er_su_disable) params |= HE_OPERATION_ER_SU_DISABLE; - if (hapd->iface->conf->he_op.he_bss_color_disabled) + if (hapd->iface->conf->he_op.he_bss_color_disabled || + hapd->cca_in_progress) params |= HE_OPERATION_BSS_COLOR_DISABLED; if (hapd->iface->conf->he_op.he_bss_color_partial) params |= HE_OPERATION_BSS_COLOR_PARTIAL; @@ -211,8 +220,20 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) pos += 6; /* skip the fixed part */ if (is_6ghz_op_class(hapd->iconf->op_class)) { - u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf); + enum oper_chan_width oper_chwidth = + hostapd_get_oper_chwidth(hapd->iconf); + u8 seg0 = hapd->iconf->he_oper_centr_freq_seg0_idx; u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf); + u8 control; +#ifdef CONFIG_IEEE80211BE + u16 punct_bitmap = hostapd_get_punct_bitmap(hapd); + + if (punct_bitmap) { + punct_update_legacy_bw(punct_bitmap, + hapd->iconf->channel, + &oper_chwidth, &seg0, &seg1); + } +#endif /* CONFIG_IEEE80211BE */ if (!seg0) seg0 = hapd->iconf->channel; @@ -220,19 +241,30 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) params |= HE_OPERATION_6GHZ_OPER_INFO; /* 6 GHz Operation Information field - * IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element, + * IEEE Std 802.11ax-2021, 9.4.2.249 HE Operation element, * Figure 9-788k */ *pos++ = hapd->iconf->channel; /* Primary Channel */ - /* Control: Channel Width */ + /* Control: + * bits 0-1: Channel Width + * bit 2: Duplicate Beacon + * bits 3-5: Regulatory Info + */ + /* Channel Width */ if (seg1) - *pos++ = 3; + control = 3; else - *pos++ = center_idx_to_bw_6ghz(seg0); + control = center_idx_to_bw_6ghz(seg0); + + control |= hapd->iconf->he_6ghz_reg_pwr_type << + HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT; + + *pos++ = control; /* Channel Center Freq Seg0/Seg1 */ - if (hapd->iconf->he_oper_chwidth == 2) { + if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ || + oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) { /* * Seg 0 indicates the channel center frequency index of * the 160 MHz channel. @@ -411,10 +443,10 @@ static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab, * band/stream cases. */ switch (hapd->iface->conf->he_oper_chwidth) { - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: mcs_count = 3; break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: mcs_count = 2; break; default: @@ -512,7 +544,8 @@ int hostapd_get_he_twt_responder(struct hostapd_data *hapd, u8 *mac_cap; if (!hapd->iface->current_mode || - !hapd->iface->current_mode->he_capab[mode].he_supported) + !hapd->iface->current_mode->he_capab[mode].he_supported || + !hapd->iconf->ieee80211ax || hapd->conf->disable_11ax) return 0; mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap; @@ -520,3 +553,19 @@ int hostapd_get_he_twt_responder(struct hostapd_data *hapd, return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) && hapd->iface->conf->he_op.he_twt_responder; } + + +u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid) +{ + if (!hapd->cca_in_progress) + return eid; + + /* BSS Color Change Announcement element */ + *eid++ = WLAN_EID_EXTENSION; + *eid++ = 3; + *eid++ = WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT; + *eid++ = hapd->cca_count; /* Color Switch Countdown */ + *eid++ = hapd->cca_color; /* New BSS Color Information */ + + return eid; +} diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_ht.c b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_ht.c index 107c455266c98c1586c146591cff474991cfd346..d3b97041c624fe1686c8efd39dddb69de0a1268f 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_ht.c +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_ht.c @@ -479,15 +479,14 @@ static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta) } -void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta) +int update_ht_state(struct hostapd_data *hapd, struct sta_info *sta) { if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) update_sta_ht(hapd, sta); else update_sta_no_ht(hapd, sta); - if (hostapd_ht_operation_update(hapd->iface) > 0) - ieee802_11_set_beacons(hapd->iface); + return hostapd_ht_operation_update(hapd->iface); } diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_shared.c b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_shared.c index 805e028d46e33d36e782f0e8dc34370ebcda16e1..3846bd2006024b356d706c76a37971d3cb534949 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_shared.c +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_shared.c @@ -1,6 +1,6 @@ /* * hostapd / IEEE 802.11 Management - * Copyright (c) 2002-2012, Jouni Malinen + * Copyright (c) 2002-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -17,19 +17,29 @@ #include "ap_config.h" #include "ap_drv_ops.h" #include "wpa_auth.h" +#include "dpp_hostapd.h" #include "ieee802_11.h" +static u8 * hostapd_eid_timeout_interval(u8 *pos, u8 type, u32 value) +{ + *pos++ = WLAN_EID_TIMEOUT_INTERVAL; + *pos++ = 5; + *pos++ = type; + WPA_PUT_LE32(pos, value); + pos += 4; + + return pos; +} + + u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, struct sta_info *sta, u8 *eid) { - u8 *pos = eid; u32 timeout, tu; struct os_reltime now, passed; + u8 type = WLAN_TIMEOUT_ASSOC_COMEBACK; - *pos++ = WLAN_EID_TIMEOUT_INTERVAL; - *pos++ = 5; - *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; os_get_reltime(&now); os_reltime_sub(&now, &sta->sa_query_start, &passed); tu = (passed.sec * 1000000 + passed.usec) / 1024; @@ -39,10 +49,12 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, timeout = 0; if (timeout < hapd->conf->assoc_sa_query_max_timeout) timeout++; /* add some extra time for local timers */ - WPA_PUT_LE32(pos, timeout); - pos += 4; - return pos; +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->conf->test_assoc_comeback_type != -1) + type = hapd->conf->test_assoc_comeback_type; +#endif /* CONFIG_TESTING_OPTIONS */ + return hostapd_eid_timeout_interval(eid, type, timeout); } @@ -50,13 +62,14 @@ u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, const u8 *addr, const u8 *trans_id) { -#ifdef CONFIG_OCV - struct sta_info *sta; -#endif /* CONFIG_OCV */ +#if defined(CONFIG_OCV) || defined(CONFIG_IEEE80211BE) + struct sta_info *sta = ap_get_sta(hapd, addr); +#endif /* CONFIG_OCV || CONFIG_IEEE80211BE */ struct ieee80211_mgmt *mgmt; u8 *oci_ie = NULL; u8 oci_ie_len = 0; u8 *end; + const u8 *own_addr = hapd->own_addr; wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to " MACSTR_SEC, MAC2STR_SEC(addr)); @@ -64,7 +77,6 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, trans_id, WLAN_SA_QUERY_TR_ID_LEN); #ifdef CONFIG_OCV - sta = ap_get_sta(hapd, addr); if (sta && wpa_auth_uses_ocv(sta->wpa_sm)) { struct wpa_channel_info ci; @@ -107,11 +119,16 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, return; } +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) + own_addr = hapd->mld->mld_addr; +#endif /* CONFIG_IEEE80211BE */ + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->sa, own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); mgmt->u.action.category = WLAN_ACTION_SA_QUERY; mgmt->u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST; os_memcpy(mgmt->u.action.u.sa_query_req.trans_id, trans_id, @@ -140,6 +157,7 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd, u8 *oci_ie = NULL; u8 oci_ie_len = 0; u8 *end; + const u8 *own_addr = hapd->own_addr; wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from " MACSTR_SEC, MAC2STR_SEC(sa)); @@ -199,11 +217,16 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to " MACSTR_SEC, MAC2STR_SEC(sa)); +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) + own_addr = hapd->mld->mld_addr; +#endif /* CONFIG_IEEE80211BE */ + resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); os_memcpy(resp->da, sa, ETH_ALEN); - os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); + os_memcpy(resp->sa, own_addr, ETH_ALEN); + os_memcpy(resp->bssid, own_addr, ETH_ALEN); resp->u.action.category = WLAN_ACTION_SA_QUERY; resp->u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE; os_memcpy(resp->u.action.u.sa_query_req.trans_id, trans_id, @@ -339,7 +362,8 @@ void ieee802_11_sa_query_action(struct hostapd_data *hapd, } -static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) +static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx, + bool mbssid_complete) { *pos = 0x00; @@ -363,6 +387,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */ if (hapd->conf->bss_transition) *pos |= 0x08; /* Bit 19 - BSS Transition */ + if (hapd->iconf->mbssid) + *pos |= 0x40; /* Bit 22 - Multiple BSSID */ break; case 3: /* Bits 24-31 */ #ifdef CONFIG_WNM_AP @@ -412,10 +438,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) *pos |= 0x01; #endif /* CONFIG_FILS */ #ifdef CONFIG_IEEE80211AX - if (hapd->iconf->ieee80211ax && - hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP)) + if (hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP)) *pos |= 0x40; /* Bit 78 - TWT responder */ #endif /* CONFIG_IEEE80211AX */ + if (hostapd_get_ht_vht_twt_responder(hapd)) + *pos |= 0x40; /* Bit 78 - TWT responder */ break; case 10: /* Bits 80-87 */ #ifdef CONFIG_SAE @@ -435,6 +462,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_BEACON_PROTECTION)) *pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */ + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED) + *pos |= 0x08; /* Bit 83 - Enhanced multiple BSSID */ + if (mbssid_complete) + *pos |= 0x01; /* Bit 80 - Complete List of NonTxBSSID + * Profiles */ break; case 11: /* Bits 88-95 */ #ifdef CONFIG_SAE_PK @@ -448,7 +480,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) } -u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) +u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid, + bool mbssid_complete) { u8 *pos = eid; u8 len = EXT_CAPA_MAX_LEN, i; @@ -459,7 +492,7 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) *pos++ = WLAN_EID_EXT_CAPAB; *pos++ = len; for (i = 0; i < len; i++, pos++) { - hostapd_ext_capab_byte(hapd, pos, i); + hostapd_ext_capab_byte(hapd, pos, i, mbssid_complete); if (i < hapd->iface->extended_capa_len) { *pos &= ~hapd->iface->extended_capa_mask[i]; @@ -470,6 +503,13 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) *pos &= ~hapd->conf->ext_capa_mask[i]; *pos |= hapd->conf->ext_capa[i]; } + + /* Clear bits 83 and 22 if EMA and MBSSID are not enabled + * otherwise association fails with some clients */ + if (i == 10 && hapd->iconf->mbssid < ENHANCED_MBSSID_ENABLED) + *pos &= ~0x08; + if (i == 2 && !hapd->iconf->mbssid) + *pos &= ~0x40; } while (len > 0 && eid[1 + len] == 0) { @@ -697,12 +737,14 @@ int hostapd_update_time_adv(struct hostapd_data *hapd) } -u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid) +u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid, + u16 value) { u8 *pos = eid; #ifdef CONFIG_WNM_AP - if (hapd->conf->ap_max_inactivity > 0) { + if (hapd->conf->ap_max_inactivity > 0 && + hapd->conf->bss_max_idle) { unsigned int val; *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD; *pos++ = 3; @@ -715,9 +757,13 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid) val = 1; if (val > 65535) val = 65535; + if (value) + val = value; WPA_PUT_LE16(pos, val); pos += 2; - *pos++ = 0x00; /* TODO: Protected Keep-Alive Required */ + /* Set the Protected Keep-Alive Required bit based on + * configuration */ + *pos++ = hapd->conf->bss_max_idle == 2 ? BIT(0) : 0x00; } #endif /* CONFIG_WNM_AP */ @@ -873,7 +919,7 @@ u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd) { #ifdef CONFIG_DPP2 - if (hapd->conf->dpp_configurator_connectivity) + if (hostapd_dpp_configurator_connectivity(hapd)) return 6; #endif /* CONFIG_DPP2 */ return 0; @@ -885,7 +931,7 @@ u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len) u8 *pos = eid; #ifdef CONFIG_DPP2 - if (!hapd->conf->dpp_configurator_connectivity || len < 6) + if (!hostapd_dpp_configurator_connectivity(hapd) || len < 6) return pos; *pos++ = WLAN_EID_VENDOR_SPECIFIC; @@ -998,7 +1044,7 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth, * If a VHT Operation element was present, use it to determine * the supported channel bandwidth. */ - if (oper->vht_op_info_chwidth == 0) { + if (oper->vht_op_info_chwidth == CHANWIDTH_USE_HT) { requested_bw = ht_40mhz ? 40 : 20; } else if (oper->vht_op_info_chan_center_freq_seg1_idx == 0) { requested_bw = 80; @@ -1051,7 +1097,7 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len) { u8 *pos = eid; bool sae_pk = false; - u16 capab = 0; + u32 capab = 0, tmp; size_t flen; if (!(hapd->conf->wpa & WPA_PROTO_RSN)) @@ -1062,10 +1108,11 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len) #endif /* CONFIG_SAE_PK */ if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && - (hapd->conf->sae_pwe == 1 || hapd->conf->sae_pwe == 2 || + (hapd->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || + hapd->conf->sae_pwe == SAE_PWE_BOTH || hostapd_sae_pw_id_in_use(hapd->conf) || sae_pk || wpa_key_mgmt_sae_ext_key(hapd->conf->wpa_key_mgmt)) && - hapd->conf->sae_pwe != 3) { + hapd->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) { capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); #ifdef CONFIG_SAE_PK if (sae_pk) @@ -1073,24 +1120,109 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len) #endif /* CONFIG_SAE_PK */ } - if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF) + if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP) capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF); - if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT) + if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_AP) capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT); - if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG) - capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG); + if (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP) + capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR); + if (hapd->conf->ssid_protection) + capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION); - flen = (capab & 0xff00) ? 2 : 1; - if (len < 2 + flen || !capab) + if (!capab) + return eid; /* no supported extended RSN capabilities */ + tmp = capab; + flen = 0; + while (tmp) { + flen++; + tmp >>= 8; + } + + if (len < 2 + flen) return eid; /* no supported extended RSN capabilities */ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ *pos++ = WLAN_EID_RSNX; *pos++ = flen; - *pos++ = capab & 0x00ff; - capab >>= 8; - if (capab) - *pos++ = capab; + while (capab) { + *pos++ = capab & 0xff; + capab >>= 8; + } return pos; } + + +u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *ext_capab_ie, size_t ext_capab_ie_len) +{ + /* check for QoS Map support */ + if (ext_capab_ie_len >= 5) { + if (ext_capab_ie[4] & 0x01) + sta->qos_map_enabled = 1; + } + + if (ext_capab_ie_len > 0) { + sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2)); + os_free(sta->ext_capability); + sta->ext_capability = os_malloc(1 + ext_capab_ie_len); + if (sta->ext_capability) { + sta->ext_capability[0] = ext_capab_ie_len; + os_memcpy(sta->ext_capability + 1, ext_capab_ie, + ext_capab_ie_len); + } + } + + return WLAN_STATUS_SUCCESS; +} + + +struct sta_info * hostapd_ml_get_assoc_sta(struct hostapd_data *hapd, + struct sta_info *sta, + struct hostapd_data **assoc_hapd) +{ +#ifdef CONFIG_IEEE80211BE + struct hostapd_data *other_hapd = NULL; + struct sta_info *tmp_sta; + + if (!ap_sta_is_mld(hapd, sta)) + return NULL; + + *assoc_hapd = hapd; + + /* The station is the one on which the association was performed */ + if (sta->mld_assoc_link_id == hapd->mld_link_id) + return sta; + + other_hapd = hostapd_mld_get_link_bss(hapd, sta->mld_assoc_link_id); + if (!other_hapd) { + wpa_printf(MSG_DEBUG, "MLD: No link match for link_id=%u", + sta->mld_assoc_link_id); + return sta; + } + + /* + * Iterate over the stations and find the one with the matching link ID + * and association ID. + */ + for (tmp_sta = other_hapd->sta_list; tmp_sta; tmp_sta = tmp_sta->next) { + if (tmp_sta->mld_assoc_link_id == sta->mld_assoc_link_id && + tmp_sta->aid == sta->aid) { + *assoc_hapd = other_hapd; + return tmp_sta; + } + } +#endif /* CONFIG_IEEE80211BE */ + + return sta; +} + + +bool hostapd_get_ht_vht_twt_responder(struct hostapd_data *hapd) +{ + return hapd->iconf->ht_vht_twt_responder && + ((hapd->iconf->ieee80211n && !hapd->conf->disable_11n) || + (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac)) && + (hapd->iface->drv_flags2 & + WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER); +} diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_vht.c b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_vht.c index 828f0abb5aad6446057fb30401b4ad150f43e55d..4dc325ce89bb731e92f9102201dfc8601e564841 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ieee802_11_vht.c +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_11_vht.c @@ -12,6 +12,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" +#include "common/hw_features_common.h" #include "hostapd.h" #include "ap_config.h" #include "sta_info.h" @@ -75,6 +76,13 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid) { struct ieee80211_vht_operation *oper; u8 *pos = eid; + enum oper_chan_width oper_chwidth = + hostapd_get_oper_chwidth(hapd->iconf); + u8 seg0 = hapd->iconf->vht_oper_centr_freq_seg0_idx; + u8 seg1 = hapd->iconf->vht_oper_centr_freq_seg1_idx; +#ifdef CONFIG_IEEE80211BE + u16 punct_bitmap = hostapd_get_punct_bitmap(hapd); +#endif /* CONFIG_IEEE80211BE */ if (is_6ghz_op_class(hapd->iconf->op_class)) return eid; @@ -85,23 +93,29 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid) oper = (struct ieee80211_vht_operation *) pos; os_memset(oper, 0, sizeof(*oper)); +#ifdef CONFIG_IEEE80211BE + if (punct_bitmap) { + punct_update_legacy_bw(punct_bitmap, + hapd->iconf->channel, + &oper_chwidth, &seg0, &seg1); + } +#endif /* CONFIG_IEEE80211BE */ + /* * center freq = 5 GHz + (5 * index) * So index 42 gives center freq 5.210 GHz * which is channel 42 in 5G band */ - oper->vht_op_info_chan_center_freq_seg0_idx = - hapd->iconf->vht_oper_centr_freq_seg0_idx; - oper->vht_op_info_chan_center_freq_seg1_idx = - hapd->iconf->vht_oper_centr_freq_seg1_idx; + oper->vht_op_info_chan_center_freq_seg0_idx = seg0; + oper->vht_op_info_chan_center_freq_seg1_idx = seg1; - oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth; - if (hapd->iconf->vht_oper_chwidth == 2) { + oper->vht_op_info_chwidth = oper_chwidth; + if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) { /* * Convert 160 MHz channel width to new style as interop * workaround. */ - oper->vht_op_info_chwidth = 1; + oper->vht_op_info_chwidth = CHANWIDTH_80MHZ; oper->vht_op_info_chan_center_freq_seg1_idx = oper->vht_op_info_chan_center_freq_seg0_idx; if (hapd->iconf->channel < @@ -109,12 +123,12 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid) oper->vht_op_info_chan_center_freq_seg0_idx -= 8; else oper->vht_op_info_chan_center_freq_seg0_idx += 8; - } else if (hapd->iconf->vht_oper_chwidth == 3) { + } else if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) { /* * Convert 80+80 MHz channel width to new style as interop * workaround. */ - oper->vht_op_info_chwidth = 1; + oper->vht_op_info_chwidth = CHANWIDTH_80MHZ; } /* VHT Basic MCS set comes from hw */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_1x.c b/wpa_supplicant-2.9_standard/src/ap/ieee802_1x.c index d2ae7eeb3fe6fbed9c511954ba8bc49c58c6130f..3edb42a44d00291b0480520860552a718e1ec788 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ieee802_1x.c +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_1x.c @@ -43,9 +43,9 @@ #ifdef CONFIG_HS20 static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx); #endif /* CONFIG_HS20 */ -static void ieee802_1x_finished(struct hostapd_data *hapd, +static bool ieee802_1x_finished(struct hostapd_data *hapd, struct sta_info *sta, int success, - int remediation); + int remediation, bool logoff); static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, @@ -95,39 +95,46 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, if (sta->flags & WLAN_STA_PREAUTH) { rsn_preauth_send(hapd, sta, buf, len); } else { + int link_id = -1; + +#ifdef CONFIG_IEEE80211BE + link_id = hapd->conf->mld_ap ? hapd->mld_link_id : -1; +#endif /* CONFIG_IEEE80211BE */ hostapd_drv_hapd_send_eapol( hapd, sta->addr, buf, len, - encrypt, hostapd_sta_flags_to_drv(sta->flags)); + encrypt, hostapd_sta_flags_to_drv(sta->flags), link_id); } os_free(buf); } -void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, - struct sta_info *sta, int authorized) +static void ieee802_1x_set_authorized(struct hostapd_data *hapd, + struct sta_info *sta, + bool authorized, bool mld) { int res; + bool update; if (sta->flags & WLAN_STA_PREAUTH) return; - if (authorized) { - ap_sta_set_authorized(hapd, sta, 1); - res = hostapd_set_authorized(hapd, sta, 1); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "authorizing port"); - } else { - ap_sta_set_authorized(hapd, sta, 0); - res = hostapd_set_authorized(hapd, sta, 0); - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, - HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); - } + update = ap_sta_set_authorized_flag(hapd, sta, authorized); + res = hostapd_set_authorized(hapd, sta, authorized); + if (update) + ap_sta_set_authorized_event(hapd, sta, authorized); + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, + HOSTAPD_LEVEL_DEBUG, "%sauthorizing port", + authorized ? "" : "un"); - if (res && errno != ENOENT) { + if (!mld && res && errno != ENOENT) { wpa_printf(MSG_DEBUG, "Could not set station " MACSTR_SEC " flags for kernel driver (errno=%d).", MAC2STR_SEC(sta->addr), errno); + } else if (mld && res) { + wpa_printf(MSG_DEBUG, + "MLD: Could not set station " MACSTR_SEC " flags", + MAC2STR_SEC(sta->addr)); } if (authorized) { @@ -137,6 +144,64 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, } +static void ieee802_1x_ml_set_sta_authorized(struct hostapd_data *hapd, + struct sta_info *sta, + bool authorized) +{ +#ifdef CONFIG_IEEE80211BE + unsigned int i, link_id; + + if (!hostapd_is_mld_ap(hapd)) + return; + + /* + * Authorizing the station should be done only in the station + * performing the association + */ + if (authorized && hapd->mld_link_id != sta->mld_assoc_link_id) + return; + + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + struct mld_link_info *link = &sta->mld_info.links[link_id]; + + if (!link->valid) + continue; + + for (i = 0; i < hapd->iface->interfaces->count; i++) { + struct sta_info *tmp_sta; + struct hostapd_data *tmp_hapd = + hapd->iface->interfaces->iface[i]->bss[0]; + + if (!hostapd_is_ml_partner(hapd, tmp_hapd)) + continue; + + for (tmp_sta = tmp_hapd->sta_list; tmp_sta; + tmp_sta = tmp_sta->next) { + if (tmp_sta == sta || + tmp_sta->mld_assoc_link_id != + sta->mld_assoc_link_id || + tmp_sta->aid != sta->aid) + continue; + + ieee802_1x_set_authorized(tmp_hapd, tmp_sta, + authorized, true); + break; + } + } + } +#endif /* CONFIG_IEEE80211BE */ +} + + + +void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, + struct sta_info *sta, int authorized) +{ + ieee802_1x_set_authorized(hapd, sta, authorized, false); + ieee802_1x_ml_set_sta_authorized(hapd, sta, !!authorized); +} + + #ifdef CONFIG_WEP #ifndef CONFIG_FIPS #ifndef CONFIG_NO_RC4 @@ -702,6 +767,9 @@ void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, goto fail; } + if (!radius_msg_add_msg_auth(msg)) + goto fail; + if (sm->identity && !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, sm->identity, sm->identity_len)) { @@ -998,7 +1066,7 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf, - size_t len) + size_t len, enum frame_encryption encrypted) { if (sta->pending_eapol_rx) { wpabuf_free(sta->pending_eapol_rx->buf); @@ -1016,21 +1084,39 @@ static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf, return; } + sta->pending_eapol_rx->encrypted = encrypted; os_get_reltime(&sta->pending_eapol_rx->rx_time); } +static bool ieee802_1x_check_encryption(struct sta_info *sta, + enum frame_encryption encrypted, + u8 type) +{ + if (encrypted != FRAME_NOT_ENCRYPTED) + return true; + if (type != IEEE802_1X_TYPE_EAP_PACKET && + type != IEEE802_1X_TYPE_EAPOL_START && + type != IEEE802_1X_TYPE_EAPOL_LOGOFF) + return true; + if (!(sta->flags & WLAN_STA_MFP)) + return true; + return !wpa_auth_pairwise_set(sta->wpa_sm); +} + + /** * ieee802_1x_receive - Process the EAPOL frames from the Supplicant * @hapd: hostapd BSS data * @sa: Source address (sender of the EAPOL frame) * @buf: EAPOL frame * @len: Length of buf in octets + * @encrypted: Whether the frame was encrypted * * This function is called for each incoming EAPOL frame from the interface */ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, - size_t len) + size_t len, enum frame_encryption encrypted) { struct sta_info *sta; struct ieee802_1x_hdr *hdr; @@ -1043,8 +1129,9 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, !hapd->conf->wps_state) return; - wpa_printf(MSG_EXCESSIVE, "IEEE 802.1X: %lu bytes from " MACSTR_SEC, - (unsigned long) len, MAC2STR_SEC(sa)); + wpa_printf(MSG_EXCESSIVE, "IEEE 802.1X: %lu bytes from " MACSTR_SEC + " (encrypted=%d)", + (unsigned long) len, MAC2STR_SEC(sa), encrypted); sta = ap_get_sta(hapd, sa); if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { @@ -1054,7 +1141,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, if (sta && (sta->flags & WLAN_STA_AUTH)) { wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR_SEC " for later use", MAC2STR_SEC(sta->addr)); - ieee802_1x_save_eapol(sta, buf, len); + ieee802_1x_save_eapol(sta, buf, len, encrypted); } return; @@ -1114,6 +1201,12 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, return; } + if (!ieee802_1x_check_encryption(sta, encrypted, hdr->type)) { + wpa_printf(MSG_DEBUG, + "IEEE 802.1X: Discard unencrypted EAPOL message - encryption was expected"); + return; + } + if (!sta->eapol_sm) { sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); if (!sta->eapol_sm) @@ -1684,23 +1777,35 @@ static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len) static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd, - struct sta_info *sta, u8 *pos, + struct sta_info *sta, const u8 *pos, size_t len) { + size_t url_len; + unsigned int timeout; + if (len < 3) return; /* Malformed information */ + url_len = len - 3; sta->hs20_deauth_requested = 1; + sta->hs20_deauth_on_ack = url_len == 0; wpa_printf(MSG_DEBUG, - "HS 2.0: Deauthentication request - Code %u Re-auth Delay %u", - *pos, WPA_GET_LE16(pos + 1)); + "HS 2.0: Deauthentication request - Code %u Re-auth Delay %u URL length %zu", + *pos, WPA_GET_LE16(pos + 1), url_len); wpabuf_free(sta->hs20_deauth_req); sta->hs20_deauth_req = wpabuf_alloc(len + 1); if (sta->hs20_deauth_req) { wpabuf_put_data(sta->hs20_deauth_req, pos, 3); - wpabuf_put_u8(sta->hs20_deauth_req, len - 3); - wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3); + wpabuf_put_u8(sta->hs20_deauth_req, url_len); + wpabuf_put_data(sta->hs20_deauth_req, pos + 3, url_len); } - ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout); + timeout = hapd->conf->hs20_deauth_req_timeout; + /* If there is no URL, no need to provide time to fetch it. Use a short + * timeout here to allow maximum time for completing 4-way handshake and + * WNM-Notification delivery. Acknowledgement of the frame will result + * in cutting this wait further. */ + if (!url_len && timeout > 2) + timeout = 2; + ap_sta_session_timeout(hapd, sta, timeout); } @@ -1788,6 +1893,7 @@ static void ieee802_1x_check_hs20(struct hostapd_data *hapd, buf = NULL; sta->remediation = 0; sta->hs20_deauth_requested = 0; + sta->hs20_deauth_on_ack = 0; for (;;) { if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, @@ -1936,16 +2042,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, } sta = sm->sta; - /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be - * present when packet contains an EAP-Message attribute */ - if (hdr->code == RADIUS_CODE_ACCESS_REJECT && - radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, - 0) < 0 && - radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { - wpa_printf(MSG_DEBUG, - "Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message"); - } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, - req, 1)) { + if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 1)) { wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped"); return RADIUS_RX_INVALID_AUTHENTICATOR; @@ -2249,16 +2346,18 @@ static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, } -static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, - int preauth, int remediation) +static bool _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, + int preauth, int remediation, bool logoff) { struct hostapd_data *hapd = ctx; struct sta_info *sta = sta_ctx; - if (preauth) + if (preauth) { rsn_preauth_finished(hapd, sta, success); - else - ieee802_1x_finished(hapd, sta, success, remediation); + return false; + } + + return ieee802_1x_finished(hapd, sta, success, remediation, logoff); } @@ -2434,6 +2533,30 @@ int ieee802_1x_init(struct hostapd_data *hapd) struct eapol_auth_config conf; struct eapol_auth_cb cb; +#ifdef CONFIG_IEEE80211BE + if (!hostapd_mld_is_first_bss(hapd)) { + struct hostapd_data *first; + + first = hostapd_mld_get_first_bss(hapd); + if (!first) + return -1; + + if (!first->eapol_auth) { + wpa_printf(MSG_DEBUG, + "MLD: First BSS IEEE 802.1X state machine does not exist. Init on its behalf"); + + if (ieee802_1x_init(first)) + return -1; + } + + wpa_printf(MSG_DEBUG, + "MLD: Using IEEE 802.1X state machine of the first BSS"); + + hapd->eapol_auth = first->eapol_auth; + return 0; + } +#endif /* CONFIG_IEEE80211BE */ + dl_list_init(&hapd->erp_keys); os_memset(&conf, 0, sizeof(conf)); @@ -2448,6 +2571,9 @@ int ieee802_1x_init(struct hostapd_data *hapd) conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start; conf.erp_domain = hapd->conf->erp_domain; +#ifdef CONFIG_TESTING_OPTIONS + conf.eap_skip_prot_success = hapd->conf->eap_skip_prot_success; +#endif /* CONFIG_TESTING_OPTIONS */ os_memset(&cb, 0, sizeof(cb)); cb.eapol_send = ieee802_1x_eapol_send; @@ -2515,6 +2641,16 @@ void ieee802_1x_erp_flush(struct hostapd_data *hapd) void ieee802_1x_deinit(struct hostapd_data *hapd) { +#ifdef CONFIG_IEEE80211BE + if (!hostapd_mld_is_first_bss(hapd)) { + wpa_printf(MSG_DEBUG, + "MLD: Deinit IEEE 802.1X state machine of a non-first BSS"); + + hapd->eapol_auth = NULL; + return; + } +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_WEP eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); #endif /* CONFIG_WEP */ @@ -2936,9 +3072,9 @@ static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx) #endif /* CONFIG_HS20 */ -static void ieee802_1x_finished(struct hostapd_data *hapd, +static bool ieee802_1x_finished(struct hostapd_data *hapd, struct sta_info *sta, int success, - int remediation) + int remediation, bool logoff) { const u8 *key; size_t len; @@ -2998,6 +3134,11 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, * EAP-FAST with anonymous provisioning, may require another * EAPOL authentication to be started to complete connection. */ - ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta); + ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta, + logoff ? 0 : 10); + if (logoff && sta->wpa_sm) + return true; } + + return false; } diff --git a/wpa_supplicant-2.9_standard/src/ap/ieee802_1x.h b/wpa_supplicant-2.9_standard/src/ap/ieee802_1x.h index 70dc11afec74006b91863d875e0c87f925cf4670..1469351c1e5502b99b802c670c6118a527b01f4c 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ieee802_1x.h +++ b/wpa_supplicant-2.9_standard/src/ap/ieee802_1x.h @@ -19,7 +19,7 @@ struct radius_msg; void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, - size_t len); + size_t len, enum frame_encryption encrypted); void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta); void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta); diff --git a/wpa_supplicant-2.9_standard/src/ap/nan_usd_ap.c b/wpa_supplicant-2.9_standard/src/ap/nan_usd_ap.c new file mode 100644 index 0000000000000000000000000000000000000000..52a967a4ec41b591af5c9fa3bf0239faa1bc2365 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/ap/nan_usd_ap.c @@ -0,0 +1,267 @@ +/* + * NAN unsynchronized service discovery (USD) + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/wpa_ctrl.h" +#include "common/nan_de.h" +#include "hostapd.h" +#include "ap_drv_ops.h" +#include "nan_usd_ap.h" + + +static int hostapd_nan_de_tx(void *ctx, unsigned int freq, + unsigned int wait_time, + const u8 *dst, const u8 *src, const u8 *bssid, + const struct wpabuf *buf) +{ + struct hostapd_data *hapd = ctx; + + wpa_printf(MSG_DEBUG, "NAN: TX NAN SDF A1=" MACSTR " A2=" MACSTR + " A3=" MACSTR " len=%zu", + MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), + wpabuf_len(buf)); + + /* TODO: Force use of OFDM */ + return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst, + wpabuf_head(buf), wpabuf_len(buf)); +} + + +static int hostapd_nan_de_listen(void *ctx, unsigned int freq, + unsigned int duration) +{ + return 0; +} + + +static void +hostapd_nan_de_discovery_result(void *ctx, int subscribe_id, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len, + int peer_publish_id, const u8 *peer_addr, + bool fsd, bool fsd_gas) +{ + struct hostapd_data *hapd = ctx; + char *ssi_hex; + + ssi_hex = os_zalloc(2 * ssi_len + 1); + if (!ssi_hex) + return; + if (ssi) + wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len); + wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_DISCOVERY_RESULT + "subscribe_id=%d publish_id=%d address=" MACSTR + " fsd=%d fsd_gas=%d srv_proto_type=%u ssi=%s", + subscribe_id, peer_publish_id, MAC2STR(peer_addr), + fsd, fsd_gas, srv_proto_type, ssi_hex); + os_free(ssi_hex); +} + + +static void +hostapd_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr, + int peer_subscribe_id, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len) +{ + struct hostapd_data *hapd = ctx; + char *ssi_hex; + + ssi_hex = os_zalloc(2 * ssi_len + 1); + if (!ssi_hex) + return; + if (ssi) + wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len); + wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_REPLIED + "publish_id=%d address=" MACSTR + " subscribe_id=%d srv_proto_type=%u ssi=%s", + publish_id, MAC2STR(peer_addr), peer_subscribe_id, + srv_proto_type, ssi_hex); + os_free(ssi_hex); +} + + +static const char * nan_reason_txt(enum nan_de_reason reason) +{ + switch (reason) { + case NAN_DE_REASON_TIMEOUT: + return "timeout"; + case NAN_DE_REASON_USER_REQUEST: + return "user-request"; + case NAN_DE_REASON_FAILURE: + return "failure"; + } + + return "unknown"; +} + + +static void hostapd_nan_de_publish_terminated(void *ctx, int publish_id, + enum nan_de_reason reason) +{ + struct hostapd_data *hapd = ctx; + + wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_PUBLISH_TERMINATED + "publish_id=%d reason=%s", + publish_id, nan_reason_txt(reason)); +} + + +static void hostapd_nan_de_subscribe_terminated(void *ctx, int subscribe_id, + enum nan_de_reason reason) +{ + struct hostapd_data *hapd = ctx; + + wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_SUBSCRIBE_TERMINATED + "subscribe_id=%d reason=%s", + subscribe_id, nan_reason_txt(reason)); +} + + +static void hostapd_nan_de_receive(void *ctx, int id, int peer_instance_id, + const u8 *ssi, size_t ssi_len, + const u8 *peer_addr) +{ + struct hostapd_data *hapd = ctx; + char *ssi_hex; + + ssi_hex = os_zalloc(2 * ssi_len + 1); + if (!ssi_hex) + return; + if (ssi) + wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len); + wpa_msg(hapd->msg_ctx, MSG_INFO, NAN_RECEIVE + "id=%d peer_instance_id=%d address=" MACSTR " ssi=%s", + id, peer_instance_id, MAC2STR(peer_addr), ssi_hex); + os_free(ssi_hex); +} + + +int hostapd_nan_usd_init(struct hostapd_data *hapd) +{ + struct nan_callbacks cb; + + os_memset(&cb, 0, sizeof(cb)); + cb.ctx = hapd; + cb.tx = hostapd_nan_de_tx; + cb.listen = hostapd_nan_de_listen; + cb.discovery_result = hostapd_nan_de_discovery_result; + cb.replied = hostapd_nan_de_replied; + cb.publish_terminated = hostapd_nan_de_publish_terminated; + cb.subscribe_terminated = hostapd_nan_de_subscribe_terminated; + cb.receive = hostapd_nan_de_receive; + + hapd->nan_de = nan_de_init(hapd->own_addr, true, &cb); + if (!hapd->nan_de) + return -1; + return 0; +} + + +void hostapd_nan_usd_deinit(struct hostapd_data *hapd) +{ + nan_de_deinit(hapd->nan_de); + hapd->nan_de = NULL; +} + + +void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src, + unsigned int freq, const u8 *buf, size_t len) +{ + if (!hapd->nan_de) + return; + nan_de_rx_sdf(hapd->nan_de, src, freq, buf, len); +} + + +void hostapd_nan_usd_flush(struct hostapd_data *hapd) +{ + if (!hapd->nan_de) + return; + nan_de_flush(hapd->nan_de); +} + + +int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, + struct nan_publish_params *params) +{ + int publish_id; + struct wpabuf *elems = NULL; + + if (!hapd->nan_de) + return -1; + + publish_id = nan_de_publish(hapd->nan_de, service_name, srv_proto_type, + ssi, elems, params); + wpabuf_free(elems); + return publish_id; +} + + +void hostapd_nan_usd_cancel_publish(struct hostapd_data *hapd, int publish_id) +{ + if (!hapd->nan_de) + return; + nan_de_cancel_publish(hapd->nan_de, publish_id); +} + + +int hostapd_nan_usd_update_publish(struct hostapd_data *hapd, int publish_id, + const struct wpabuf *ssi) +{ + int ret; + + if (!hapd->nan_de) + return -1; + ret = nan_de_update_publish(hapd->nan_de, publish_id, ssi); + return ret; +} + + +int hostapd_nan_usd_subscribe(struct hostapd_data *hapd, + const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, + struct nan_subscribe_params *params) +{ + int subscribe_id; + struct wpabuf *elems = NULL; + + if (!hapd->nan_de) + return -1; + + subscribe_id = nan_de_subscribe(hapd->nan_de, service_name, + srv_proto_type, ssi, elems, params); + wpabuf_free(elems); + return subscribe_id; +} + + +void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd, + int subscribe_id) +{ + if (!hapd->nan_de) + return; + nan_de_cancel_subscribe(hapd->nan_de, subscribe_id); +} + + +int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle, + const struct wpabuf *ssi, + const struct wpabuf *elems, + const u8 *peer_addr, u8 req_instance_id) +{ + if (!hapd->nan_de) + return -1; + return nan_de_transmit(hapd->nan_de, handle, ssi, elems, peer_addr, + req_instance_id); +} diff --git a/wpa_supplicant-2.9_standard/src/ap/nan_usd_ap.h b/wpa_supplicant-2.9_standard/src/ap/nan_usd_ap.h new file mode 100644 index 0000000000000000000000000000000000000000..58ff5fc4808ba523e5e8e77172940c3ba6c4c08b --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/ap/nan_usd_ap.h @@ -0,0 +1,46 @@ +/* + * NAN unsynchronized service discovery (USD) + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef NAN_USD_AP_H +#define NAN_USD_AP_H + +struct nan_subscribe_params; +struct nan_publish_params; +enum nan_service_protocol_type; + +int hostapd_nan_usd_init(struct hostapd_data *hapd); +void hostapd_nan_usd_deinit(struct hostapd_data *hapd); +void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src, + unsigned int freq, const u8 *buf, size_t len); +void hostapd_nan_usd_flush(struct hostapd_data *hapd); +int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, + struct nan_publish_params *params); +void hostapd_nan_usd_cancel_publish(struct hostapd_data *hapd, int publish_id); +int hostapd_nan_usd_update_publish(struct hostapd_data *hapd, int publish_id, + const struct wpabuf *ssi); +int hostapd_nan_usd_subscribe(struct hostapd_data *hapd, + const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, + struct nan_subscribe_params *params); +void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd, + int subscribe_id); +int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle, + const struct wpabuf *ssi, + const struct wpabuf *elems, + const u8 *peer_addr, u8 req_instance_id); +void hostapd_nan_usd_remain_on_channel_cb(struct hostapd_data *hapd, + unsigned int freq, + unsigned int duration); +void hostapd_nan_usd_cancel_remain_on_channel_cb(struct hostapd_data *hapd, + unsigned int freq); +void hostapd_nan_usd_tx_wait_expire(struct hostapd_data *hapd); + +#endif /* NAN_USD_AP_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/ndisc_snoop.c b/wpa_supplicant-2.9_standard/src/ap/ndisc_snoop.c index 6b5a6e24486c749ba0ceb94daf8d8b8e09c4c89e..83125bc8b723f33151984c053853d85493107c09 100644 --- a/wpa_supplicant-2.9_standard/src/ap/ndisc_snoop.c +++ b/wpa_supplicant-2.9_standard/src/ap/ndisc_snoop.c @@ -61,6 +61,7 @@ void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta) dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr, list) { hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr); + dl_list_del(&ip6addr->list); os_free(ip6addr); } } diff --git a/wpa_supplicant-2.9_standard/src/ap/neighbor_db.c b/wpa_supplicant-2.9_standard/src/ap/neighbor_db.c index 229edd2a94c4ec6765f6349be29b57eb0811555d..f7a7d83d427deb690dbe11d6cd4b1957b5a2c786 100644 --- a/wpa_supplicant-2.9_standard/src/ap/neighbor_db.c +++ b/wpa_supplicant-2.9_standard/src/ap/neighbor_db.c @@ -24,7 +24,7 @@ hostapd_neighbor_get(struct hostapd_data *hapd, const u8 *bssid, dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list) { - if (os_memcmp(bssid, nr->bssid, ETH_ALEN) == 0 && + if (ether_addr_equal(bssid, nr->bssid) && (!ssid || (ssid->ssid_len == nr->ssid.ssid_len && os_memcmp(ssid->ssid, nr->ssid.ssid, @@ -99,7 +99,10 @@ static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr) nr->civic = NULL; os_memset(nr->bssid, 0, sizeof(nr->bssid)); os_memset(&nr->ssid, 0, sizeof(nr->ssid)); + os_memset(&nr->lci_date, 0, sizeof(nr->lci_date)); nr->stationary = 0; + nr->short_ssid = 0; + nr->bss_parameters = 0; } @@ -136,7 +139,7 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid, os_memcpy(entry->bssid, bssid, ETH_ALEN); os_memcpy(&entry->ssid, ssid, sizeof(entry->ssid)); - entry->short_ssid = crc32(ssid->ssid, ssid->ssid_len); + entry->short_ssid = ieee80211_crc32(ssid->ssid, ssid->ssid_len); entry->nr = wpabuf_dup(nr); if (!entry->nr) @@ -165,6 +168,14 @@ fail: } +static void hostapd_neighbor_free(struct hostapd_neighbor_entry *nr) +{ + hostapd_neighbor_clear_entry(nr); + dl_list_del(&nr->list); + os_free(nr); +} + + int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid, const struct wpa_ssid_value *ssid) { @@ -174,9 +185,7 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid, if (!nr) return -1; - hostapd_neighbor_clear_entry(nr); - dl_list_del(&nr->list); - os_free(nr); + hostapd_neighbor_free(nr); return 0; } @@ -188,9 +197,7 @@ void hostapd_free_neighbor_db(struct hostapd_data *hapd) dl_list_for_each_safe(nr, prev, &hapd->nr_db, struct hostapd_neighbor_entry, list) { - hostapd_neighbor_clear_entry(nr); - dl_list_del(&nr->list); - os_free(nr); + hostapd_neighbor_free(nr); } } @@ -199,19 +206,21 @@ void hostapd_free_neighbor_db(struct hostapd_data *hapd) static enum nr_chan_width hostapd_get_nr_chan_width(struct hostapd_data *hapd, int ht, int vht, int he) { - u8 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf); + enum oper_chan_width oper_chwidth; + + oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf); if (!ht && !vht && !he) return NR_CHAN_WIDTH_20; if (!hapd->iconf->secondary_channel) return NR_CHAN_WIDTH_20; - if ((!vht && !he) || oper_chwidth == CHANWIDTH_USE_HT) + if ((!vht && !he) || oper_chwidth == CONF_OPER_CHWIDTH_USE_HT) return NR_CHAN_WIDTH_40; - if (oper_chwidth == CHANWIDTH_80MHZ) + if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ) return NR_CHAN_WIDTH_80; - if (oper_chwidth == CHANWIDTH_160MHZ) + if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) return NR_CHAN_WIDTH_160; - if (oper_chwidth == CHANWIDTH_80P80MHZ) + if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) return NR_CHAN_WIDTH_80P80; return NR_CHAN_WIDTH_20; } @@ -225,6 +234,7 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd) int ht = hapd->iconf->ieee80211n && !hapd->conf->disable_11n; int vht = hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac; int he = hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax; + bool eht = he && hapd->iconf->ieee80211be && !hapd->conf->disable_11be; struct wpa_ssid_value ssid; u8 channel, op_class; u8 center_freq1_idx = 0, center_freq2_idx = 0; @@ -260,10 +270,12 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd) /* VHT bit added in IEEE P802.11-REVmc/D4.3 */ if (vht) bssid_info |= NEI_REP_BSSID_INFO_VHT; - if (he) - bssid_info |= NEI_REP_BSSID_INFO_HE; } + if (he) + bssid_info |= NEI_REP_BSSID_INFO_HE; + if (eht) + bssid_info |= NEI_REP_BSSID_INFO_EHT; /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */ if (ieee80211_freq_to_channel_ext(hapd->iface->freq, @@ -320,3 +332,35 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd) wpabuf_free(nr); #endif /* NEED_AP_MLME */ } + + +static struct hostapd_neighbor_entry * +hostapd_neighbor_get_diff_short_ssid(struct hostapd_data *hapd, const u8 *bssid) +{ + struct hostapd_neighbor_entry *nr; + + dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, + list) { + if (ether_addr_equal(bssid, nr->bssid) && + nr->short_ssid != hapd->conf->ssid.short_ssid) + return nr; + } + return NULL; +} + + +int hostapd_neighbor_sync_own_report(struct hostapd_data *hapd) +{ + struct hostapd_neighbor_entry *nr; + + nr = hostapd_neighbor_get_diff_short_ssid(hapd, hapd->own_addr); + if (!nr) + return -1; + + /* Clear old entry due to SSID change */ + hostapd_neighbor_free(nr); + + hostapd_neighbor_set_own_report(hapd); + + return 0; +} diff --git a/wpa_supplicant-2.9_standard/src/ap/neighbor_db.h b/wpa_supplicant-2.9_standard/src/ap/neighbor_db.h index 992671b62608a8306f3ca4eef9362480313533ec..53f71420322b37f03d16104bcc1033566fbea011 100644 --- a/wpa_supplicant-2.9_standard/src/ap/neighbor_db.h +++ b/wpa_supplicant-2.9_standard/src/ap/neighbor_db.h @@ -20,6 +20,7 @@ int hostapd_neighbor_set(struct hostapd_data *hapd, const u8 *bssid, const struct wpabuf *civic, int stationary, u8 bss_parameters); void hostapd_neighbor_set_own_report(struct hostapd_data *hapd); +int hostapd_neighbor_sync_own_report(struct hostapd_data *hapd); int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid, const struct wpa_ssid_value *ssid); void hostapd_free_neighbor_db(struct hostapd_data *hapd); diff --git a/wpa_supplicant-2.9_standard/src/ap/pmksa_cache_auth.c b/wpa_supplicant-2.9_standard/src/ap/pmksa_cache_auth.c index a14ed035e9a0f4f707a9204c628e15f0eabb036c..51c14fd77cfed0f34de4ab856645dd4ca96d65d3 100644 --- a/wpa_supplicant-2.9_standard/src/ap/pmksa_cache_auth.c +++ b/wpa_supplicant-2.9_standard/src/ap/pmksa_cache_auth.c @@ -40,6 +40,7 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) { os_free(entry->vlan_desc); os_free(entry->identity); + os_free(entry->dpp_pkhash); wpabuf_free(entry->cui); #ifndef CONFIG_NO_RADIUS radius_free_class(&entry->radius_class); @@ -55,7 +56,9 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, unsigned int hash; pmksa->pmksa_count--; - pmksa->free_cb(entry, pmksa->ctx); + + if (pmksa->free_cb) + pmksa->free_cb(entry, pmksa->ctx); /* unlink from hash list */ hash = PMKID_HASH(entry->pmkid); @@ -331,6 +334,10 @@ pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid, return NULL; os_memcpy(entry->pmk, pmk, pmk_len); entry->pmk_len = pmk_len; + if (kck && kck_len && kck_len < WPA_KCK_MAX_LEN) { + os_memcpy(entry->kck, kck, kck_len); + entry->kck_len = kck_len; + } if (pmkid) os_memcpy(entry->pmkid, pmkid, PMKID_LEN); else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) @@ -480,14 +487,14 @@ pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa, for (entry = pmksa->pmkid[PMKID_HASH(pmkid)]; entry; entry = entry->hnext) { if ((spa == NULL || - os_memcmp(entry->spa, spa, ETH_ALEN) == 0) && + ether_addr_equal(entry->spa, spa)) && os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) return entry; } } else { for (entry = pmksa->pmksa; entry; entry = entry->next) { if (spa == NULL || - os_memcmp(entry->spa, spa, ETH_ALEN) == 0) + ether_addr_equal(entry->spa, spa)) return entry; } } @@ -514,7 +521,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( u8 new_pmkid[PMKID_LEN]; for (entry = pmksa->pmksa; entry; entry = entry->next) { - if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0) + if (!ether_addr_equal(entry->spa, spa)) continue; if (wpa_key_mgmt_sae(entry->akmp) || wpa_key_mgmt_fils(entry->akmp)) { @@ -522,8 +529,17 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( return entry; continue; } - rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid, - entry->akmp); + if (entry->akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 && + entry->kck_len > 0) + rsn_pmkid_suite_b_192(entry->kck, entry->kck_len, + aa, spa, new_pmkid); + else if (wpa_key_mgmt_suite_b(entry->akmp) && + entry->kck_len > 0) + rsn_pmkid_suite_b(entry->kck, entry->kck_len, aa, spa, + new_pmkid); + else + rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, + new_pmkid, entry->akmp); if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0) return entry; } @@ -559,7 +575,7 @@ static int das_attr_match(struct rsn_pmksa_cache_entry *entry, int match = 0; if (attr->sta_addr) { - if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0) + if (!ether_addr_equal(attr->sta_addr, entry->spa)) return 0; match++; } @@ -701,7 +717,7 @@ int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr, * */ for (entry = pmksa->pmksa; entry; entry = entry->next) { - if (addr && os_memcmp(entry->spa, addr, ETH_ALEN) != 0) + if (addr && !ether_addr_equal(entry->spa, addr)) continue; ret = os_snprintf(pos, end - pos, MACSTR " ", diff --git a/wpa_supplicant-2.9_standard/src/ap/pmksa_cache_auth.h b/wpa_supplicant-2.9_standard/src/ap/pmksa_cache_auth.h index 2ef217435b11f7bdcbebfb31803184eafef0c20e..e38e7eca66e74cecbf90576afd3f423e1e1092ff 100644 --- a/wpa_supplicant-2.9_standard/src/ap/pmksa_cache_auth.h +++ b/wpa_supplicant-2.9_standard/src/ap/pmksa_cache_auth.h @@ -19,10 +19,14 @@ struct rsn_pmksa_cache_entry { u8 pmkid[PMKID_LEN]; u8 pmk[PMK_LEN_MAX]; size_t pmk_len; + u8 kck[WPA_KCK_MAX_LEN]; + size_t kck_len; os_time_t expiration; int akmp; /* WPA_KEY_MGMT_* */ u8 spa[ETH_ALEN]; + u8 *dpp_pkhash; /* SHA256_MAC_LEN octet hash value of DPP Connector + * public key */ u8 *identity; size_t identity_len; struct wpabuf *cui; diff --git a/wpa_supplicant-2.9_standard/src/ap/preauth_auth.c b/wpa_supplicant-2.9_standard/src/ap/preauth_auth.c index f526c06a86b06b1eeafb625192a2bd37e4eff456..02f795edaba3d211d39ac06d06d45d525e8786c6 100644 --- a/wpa_supplicant-2.9_standard/src/ap/preauth_auth.c +++ b/wpa_supplicant-2.9_standard/src/ap/preauth_auth.c @@ -58,7 +58,7 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr, ethhdr = (struct l2_ethhdr *) buf; hdr = (struct ieee802_1x_hdr *) (ethhdr + 1); - if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(ethhdr->h_dest, hapd->own_addr)) { wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address " MACSTR_SEC, MAC2STR_SEC(ethhdr->h_dest)); return; @@ -90,7 +90,7 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr, return; sta->preauth_iface = piface; ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1), - len - sizeof(*ethhdr)); + len - sizeof(*ethhdr), FRAME_ENCRYPTION_UNKNOWN); } diff --git a/wpa_supplicant-2.9_standard/src/ap/rrm.c b/wpa_supplicant-2.9_standard/src/ap/rrm.c index c6837831d685cfdc56b2b8de971158b0037fb7a8..f6b2a30f8d40499aee6dc2f9628bf883ad28246c 100644 --- a/wpa_supplicant-2.9_standard/src/ap/rrm.c +++ b/wpa_supplicant-2.9_standard/src/ap/rrm.c @@ -334,6 +334,53 @@ static void hostapd_handle_nei_report_req(struct hostapd_data *hapd, } +static void hostapd_link_mesr_rep_timeout_handler(void *eloop_data, + void *user_ctx) +{ + struct hostapd_data *hapd = eloop_data; + + wpa_printf(MSG_DEBUG, + "RRM: Link measurement request (token %u) timed out", + hapd->link_measurement_req_token); + hapd->link_mesr_req_active = 0; +} + + +static void hostapd_handle_link_mesr_report(struct hostapd_data *hapd, + const u8 *buf, size_t len) +{ + const struct ieee80211_mgmt *mgmt = (const struct ieee80211_mgmt *) buf; + const struct rrm_link_measurement_report *report; + const u8 *pos, *end; + char report_msg[2 * 8 + 1]; + + end = buf + len; + pos = mgmt->u.action.u.rrm.variable; + report = (const struct rrm_link_measurement_report *) (pos - 1); + if (end - (const u8 *) report < (int) sizeof(*report)) + return; + + if (!hapd->link_mesr_req_active || + (hapd->link_measurement_req_token != report->dialog_token)) { + wpa_printf(MSG_INFO, + "Unexpected Link measurement report, token %u", + report->dialog_token); + return; + } + + hapd->link_mesr_req_active = 0; + eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL); + + report_msg[0] = '\0'; + if (wpa_snprintf_hex(report_msg, sizeof(report_msg), + pos, end - pos) < 0) + return; + + wpa_msg(hapd->msg_ctx, MSG_DEBUG, LINK_MSR_RESP_RX MACSTR " %u %s", + MAC2STR(mgmt->sa), report->dialog_token, report_msg); +} + + void hostapd_handle_radio_measurement(struct hostapd_data *hapd, const u8 *buf, size_t len) { @@ -356,6 +403,9 @@ void hostapd_handle_radio_measurement(struct hostapd_data *hapd, case WLAN_RRM_NEIGHBOR_REPORT_REQUEST: hostapd_handle_nei_report_req(hapd, buf, len); break; + case WLAN_RRM_LINK_MEASUREMENT_REPORT: + hostapd_handle_link_mesr_report(hapd, buf, len); + break; default: wpa_printf(MSG_DEBUG, "RRM action %u is not supported", mgmt->u.action.u.rrm.action); @@ -563,6 +613,7 @@ void hostapd_clean_rrm(struct hostapd_data *hapd) hapd->lci_req_active = 0; eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd, NULL); hapd->range_req_active = 0; + eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, hapd, NULL); } @@ -672,3 +723,73 @@ void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd, " %u ack=%d", MAC2STR(mgmt->da), mgmt->u.action.u.rrm.dialog_token, ok); } + + +int hostapd_send_link_measurement_req(struct hostapd_data *hapd, const u8 *addr) +{ + struct wpabuf *buf; + struct sta_info *sta; + int ret; + + wpa_printf(MSG_DEBUG, "Request Link Measurement: dest addr " MACSTR, + MAC2STR(addr)); + + if (!(hapd->iface->drv_rrm_flags & + WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) { + wpa_printf(MSG_INFO, + "Request Link Measurement: the driver does not support TX power insertion"); + return -1; + } + + sta = ap_get_sta(hapd, addr); + if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { + wpa_printf(MSG_INFO, + "Request Link Measurement: specied STA is not connected"); + return -1; + } + + if (!(sta->rrm_enabled_capa[0] & WLAN_RRM_CAPS_LINK_MEASUREMENT)) { + wpa_printf(MSG_INFO, + "Request Link Measurement: destination STA does not support link measurement"); + return -1; + } + + if (hapd->link_mesr_req_active) { + wpa_printf(MSG_DEBUG, + "Request Link Measurement: request already in process - overriding"); + hapd->link_mesr_req_active = 0; + eloop_cancel_timeout(hostapd_link_mesr_rep_timeout_handler, + hapd, NULL); + } + + /* Action + Action type + token + Tx Power used + Max Tx Power = 5 */ + buf = wpabuf_alloc(5); + if (!buf) + return -1; + + hapd->link_measurement_req_token++; + if (!hapd->link_measurement_req_token) + hapd->link_measurement_req_token++; + + wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT); + wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REQUEST); + wpabuf_put_u8(buf, hapd->link_measurement_req_token); + /* NOTE: The driver is expected to fill the Tx Power Used and Max Tx + * Power */ + wpabuf_put_u8(buf, 0); + wpabuf_put_u8(buf, 0); + + ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, + wpabuf_head(buf), wpabuf_len(buf)); + wpabuf_free(buf); + if (ret < 0) + return ret; + + hapd->link_mesr_req_active = 1; + + eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0, + hostapd_link_mesr_rep_timeout_handler, hapd, + NULL); + + return hapd->link_measurement_req_token; +} diff --git a/wpa_supplicant-2.9_standard/src/ap/rrm.h b/wpa_supplicant-2.9_standard/src/ap/rrm.h index 02cd522ee9d633c493db700e13baed180bcae022..17751e02c958995caf56c7ca75e6cf4d5dee0148 100644 --- a/wpa_supplicant-2.9_standard/src/ap/rrm.h +++ b/wpa_supplicant-2.9_standard/src/ap/rrm.h @@ -29,5 +29,7 @@ int hostapd_send_beacon_req(struct hostapd_data *hapd, const u8 *addr, void hostapd_rrm_beacon_req_tx_status(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len, int ok); +int hostapd_send_link_measurement_req(struct hostapd_data *hapd, + const u8 *addr); #endif /* RRM_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/sta_info.c b/wpa_supplicant-2.9_standard/src/ap/sta_info.c index 4e3881b9cd9934c3288c79209834868a053f7b77..1fa2802e2e3f1b97ca7246357de7a5ccf357f6fb 100644 --- a/wpa_supplicant-2.9_standard/src/ap/sta_info.c +++ b/wpa_supplicant-2.9_standard/src/ap/sta_info.c @@ -7,6 +7,7 @@ */ #include "utils/includes.h" + #include "utils/common.h" #include "utils/eloop.h" #include "common/ieee802_11_defs.h" @@ -107,7 +108,7 @@ struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr) if (p2p_dev_addr == NULL) continue; - if (os_memcmp(p2p_dev_addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(p2p_dev_addr, addr)) return sta; } @@ -155,7 +156,7 @@ static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta) } while (s->hnext != NULL && - os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0) + !ether_addr_equal(s->hnext->addr, sta->addr)) s = s->hnext; if (s->hnext != NULL) s->hnext = s->hnext->hnext; @@ -195,13 +196,48 @@ void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta) sta->pasn->fils.erp_resp = NULL; #endif /* CONFIG_FILS */ - bin_clear_free(sta->pasn, sizeof(*sta->pasn)); + pasn_data_deinit(sta->pasn); sta->pasn = NULL; } } #endif /* CONFIG_PASN */ + +static void __ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) +{ +#ifdef CONFIG_IEEE80211BE + if (hostapd_sta_is_link_sta(hapd, sta) && + !hostapd_drv_link_sta_remove(hapd, sta->addr)) + return; +#endif /* CONFIG_IEEE80211BE */ + + hostapd_drv_sta_remove(hapd, sta->addr); +} + + +#ifdef CONFIG_IEEE80211BE +static void clear_wpa_sm_for_each_partner_link(struct hostapd_data *hapd, + struct sta_info *psta) +{ + struct sta_info *lsta; + struct hostapd_data *lhapd; + + if (!ap_sta_is_mld(hapd, psta)) + return; + + for_each_mld_link(lhapd, hapd) { + if (lhapd == hapd) + continue; + + lsta = ap_get_sta(lhapd, psta->addr); + if (lsta) + lsta->wpa_sm = NULL; + } +} +#endif /* CONFIG_IEEE80211BE */ + + void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) { int set_beacon = 0; @@ -212,7 +248,11 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) ap_sta_set_authorized(hapd, sta, 0); hostapd_set_sta_flags(hapd, sta); - if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) + if ((sta->flags & WLAN_STA_WDS) || + (sta->flags & WLAN_STA_MULTI_AP && + (hapd->conf->multi_ap & BACKHAUL_BSS) && + hapd->conf->wds_sta && + !(sta->flags & WLAN_STA_WPS))) hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); if (sta->ipaddr) @@ -220,11 +260,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) ap_sta_ip6addr_del(hapd, sta); if (!hapd->iface->driver_ap_teardown && - !(sta->flags & WLAN_STA_PREAUTH) && - !(sta->flags & WLAN_STA_P2PGO_WPS_NO_SECOND_DISASSOC)) { - wpa_printf(MSG_INFO, - "WLAN_STA_P2PGO_WPS_NO_SECOND_DISASSOC is not set, not in P2P_GO_WSC ending process"); - hostapd_drv_sta_remove(hapd, sta->addr); + !(sta->flags & WLAN_STA_PREAUTH)) { + __ap_free_sta(hapd, sta); sta->added_unassoc = 0; } @@ -305,9 +342,9 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) #endif /* CONFIG_MESH */ if (set_beacon) - ieee802_11_set_beacons(hapd->iface); + ieee802_11_update_beacons(hapd->iface); - wpa_printf(MSG_EXCESSIVE, "%s: cancel ap_handle_timer for " MACSTR_SEC, + wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR_SEC, __func__, MAC2STR_SEC(sta->addr)); eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); @@ -316,7 +353,23 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) sae_clear_retransmit_timer(hapd, sta); ieee802_1x_free_station(hapd, sta); + +#ifdef CONFIG_IEEE80211BE + if (!ap_sta_is_mld(hapd, sta) || + hapd->mld_link_id == sta->mld_assoc_link_id) { + wpa_auth_sta_deinit(sta->wpa_sm); + /* Remove references from partner links. */ + clear_wpa_sm_for_each_partner_link(hapd, sta); + } + + /* Release group references in case non-association link STA is removed + * before association link STA */ + if (hostapd_sta_is_link_sta(hapd, sta)) + wpa_release_link_auth_ref(sta->wpa_sm, hapd->mld_link_id); +#else /* CONFIG_IEEE80211BE */ wpa_auth_sta_deinit(sta->wpa_sm); +#endif /* CONFIG_IEEE80211BE */ + rsn_preauth_free_station(hapd, sta); #ifndef CONFIG_NO_RADIUS if (hapd->radius) @@ -337,7 +390,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) * VLAN. */ if (hapd->iface->driver_ap_teardown && - !(sta->flags & WLAN_STA_PREAUTH)) { + !(sta->flags & WLAN_STA_PREAUTH) && + !(sta->flags & WLAN_STA_P2PGO_WPS_NO_SECOND_DISASSOC)) { + wpa_printf(MSG_INFO, + "WLAN_STA_P2PGO_WPS_NO_SECOND_DISASSOC is not set, not in P2P_GO_WSC ending process"); hostapd_drv_sta_remove(hapd, sta->addr); sta->added_unassoc = 0; } @@ -357,6 +413,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) #ifdef CONFIG_INTERWORKING if (sta->gas_dialog) { int i; + for (i = 0; i < GAS_DIALOG_MAX; i++) gas_serv_dialog_clear(&sta->gas_dialog[i]); os_free(sta->gas_dialog); @@ -376,6 +433,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) os_free(sta->vht_operation); os_free(sta->he_capab); os_free(sta->he_6ghz_capab); + os_free(sta->eht_capab); hostapd_free_psk_list(sta->psk); os_free(sta->identity); os_free(sta->radius_cui); @@ -426,8 +484,13 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) os_free(sta->ifname_wds); +#ifdef CONFIG_IEEE80211BE + ap_sta_free_sta_profile(&sta->mld_info); +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_TESTING_OPTIONS os_free(sta->sae_postponed_commit); + forced_memzero(sta->last_tk, WPA_TK_MAX_LEN); #endif /* CONFIG_TESTING_OPTIONS */ os_free(sta); @@ -454,6 +517,27 @@ void hostapd_free_stas(struct hostapd_data *hapd) } +#ifdef CONFIG_IEEE80211BE +void hostapd_free_link_stas(struct hostapd_data *hapd) +{ + struct sta_info *sta, *prev; + + sta = hapd->sta_list; + while (sta) { + prev = sta; + sta = sta->next; + + if (!hostapd_sta_is_link_sta(hapd, prev)) + continue; + + wpa_printf(MSG_DEBUG, "Removing link station from MLD " MACSTR, + MAC2STR(prev->addr)); + ap_free_sta(hapd, prev); + } +} +#endif /* CONFIG_IEEE80211BE */ + + /** * ap_handle_timer - Per STA timer handler * @eloop_ctx: struct hostapd_data * @@ -468,6 +552,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) struct sta_info *sta = timeout_ctx; unsigned long next_time = 0; int reason; + int max_inactivity = hapd->conf->ap_max_inactivity; wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR_SEC " flags=0x%x timeout_next=%d", hapd->conf->iface, __func__, MAC2STR_SEC(sta->addr), sta->flags, @@ -480,6 +565,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) return; } + if (sta->max_idle_period) + max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000; + if ((sta->flags & WLAN_STA_ASSOC) && (sta->timeout_next == STA_NULLFUNC || sta->timeout_next == STA_DISASSOC)) { @@ -504,7 +592,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) * Anyway, try again after the next inactivity timeout, * but do not disconnect the station now. */ - next_time = hapd->conf->ap_max_inactivity + fuzz; + next_time = max_inactivity + fuzz; } else if (inactive_sec == -ENOENT) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " has lost its driver entry", @@ -513,20 +601,19 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) /* Avoid sending client probe on removed client */ sta->timeout_next = STA_DISASSOC; goto skip_poll; - } else if (inactive_sec < hapd->conf->ap_max_inactivity) { + } else if (inactive_sec < max_inactivity) { /* station activity detected; reset timeout state */ wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " has been active %is ago", MAC2STR(sta->addr), inactive_sec); sta->timeout_next = STA_NULLFUNC; - next_time = hapd->conf->ap_max_inactivity + fuzz - - inactive_sec; + next_time = max_inactivity + fuzz - inactive_sec; } else { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " has been " "inactive too long: %d sec, max allowed: %d", MAC2STR(sta->addr), inactive_sec, - hapd->conf->ap_max_inactivity); + max_inactivity); if (hapd->conf->skip_inactivity_poll) sta->timeout_next = STA_DISASSOC; @@ -542,7 +629,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) /* data nullfunc frame poll did not produce TX errors; assume * station ACKed it */ sta->timeout_next = STA_NULLFUNC; - next_time = hapd->conf->ap_max_inactivity; + next_time = max_inactivity; } skip_poll: @@ -730,6 +817,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) { struct sta_info *sta; int i; + int max_inactivity = hapd->conf->ap_max_inactivity; sta = ap_get_sta(hapd, addr); if (sta) @@ -763,12 +851,15 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) } sta->supported_rates_len = i; + if (sta->max_idle_period) + max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000; + if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) { wpa_printf(MSG_EXCESSIVE, "%s: register ap_handle_timer timeout " "for " MACSTR_SEC " (%d seconds - ap_max_inactivity)", __func__, MAC2STR_SEC(addr), - hapd->conf->ap_max_inactivity); - eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, + max_inactivity); + eloop_register_timeout(max_inactivity, 0, ap_handle_timer, hapd, sta); } @@ -854,12 +945,42 @@ static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx) } -void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, - u16 reason) +static void ap_sta_disconnect_common(struct hostapd_data *hapd, + struct sta_info *sta, unsigned int timeout) +{ + sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; + + ap_sta_set_authorized(hapd, sta, 0); + hostapd_set_sta_flags(hapd, sta); + + wpa_printf(MSG_DEBUG, + "reschedule ap_handle_timer timeout (%u sec) for " MACSTR_SEC, + timeout, MAC2STR_SEC(sta->addr)); + + eloop_cancel_timeout(ap_handle_timer, hapd, sta); + eloop_register_timeout(timeout, 0, ap_handle_timer, hapd, sta); + accounting_sta_stop(hapd, sta); + ieee802_1x_free_station(hapd, sta); +#ifdef CONFIG_IEEE80211BE + if (!hapd->conf->mld_ap || + hapd->mld_link_id == sta->mld_assoc_link_id) { + wpa_auth_sta_deinit(sta->wpa_sm); + clear_wpa_sm_for_each_partner_link(hapd, sta); + } +#else /* CONFIG_IEEE80211BE */ + wpa_auth_sta_deinit(sta->wpa_sm); +#endif /* CONFIG_IEEE80211BE */ + + sta->wpa_sm = NULL; +} + + +static void ap_sta_handle_disassociate(struct hostapd_data *hapd, + struct sta_info *sta, u16 reason) { wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR_SEC, hapd->conf->iface, MAC2STR_SEC(sta->addr)); - sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; + if (hapd->iface->current_mode && hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { /* Skip deauthentication in DMG/IEEE 802.11ad */ @@ -870,20 +991,8 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); sta->timeout_next = STA_DEAUTH; } - ap_sta_set_authorized(hapd, sta, 0); - hostapd_set_sta_flags(hapd, sta); - wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " - "for " MACSTR_SEC " (%d seconds - " - "AP_MAX_INACTIVITY_AFTER_DISASSOC)", - __func__, MAC2STR_SEC(sta->addr), - AP_MAX_INACTIVITY_AFTER_DISASSOC); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0, - ap_handle_timer, hapd, sta); - accounting_sta_stop(hapd, sta); - ieee802_1x_free_station(hapd, sta); - wpa_auth_sta_deinit(sta->wpa_sm); - sta->wpa_sm = NULL; + + ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DISASSOC); sta->disassoc_reason = reason; sta->flags |= WLAN_STA_PENDING_DISASSOC_CB; @@ -906,8 +1015,8 @@ static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx) } -void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, - u16 reason) +static void ap_sta_handle_deauthenticate(struct hostapd_data *hapd, + struct sta_info *sta, u16 reason) { if (hapd->iface->current_mode && hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { @@ -919,21 +1028,11 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR_SEC, hapd->conf->iface, MAC2STR_SEC(sta->addr)); - sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); - ap_sta_set_authorized(hapd, sta, 0); - hostapd_set_sta_flags(hapd, sta); + sta->timeout_next = STA_REMOVE; - wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " - "for " MACSTR_SEC " (%d seconds - " - "AP_MAX_INACTIVITY_AFTER_DEAUTH)", - __func__, MAC2STR_SEC(sta->addr), - AP_MAX_INACTIVITY_AFTER_DEAUTH); - eloop_cancel_timeout(ap_handle_timer, hapd, sta); - eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, - ap_handle_timer, hapd, sta); - accounting_sta_stop(hapd, sta); - ieee802_1x_free_station(hapd, sta); + ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH); sta->deauth_reason = reason; sta->flags |= WLAN_STA_PENDING_DEAUTH_CB; @@ -944,6 +1043,104 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, } +static bool ap_sta_ml_disconnect(struct hostapd_data *hapd, + struct sta_info *sta, u16 reason, + bool disassoc) +{ +#ifdef CONFIG_IEEE80211BE + struct hostapd_data *assoc_hapd, *tmp_hapd; + struct sta_info *assoc_sta; + unsigned int i, link_id; + struct hapd_interfaces *interfaces; + + if (!hostapd_is_mld_ap(hapd)) + return false; + + /* + * Get the station on which the association was performed, as it holds + * the information about all the other links. + */ + assoc_sta = hostapd_ml_get_assoc_sta(hapd, sta, &assoc_hapd); + if (!assoc_sta) + return false; + interfaces = assoc_hapd->iface->interfaces; + + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!assoc_sta->mld_info.links[link_id].valid) + continue; + + for (i = 0; i < interfaces->count; i++) { + struct sta_info *tmp_sta; + + tmp_hapd = interfaces->iface[i]->bss[0]; + + if (!hostapd_is_ml_partner(tmp_hapd, assoc_hapd)) + continue; + + for (tmp_sta = tmp_hapd->sta_list; tmp_sta; + tmp_sta = tmp_sta->next) { + /* + * Handle the station on which the association + * was done only after all other link station + * are removed. Since there is a only a single + * station per hapd with the same association + * link simply break; + */ + if (tmp_sta == assoc_sta) + break; + + if (tmp_sta->mld_assoc_link_id != + assoc_sta->mld_assoc_link_id || + tmp_sta->aid != assoc_sta->aid) + continue; + + if (disassoc) + ap_sta_handle_disassociate(tmp_hapd, + tmp_sta, + reason); + else + ap_sta_handle_deauthenticate(tmp_hapd, + tmp_sta, + reason); + + break; + } + } + } + + /* Disconnect the station on which the association was performed. */ + if (disassoc) + ap_sta_handle_disassociate(assoc_hapd, assoc_sta, reason); + else + ap_sta_handle_deauthenticate(assoc_hapd, assoc_sta, reason); + + return true; +#else /* CONFIG_IEEE80211BE */ + return false; +#endif /* CONFIG_IEEE80211BE */ +} + + +void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, + u16 reason) +{ + if (ap_sta_ml_disconnect(hapd, sta, reason, true)) + return; + + ap_sta_handle_disassociate(hapd, sta, reason); +} + + +void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, + u16 reason) +{ + if (ap_sta_ml_disconnect(hapd, sta, reason, false)) + return; + + ap_sta_handle_deauthenticate(hapd, sta, reason); +} + + #ifdef CONFIG_WPS int ap_sta_wps_cancel(struct hostapd_data *hapd, struct sta_info *sta, void *ctx) @@ -1087,6 +1284,12 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta) struct hostapd_vlan *vlan = NULL; int ret; int old_vlanid = sta->vlan_id_bound; + int mld_link_id = -1; + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap) + mld_link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) { wpa_printf(MSG_DEBUG, @@ -1144,7 +1347,8 @@ skip_counting: if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0) wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA"); - ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id); + ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id, + mld_link_id); if (ret < 0) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "could not bind the STA " @@ -1272,8 +1476,6 @@ const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd, for (psk = ssid->wpa_psk; psk; psk = psk->next) if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0) break; - if (!psk) - return NULL; if (!psk || !psk->keyid[0]) return NULL; @@ -1281,8 +1483,44 @@ const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd, } -void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, - int authorized) +const u8 * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd, + struct sta_info *sta) +{ + return wpa_auth_get_dpp_pkhash(sta->wpa_sm); +} + + +bool ap_sta_set_authorized_flag(struct hostapd_data *hapd, struct sta_info *sta, + int authorized) +{ + if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) + return false; + + if (authorized) { + int mld_assoc_link_id = -1; + +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) { + if (sta->mld_assoc_link_id == hapd->mld_link_id) + mld_assoc_link_id = sta->mld_assoc_link_id; + else + mld_assoc_link_id = -2; + } +#endif /* CONFIG_IEEE80211BE */ + if (mld_assoc_link_id != -2) + hostapd_prune_associations(hapd, sta->addr, + mld_assoc_link_id); + sta->flags |= WLAN_STA_AUTHORIZED; + } else { + sta->flags &= ~WLAN_STA_AUTHORIZED; + } + + return true; +} + + +void ap_sta_set_authorized_event(struct hostapd_data *hapd, + struct sta_info *sta, int authorized) { const u8 *dev_addr = NULL; char buf[100]; @@ -1296,15 +1534,8 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, #endif /* CONFIG_P2P */ #ifdef CONFIG_LIBWPA_VENDOR int result; -#endif - - if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED)) - return; - - if (authorized) - sta->flags |= WLAN_STA_AUTHORIZED; - else - sta->flags &= ~WLAN_STA_AUTHORIZED; +#endif /* CONFIG_P2P */ + const u8 *ip_ptr = NULL; #ifdef CONFIG_P2P if (hapd->p2p_group == NULL) { @@ -1329,20 +1560,14 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, wpa_printf(MSG_INFO, MACSTR_SEC, MAC2STR_SEC(sta->addr)); } - if (hapd->sta_authorized_cb) - hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx, sta->addr, authorized, -#ifdef CONFIG_WIFI_RPT - (dev_addr ? dev_addr : sta->addr) -#else - dev_addr -#endif /* CONFIG_WIFI_RPT */ - ); - if (authorized) { + const u8 *dpp_pkhash; const char *keyid; + char dpp_pkhash_buf[100]; char keyid_buf[100]; char ip_addr[100]; + dpp_pkhash_buf[0] = '\0'; keyid_buf[0] = '\0'; ip_addr[0] = '\0'; #ifdef CONFIG_P2P @@ -1351,6 +1576,7 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, " ip_addr=%u.%u.%u.%u", ip_addr_buf[0], ip_addr_buf[1], ip_addr_buf[2], ip_addr_buf[3]); + ip_ptr = ip_addr_buf; } #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) peer = hm_p2p_find_peer(dev_addr); @@ -1428,14 +1654,29 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, #endif wpa_printf(MSG_INFO, AP_STA_CONNECTED); + dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta); + if (dpp_pkhash) { + const char *prefix = " dpp_pkhash="; + size_t plen = os_strlen(prefix); + + os_strlcpy(dpp_pkhash_buf, prefix, + sizeof(dpp_pkhash_buf)); + wpa_snprintf_hex(&dpp_pkhash_buf[plen], + sizeof(dpp_pkhash_buf) - plen, + dpp_pkhash, SHA256_MAC_LEN); + } + + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s", + buf, ip_addr, keyid_buf, dpp_pkhash_buf); + if (hapd->msg_ctx_parent && hapd->msg_ctx_parent != hapd->msg_ctx) { wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_CONNECTED "%s%s%s", - buf, ip_addr, - keyid_buf); + AP_STA_CONNECTED "%s%s%s%s", + buf, ip_addr, keyid_buf, + dpp_pkhash_buf); wpa_printf(MSG_INFO, AP_STA_CONNECTED); - } + } } else { #ifdef CONFIG_VENDOR_EXT int ret = wpa_vendor_ext_ap_disconnect(hapd, buf); @@ -1502,9 +1743,18 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); wpa_printf(MSG_INFO, AP_STA_DISCONNECTED); - } + } } + if (hapd->sta_authorized_cb) + hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx, sta->addr, authorized, +#ifdef CONFIG_WIFI_RPT + (dev_addr ? dev_addr : sta->addr), +#else + dev_addr, +#endif /* CONFIG_WIFI_RPT */ + ip_ptr); + #ifdef CONFIG_FST if (hapd->iface->fst) { if (authorized) @@ -1517,6 +1767,15 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, } +void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, + int authorized) +{ + if (!ap_sta_set_authorized_flag(hapd, sta, authorized)) + return; + ap_sta_set_authorized_event(hapd, sta, authorized); +} + + void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, const u8 *addr, u16 reason) { @@ -1638,7 +1897,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) buf[0] = '\0'; res = os_snprintf(buf, buflen, - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", (flags & WLAN_STA_AUTH ? "[AUTH]" : ""), (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""), (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""), @@ -1658,6 +1917,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen) (flags & WLAN_STA_HT ? "[HT]" : ""), (flags & WLAN_STA_VHT ? "[VHT]" : ""), (flags & WLAN_STA_HE ? "[HE]" : ""), + (flags & WLAN_STA_EHT ? "[EHT]" : ""), (flags & WLAN_STA_6GHZ ? "[6GHZ]" : ""), (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""), (flags & WLAN_STA_WNM_SLEEP_MODE ? @@ -1698,13 +1958,14 @@ static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx) void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, - struct sta_info *sta) + struct sta_info *sta, + unsigned timeout) { wpa_msg_only_for_cb(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force disconnection of " MACSTR - " after EAP-Failure in 10 ms", MAC2STR(sta->addr)); + " after EAP-Failure in %u ms", MAC2STR(sta->addr), timeout); wpa_printf(MSG_DEBUG, "IEEE 802.1X: Force disconnection of " MACSTR_SEC - " after EAP-Failure in 10 ms", MAC2STR_SEC(sta->addr)); + " after EAP-Failure in %u ms", MAC2STR_SEC(sta->addr), timeout); /* * Add a small sleep to increase likelihood of previously requested @@ -1712,8 +1973,8 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, * operations. */ eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta); - eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb, - hapd, sta); + eloop_register_timeout(0, timeout * 1000, + ap_sta_delayed_1x_auth_fail_cb, hapd, sta); } @@ -1725,8 +1986,37 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, } +#ifdef CONFIG_IEEE80211BE +static void ap_sta_remove_link_sta(struct hostapd_data *hapd, + struct sta_info *sta) +{ + struct hostapd_data *tmp_hapd; + + for_each_mld_link(tmp_hapd, hapd) { + struct sta_info *tmp_sta; + + if (hapd == tmp_hapd) + continue; + + for (tmp_sta = tmp_hapd->sta_list; tmp_sta; + tmp_sta = tmp_sta->next) { + if (tmp_sta == sta || + !ether_addr_equal(tmp_sta->addr, sta->addr)) + continue; + + ap_free_sta(tmp_hapd, tmp_sta); + break; + } + } +} +#endif /* CONFIG_IEEE80211BE */ + + int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta) { + const u8 *mld_link_addr = NULL; + bool mld_link_sta = false; + /* * If a station that is already associated to the AP, is trying to * authenticate again, remove the STA entry, in order to make sure the @@ -1734,6 +2024,22 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta) * this, station's added_unassoc flag is cleared once the station has * completed association. */ + +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) { + u8 mld_link_id = hapd->mld_link_id; + + mld_link_sta = sta->mld_assoc_link_id != mld_link_id; + mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr; + + /* + * In case the AP is affiliated with an AP MLD, we need to + * remove the station from all relevant links/APs. + */ + ap_sta_remove_link_sta(hapd, sta); + } +#endif /* CONFIG_IEEE80211BE */ + ap_sta_set_authorized(hapd, sta, 0); hostapd_drv_sta_remove(hapd, sta->addr); sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED); @@ -1741,8 +2047,9 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta) if (hostapd_sta_add(hapd, sta->addr, 0, 0, sta->supported_rates, sta->supported_rates_len, - 0, NULL, NULL, NULL, 0, NULL, - sta->flags, 0, 0, 0, 0)) { + 0, NULL, NULL, NULL, 0, NULL, 0, NULL, + sta->flags, 0, 0, 0, 0, + mld_link_addr, mld_link_sta)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, @@ -1753,3 +2060,19 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta) sta->added_unassoc = 1; return 0; } + + +#ifdef CONFIG_IEEE80211BE +void ap_sta_free_sta_profile(struct mld_info *info) +{ + int i; + + if (!info) + return; + + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + os_free(info->links[i].resp_sta_profile); + info->links[i].resp_sta_profile = NULL; + } +} +#endif /* CONFIG_IEEE80211BE */ diff --git a/wpa_supplicant-2.9_standard/src/ap/sta_info.h b/wpa_supplicant-2.9_standard/src/ap/sta_info.h index b98fa2bef61784ccd0c6ae070907582a5d6f2aeb..b3f386244e99d464755b1c7d1958c837479f637c 100644 --- a/wpa_supplicant-2.9_standard/src/ap/sta_info.h +++ b/wpa_supplicant-2.9_standard/src/ap/sta_info.h @@ -16,6 +16,8 @@ #include "common/ieee802_11_defs.h" #include "common/sae.h" #include "crypto/sha384.h" +#include "pasn/pasn_common.h" +#include "hostapd.h" /* STA flags */ #define WLAN_STA_AUTH BIT(0) @@ -42,7 +44,8 @@ #define WLAN_STA_HE BIT(24) #define WLAN_STA_6GHZ BIT(25) #define WLAN_STA_PENDING_PASN_FILS_ERP BIT(26) -#define WLAN_STA_P2PGO_WPS_NO_SECOND_DISASSOC BIT(27) +#define WLAN_STA_P2PGO_WPS_NO_SECOND_DISASSOC BIT(28) +#define WLAN_STA_EHT BIT(27) #define WLAN_STA_PENDING_DISASSOC_CB BIT(29) #define WLAN_STA_PENDING_DEAUTH_CB BIT(30) #define WLAN_STA_NONERP BIT(31) @@ -65,43 +68,34 @@ struct mbo_non_pref_chan_info { struct pending_eapol_rx { struct wpabuf *buf; struct os_reltime rx_time; + enum frame_encryption encrypted; }; -enum pasn_fils_state { - PASN_FILS_STATE_NONE = 0, - PASN_FILS_STATE_PENDING_AS, - PASN_FILS_STATE_COMPLETE -}; +#define EHT_ML_MAX_STA_PROF_LEN 1024 +struct mld_info { + bool mld_sta; -struct pasn_fils_data { - u8 state; - u8 nonce[FILS_NONCE_LEN]; - u8 anonce[FILS_NONCE_LEN]; - u8 session[FILS_SESSION_LEN]; - u8 erp_pmkid[PMKID_LEN]; + struct ml_common_info { + u8 mld_addr[ETH_ALEN]; + u16 medium_sync_delay; + u16 eml_capa; + u16 mld_capa; + } common_info; - struct wpabuf *erp_resp; -}; + struct mld_link_info { + u8 valid:1; + u8 nstr_bitmap_len:2; + u8 local_addr[ETH_ALEN]; + u8 peer_addr[ETH_ALEN]; -struct pasn_data { - int akmp; - int cipher; - u16 group; - u8 trans_seq; - u8 wrapped_data_format; - size_t kdk_len; + u8 nstr_bitmap[2]; - u8 hash[SHA384_MAC_LEN]; - struct wpa_ptk ptk; - struct crypto_ecdh *ecdh; + u16 capability; - struct wpabuf *secret; -#ifdef CONFIG_SAE - struct sae_data sae; -#endif /* CONFIG_SAE */ -#ifdef CONFIG_FILS - struct pasn_fils_data fils; -#endif /* CONFIG_FILS */ + u16 status; + u16 resp_sta_profile_len; + u8 *resp_sta_profile; + } links[MAX_NUM_MLD_LINKS]; }; struct sta_info { @@ -153,6 +147,7 @@ struct sta_info { unsigned int qos_map_enabled:1; unsigned int remediation:1; unsigned int hs20_deauth_requested:1; + unsigned int hs20_deauth_on_ack:1; unsigned int session_timeout_set:1; unsigned int radius_das_match:1; unsigned int ecsa_supported:1; @@ -214,6 +209,8 @@ struct sta_info { struct ieee80211_he_capabilities *he_capab; size_t he_capab_len; struct ieee80211_he_6ghz_band_cap *he_6ghz_capab; + struct ieee80211_eht_capabilities *eht_capab; + size_t eht_capab_len; int sa_query_count; /* number of pending SA Query requests; * 0 = no SA Query in progress */ @@ -331,6 +328,14 @@ struct sta_info { #ifdef CONFIG_PASN struct pasn_data *pasn; #endif /* CONFIG_PASN */ + +#ifdef CONFIG_IEEE80211BE + struct mld_info mld_info; + u8 mld_assoc_link_id; +#endif /* CONFIG_IEEE80211BE */ + + u16 max_idle_period; /* if nonzero, the granted BSS max idle period in + * units of 1000 TUs */ }; @@ -386,9 +391,15 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta); int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta); const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd, struct sta_info *sta); +const u8 * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd, + struct sta_info *sta); void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, const u8 *addr, u16 reason); +bool ap_sta_set_authorized_flag(struct hostapd_data *hapd, struct sta_info *sta, + int authorized); +void ap_sta_set_authorized_event(struct hostapd_data *hapd, + struct sta_info *sta, int authorized); void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized); static inline int ap_sta_is_authorized(struct sta_info *sta) @@ -403,11 +414,34 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd, int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen); void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, - struct sta_info *sta); + struct sta_info *sta, + unsigned timeout); int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, struct sta_info *sta); int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta); void ap_free_sta_pasn(struct hostapd_data *hapd, struct sta_info *sta); +static inline bool ap_sta_is_mld(struct hostapd_data *hapd, + struct sta_info *sta) +{ +#ifdef CONFIG_IEEE80211BE + return hapd->conf->mld_ap && sta && sta->mld_info.mld_sta; +#else /* CONFIG_IEEE80211BE */ + return false; +#endif /* CONFIG_IEEE80211BE */ +} + +static inline void ap_sta_set_mld(struct sta_info *sta, bool mld) +{ +#ifdef CONFIG_IEEE80211BE + if (sta) + sta->mld_info.mld_sta = mld; +#endif /* CONFIG_IEEE80211BE */ +} + +void ap_sta_free_sta_profile(struct mld_info *info); + +void hostapd_free_link_stas(struct hostapd_data *hapd); + #endif /* STA_INFO_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/utils.c b/wpa_supplicant-2.9_standard/src/ap/utils.c index fc3ab1cbe02e10ee484d808a3e0c0a4e9cbae7fc..283a65648f1938da9610db0616d027a4bf862f27 100644 --- a/wpa_supplicant-2.9_standard/src/ap/utils.c +++ b/wpa_supplicant-2.9_standard/src/ap/utils.c @@ -43,6 +43,7 @@ int hostapd_register_probereq_cb(struct hostapd_data *hapd, struct prune_data { struct hostapd_data *hapd; const u8 *addr; + int mld_assoc_link_id; }; static int prune_associations(struct hostapd_iface *iface, void *ctx) @@ -72,6 +73,12 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx) if (!osta) continue; +#ifdef CONFIG_IEEE80211BE + if (data->mld_assoc_link_id >= 0 && + osta->mld_assoc_link_id == data->mld_assoc_link_id) + continue; +#endif /* CONFIG_IEEE80211BE */ + wpa_printf(MSG_INFO, "%s: Prune association for " MACSTR_SEC, ohapd->conf->iface, MAC2STR_SEC(osta->addr)); ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED); @@ -84,15 +91,20 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx) * hostapd_prune_associations - Remove extraneous associations * @hapd: Pointer to BSS data for the most recent association * @addr: Associated STA address + * @mld_assoc_link_id: MLD link id used for association or -1 for non MLO * * This function looks through all radios and BSS's for previous * (stale) associations of STA. If any are found they are removed. */ -void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr) +void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr, + int mld_assoc_link_id) { struct prune_data data; + data.hapd = hapd; data.addr = addr; + data.mld_assoc_link_id = mld_assoc_link_id; + if (hapd->iface->interfaces && hapd->iface->interfaces->for_each_interface) hapd->iface->interfaces->for_each_interface( diff --git a/wpa_supplicant-2.9_standard/src/ap/wmm.c b/wpa_supplicant-2.9_standard/src/ap/wmm.c index 623ab9aed0a8dbaeaf84b541381c505332bc54f6..623df36d9bc069c1f8295e6a42523a1a5af6b2b5 100644 --- a/wpa_supplicant-2.9_standard/src/ap/wmm.c +++ b/wpa_supplicant-2.9_standard/src/ap/wmm.c @@ -20,13 +20,6 @@ #include "ap_drv_ops.h" #include "wmm.h" -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci) { diff --git a/wpa_supplicant-2.9_standard/src/ap/wnm_ap.c b/wpa_supplicant-2.9_standard/src/ap/wnm_ap.c index 2fd1a518004c6e21bf8f6bf11d50d214c89cd23b..1226eee3f4e0d8795b26fdc42a833c136f2dfd95 100644 --- a/wpa_supplicant-2.9_standard/src/ap/wnm_ap.c +++ b/wpa_supplicant-2.9_standard/src/ap/wnm_ap.c @@ -44,6 +44,20 @@ static int ieee80211_11_set_tfs_ie(struct hostapd_data *hapd, const u8 *addr, } +static const u8 * wnm_ap_get_own_addr(struct hostapd_data *hapd, + struct sta_info *sta) +{ + const u8 *own_addr = hapd->own_addr; + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap && (!sta || ap_sta_is_mld(hapd, sta))) + own_addr = hapd->mld->mld_addr; +#endif /* CONFIG_IEEE80211BE */ + + return own_addr; +} + + /* MLME-SLEEPMODE.response */ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, @@ -63,6 +77,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, struct sta_info *sta; enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ? WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE; + const u8 *own_addr; sta = ap_get_sta(hapd, addr); if (sta == NULL) { @@ -143,9 +158,12 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, res = -1; goto fail; } + + own_addr = wnm_ap_get_own_addr(hapd, sta); + os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->sa, own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; @@ -366,6 +384,8 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd, u8 dialog_token) { struct ieee80211_mgmt *mgmt; + const u8 *own_addr; + struct sta_info *sta; size_t len; u8 *pos; int res; @@ -373,9 +393,13 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd, mgmt = os_zalloc(sizeof(*mgmt)); if (mgmt == NULL) return -1; + + sta = ap_get_sta(hapd, addr); + own_addr = wnm_ap_get_own_addr(hapd, sta); + os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->sa, own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); mgmt->u.action.category = WLAN_ACTION_WNM; @@ -409,6 +433,8 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd, u8 dialog_token, reason; const u8 *pos, *end; int enabled = hapd->conf->bss_transition; + char *hex = NULL; + size_t hex_len; #ifdef CONFIG_MBO if (hapd->conf->mbo_enabled) @@ -441,6 +467,17 @@ static void ieee802_11_rx_bss_trans_mgmt_query(struct hostapd_data *hapd, wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", pos, end - pos); + hex_len = 2 * (end - pos) + 1; + if (hex_len > 1) { + hex = os_malloc(hex_len); + if (hex) + wpa_snprintf_hex(hex, hex_len, pos, end - pos); + } + wpa_msg(hapd->msg_ctx, MSG_INFO, + BSS_TM_QUERY MACSTR " reason=%u%s%s", + MAC2STR(addr), reason, hex ? " neighbor=" : "", hex); + os_free(hex); + ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token); } @@ -635,6 +672,133 @@ static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd, } + +static const char * wnm_event_type2str(enum wnm_event_report_type wtype) +{ +#define W2S(wtype) case WNM_EVENT_TYPE_ ## wtype: return #wtype; + switch (wtype) { + W2S(TRANSITION) + W2S(RSNA) + W2S(P2P_LINK) + W2S(WNM_LOG) + W2S(BSS_COLOR_COLLISION) + W2S(BSS_COLOR_IN_USE) + } + return "UNKNOWN"; +#undef W2S +} + + +static void ieee802_11_rx_wnm_event_report(struct hostapd_data *hapd, + const u8 *addr, const u8 *buf, + size_t len) +{ + struct sta_info *sta; + u8 dialog_token; + struct wnm_event_report_element *report_ie; + const u8 *pos = buf, *end = buf + len; + const size_t fixed_field_len = 3; /* Event Token/Type/Report Status */ +#ifdef CONFIG_IEEE80211AX + const size_t tsf_len = 8; + u8 color; + u64 bitmap; +#endif /* CONFIG_IEEE80211AX */ + + if (end - pos < 1 + 2) { + wpa_printf(MSG_DEBUG, + "WNM: Ignore too short WNM Event Report frame from " + MACSTR, MAC2STR(addr)); + return; + } + + dialog_token = *pos++; + report_ie = (struct wnm_event_report_element *) pos; + + if (end - pos < 2 + report_ie->len || + report_ie->len < fixed_field_len) { + wpa_printf(MSG_DEBUG, + "WNM: Ignore truncated WNM Event Report frame from " + MACSTR, MAC2STR(addr)); + return; + } + + if (report_ie->eid != WLAN_EID_EVENT_REPORT || + report_ie->status != WNM_STATUS_SUCCESSFUL) + return; + + wpa_printf(MSG_DEBUG, "WNM: Received WNM Event Report frame from " + MACSTR " dialog_token=%u event_token=%u type=%d (%s)", + MAC2STR(addr), dialog_token, report_ie->token, + report_ie->type, wnm_event_type2str(report_ie->type)); + + pos += 2 + fixed_field_len; + wpa_hexdump(MSG_MSGDUMP, "WNM: Event Report", pos, end - pos); + + sta = ap_get_sta(hapd, addr); + if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for received WNM Event Report", + MAC2STR(addr)); + return; + } + + switch (report_ie->type) { +#ifdef CONFIG_IEEE80211AX + case WNM_EVENT_TYPE_BSS_COLOR_COLLISION: + if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax) + return; + if (report_ie->len < + fixed_field_len + tsf_len + 8) { + wpa_printf(MSG_DEBUG, + "WNM: Too short BSS color collision event report from " + MACSTR, MAC2STR(addr)); + return; + } + bitmap = WPA_GET_LE64(report_ie->u.bss_color_collision.color_bitmap); + wpa_printf(MSG_DEBUG, + "WNM: BSS color collision bitmap 0x%llx reported by " + MACSTR, (unsigned long long) bitmap, MAC2STR(addr)); + hostapd_switch_color(hapd->iface->bss[0], bitmap); + break; + case WNM_EVENT_TYPE_BSS_COLOR_IN_USE: + if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax) + return; + if (report_ie->len < fixed_field_len + tsf_len + 1) { + wpa_printf(MSG_DEBUG, + "WNM: Too short BSS color in use event report from " + MACSTR, MAC2STR(addr)); + return; + } + color = report_ie->u.bss_color_in_use.color; + if (color > 63) { + wpa_printf(MSG_DEBUG, + "WNM: Invalid BSS color %u report from " + MACSTR, color, MAC2STR(addr)); + return; + } + if (color == 0) { + wpa_printf(MSG_DEBUG, + "WNM: BSS color use report canceled by " + MACSTR, MAC2STR(addr)); + /* TODO: Clear stored color from the collision bitmap + * if there are no other users for it. */ + return; + } + wpa_printf(MSG_DEBUG, "WNM: BSS color %u use report by " + MACSTR, color, MAC2STR(addr)); + hapd->color_collision_bitmap |= 1ULL << color; + break; +#endif /* CONFIG_IEEE80211AX */ + default: + wpa_printf(MSG_DEBUG, + "WNM Event Report type=%d (%s) not supported", + report_ie->type, + wnm_event_type2str(report_ie->type)); + break; + } +} + + int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { @@ -650,6 +814,10 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, plen = len - IEEE80211_HDRLEN - 2; switch (action) { + case WNM_EVENT_REPORT: + ieee802_11_rx_wnm_event_report(hapd, mgmt->sa, payload, + plen); + return 0; case WNM_BSS_TRANS_MGMT_QUERY: ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload, plen); @@ -682,14 +850,15 @@ int wnm_send_disassoc_imminent(struct hostapd_data *hapd, { u8 buf[1000], *pos; struct ieee80211_mgmt *mgmt; + const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta); os_memset(buf, 0, sizeof(buf)); mgmt = (struct ieee80211_mgmt *) buf; mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); os_memcpy(mgmt->da, sta->addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->sa, own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; mgmt->u.action.u.bss_tm_req.dialog_token = 1; @@ -748,14 +917,15 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, u8 buf[1000], *pos; struct ieee80211_mgmt *mgmt; size_t url_len; + const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta); os_memset(buf, 0, sizeof(buf)); mgmt = (struct ieee80211_mgmt *) buf; mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); os_memcpy(mgmt->da, sta->addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->sa, own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; mgmt->u.action.u.bss_tm_req.dialog_token = 1; @@ -800,6 +970,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta, u8 *buf, *pos; struct ieee80211_mgmt *mgmt; size_t url_len; + const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta); wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to " MACSTR_SEC @@ -813,8 +984,8 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta, mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); os_memcpy(mgmt->da, sta->addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->sa, own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token; @@ -863,6 +1034,26 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta, os_free(buf); if (disassoc_timer) { +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta)) { + int i; + unsigned int links = 0; + + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + if (sta->mld_info.links[i].valid) + links++; + } + + if (links > 1) { + wpa_printf(MSG_DEBUG, + "WNM: Only terminating one link - other links remains associated for " + MACSTR, + MAC2STR(sta->mld_info.common_info.mld_addr)); + return 0; + } + } +#endif /* CONFIG_IEEE80211BE */ + /* send disassociation frame after time-out */ set_disassoc_timer(hapd, sta, disassoc_timer); } @@ -877,6 +1068,7 @@ int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta, u8 buf[100], *pos; struct ieee80211_mgmt *mgmt; u8 dialog_token = 1; + const u8 *own_addr = wnm_ap_get_own_addr(hapd, sta); if (auto_report > 3 || timeout > 63) return -1; @@ -885,8 +1077,8 @@ int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta, mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION); os_memcpy(mgmt->da, sta->addr, ETH_ALEN); - os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); + os_memcpy(mgmt->sa, own_addr, ETH_ALEN); + os_memcpy(mgmt->bssid, own_addr, ETH_ALEN); mgmt->u.action.category = WLAN_ACTION_WNM; mgmt->u.action.u.coloc_intf_req.action = WNM_COLLOCATED_INTERFERENCE_REQ; diff --git a/wpa_supplicant-2.9_standard/src/ap/wpa_auth.c b/wpa_supplicant-2.9_standard/src/ap/wpa_auth.c index 0361ce16333df7579a9b11c7853d8d692a7c0ed0..a7e514c624c5226b4160c7f3dd724adbfd103a21 100755 --- a/wpa_supplicant-2.9_standard/src/ap/wpa_auth.c +++ b/wpa_supplicant-2.9_standard/src/ap/wpa_auth.c @@ -1,6 +1,6 @@ /* * IEEE 802.11 RSN / WPA Authenticator - * Copyright (c) 2004-2019, Jouni Malinen + * Copyright (c) 2004-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -23,11 +23,13 @@ #include "crypto/sha1.h" #include "crypto/sha256.h" #include "crypto/sha384.h" +#include "crypto/sha512.h" #include "crypto/random.h" #include "eapol_auth/eapol_auth_sm.h" #include "drivers/driver.h" #include "ap_config.h" #include "ieee802_11.h" +#include "sta_info.h" #include "wpa_auth.h" #include "pmksa_cache_auth.h" #include "wpa_auth_i.h" @@ -46,7 +48,7 @@ #define STATE_MACHINE_DATA struct wpa_state_machine #define STATE_MACHINE_DEBUG_PREFIX "WPA" -#define STATE_MACHINE_ADDR sm->addr +#define STATE_MACHINE_ADDR wpa_auth_get_spa(sm) static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx); @@ -69,7 +71,9 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, const u8 *pmk, unsigned int pmk_len, - struct wpa_ptk *ptk, int force_sha256); + struct wpa_ptk *ptk, int force_sha256, + u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name, + size_t *key_len, bool no_kdk); static void wpa_group_free(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static void wpa_group_get(struct wpa_authenticator *wpa_auth, @@ -78,6 +82,9 @@ static void wpa_group_put(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static int ieee80211w_kde_len(struct wpa_state_machine *sm); static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos); +static void wpa_group_update_gtk(struct wpa_authenticator *wpa_auth, + struct wpa_group *group); + #ifdef OPEN_HARMONY_MIRACAST_SINK_OPT /* hostapd send and recv packet more then 100ms */ @@ -96,6 +103,145 @@ static const int dot11RSNAConfigPMKReauthThreshold = 70; static const int dot11RSNAConfigSATimeout = 60; +static const u8 * wpa_auth_get_aa(const struct wpa_state_machine *sm) +{ +#ifdef CONFIG_IEEE80211BE + if (sm->mld_assoc_link_id >= 0) + return sm->wpa_auth->mld_addr; +#endif /* CONFIG_IEEE80211BE */ + return sm->wpa_auth->addr; +} + + +static const u8 * wpa_auth_get_spa(const struct wpa_state_machine *sm) +{ +#ifdef CONFIG_IEEE80211BE + if (sm->mld_assoc_link_id >= 0) + return sm->peer_mld_addr; +#endif /* CONFIG_IEEE80211BE */ + return sm->addr; +} + + +static void wpa_gkeydone_sta(struct wpa_state_machine *sm) +{ +#ifdef CONFIG_IEEE80211BE + int link_id; +#endif /* CONFIG_IEEE80211BE */ + + if (!sm->wpa_auth) + return; + + sm->wpa_auth->group->GKeyDoneStations--; + sm->GUpdateStationKeys = false; + +#ifdef CONFIG_IEEE80211BE + for_each_sm_auth(sm, link_id) + sm->mld_links[link_id].wpa_auth->group->GKeyDoneStations--; +#endif /* CONFIG_IEEE80211BE */ +} + + +#ifdef CONFIG_IEEE80211BE + +void wpa_release_link_auth_ref(struct wpa_state_machine *sm, + int release_link_id) +{ + int link_id; + + if (!sm || release_link_id >= MAX_NUM_MLD_LINKS) + return; + + for_each_sm_auth(sm, link_id) { + if (link_id == release_link_id) { + wpa_group_put(sm->mld_links[link_id].wpa_auth, + sm->mld_links[link_id].wpa_auth->group); + sm->mld_links[link_id].wpa_auth = NULL; + } + } +} + + +struct wpa_get_link_auth_ctx { + const u8 *addr; + const u8 *mld_addr; + int link_id; + struct wpa_authenticator *wpa_auth; +}; + +static int wpa_get_link_sta_auth(struct wpa_authenticator *wpa_auth, void *data) +{ + struct wpa_get_link_auth_ctx *ctx = data; + + if (!wpa_auth->is_ml) + return 0; + + if (ctx->mld_addr && + !ether_addr_equal(wpa_auth->mld_addr, ctx->mld_addr)) + return 0; + + if ((ctx->addr && ether_addr_equal(wpa_auth->addr, ctx->addr)) || + (ctx->link_id > -1 && wpa_auth->is_ml && + wpa_auth->link_id == ctx->link_id)) { + ctx->wpa_auth = wpa_auth; + return 1; + + } + return 0; +} + + +static struct wpa_authenticator * +wpa_get_link_auth(struct wpa_authenticator *wpa_auth, int link_id) +{ + struct wpa_get_link_auth_ctx ctx; + + ctx.addr = NULL; + ctx.mld_addr = wpa_auth->mld_addr; + ctx.link_id = link_id; + ctx.wpa_auth = NULL; + wpa_auth_for_each_auth(wpa_auth, wpa_get_link_sta_auth, &ctx); + return ctx.wpa_auth; +} + + +static int wpa_get_primary_auth_cb(struct wpa_authenticator *wpa_auth, + void *data) +{ + struct wpa_get_link_auth_ctx *ctx = data; + + if (!wpa_auth->is_ml || + !ether_addr_equal(wpa_auth->mld_addr, ctx->addr) || + !wpa_auth->primary_auth) + return 0; + + ctx->wpa_auth = wpa_auth; + return 1; +} + +#endif /* CONFIG_IEEE80211BE */ + + +static struct wpa_authenticator * +wpa_get_primary_auth(struct wpa_authenticator *wpa_auth) +{ +#ifdef CONFIG_IEEE80211BE + struct wpa_get_link_auth_ctx ctx; + + if (!wpa_auth || !wpa_auth->is_ml || wpa_auth->primary_auth) + return wpa_auth; + + ctx.addr = wpa_auth->mld_addr; + ctx.wpa_auth = NULL; + wpa_auth_for_each_auth(wpa_auth, wpa_get_primary_auth_cb, &ctx); + + return ctx.wpa_auth; +#else /* CONFIG_IEEE80211BE */ + return wpa_auth; +#endif /* CONFIG_IEEE80211BE */ +} + + static inline int wpa_auth_mic_failure_report( struct wpa_authenticator *wpa_auth, const u8 *addr) { @@ -172,6 +318,20 @@ int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, } +#ifdef CONFIG_PASN +static inline int wpa_auth_set_ltf_keyseed(struct wpa_authenticator *wpa_auth, + const u8 *peer_addr, + const u8 *ltf_keyseed, + size_t ltf_keyseed_len) +{ + if (!wpa_auth->cb->set_ltf_keyseed) + return -1; + return wpa_auth->cb->set_ltf_keyseed(wpa_auth->cb_ctx, peer_addr, + ltf_keyseed, ltf_keyseed_len); +} +#endif /* CONFIG_PASN */ + + static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, const u8 *addr, int idx, u8 *seq) { @@ -179,6 +339,9 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, if (!wpa_auth->cb->get_seqnum) return -1; +#ifdef CONFIG_TESTING_OPTIONS + os_memset(seq, 0, WPA_KEY_RSC_LEN); +#endif /* CONFIG_TESTING_OPTIONS */ res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq); #ifdef CONFIG_TESTING_OPTIONS if (!addr && idx < 4 && wpa_auth->conf.gtk_rsc_override_set) { @@ -257,13 +420,14 @@ void wpa_auth_store_ptksa(struct wpa_authenticator *wpa_auth, } -void wpa_auth_remove_ptksa(struct wpa_authenticator *wpa_auth, - const u8 *addr, int cipher) +static 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) { @@ -349,14 +513,16 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx) } -static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx) +static void wpa_rekey_all_groups(struct wpa_authenticator *wpa_auth) { - struct wpa_authenticator *wpa_auth = eloop_ctx; struct wpa_group *group, *next; wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK"); group = wpa_auth->group; while (group) { + wpa_printf(MSG_DEBUG, "GTK rekey start for authenticator (" + MACSTR "), group vlan %d", + MAC2STR(wpa_auth->addr), group->vlan_id); wpa_group_get(wpa_auth, group); group->GTKReKey = true; @@ -369,6 +535,83 @@ static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx) wpa_group_put(wpa_auth, group); group = next; } +} + + +#ifdef CONFIG_IEEE80211BE + +static void wpa_update_all_gtks(struct wpa_authenticator *wpa_auth) +{ + struct wpa_group *group, *next; + + group = wpa_auth->group; + while (group) { + wpa_group_get(wpa_auth, group); + + wpa_group_update_gtk(wpa_auth, group); + next = group->next; + wpa_group_put(wpa_auth, group); + group = next; + } +} + + +static int wpa_update_all_gtks_cb(struct wpa_authenticator *wpa_auth, void *ctx) +{ + const u8 *mld_addr = ctx; + + if (!ether_addr_equal(wpa_auth->mld_addr, mld_addr)) + return 0; + + wpa_update_all_gtks(wpa_auth); + return 0; +} + + +static int wpa_rekey_all_groups_cb(struct wpa_authenticator *wpa_auth, + void *ctx) +{ + const u8 *mld_addr = ctx; + + if (!ether_addr_equal(wpa_auth->mld_addr, mld_addr)) + return 0; + + wpa_rekey_all_groups(wpa_auth); + return 0; +} + +#endif /* CONFIG_IEEE80211BE */ + + +static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_authenticator *wpa_auth = eloop_ctx; + +#ifdef CONFIG_IEEE80211BE + if (wpa_auth->is_ml) { + /* Non-primary ML authenticator eloop timer for group rekey is + * never started and shouldn't fire. Check and warn just in + * case. */ + if (!wpa_auth->primary_auth) { + wpa_printf(MSG_DEBUG, + "RSN: Cannot start GTK rekey on non-primary ML authenticator"); + return; + } + + /* Generate all the new group keys */ + wpa_auth_for_each_auth(wpa_auth, wpa_update_all_gtks_cb, + wpa_auth->mld_addr); + + /* Send all the generated group keys to the respective stations + * with group key handshake. */ + wpa_auth_for_each_auth(wpa_auth, wpa_rekey_all_groups_cb, + wpa_auth->mld_addr); + } else { + wpa_rekey_all_groups(wpa_auth); + } +#else /* CONFIG_IEEE80211BE */ + wpa_rekey_all_groups(wpa_auth); +#endif /* CONFIG_IEEE80211BE */ if (wpa_auth->conf.wpa_group_rekey) { eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, @@ -382,7 +625,8 @@ static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx) struct wpa_authenticator *wpa_auth = eloop_ctx; struct wpa_state_machine *sm = timeout_ctx; - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK"); + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, + "rekeying PTK"); wpa_request_new_ptk(sm); wpa_sm_step(sm); } @@ -392,7 +636,8 @@ void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm) { if (sm && sm->wpa_auth->conf.wpa_ptk_rekey) { wpa_printf(MSG_DEBUG, "WPA: Start PTK rekeying timer for " - MACSTR_SEC " (%d seconds)", MAC2STR_SEC(sm->addr), + MACSTR_SEC " (%d seconds)", + MAC2STR_SEC(wpa_auth_get_spa(sm)), sm->wpa_auth->conf.wpa_ptk_rekey); eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); eloop_register_timeout(sm->wpa_auth->conf.wpa_ptk_rekey, 0, @@ -516,8 +761,19 @@ struct wpa_authenticator * wpa_init(const u8 *addr, wpa_auth = os_zalloc(sizeof(struct wpa_authenticator)); if (!wpa_auth) return NULL; + os_memcpy(wpa_auth->addr, addr, ETH_ALEN); os_memcpy(&wpa_auth->conf, conf, sizeof(*conf)); + +#ifdef CONFIG_IEEE80211BE + if (conf->mld_addr) { + wpa_auth->is_ml = true; + wpa_auth->link_id = conf->link_id; + wpa_auth->primary_auth = !conf->first_link_auth; + os_memcpy(wpa_auth->mld_addr, conf->mld_addr, ETH_ALEN); + } +#endif /* CONFIG_IEEE80211BE */ + wpa_auth->cb = cb; wpa_auth->cb_ctx = cb_ctx; @@ -561,7 +817,15 @@ struct wpa_authenticator * wpa_init(const u8 *addr, wpa_rekey_gmk, wpa_auth, NULL); } +#ifdef CONFIG_IEEE80211BE + /* For AP MLD, run group rekey timer only on one link (first) and + * whenever it fires do rekey on all associated ML links in one shot. + */ + if ((!wpa_auth->is_ml || !conf->first_link_auth) && + wpa_auth->conf.wpa_group_rekey) { +#else /* CONFIG_IEEE80211BE */ if (wpa_auth->conf.wpa_group_rekey) { +#endif /* CONFIG_IEEE80211BE */ eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0, wpa_rekey_gtk, wpa_auth, NULL); } @@ -577,6 +841,15 @@ struct wpa_authenticator * wpa_init(const u8 *addr, } #endif /* CONFIG_P2P */ + if (conf->tx_bss_auth && conf->beacon_prot) { + conf->tx_bss_auth->non_tx_beacon_prot = true; + if (!conf->tx_bss_auth->conf.beacon_prot) + conf->tx_bss_auth->conf.beacon_prot = true; + if (!conf->tx_bss_auth->conf.group_mgmt_cipher) + conf->tx_bss_auth->conf.group_mgmt_cipher = + conf->group_mgmt_cipher; + } + return wpa_auth; } @@ -596,6 +869,17 @@ int wpa_init_keys(struct wpa_authenticator *wpa_auth) } +static void wpa_auth_free_conf(struct wpa_auth_config *conf) +{ +#ifdef CONFIG_TESTING_OPTIONS + wpabuf_free(conf->eapol_m1_elements); + conf->eapol_m1_elements = NULL; + wpabuf_free(conf->eapol_m3_elements); + conf->eapol_m3_elements = NULL; +#endif /* CONFIG_TESTING_OPTIONS */ +} + + /** * wpa_deinit - Deinitialize WPA authenticator * @wpa_auth: Pointer to WPA authenticator data from wpa_init() @@ -605,6 +889,9 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth) struct wpa_group *group, *prev; eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL); + + /* TODO: Assign ML primary authenticator to next link authenticator and + * start rekey timer. */ eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); pmksa_cache_auth_deinit(wpa_auth->pmksa); @@ -626,9 +913,10 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth) while (group) { prev = group; group = group->next; - os_free(prev); + bin_clear_free(prev, sizeof(*prev)); } + wpa_auth_free_conf(&wpa_auth->conf); os_free(wpa_auth); } @@ -646,6 +934,7 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth, if (!wpa_auth) return 0; + wpa_auth_free_conf(&wpa_auth->conf); os_memcpy(&wpa_auth->conf, conf, sizeof(*conf)); if (wpa_auth_gen_wpa_ie(wpa_auth)) { wpa_printf(MSG_ERROR, "Could not generate WPA IE."); @@ -686,6 +975,9 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr, sm->wpa_auth = wpa_auth; sm->group = wpa_auth->group; wpa_group_get(sm->wpa_auth, sm->group); +#ifdef CONFIG_IEEE80211BE + sm->mld_assoc_link_id = -1; +#endif /* CONFIG_IEEE80211BE */ return sm; } @@ -699,7 +991,7 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, #ifdef CONFIG_IEEE80211R_AP if (sm->ft_completed) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "FT authentication already completed - do not start 4-way handshake"); /* Go to PTKINITDONE state to allow GTK rekeying */ sm->wpa_ptk_state = WPA_PTK_PTKINITDONE; @@ -710,7 +1002,7 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, #ifdef CONFIG_FILS if (sm->fils_completed) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "FILS authentication already completed - do not start 4-way handshake"); /* Go to PTKINITDONE state to allow GTK rekeying */ sm->wpa_ptk_state = WPA_PTK_PTKINITDONE; @@ -729,7 +1021,7 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, return wpa_sm_step(sm); } - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "start authentication"); sm->started = 1; @@ -756,24 +1048,24 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm) static void wpa_free_sta_sm(struct wpa_state_machine *sm) { +#ifdef CONFIG_IEEE80211BE + int link_id; +#endif /* CONFIG_IEEE80211BE */ + #ifdef CONFIG_P2P if (WPA_GET_BE32(sm->ip_addr)) { - u32 start; wpa_printf(MSG_DEBUG, "P2P: Free assigned IP address %u.%u.%u.%u from " - MACSTR_SEC, + MACSTR_SEC " (bit %u)", sm->ip_addr[0], sm->ip_addr[1], sm->ip_addr[2], sm->ip_addr[3], - MAC2STR_SEC(sm->addr)); - start = WPA_GET_BE32(sm->wpa_auth->conf.ip_addr_start); - bitfield_clear(sm->wpa_auth->ip_pool, - WPA_GET_BE32(sm->ip_addr) - start); + MAC2STR_SEC(wpa_auth_get_spa(sm)), + sm->ip_addr_bit); + bitfield_clear(sm->wpa_auth->ip_pool, sm->ip_addr_bit); } #endif /* CONFIG_P2P */ - if (sm->GUpdateStationKeys) { - sm->group->GKeyDoneStations--; - sm->GUpdateStationKeys = false; - } + if (sm->GUpdateStationKeys) + wpa_gkeydone_sta(sm); #ifdef CONFIG_IEEE80211R_AP os_free(sm->assoc_resp_ftie); wpabuf_free(sm->ft_pending_req_ies); @@ -781,6 +1073,13 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm) os_free(sm->last_rx_eapol_key); os_free(sm->wpa_ie); os_free(sm->rsnxe); +#ifdef CONFIG_IEEE80211BE + for_each_sm_auth(sm, link_id) { + wpa_group_put(sm->mld_links[link_id].wpa_auth, + sm->mld_links[link_id].wpa_auth->group); + sm->mld_links[link_id].wpa_auth = NULL; + } +#endif /* CONFIG_IEEE80211BE */ wpa_group_put(sm->wpa_auth, sm->group); #ifdef CONFIG_DPP2 wpabuf_clear_free(sm->dpp_z); @@ -798,12 +1097,20 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm) wpa_auth = sm->wpa_auth; if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, + struct wpa_authenticator *primary_auth = wpa_auth; + + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "strict rekeying - force GTK rekey since STA is leaving"); + +#ifdef CONFIG_IEEE80211BE + if (wpa_auth->is_ml && !wpa_auth->primary_auth) + primary_auth = wpa_get_primary_auth(wpa_auth); +#endif /* CONFIG_IEEE80211BE */ + if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk, - wpa_auth, NULL) == -1) + primary_auth, NULL) == -1) eloop_register_timeout(0, 500000, wpa_rekey_gtk, - wpa_auth, NULL); + primary_auth, NULL); } eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); @@ -818,7 +1125,7 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm) * Freeing will be completed in the end of wpa_sm_step(). */ wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state machine deinit for " - MACSTR_SEC, MAC2STR_SEC(sm->addr)); + MACSTR_SEC, MAC2STR_SEC(wpa_auth_get_spa(sm))); sm->pending_deinit = 1; } else wpa_free_sta_sm(sm); @@ -833,7 +1140,7 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm) if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { wpa_printf(MSG_INFO, "WPA: PTK0 rekey not allowed, disconnect " MACSTR_SEC, - MAC2STR_SEC(sm->addr)); + MAC2STR_SEC(wpa_auth_get_spa(sm))); sm->Disconnect = true; /* Try to encourage the STA to reconnect */ sm->disconnect_reason = @@ -881,19 +1188,70 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, struct wpa_eapol_ie_parse *kde) { - struct wpa_ie_data ie; + struct wpa_ie_data ie, assoc_ie; struct rsn_mdie *mdie; + unsigned int i, j; + bool found = false; + + /* Verify that PMKR1Name from EAPOL-Key message 2/4 matches the value + * we derived. */ if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 || - ie.num_pmkid != 1 || !ie.pmkid) { + ie.num_pmkid < 1 || !ie.pmkid) { wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in FT 4-way handshake message 2/4"); return -1; } - os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant", - sm->sup_pmk_r1_name, PMKID_LEN); + if (wpa_parse_wpa_ie_rsn(sm->wpa_ie, sm->wpa_ie_len, &assoc_ie) < 0) { + wpa_printf(MSG_DEBUG, + "FT: Could not parse (Re)Association Request frame RSNE"); + os_memset(&assoc_ie, 0, sizeof(assoc_ie)); + /* Continue to allow PMKR1Name matching to be done to cover the + * case where it is the only listed PMKID. */ + } + + for (i = 0; i < ie.num_pmkid; i++) { + const u8 *pmkid = ie.pmkid + i * PMKID_LEN; + + if (os_memcmp_const(pmkid, sm->pmk_r1_name, + WPA_PMK_NAME_LEN) == 0) { + wpa_printf(MSG_DEBUG, + "FT: RSNE[PMKID[%u]] from supplicant matches PMKR1Name", + i); + found = true; + } else { + for (j = 0; j < assoc_ie.num_pmkid; j++) { + if (os_memcmp(pmkid, + assoc_ie.pmkid + j * PMKID_LEN, + PMKID_LEN) == 0) + break; + } + + if (j == assoc_ie.num_pmkid) { + wpa_printf(MSG_DEBUG, + "FT: RSNE[PMKID[%u]] from supplicant is neither PMKR1Name nor included in AssocReq", + i); + found = false; + break; + } + wpa_printf(MSG_DEBUG, + "FT: RSNE[PMKID[%u]] from supplicant is not PMKR1Name, but matches a PMKID in AssocReq", + i); + } + } + + if (!found) { + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, + "PMKR1Name mismatch in FT 4-way handshake"); + wpa_hexdump(MSG_DEBUG, + "FT: PMKIDs/PMKR1Name from Supplicant", + ie.pmkid, ie.num_pmkid * PMKID_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", + sm->pmk_r1_name, WPA_PMK_NAME_LEN); + return -1; + } if (!kde->mdie || !kde->ftie) { wpa_printf(MSG_DEBUG, @@ -931,18 +1289,19 @@ static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int group) { /* Supplicant reported a Michael MIC error */ - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "received EAPOL-Key Error Request (STA detected Michael MIC failure (group=%d))", group); if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "ignore Michael MIC failure report since group cipher is not TKIP"); } else if (!group && sm->pairwise != WPA_CIPHER_TKIP) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "ignore Michael MIC failure report since pairwise cipher is not TKIP"); } else { - if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0) + if (wpa_auth_mic_failure_report(wpa_auth, + wpa_auth_get_spa(sm)) > 0) return 1; /* STA entry was removed */ sm->dot11RSNAStatsTKIPRemoteMICFailures++; wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++; @@ -965,6 +1324,10 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, const u8 *pmk = NULL; size_t pmk_len; int vlan_id = 0; + u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN]; + u8 pmk_r1[PMK_LEN_MAX]; + size_t key_len; + int ret = -1; os_memset(&PTK, 0, sizeof(PTK)); for (;;) { @@ -986,8 +1349,9 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, pmk_len = sm->pmk_len; } - if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) < - 0) + if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0, + pmk_r0, pmk_r1, pmk_r0_name, &key_len, + false) < 0) break; if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK, @@ -1008,7 +1372,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, if (!ok) { wpa_printf(MSG_DEBUG, "WPA: Earlier SNonce did not result in matching MIC"); - return -1; + goto fail; } wpa_printf(MSG_DEBUG, @@ -1017,14 +1381,26 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0) - return -1; + goto fail; + +#ifdef CONFIG_IEEE80211R_AP + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && !sm->ft_completed) { + wpa_printf(MSG_DEBUG, "FT: Store PMK-R0/PMK-R1"); + wpa_auth_ft_store_keys(sm, pmk_r0, pmk_r1, pmk_r0_name, + key_len); + } +#endif /* CONFIG_IEEE80211R_AP */ os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN); os_memcpy(&sm->PTK, &PTK, sizeof(PTK)); forced_memzero(&PTK, sizeof(PTK)); sm->PTK_valid = true; - return 0; + ret = 0; +fail: + forced_memzero(pmk_r0, sizeof(pmk_r0)); + forced_memzero(pmk_r1, sizeof(pmk_r1)); + return ret; } @@ -1040,22 +1416,176 @@ static bool wpa_auth_gtk_rekey_in_process(struct wpa_authenticator *wpa_auth) } +enum eapol_key_msg { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST }; + +static bool wpa_auth_valid_key_desc_ver(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, u16 ver) +{ + if (ver > WPA_KEY_INFO_TYPE_AES_128_CMAC) { + wpa_printf(MSG_INFO, "RSN: " MACSTR + " used undefined Key Descriptor Version %d", + MAC2STR(wpa_auth_get_spa(sm)), ver); + return false; + } + + if (!wpa_use_akm_defined(sm->wpa_key_mgmt) && + wpa_use_cmac(sm->wpa_key_mgmt) && + ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_WARNING, + "advertised support for AES-128-CMAC, but did not use it"); +#ifdef CONFIG_P2P_CHR + wpa_supplicant_upload_go_p2p_state(wpa_auth->cb_ctx, sm->addr, + P2P_INTERFACE_STATE_DISCONNECTED, + DR_RX_EAPOL_FRAME_NOT_USE_AES_128_CMAC); +#endif + return false; + } + + if (sm->pairwise != WPA_CIPHER_TKIP && + !wpa_use_akm_defined(sm->wpa_key_mgmt) && + !wpa_use_cmac(sm->wpa_key_mgmt) && + ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_WARNING, + "did not use HMAC-SHA1-AES with CCMP/GCMP"); +#ifdef CONFIG_P2P_CHR + wpa_supplicant_upload_go_p2p_state(wpa_auth->cb_ctx, sm->addr, + P2P_INTERFACE_STATE_DISCONNECTED, + DR_RX_EAPOL_FRAME_NOT_USE_HMAC_SHA1_AES); +#endif + return false; + } + + if (wpa_use_akm_defined(sm->wpa_key_mgmt) && + ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) { + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_WARNING, + "did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases"); + return false; + } + + return true; +} + + +static bool wpa_auth_valid_request_counter(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + const u8 *replay_counter) +{ + + if (sm->req_replay_counter_used && + os_memcmp(replay_counter, sm->req_replay_counter, + WPA_REPLAY_COUNTER_LEN) <= 0) { + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_WARNING, + "received EAPOL-Key request with replayed counter"); + return false; + } + + return true; +} + + +static bool wpa_auth_valid_counter(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, + const struct wpa_eapol_key *key, + enum eapol_key_msg msg, + const char *msgtxt) +{ + int i; + + if (msg == REQUEST) + return wpa_auth_valid_request_counter(wpa_auth, sm, + key->replay_counter); + + if (wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) + return true; + + if (msg == PAIRWISE_2 && + wpa_replay_counter_valid(sm->prev_key_replay, + key->replay_counter) && + sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING && + os_memcmp(sm->SNonce, key->key_nonce, WPA_NONCE_LEN) != 0) { + /* + * Some supplicant implementations (e.g., Windows XP + * WZC) update SNonce for each EAPOL-Key 2/4. This + * breaks the workaround on accepting any of the + * pending requests, so allow the SNonce to be updated + * even if we have already sent out EAPOL-Key 3/4. + */ + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, + "Process SNonce update from STA based on retransmitted EAPOL-Key 1/4"); + sm->update_snonce = 1; + os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN); + sm->alt_snonce_valid = true; + os_memcpy(sm->alt_replay_counter, + sm->key_replay[0].counter, + WPA_REPLAY_COUNTER_LEN); + return true; + } + + if (msg == PAIRWISE_4 && sm->alt_snonce_valid && + sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING && + os_memcmp(key->replay_counter, sm->alt_replay_counter, + WPA_REPLAY_COUNTER_LEN) == 0) { + /* + * Supplicant may still be using the old SNonce since + * there was two EAPOL-Key 2/4 messages and they had + * different SNonce values. + */ + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, + "Try to process received EAPOL-Key 4/4 based on old Replay Counter and SNonce from an earlier EAPOL-Key 1/4"); + return true; + } + + if (msg == PAIRWISE_2 && + wpa_replay_counter_valid(sm->prev_key_replay, + key->replay_counter) && + sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) { + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, + "ignore retransmitted EAPOL-Key %s - SNonce did not change", + msgtxt); + } else { + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, + "received EAPOL-Key %s with unexpected replay counter", + msgtxt); + } + for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { + if (!sm->key_replay[i].valid) + break; + wpa_hexdump(MSG_DEBUG, "pending replay counter", + sm->key_replay[i].counter, + WPA_REPLAY_COUNTER_LEN); + } + wpa_hexdump(MSG_DEBUG, "received replay counter", + key->replay_counter, WPA_REPLAY_COUNTER_LEN); + return false; +} + + void wpa_receive(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, u8 *data, size_t data_len) { struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; - u16 key_info, key_data_length; - enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST } msg; - char *msgtxt; - struct wpa_eapol_ie_parse kde; + u16 key_info, ver, key_data_length; + enum eapol_key_msg msg; + const char *msgtxt; const u8 *key_data; size_t keyhdrlen, mic_len; u8 *mic; + u8 *key_data_buf = NULL; + size_t key_data_buf_len = 0; if (!wpa_auth || !wpa_auth->conf.wpa || !sm) return; + wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len); mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len); @@ -1079,7 +1609,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, key_data_length = WPA_GET_BE16(mic + mic_len); wpa_printf(MSG_INFO, "WPA: Received EAPOL-Key from " MACSTR_SEC " key_info=0x%x type=%u mic_len=%zu key_data_length=%u", - MAC2STR_SEC(sm->addr), key_info, key->type, + MAC2STR_SEC(wpa_auth_get_spa(sm)), key_info, key->type, mic_len, key_data_length); wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key header (ending before Key MIC)", @@ -1140,6 +1670,31 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, return; } + ver = key_info & WPA_KEY_INFO_TYPE_MASK; + if (!wpa_auth_valid_key_desc_ver(wpa_auth, sm, ver)) + goto out; + if (mic_len > 0 && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && + sm->PTK_valid && + (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || + ver == WPA_KEY_INFO_TYPE_AES_128_CMAC || + wpa_use_aes_key_wrap(sm->wpa_key_mgmt)) && + key_data_length >= 8 && key_data_length % 8 == 0) { + key_data_length -= 8; /* AES-WRAP adds 8 bytes */ + key_data_buf = os_malloc(key_data_length); + if (!key_data_buf) + goto out; + key_data_buf_len = key_data_length; + if (aes_unwrap(sm->PTK.kek, sm->PTK.kek_len, + key_data_length / 8, key_data, key_data_buf)) { + wpa_printf(MSG_INFO, + "RSN: AES unwrap failed - could not decrypt EAPOL-Key key data"); + goto out; + } + key_data = key_data_buf; + wpa_hexdump_key(MSG_DEBUG, "RSN: Decrypted EAPOL-Key Key Data", + key_data, key_data_length); + } + if (key_info & WPA_KEY_INFO_REQUEST) { msg = REQUEST; msgtxt = "Request"; @@ -1147,6 +1702,11 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, msg = GROUP_2; msgtxt = "2/2 Group"; } else if (key_data_length == 0 || + (sm->wpa == WPA_VERSION_WPA2 && + (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA) || + key_data_buf) && + (key_info & WPA_KEY_INFO_SECURE) && + !get_ie(key_data, key_data_length, WLAN_EID_RSN)) || (mic_len == 0 && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) && key_data_length == AES_BLOCK_SIZE)) { msg = PAIRWISE_4; @@ -1156,149 +1716,34 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, msgtxt = "2/4 Pairwise"; } - if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 || - msg == GROUP_2) { - u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK; - if (sm->pairwise == WPA_CIPHER_CCMP || - sm->pairwise == WPA_CIPHER_GCMP) { - if (wpa_use_cmac(sm->wpa_key_mgmt) && - !wpa_use_akm_defined(sm->wpa_key_mgmt) && - ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { - wpa_auth_logger(wpa_auth, sm->addr, - LOGGER_WARNING, - "advertised support for AES-128-CMAC, but did not use it"); -#ifdef CONFIG_P2P_CHR - wpa_supplicant_upload_go_p2p_state(wpa_auth->cb_ctx, sm->addr, - P2P_INTERFACE_STATE_DISCONNECTED, - DR_RX_EAPOL_FRAME_NOT_USE_AES_128_CMAC); -#endif - return; - } + if (!wpa_auth_valid_counter(wpa_auth, sm, key, msg, msgtxt)) + goto out; + +#ifdef CONFIG_FILS + if (sm->wpa == WPA_VERSION_WPA2 && mic_len == 0 && + !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, + "WPA: Encr Key Data bit not set even though AEAD cipher is supposed to be used - drop frame"); + goto out; + } +#endif /* CONFIG_FILS */ - if (!wpa_use_cmac(sm->wpa_key_mgmt) && - !wpa_use_akm_defined(sm->wpa_key_mgmt) && - ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { - wpa_auth_logger(wpa_auth, sm->addr, - LOGGER_WARNING, - "did not use HMAC-SHA1-AES with CCMP/GCMP"); + switch (msg) { + case PAIRWISE_2: + if (sm->wpa_ptk_state != WPA_PTK_PTKSTART && + sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING && + (!sm->update_snonce || + sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) { + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, + "received EAPOL-Key msg 2/4 in invalid state (%d) - dropped", + sm->wpa_ptk_state); #ifdef CONFIG_P2P_CHR - wpa_supplicant_upload_go_p2p_state(wpa_auth->cb_ctx, sm->addr, - P2P_INTERFACE_STATE_DISCONNECTED, - DR_RX_EAPOL_FRAME_NOT_USE_HMAC_SHA1_AES); + wpa_supplicant_upload_go_p2p_state(wpa_auth->cb_ctx, sm->addr, + P2P_INTERFACE_STATE_DISCONNECTED, + DR_RX_EAPOL_FRAME_MSG_2_4_DROP_INVALID_STATE); #endif - return; - } - } - - if (wpa_use_akm_defined(sm->wpa_key_mgmt) && - ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, - "did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases"); - return; - } - } - - if (key_info & WPA_KEY_INFO_REQUEST) { - if (sm->req_replay_counter_used && - os_memcmp(key->replay_counter, sm->req_replay_counter, - WPA_REPLAY_COUNTER_LEN) <= 0) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, - "received EAPOL-Key request with replayed counter"); - return; - } - } - - if (!(key_info & WPA_KEY_INFO_REQUEST) && - !wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) { - int i; - - if (msg == PAIRWISE_2 && - wpa_replay_counter_valid(sm->prev_key_replay, - key->replay_counter) && - sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING && - os_memcmp(sm->SNonce, key->key_nonce, WPA_NONCE_LEN) != 0) - { - /* - * Some supplicant implementations (e.g., Windows XP - * WZC) update SNonce for each EAPOL-Key 2/4. This - * breaks the workaround on accepting any of the - * pending requests, so allow the SNonce to be updated - * even if we have already sent out EAPOL-Key 3/4. - */ - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "Process SNonce update from STA based on retransmitted EAPOL-Key 1/4"); - sm->update_snonce = 1; - os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN); - sm->alt_snonce_valid = true; - os_memcpy(sm->alt_replay_counter, - sm->key_replay[0].counter, - WPA_REPLAY_COUNTER_LEN); - goto continue_processing; - } - - if (msg == PAIRWISE_4 && sm->alt_snonce_valid && - sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING && - os_memcmp(key->replay_counter, sm->alt_replay_counter, - WPA_REPLAY_COUNTER_LEN) == 0) { - /* - * Supplicant may still be using the old SNonce since - * there was two EAPOL-Key 2/4 messages and they had - * different SNonce values. - */ - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "Try to process received EAPOL-Key 4/4 based on old Replay Counter and SNonce from an earlier EAPOL-Key 1/4"); - goto continue_processing; - } - - if (msg == PAIRWISE_2 && - wpa_replay_counter_valid(sm->prev_key_replay, - key->replay_counter) && - sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "ignore retransmitted EAPOL-Key %s - SNonce did not change", - msgtxt); - } else { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "received EAPOL-Key %s with unexpected replay counter", - msgtxt); - } - for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { - if (!sm->key_replay[i].valid) - break; - wpa_hexdump(MSG_DEBUG, "pending replay counter", - sm->key_replay[i].counter, - WPA_REPLAY_COUNTER_LEN); - } - wpa_hexdump(MSG_DEBUG, "received replay counter", - key->replay_counter, WPA_REPLAY_COUNTER_LEN); - return; - } - -continue_processing: -#ifdef CONFIG_FILS - if (sm->wpa == WPA_VERSION_WPA2 && mic_len == 0 && - !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "WPA: Encr Key Data bit not set even though AEAD cipher is supposed to be used - drop frame"); - return; - } -#endif /* CONFIG_FILS */ - - switch (msg) { - case PAIRWISE_2: - if (sm->wpa_ptk_state != WPA_PTK_PTKSTART && - sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING && - (!sm->update_snonce || - sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key msg 2/4 in invalid state (%d) - dropped", - sm->wpa_ptk_state); -#ifdef CONFIG_P2P_CHR - wpa_supplicant_upload_go_p2p_state(wpa_auth->cb_ctx, sm->addr, - P2P_INTERFACE_STATE_DISCONNECTED, - DR_RX_EAPOL_FRAME_MSG_2_4_DROP_INVALID_STATE); -#endif - return; + goto out; } random_add_randomness(key->key_nonce, WPA_NONCE_LEN); if (sm->group->reject_4way_hs_for_entropy) { @@ -1321,13 +1766,14 @@ continue_processing: #endif wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); - return; + goto out; } break; case PAIRWISE_4: if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING || !sm->PTK_valid) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "received EAPOL-Key msg 4/4 in invalid state (%d) - dropped", sm->wpa_ptk_state); #ifdef CONFIG_P2P_CHR @@ -1335,13 +1781,14 @@ continue_processing: P2P_INTERFACE_STATE_DISCONNECTED, DR_RX_EAPOL_FRAME_MSG_4_4_DROP_INVALID_STATE); #endif - return; + goto out; } break; case GROUP_2: if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING || !sm->PTK_valid) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "received EAPOL-Key msg 2/2 in invalid state (%d) - dropped", sm->wpa_ptk_group_state); #ifdef CONFIG_P2P_CHR @@ -1349,14 +1796,24 @@ continue_processing: P2P_INTERFACE_STATE_DISCONNECTED, DR_RX_EAPOL_FRAME_MSG_2_2_DROP_INVALID_STATE); #endif - return; + goto out; } break; case REQUEST: + if (sm->wpa_ptk_state == WPA_PTK_PTKSTART || + sm->wpa_ptk_state == WPA_PTK_PTKCALCNEGOTIATING || + sm->wpa_ptk_state == WPA_PTK_PTKCALCNEGOTIATING2 || + sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) { + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, + "received EAPOL-Key Request in invalid state (%d) - dropped", + sm->wpa_ptk_state); + goto out; + } break; } - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "received EAPOL-Key frame (%s)", msgtxt); #ifdef CONFIG_P2P_CHR if (msg == PAIRWISE_2) { @@ -1368,39 +1825,39 @@ continue_processing: } #endif if (key_info & WPA_KEY_INFO_ACK) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "received invalid EAPOL-Key: Key Ack set"); #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_go_p2p_state(wpa_auth->cb_ctx, sm->addr, P2P_INTERFACE_STATE_DISCONNECTED, DR_RX_EAPOL_FRAME_INVALID_KEY_ACK_SET); #endif - return; + goto out; } if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt) && !(key_info & WPA_KEY_INFO_MIC)) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "received invalid EAPOL-Key: Key MIC not set"); #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_go_p2p_state(wpa_auth->cb_ctx, sm->addr, P2P_INTERFACE_STATE_DISCONNECTED, DR_RX_EAPOL_FRAME_INVALID_KEY_MIC_NOT_SET); #endif - return; + goto out; } #ifdef CONFIG_FILS if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) && (key_info & WPA_KEY_INFO_MIC)) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "received invalid EAPOL-Key: Key MIC set"); #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_go_p2p_state(wpa_auth->cb_ctx, sm->addr, P2P_INTERFACE_STATE_DISCONNECTED, DR_RX_EAPOL_FRAME_INVALID_KEY_MIC_SET); #endif - return; + goto out; } #endif /* CONFIG_FILS */ @@ -1411,27 +1868,29 @@ continue_processing: data, data_len) && (msg != PAIRWISE_4 || !sm->alt_snonce_valid || wpa_try_alt_snonce(sm, data, data_len))) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "received EAPOL-Key with invalid MIC"); #ifdef TEST_FUZZ wpa_printf(MSG_INFO, "TEST: Ignore Key MIC failure for fuzz testing"); goto continue_fuzz; #endif /* TEST_FUZZ */ - return; + goto out; } #ifdef CONFIG_FILS if (!mic_len && wpa_aead_decrypt(sm, &sm->PTK, data, data_len, &key_data_length) < 0) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "received EAPOL-Key with invalid MIC"); #ifdef TEST_FUZZ wpa_printf(MSG_INFO, "TEST: Ignore Key MIC failure for fuzz testing"); goto continue_fuzz; #endif /* TEST_FUZZ */ - return; + goto out; } #endif /* CONFIG_FILS */ #ifdef TEST_FUZZ @@ -1443,43 +1902,47 @@ continue_processing: } if (key_info & WPA_KEY_INFO_REQUEST) { + if (!(key_info & WPA_KEY_INFO_SECURE)) { + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, + "received EAPOL-Key request without Secure=1"); + goto out; + } if (sm->MICVerified) { sm->req_replay_counter_used = 1; os_memcpy(sm->req_replay_counter, key->replay_counter, WPA_REPLAY_COUNTER_LEN); } else { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "received EAPOL-Key request with invalid MIC"); - return; + goto out; } - /* - * TODO: should decrypt key data field if encryption was used; - * even though MAC address KDE is not normally encrypted, - * supplicant is allowed to encrypt it. - */ if (key_info & WPA_KEY_INFO_ERROR) { if (wpa_receive_error_report( wpa_auth, sm, !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0) - return; /* STA entry was removed */ + goto out; /* STA entry was removed */ } else if (key_info & WPA_KEY_INFO_KEY_TYPE) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "received EAPOL-Key Request for new 4-Way Handshake"); wpa_request_new_ptk(sm); - } else if (key_data_length > 0 && - wpa_parse_kde_ies(key_data, key_data_length, - &kde) == 0 && - kde.mac_addr) { } else { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "received EAPOL-Key Request for GTK rekeying"); - eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); + + eloop_cancel_timeout(wpa_rekey_gtk, + wpa_get_primary_auth(wpa_auth), + NULL); if (wpa_auth_gtk_rekey_in_process(wpa_auth)) wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "skip new GTK rekey - already in process"); else - wpa_rekey_gtk(wpa_auth, NULL); + wpa_rekey_gtk(wpa_get_primary_auth(wpa_auth), + NULL); } } else { /* Do not allow the same key replay counter to be reused. */ @@ -1511,7 +1974,7 @@ continue_processing: os_free(sm->last_rx_eapol_key); sm->last_rx_eapol_key = os_memdup(data, data_len); if (!sm->last_rx_eapol_key) - return; + goto out; sm->last_rx_eapol_key_len = data_len; sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE); @@ -1520,6 +1983,9 @@ continue_processing: sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST); os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN); wpa_sm_step(sm); + +out: + bin_clear_free(key_data_buf, key_data_buf_len); } @@ -1576,8 +2042,15 @@ static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx) struct wpa_authenticator *wpa_auth = eloop_ctx; struct wpa_state_machine *sm = timeout_ctx; + if (sm->waiting_radius_psk) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, + "Ignore EAPOL-Key timeout while waiting for RADIUS PSK"); + return; + } + sm->pending_1_of_4_timeout = 0; - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout"); + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, + "EAPOL-Key timeout"); sm->TimeoutEvt = true; wpa_sm_step(sm); } @@ -1726,22 +2199,25 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, if (pad_len) *pos++ = 0xdd; - wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data", + wpa_hexdump_key(MSG_DEBUG, + "Plaintext EAPOL-Key Key Data (+ padding)", buf, key_data_len); if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || wpa_use_aes_key_wrap(sm->wpa_key_mgmt) || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { - wpa_printf(MSG_DEBUG, - "WPA: Encrypt Key Data using AES-WRAP (KEK length %zu)", - sm->PTK.kek_len); + wpa_hexdump_key(MSG_DEBUG, "RSN: AES-WRAP using KEK", + sm->PTK.kek, sm->PTK.kek_len); if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, (key_data_len - 8) / 8, buf, key_data)) { os_free(hdr); - os_free(buf); + bin_clear_free(buf, key_data_len); return; } + wpa_hexdump(MSG_DEBUG, + "RSN: Encrypted Key Data from AES-WRAP", + key_data, key_data_len); WPA_PUT_BE16(key_mic + mic_len, key_data_len); -#ifndef CONFIG_NO_RC4 +#if !defined(CONFIG_NO_RC4) && !defined(CONFIG_FIPS) } else if (sm->PTK.kek_len == 16) { u8 ek[32]; @@ -1755,18 +2231,19 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, os_memcpy(key_data, buf, key_data_len); rc4_skip(ek, 32, 256, key_data, key_data_len); WPA_PUT_BE16(key_mic + mic_len, key_data_len); -#endif /* CONFIG_NO_RC4 */ +#endif /* !(CONFIG_NO_RC4 || CONFIG_FIPS) */ } else { os_free(hdr); - os_free(buf); + bin_clear_free(buf, key_data_len); return; } - os_free(buf); + bin_clear_free(buf, key_data_len); } if (key_info & WPA_KEY_INFO_MIC) { if (!sm->PTK_valid || !mic_len) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, "PTK not valid when sending EAPOL-Key frame"); os_free(hdr); return; @@ -1782,7 +2259,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, if (!pairwise && conf->corrupt_gtk_rekey_mic_probability > 0.0 && drand48() < conf->corrupt_gtk_rekey_mic_probability) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "Corrupting group EAPOL-Key Key MIC"); key_mic[0]++; } @@ -1790,12 +2268,22 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, } wpa_auth_set_eapol(wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1); + wpa_hexdump(MSG_DEBUG, "Send EAPOL-Key msg", hdr, len); wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len, sm->pairwise_set); os_free(hdr); } +static int wpa_auth_get_sta_count(struct wpa_authenticator *wpa_auth) +{ + if (!wpa_auth->cb->get_sta_count) + return -1; + + return wpa_auth->cb->get_sta_count(wpa_auth->cb_ctx); +} + + static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int key_info, const u8 *key_rsc, const u8 *nonce, @@ -1809,20 +2297,40 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, if (!sm) return; + ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr; + +#ifdef CONFIG_TESTING_OPTIONS + /* When delay_eapol_tx is true, delay the EAPOL-Key transmission by + * sending it only on the last attempt after all timeouts for the prior + * skipped attemps. */ + if (wpa_auth->conf.delay_eapol_tx && + ctr != wpa_auth->conf.wpa_pairwise_update_count) { + wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO, + "DELAY-EAPOL-TX-%d", ctr); + goto skip_tx; + } +#endif /* CONFIG_TESTING_OPTIONS */ __wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len, keyidx, encr, 0); +#ifdef CONFIG_TESTING_OPTIONS +skip_tx: +#endif /* CONFIG_TESTING_OPTIONS */ - ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr; - if (ctr == 1 && wpa_auth->conf.tx_status) + if (ctr == 1 && wpa_auth->conf.tx_status) { #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) timeout_ms = pairwise ? HM_EAPOL_KEY_TIMEOUT_FIRST : eapol_key_timeout_first_group; #else - timeout_ms = pairwise ? eapol_key_timeout_first : - eapol_key_timeout_first_group; + if (pairwise) + timeout_ms = eapol_key_timeout_first; + else if (wpa_auth_get_sta_count(wpa_auth) > 100) + timeout_ms = eapol_key_timeout_first_group * 2; + else + timeout_ms = eapol_key_timeout_first_group; #endif - else + } else { timeout_ms = eapol_key_timeout_subseq; + } if (wpa_auth->conf.wpa_disable_eapol_key_retries && (!pairwise || (key_info & WPA_KEY_INFO_MIC))) timeout_ms = eapol_key_timeout_no_retrans; @@ -1899,7 +2407,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) if (!sm) return -1; - wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "event %d notification", event); switch (event) { @@ -1917,9 +2425,9 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) case WPA_DEAUTH: case WPA_DISASSOC: sm->DeauthenticationRequest = true; -#ifdef CONFIG_IEEE80211R_AP os_memset(sm->PMK, 0, sizeof(sm->PMK)); sm->pmk_len = 0; +#ifdef CONFIG_IEEE80211R_AP os_memset(sm->xxkey, 0, sizeof(sm->xxkey)); sm->xxkey_len = 0; os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1)); @@ -1947,11 +2455,19 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) break; } + if (sm->ptkstart_without_success > 3) { + wpa_printf(MSG_INFO, + "WPA: Multiple EAP reauth attempts without 4-way handshake completion, disconnect " + MACSTR, MAC2STR(sm->addr)); + sm->Disconnect = true; + break; + } + if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { wpa_printf(MSG_INFO, "WPA: PTK0 rekey not allowed, disconnect " - MACSTR_SEC, MAC2STR_SEC(sm->addr)); + MACSTR_SEC, MAC2STR_SEC(wpa_auth_get_spa(sm))); sm->Disconnect = true; /* Try to encourage the STA to reconnect */ sm->disconnect_reason = @@ -1967,8 +2483,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) * Reauthentication cancels the pending group key * update for this STA. */ - sm->group->GKeyDoneStations--; - sm->GUpdateStationKeys = false; + wpa_gkeydone_sta(sm); sm->PtkGroupInit = true; } sm->ReAuthenticationRequest = true; @@ -2044,8 +2559,7 @@ SM_STATE(WPA_PTK, INITIALIZE) sm->keycount = 0; if (sm->GUpdateStationKeys) - sm->group->GKeyDoneStations--; - sm->GUpdateStationKeys = false; + wpa_gkeydone_sta(sm); if (sm->wpa == WPA_VERSION_WPA) sm->PInitAKeys = false; if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and @@ -2198,7 +2712,8 @@ SM_STATE(WPA_PTK, INITPMK) sm->disconnect_reason = WLAN_REASON_INVALID_PMKID; return; #endif /* CONFIG_DPP */ - } else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) { + } else if (wpa_auth_get_msk(sm->wpa_auth, wpa_auth_get_spa(sm), + msk, &len) == 0) { unsigned int pmk_len; if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) @@ -2261,13 +2776,20 @@ SM_STATE(WPA_PTK, INITPSK) os_memcpy(sm->PMK, psk, psk_len); sm->pmk_len = psk_len; #ifdef CONFIG_IEEE80211R_AP - os_memcpy(sm->xxkey, psk, PMK_LEN); sm->xxkey_len = PMK_LEN; +#ifdef CONFIG_SAE + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + (psk_len == SHA512_MAC_LEN || psk_len == SHA384_MAC_LEN || + psk_len == SHA256_MAC_LEN)) + sm->xxkey_len = psk_len; +#endif /* CONFIG_SAE */ + os_memcpy(sm->xxkey, psk, sm->xxkey_len); #endif /* CONFIG_IEEE80211R_AP */ } #ifdef CONFIG_SAE if (wpa_auth_uses_sae(sm) && sm->pmksa) { - wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache"); + wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache (len=%zu)", + sm->pmksa->pmk_len); os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len); sm->pmk_len = sm->pmksa->pmk_len; #ifdef CONFIG_IEEE80211R_AP @@ -2282,13 +2804,20 @@ SM_STATE(WPA_PTK, INITPSK) SM_STATE(WPA_PTK, PTKSTART) { - u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL; - size_t pmkid_len = 0; + u8 *buf; + size_t buf_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; + u8 *pmkid = NULL; + size_t kde_len = 0; + u16 key_info; +#ifdef CONFIG_TESTING_OPTIONS + struct wpa_auth_config *conf = &sm->wpa_auth->conf; +#endif /* CONFIG_TESTING_OPTIONS */ SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk); sm->PTKRequest = false; sm->TimeoutEvt = false; sm->alt_snonce_valid = false; + sm->ptkstart_without_success++; sm->TimeoutCtr++; if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) { @@ -2297,7 +2826,20 @@ SM_STATE(WPA_PTK, PTKSTART) return; } - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, +#ifdef CONFIG_IEEE80211BE + if (sm->mld_assoc_link_id >= 0) + buf_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN; +#endif /* CONFIG_IEEE80211BE */ +#ifdef CONFIG_TESTING_OPTIONS + if (conf->eapol_m1_elements) + buf_len += wpabuf_len(conf->eapol_m1_elements); +#endif /* CONFIG_TESTING_OPTIONS */ + + buf = os_zalloc(buf_len); + if (!buf) + return; + + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "sending 1/4 msg of 4-Way Handshake"); /* * For infrastructure BSS cases, it is better for the AP not to include @@ -2319,7 +2861,7 @@ SM_STATE(WPA_PTK, PTKSTART) wpa_key_mgmt_sae(sm->wpa_key_mgmt)) && sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN) { pmkid = buf; - pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; + kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; pmkid[0] = WLAN_EID_VENDOR_SPECIFIC; pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN; RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID); @@ -2376,8 +2918,10 @@ SM_STATE(WPA_PTK, PTKSTART) * Calculate PMKID since no PMKSA cache entry was * available with pre-calculated PMKID. */ - rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr, - sm->addr, &pmkid[2 + RSN_SELECTOR_LEN], + rsn_pmkid(sm->PMK, sm->pmk_len, + wpa_auth_get_aa(sm), + wpa_auth_get_spa(sm), + &pmkid[2 + RSN_SELECTOR_LEN], sm->wpa_key_mgmt); wpa_hexdump(MSG_DEBUG, "RSN: Message 1/4 PMKID derived from PMK", @@ -2385,10 +2929,33 @@ SM_STATE(WPA_PTK, PTKSTART) } } if (!pmkid) - pmkid_len = 0; - wpa_send_eapol(sm->wpa_auth, sm, - WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL, - sm->ANonce, pmkid, pmkid_len, 0, 0); + kde_len = 0; + +#ifdef CONFIG_IEEE80211BE + if (sm->mld_assoc_link_id >= 0) { + wpa_printf(MSG_DEBUG, + "RSN: MLD: Add MAC Address KDE: kde_len=%zu", + kde_len); + wpa_add_kde(buf + kde_len, RSN_KEY_DATA_MAC_ADDR, + sm->wpa_auth->mld_addr, ETH_ALEN, NULL, 0); + kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN; + } +#endif /* CONFIG_IEEE80211BE */ + +#ifdef CONFIG_TESTING_OPTIONS + if (conf->eapol_m1_elements) { + os_memcpy(buf + kde_len, wpabuf_head(conf->eapol_m1_elements), + wpabuf_len(conf->eapol_m1_elements)); + kde_len += wpabuf_len(conf->eapol_m1_elements); + } +#endif /* CONFIG_TESTING_OPTIONS */ + + key_info = WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE; + if (sm->pairwise_set && sm->wpa != WPA_VERSION_WPA) + key_info |= WPA_KEY_INFO_SECURE; + wpa_send_eapol(sm->wpa_auth, sm, key_info, NULL, + sm->ANonce, kde_len ? buf : NULL, kde_len, 0, 0); + os_free(buf); #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_go_p2p_state(sm->wpa_auth->cb_ctx, sm->addr, P2P_INTERFACE_STATE_4WAY_HANDSHAKE_1, P2P_CHR_DEFAULT_REASON_CODE); @@ -2398,14 +2965,17 @@ SM_STATE(WPA_PTK, PTKSTART) static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, const u8 *pmk, unsigned int pmk_len, - struct wpa_ptk *ptk, int force_sha256) + struct wpa_ptk *ptk, int force_sha256, + u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name, + size_t *key_len, bool no_kdk) { const u8 *z = NULL; size_t z_len = 0, kdk_len; int akmp; + int ret; if (sm->wpa_auth->conf.force_kdk_derivation || - (sm->wpa_auth->conf.secure_ltf && + (!no_kdk && sm->wpa_auth->conf.secure_ltf && ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) kdk_len = WPA_KDK_MAX_LEN; else @@ -2416,16 +2986,36 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, if (sm->ft_completed) { u8 ptk_name[WPA_PMK_NAME_LEN]; - return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->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, - kdk_len); + ret = wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, + sm->SNonce, sm->ANonce, + wpa_auth_get_spa(sm), + wpa_auth_get_aa(sm), + sm->pmk_r1_name, ptk, + ptk_name, sm->wpa_key_mgmt, + sm->pairwise, kdk_len); + } else { + ret = wpa_auth_derive_ptk_ft(sm, ptk, pmk_r0, pmk_r1, + pmk_r0_name, key_len, + kdk_len); } - return wpa_auth_derive_ptk_ft(sm, ptk); + if (ret) { + wpa_printf(MSG_ERROR, "FT: PTK derivation failed"); + return ret; + } + +#ifdef CONFIG_PASN + if (!no_kdk && sm->wpa_auth->conf.secure_ltf && + ieee802_11_rsnx_capab(sm->rsnxe, + WLAN_RSNX_CAPAB_SECURE_LTF)) { + ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt, + sm->pairwise); + if (ret) { + wpa_printf(MSG_ERROR, + "FT: LTF keyseed derivation failed"); + } + } +#endif /* CONFIG_PASN */ + return ret; } #endif /* CONFIG_IEEE80211R_AP */ @@ -2439,9 +3029,27 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, akmp = sm->wpa_key_mgmt; if (force_sha256) akmp |= WPA_KEY_MGMT_PSK_SHA256; - return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion", - sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce, - ptk, akmp, sm->pairwise, z, z_len, kdk_len); + ret = wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion", + wpa_auth_get_aa(sm), wpa_auth_get_spa(sm), + sm->ANonce, snonce, ptk, akmp, + sm->pairwise, z, z_len, kdk_len); + if (ret) { + wpa_printf(MSG_DEBUG, + "WPA: PTK derivation failed"); + return ret; + } + +#ifdef CONFIG_PASN + if (!no_kdk && sm->wpa_auth->conf.secure_ltf && + ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) { + ret = wpa_ltf_keyseed(ptk, sm->wpa_key_mgmt, sm->pairwise); + if (ret) { + wpa_printf(MSG_DEBUG, + "WPA: LTF keyseed derivation failed"); + } + } +#endif /* CONFIG_PASN */ + return ret; } @@ -2465,13 +3073,27 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk, else kdk_len = 0; - res = fils_pmk_to_ptk(pmk, pmk_len, sm->addr, sm->wpa_auth->addr, + res = fils_pmk_to_ptk(pmk, pmk_len, wpa_auth_get_spa(sm), + wpa_auth_get_aa(sm), snonce, anonce, dhss, dhss_len, &sm->PTK, ick, &ick_len, sm->wpa_key_mgmt, sm->pairwise, fils_ft, &fils_ft_len, kdk_len); if (res < 0) return res; + +#ifdef CONFIG_PASN + if (sm->wpa_auth->conf.secure_ltf && + ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) { + res = wpa_ltf_keyseed(&sm->PTK, sm->wpa_key_mgmt, sm->pairwise); + if (res) { + wpa_printf(MSG_ERROR, + "FILS: LTF keyseed derivation failed"); + return res; + } + } +#endif /* CONFIG_PASN */ + sm->PTK_valid = true; sm->tk_already_set = false; @@ -2480,23 +3102,23 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk, struct wpa_authenticator *wpa_auth = sm->wpa_auth; 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); if (wpa_derive_pmk_r0(fils_ft, fils_ft_len, conf->ssid, conf->ssid_len, conf->mobility_domain, conf->r0_key_holder, conf->r0_key_holder_len, - sm->addr, pmk_r0, pmk_r0_name, - use_sha384) < 0) + wpa_auth_get_spa(sm), pmk_r0, pmk_r0_name, + sm->wpa_key_mgmt) < 0) return -1; wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name); forced_memzero(fils_ft, sizeof(fils_ft)); res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder, - sm->addr, sm->pmk_r1_name, - use_sha384); + wpa_auth_get_spa(sm), + sm->pmk_r1_name, + fils_ft_len); forced_memzero(pmk_r0, PMK_LEN_MAX); if (res < 0) return -1; @@ -2507,7 +3129,8 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk, #endif /* CONFIG_IEEE80211R_AP */ res = fils_key_auth_sk(ick, ick_len, snonce, anonce, - sm->addr, sm->wpa_auth->addr, + wpa_auth_get_spa(sm), + wpa_auth_get_aa(sm), g_sta ? wpabuf_head(g_sta) : NULL, g_sta ? wpabuf_len(g_sta) : 0, g_ap ? wpabuf_head(g_ap) : NULL, @@ -2542,7 +3165,7 @@ static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk, key_data_len = WPA_GET_BE16(pos); if (key_data_len < AES_BLOCK_SIZE || key_data_len > buf_len - sizeof(*hdr) - sizeof(*key) - 2) { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "No room for AES-SIV data in the frame"); return -1; } @@ -2558,7 +3181,7 @@ static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk, aad_len[0] = pos - buf; if (aes_siv_decrypt(ptk->kek, ptk->kek_len, pos, key_data_len, 1, aad, aad_len, tmp) < 0) { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "Invalid AES-SIV data in the frame"); bin_clear_free(tmp, key_data_len); return -1; @@ -2975,6 +3598,20 @@ int fils_set_tk(struct wpa_state_machine *sm) wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver"); return -1; } + +#ifdef CONFIG_PASN + if (sm->wpa_auth->conf.secure_ltf && + ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) && + wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr, + sm->PTK.ltf_keyseed, + sm->PTK.ltf_keyseed_len)) { + wpa_printf(MSG_ERROR, + "FILS: Failed to set LTF keyseed to driver"); + return -1; + } +#endif /* CONFIG_PASN */ + + sm->pairwise_set = true; sm->tk_already_set = true; wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise, @@ -3031,6 +3668,68 @@ int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth, #endif /* CONFIG_OCV */ +static int wpa_auth_validate_ml_kdes_m2(struct wpa_state_machine *sm, + struct wpa_eapol_ie_parse *kde) +{ +#ifdef CONFIG_IEEE80211BE + int i; + unsigned int n_links = 0; + + if (sm->mld_assoc_link_id < 0) + return 0; + + /* MLD MAC address must be the same */ + if (!kde->mac_addr || + !ether_addr_equal(kde->mac_addr, sm->peer_mld_addr)) { + wpa_printf(MSG_DEBUG, "RSN: MLD: Invalid MLD address"); + return -1; + } + + /* Find matching link ID and the MAC address for each link */ + for_each_link(kde->valid_mlo_links, i) { + /* + * Each entry should contain the link information and the MAC + * address. + */ + if (kde->mlo_link_len[i] != 1 + ETH_ALEN) { + wpa_printf(MSG_DEBUG, + "RSN: MLD: Invalid MLO Link (ID %u) KDE len=%zu", + i, kde->mlo_link_len[i]); + return -1; + } + + if (!sm->mld_links[i].valid || i == sm->mld_assoc_link_id) { + wpa_printf(MSG_DEBUG, + "RSN: MLD: Invalid link ID=%u", i); + return -1; + } + + if (!ether_addr_equal(sm->mld_links[i].peer_addr, + kde->mlo_link[i] + 1)) { + wpa_printf(MSG_DEBUG, + "RSN: MLD: invalid MAC address=" MACSTR + " expected " MACSTR " (link ID %u)", + MAC2STR(kde->mlo_link[i] + 1), + MAC2STR(sm->mld_links[i].peer_addr), i); + return -1; + } + + n_links++; + } + + /* Must have the same number of MLO links (excluding the local one) */ + if (n_links != sm->n_mld_affiliated_links) { + wpa_printf(MSG_DEBUG, + "RSN: MLD: Expecting %u MLD links in msg 2, but got %u", + sm->n_mld_affiliated_links, n_links); + return -1; + } +#endif /* CONFIG_IEEE80211BE */ + + return 0; +} + + SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) { struct wpa_authenticator *wpa_auth = sm->wpa_auth; @@ -3040,13 +3739,19 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) size_t pmk_len; int ft; const u8 *eapol_key_ie, *key_data, *mic; - u16 key_data_length; + u16 key_info, ver, key_data_length; size_t mic_len, eapol_key_ie_len; struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; struct wpa_eapol_ie_parse kde; int vlan_id = 0; int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround; + u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN]; + u8 pmk_r1[PMK_LEN_MAX]; + size_t key_len; + u8 *key_data_buf = NULL; + size_t key_data_buf_len = 0; + bool derive_kdk, no_kdk = false; SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); sm->EAPOLKeyReceived = false; @@ -3055,6 +3760,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len); + derive_kdk = sm->wpa_auth->conf.secure_ltf && + ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF); + /* WPA with IEEE 802.1X: use the derived PMK from EAP * WPA-PSK: iterate through possible PSKs and select the one matching * the packet */ @@ -3084,8 +3792,11 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) pmk_len = sm->pmksa->pmk_len; } + no_kdk = false; + try_without_kdk: if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK, - owe_ptk_workaround == 2) < 0) + owe_ptk_workaround == 2, pmk_r0, pmk_r1, + pmk_r0_name, &key_len, no_kdk) < 0) break; if (mic_len && @@ -3119,23 +3830,57 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) } #endif /* CONFIG_OWE */ + /* Some deployed STAs that advertise SecureLTF support in the + * RSNXE in (Re)Association Request frames, do not derive KDK + * during PTK generation. Try to work around this by checking if + * a PTK derived without KDK would result in a matching MIC. */ + if (!sm->wpa_auth->conf.force_kdk_derivation && + derive_kdk && !no_kdk) { + wpa_printf(MSG_DEBUG, + "Try new PTK derivation without KDK as a workaround"); + no_kdk = true; + goto try_without_kdk; + } + if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) || wpa_key_mgmt_sae(sm->wpa_key_mgmt)) break; } + if (no_kdk && ok) { + /* The workaround worked, so allow the 4-way handshake to be + * completed with the PTK that was derived without the KDK. */ + wpa_printf(MSG_DEBUG, + "PTK without KDK worked - misbehaving STA " + MACSTR, MAC2STR(sm->addr)); + } + + if (!ok && wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) && + wpa_auth->conf.radius_psk && wpa_auth->cb->request_radius_psk && + !sm->waiting_radius_psk) { + wpa_printf(MSG_DEBUG, "No PSK available - ask RADIUS server"); + wpa_auth->cb->request_radius_psk(wpa_auth->cb_ctx, sm->addr, + sm->wpa_key_mgmt, + sm->ANonce, + sm->last_rx_eapol_key, + sm->last_rx_eapol_key_len); + sm->waiting_radius_psk = 1; + goto out; + } + if (!ok) { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, "invalid MIC in msg 2/4 of 4-Way Handshake"); if (psk_found) { #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_go_p2p_state(sm->wpa_auth->cb_ctx, sm->addr, P2P_INTERFACE_STATE_DISCONNECTED, DR_MSG_2_4_INVALID_MIC); -#endif +#endif wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr); } - return; + goto out; } /* @@ -3145,21 +3890,55 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key; key = (struct wpa_eapol_key *) (hdr + 1); mic = (u8 *) (key + 1); + key_info = WPA_GET_BE16(key->key_info); key_data = mic + mic_len + 2; key_data_length = WPA_GET_BE16(mic + mic_len); if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) - sizeof(*key) - mic_len - 2) - return; + goto out; + + ver = key_info & WPA_KEY_INFO_TYPE_MASK; + if (mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + if (ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES && + ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && + !wpa_use_aes_key_wrap(sm->wpa_key_mgmt)) { + wpa_printf(MSG_INFO, + "Unsupported EAPOL-Key Key Data field encryption"); + goto out; + } + + if (key_data_length < 8 || key_data_length % 8) { + wpa_printf(MSG_INFO, + "RSN: Unsupported AES-WRAP len %u", + key_data_length); + goto out; + } + key_data_length -= 8; /* AES-WRAP adds 8 bytes */ + key_data_buf = os_malloc(key_data_length); + if (!key_data_buf) + goto out; + key_data_buf_len = key_data_length; + if (aes_unwrap(PTK.kek, PTK.kek_len, key_data_length / 8, + key_data, key_data_buf)) { + bin_clear_free(key_data_buf, key_data_buf_len); + wpa_printf(MSG_INFO, + "RSN: AES unwrap failed - could not decrypt EAPOL-Key key data"); + goto out; + } + key_data = key_data_buf; + wpa_hexdump_key(MSG_DEBUG, "RSN: Decrypted EAPOL-Key Key Data", + key_data, key_data_length); + } if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "received EAPOL-Key msg 2/4 with invalid Key Data contents"); #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_go_p2p_state(sm->wpa_auth->cb_ctx, sm->addr, P2P_INTERFACE_STATE_DISCONNECTED, DR_MSG_2_4_INVALID_KEY_DATA_CONTENTS); #endif - return; + goto out; } if (kde.rsn_ie) { eapol_key_ie = kde.rsn_ie; @@ -3175,7 +3954,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) if (!sm->wpa_ie || wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len, eapol_key_ie, eapol_key_ie_len)) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "WPA IE from (Re)AssocReq did not match with msg 2/4"); if (sm->wpa_ie) { wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq", @@ -3191,14 +3970,14 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) /* MLME-DEAUTHENTICATE.request */ wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); - return; + goto out; } if ((!sm->rsnxe && kde.rsnxe) || (sm->rsnxe && !kde.rsnxe) || (sm->rsnxe && kde.rsnxe && (sm->rsnxe_len != kde.rsnxe_len || os_memcmp(sm->rsnxe, kde.rsnxe, sm->rsnxe_len) != 0))) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "RSNXE from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4"); wpa_hexdump(MSG_DEBUG, "RSNXE in AssocReq", sm->rsnxe, sm->rsnxe_len); @@ -3207,7 +3986,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) /* MLME-DEAUTHENTICATE.request */ wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); - return; + goto out; } #ifdef CONFIG_OCV if (wpa_auth_uses_ocv(sm)) { @@ -3217,33 +3996,37 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) enum oci_verify_result res; if (wpa_channel_info(wpa_auth, &ci) != 0) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "Failed to get channel info to validate received OCI in EAPOL-Key 2/4"); - return; + goto out; } if (get_sta_tx_parameters(sm, channel_width_to_int(ci.chanwidth), ci.seg1_idx, &tx_chanwidth, &tx_seg1_idx) < 0) - return; + goto out; 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, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + 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, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + 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; + MAC2STR(wpa_auth_get_spa(sm)), + ocv_errorstr); + goto out; } } #endif /* CONFIG_OCV */ @@ -3251,7 +4034,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) { wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); - return; + goto out; } #endif /* CONFIG_IEEE80211R_AP */ #ifdef CONFIG_P2P @@ -3264,12 +4047,15 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) if (idx >= 0) { u32 start = WPA_GET_BE32(wpa_auth->conf.ip_addr_start); bitfield_set(wpa_auth->ip_pool, idx); + sm->ip_addr_bit = idx; WPA_PUT_BE32(sm->ip_addr, start + idx); wpa_printf(MSG_DEBUG, "P2P: Assigned IP address %u.%u.%u.%u to " - MACSTR_SEC, sm->ip_addr[0], sm->ip_addr[1], + MACSTR_SEC " (bit %u)", + sm->ip_addr[0], sm->ip_addr[1], sm->ip_addr[2], sm->ip_addr[3], - MAC2STR_SEC(sm->addr)); + MAC2STR_SEC(wpa_auth_get_spa(sm)), + sm->ip_addr_bit); } } #endif /* CONFIG_P2P */ @@ -3287,30 +4073,16 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) "DPP: Peer indicated it supports PFS and local configuration allows this, but PFS was not negotiated for the association"); wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); - return; + goto out; } } #endif /* CONFIG_DPP2 */ -#ifdef CONFIG_IEEE80211R_AP - if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { - /* - * Verify that PMKR1Name from EAPOL-Key message 2/4 matches - * with the value we derived. - */ - if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name, - WPA_PMK_NAME_LEN) != 0) { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "PMKR1Name mismatch in FT 4-way handshake"); - wpa_hexdump(MSG_DEBUG, - "FT: PMKR1Name from Supplicant", - sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN); - wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", - sm->pmk_r1_name, WPA_PMK_NAME_LEN); - return; - } + if (wpa_auth_validate_ml_kdes_m2(sm, &kde) < 0) { + wpa_sta_disconnect(wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; } -#endif /* CONFIG_IEEE80211R_AP */ if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) && wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) { @@ -3321,7 +4093,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) #endif wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); - return; + goto out; } sm->pending_1_of_4_timeout = 0; @@ -3337,9 +4109,21 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) sm->MICVerified = true; +#ifdef CONFIG_IEEE80211R_AP + if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) && !sm->ft_completed) { + wpa_printf(MSG_DEBUG, "FT: Store PMK-R0/PMK-R1"); + wpa_auth_ft_store_keys(sm, pmk_r0, pmk_r1, pmk_r0_name, + key_len); + } +#endif /* CONFIG_IEEE80211R_AP */ + os_memcpy(&sm->PTK, &PTK, sizeof(PTK)); forced_memzero(&PTK, sizeof(PTK)); sm->PTK_valid = true; +out: + forced_memzero(pmk_r0, sizeof(pmk_r0)); + forced_memzero(pmk_r1, sizeof(pmk_r1)); + bin_clear_free(key_data_buf, key_data_buf_len); } @@ -3353,14 +4137,18 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2) static int ieee80211w_kde_len(struct wpa_state_machine *sm) { size_t len = 0; + struct wpa_authenticator *wpa_auth = sm->wpa_auth; if (sm->mgmt_frame_prot) { len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN; - len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); } + + if (wpa_auth->conf.tx_bss_auth) + wpa_auth = wpa_auth->conf.tx_bss_auth; if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) { len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN; - len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); } return len; @@ -3373,12 +4161,18 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) struct wpa_bigtk_kde bigtk; struct wpa_group *gsm = sm->group; u8 rsc[WPA_KEY_RSC_LEN]; - struct wpa_auth_config *conf = &sm->wpa_auth->conf; + struct wpa_authenticator *wpa_auth = sm->wpa_auth; + struct wpa_auth_config *conf = &wpa_auth->conf; size_t len = wpa_cipher_key_len(conf->group_mgmt_cipher); if (!sm->mgmt_frame_prot) return pos; +#ifdef CONFIG_IEEE80211BE + if (sm->mld_assoc_link_id >= 0) + return pos; /* Use per-link MLO KDEs instead */ +#endif /* CONFIG_IEEE80211BE */ + igtk.keyid[0] = gsm->GN_igtk; igtk.keyid[1] = 0; if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE || @@ -3398,8 +4192,16 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK, (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len, NULL, 0); + forced_memzero(&igtk, sizeof(igtk)); - if (!conf->beacon_prot) + if (wpa_auth->conf.tx_bss_auth) { + wpa_auth = wpa_auth->conf.tx_bss_auth; + conf = &wpa_auth->conf; + len = wpa_cipher_key_len(conf->group_mgmt_cipher); + gsm = wpa_auth->group; + } + + if (!sm->wpa_auth->conf.beacon_prot) return pos; bigtk.keyid[0] = gsm->GN_bigtk; @@ -3421,6 +4223,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK, (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len, NULL, 0); + forced_memzero(&bigtk, sizeof(bigtk)); return pos; } @@ -3466,48 +4269,425 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos, } -#ifdef CONFIG_TESTING_OPTIONS -static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid, - const u8 *ie, size_t ie_len) +#ifdef CONFIG_TESTING_OPTIONS +static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid, + const u8 *ie, size_t ie_len) +{ + const u8 *elem; + u8 *buf; + + wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name); + wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override", + old_buf, *len); + buf = os_malloc(*len + ie_len); + if (!buf) + return NULL; + os_memcpy(buf, old_buf, *len); + elem = get_ie(buf, *len, eid); + if (elem) { + u8 elem_len = 2 + elem[1]; + + os_memmove((void *) elem, elem + elem_len, + *len - (elem - buf) - elem_len); + *len -= elem_len; + } + os_memcpy(buf + *len, ie, ie_len); + *len += ie_len; + wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override", + buf, *len); + + return buf; +} +#endif /* CONFIG_TESTING_OPTIONS */ + + +#ifdef CONFIG_IEEE80211BE + +void wpa_auth_ml_get_key_info(struct wpa_authenticator *a, + struct wpa_auth_ml_link_key_info *info, + bool mgmt_frame_prot, bool beacon_prot) +{ + struct wpa_group *gsm = a->group; + u8 rsc[WPA_KEY_RSC_LEN]; + + wpa_printf(MSG_DEBUG, + "MLD: Get group key info: link_id=%u, IGTK=%u, BIGTK=%u", + info->link_id, mgmt_frame_prot, beacon_prot); + + info->gtkidx = gsm->GN & 0x03; + info->gtk = gsm->GTK[gsm->GN - 1]; + info->gtk_len = gsm->GTK_len; + + if (wpa_auth_get_seqnum(a, NULL, gsm->GN, rsc) < 0) + os_memset(info->pn, 0, sizeof(info->pn)); + else + os_memcpy(info->pn, rsc, sizeof(info->pn)); + + if (!mgmt_frame_prot) + return; + + info->igtkidx = gsm->GN_igtk; + info->igtk = gsm->IGTK[gsm->GN_igtk - 4]; + info->igtk_len = wpa_cipher_key_len(a->conf.group_mgmt_cipher); + + if (wpa_auth_get_seqnum(a, NULL, gsm->GN_igtk, rsc) < 0) + os_memset(info->ipn, 0, sizeof(info->ipn)); + else + os_memcpy(info->ipn, rsc, sizeof(info->ipn)); + + if (!beacon_prot) + return; + + if (a->conf.tx_bss_auth) { + a = a->conf.tx_bss_auth; + gsm = a->group; + } + + info->bigtkidx = gsm->GN_bigtk; + info->bigtk = gsm->BIGTK[gsm->GN_bigtk - 6]; + + if (wpa_auth_get_seqnum(a, NULL, gsm->GN_bigtk, rsc) < 0) + os_memset(info->bipn, 0, sizeof(info->bipn)); + else + os_memcpy(info->bipn, rsc, sizeof(info->bipn)); +} + + +static void wpa_auth_get_ml_key_info(struct wpa_authenticator *wpa_auth, + struct wpa_auth_ml_key_info *info) +{ + if (!wpa_auth->cb->get_ml_key_info) + return; + + wpa_auth->cb->get_ml_key_info(wpa_auth->cb_ctx, info); +} + + +static size_t wpa_auth_ml_group_kdes_len(struct wpa_state_machine *sm) +{ + struct wpa_authenticator *wpa_auth; + size_t kde_len = 0; + int link_id; + + if (sm->mld_assoc_link_id < 0) + return 0; + + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid) + continue; + + wpa_auth = sm->mld_links[link_id].wpa_auth; + if (!wpa_auth || !wpa_auth->group) + continue; + + /* MLO GTK KDE + * Header + Key ID + Tx + LinkID + PN + GTK */ + kde_len += KDE_HDR_LEN + 1 + RSN_PN_LEN; + kde_len += wpa_auth->group->GTK_len; + + if (!sm->mgmt_frame_prot) + continue; + + if (wpa_auth->conf.tx_bss_auth) + wpa_auth = wpa_auth->conf.tx_bss_auth; + + /* MLO IGTK KDE + * Header + Key ID + IPN + LinkID + IGTK */ + kde_len += KDE_HDR_LEN + WPA_IGTK_KDE_PREFIX_LEN + 1; + kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); + + if (!wpa_auth->conf.beacon_prot) + continue; + + /* MLO BIGTK KDE + * Header + Key ID + BIPN + LinkID + BIGTK */ + kde_len += KDE_HDR_LEN + WPA_BIGTK_KDE_PREFIX_LEN + 1; + kde_len += wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); + } + + wpa_printf(MSG_DEBUG, "MLO Group KDEs len = %zu", kde_len); + + return kde_len; +} + + +static u8 * wpa_auth_ml_group_kdes(struct wpa_state_machine *sm, u8 *pos) +{ + struct wpa_auth_ml_key_info ml_key_info; + unsigned int i, link_id; + u8 *start = pos; + + /* First fetch the key information from all the authenticators */ + os_memset(&ml_key_info, 0, sizeof(ml_key_info)); + ml_key_info.n_mld_links = sm->n_mld_affiliated_links + 1; + + /* + * Assume that management frame protection and beacon protection are the + * same on all links. + */ + ml_key_info.mgmt_frame_prot = sm->mgmt_frame_prot; + ml_key_info.beacon_prot = sm->wpa_auth->conf.beacon_prot; + + for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid) + continue; + + ml_key_info.links[i++].link_id = link_id; + } + + wpa_auth_get_ml_key_info(sm->wpa_auth, &ml_key_info); + + /* Add MLO GTK KDEs */ + for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid || + !ml_key_info.links[i].gtk_len) + continue; + + wpa_printf(MSG_DEBUG, "RSN: MLO GTK: link=%u", link_id); + wpa_hexdump_key(MSG_DEBUG, "RSN: MLO GTK", + ml_key_info.links[i].gtk, + ml_key_info.links[i].gtk_len); + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = RSN_SELECTOR_LEN + 1 + 6 + + ml_key_info.links[i].gtk_len; + + RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_GTK); + pos += RSN_SELECTOR_LEN; + + *pos++ = (ml_key_info.links[i].gtkidx & 0x3) | (link_id << 4); + + os_memcpy(pos, ml_key_info.links[i].pn, 6); + pos += 6; + + os_memcpy(pos, ml_key_info.links[i].gtk, + ml_key_info.links[i].gtk_len); + pos += ml_key_info.links[i].gtk_len; + + i++; + } + + if (!sm->mgmt_frame_prot) { + wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %ld", + (long)(pos - start)); + return pos; + } + + /* Add MLO IGTK KDEs */ + for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid || + !ml_key_info.links[i].igtk_len) + continue; + + wpa_printf(MSG_DEBUG, "RSN: MLO IGTK: link=%u", link_id); + wpa_hexdump_key(MSG_DEBUG, "RSN: MLO IGTK", + ml_key_info.links[i].igtk, + ml_key_info.links[i].igtk_len); + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = RSN_SELECTOR_LEN + 2 + 1 + + sizeof(ml_key_info.links[i].ipn) + + ml_key_info.links[i].igtk_len; + + RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_IGTK); + pos += RSN_SELECTOR_LEN; + + /* Add the Key ID */ + *pos++ = ml_key_info.links[i].igtkidx; + *pos++ = 0; + + /* Add the IPN */ + os_memcpy(pos, ml_key_info.links[i].ipn, + sizeof(ml_key_info.links[i].ipn)); + pos += sizeof(ml_key_info.links[i].ipn); + + *pos++ = ml_key_info.links[i].link_id << 4; + + os_memcpy(pos, ml_key_info.links[i].igtk, + ml_key_info.links[i].igtk_len); + pos += ml_key_info.links[i].igtk_len; + + i++; + } + + if (!sm->wpa_auth->conf.beacon_prot) { + wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %ld", + (long)(pos - start)); + return pos; + } + + /* Add MLO BIGTK KDEs */ + for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (!sm->mld_links[link_id].valid || + !ml_key_info.links[i].bigtk || + !ml_key_info.links[i].igtk_len) + continue; + + wpa_printf(MSG_DEBUG, "RSN: MLO BIGTK: link=%u", link_id); + wpa_hexdump_key(MSG_DEBUG, "RSN: MLO BIGTK", + ml_key_info.links[i].bigtk, + ml_key_info.links[i].igtk_len); + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = RSN_SELECTOR_LEN + 2 + 1 + + sizeof(ml_key_info.links[i].bipn) + + ml_key_info.links[i].igtk_len; + + RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_BIGTK); + pos += RSN_SELECTOR_LEN; + + /* Add the Key ID */ + *pos++ = ml_key_info.links[i].bigtkidx; + *pos++ = 0; + + /* Add the BIPN */ + os_memcpy(pos, ml_key_info.links[i].bipn, + sizeof(ml_key_info.links[i].bipn)); + pos += sizeof(ml_key_info.links[i].bipn); + + *pos++ = ml_key_info.links[i].link_id << 4; + + os_memcpy(pos, ml_key_info.links[i].bigtk, + ml_key_info.links[i].igtk_len); + pos += ml_key_info.links[i].igtk_len; + + i++; + } + + wpa_printf(MSG_DEBUG, "RSN: MLO Group KDE len = %ld", (long)(pos - start)); + return pos; +} + +#endif /* CONFIG_IEEE80211BE */ + + +static size_t wpa_auth_ml_kdes_len(struct wpa_state_machine *sm) +{ + size_t kde_len = 0; + +#ifdef CONFIG_IEEE80211BE + unsigned int link_id; + + if (sm->mld_assoc_link_id < 0) + return 0; + + /* For the MAC Address KDE */ + kde_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN; + + /* MLO Link KDE for each link */ + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + struct wpa_authenticator *wpa_auth; + const u8 *ie; + + wpa_auth = wpa_get_link_auth(sm->wpa_auth, link_id); + if (!wpa_auth) + continue; + + kde_len += 2 + RSN_SELECTOR_LEN + 1 + ETH_ALEN; + ie = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len, + WLAN_EID_RSN); + if (ie) + kde_len += 2 + ie[1]; + ie = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len, + WLAN_EID_RSNX); + if (ie) + kde_len += 2 + ie[1]; + } + + kde_len += wpa_auth_ml_group_kdes_len(sm); +#endif /* CONFIG_IEEE80211BE */ + + return kde_len; +} + + +static u8 * wpa_auth_ml_kdes(struct wpa_state_machine *sm, u8 *pos) { - const u8 *elem; - u8 *buf; +#ifdef CONFIG_IEEE80211BE + u8 link_id; + u8 *start = pos; - wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name); - wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override", - old_buf, *len); - buf = os_malloc(*len + ie_len); - if (!buf) - return NULL; - os_memcpy(buf, old_buf, *len); - elem = get_ie(buf, *len, eid); - if (elem) { - u8 elem_len = 2 + elem[1]; + if (sm->mld_assoc_link_id < 0) + return pos; - os_memmove((void *) elem, elem + elem_len, - *len - (elem - buf) - elem_len); - *len -= elem_len; + wpa_printf(MSG_DEBUG, "RSN: MLD: Adding MAC Address KDE"); + pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, + sm->wpa_auth->mld_addr, ETH_ALEN, NULL, 0); + + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + struct wpa_authenticator *wpa_auth; + const u8 *rsne, *rsnxe; + size_t rsne_len, rsnxe_len; + + wpa_auth = wpa_get_link_auth(sm->wpa_auth, link_id); + if (!wpa_auth) + continue; + + rsne = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len, + WLAN_EID_RSN); + rsne_len = rsne ? 2 + rsne[1] : 0; + + rsnxe = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len, + WLAN_EID_RSNX); + rsnxe_len = rsnxe ? 2 + rsnxe[1] : 0; + + wpa_printf(MSG_DEBUG, + "RSN: MLO Link: link=%u, len=%zu", link_id, + RSN_SELECTOR_LEN + 1 + ETH_ALEN + + rsne_len + rsnxe_len); + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = RSN_SELECTOR_LEN + 1 + ETH_ALEN + + rsne_len + rsnxe_len; + + RSN_SELECTOR_PUT(pos, RSN_KEY_DATA_MLO_LINK); + pos += RSN_SELECTOR_LEN; + + /* Add the Link Information */ + *pos = link_id; + if (rsne_len) + *pos |= RSN_MLO_LINK_KDE_LI_RSNE_INFO; + if (rsnxe_len) + *pos |= RSN_MLO_LINK_KDE_LI_RSNXE_INFO; + + pos++; + os_memcpy(pos, wpa_auth->addr, ETH_ALEN); + pos += ETH_ALEN; + + if (rsne_len) { + os_memcpy(pos, rsne, rsne_len); + pos += rsne_len; + } + + if (rsnxe_len) { + os_memcpy(pos, rsnxe, rsnxe_len); + pos += rsnxe_len; + } } - os_memcpy(buf + *len, ie, ie_len); - *len += ie_len; - wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override", - buf, *len); - return buf; + wpa_printf(MSG_DEBUG, "RSN: MLO Link KDE len = %ld", (long)(pos - start)); + pos = wpa_auth_ml_group_kdes(sm, pos); +#endif /* CONFIG_IEEE80211BE */ + + return pos; } -#endif /* CONFIG_TESTING_OPTIONS */ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) { u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, stub_gtk[32]; - size_t gtk_len, kde_len, wpa_ie_len; + size_t gtk_len, kde_len = 0, wpa_ie_len; struct wpa_group *gsm = sm->group; u8 *wpa_ie; int secure, gtkidx, encr = 0; u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL; u8 hdr[2]; struct wpa_auth_config *conf = &sm->wpa_auth->conf; +#ifdef CONFIG_IEEE80211BE + bool is_mld = sm->mld_assoc_link_id >= 0; +#else /* CONFIG_IEEE80211BE */ + bool is_mld = false; +#endif /* CONFIG_IEEE80211BE */ SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); sm->TimeoutEvt = false; @@ -3561,7 +4741,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) wpa_ie = wpa_ie_buf; } #endif /* CONFIG_TESTING_OPTIONS */ - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "sending 3/4 msg of 4-Way Handshake"); if (sm->wpa == WPA_VERSION_WPA2) { if (sm->use_ext_key_id && sm->TimeoutCtr == 1 && @@ -3576,6 +4756,21 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) return; } +#ifdef CONFIG_PASN + if (sm->wpa_auth->conf.secure_ltf && + ieee802_11_rsnx_capab(sm->rsnxe, + WLAN_RSNX_CAPAB_SECURE_LTF) && + wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr, + sm->PTK.ltf_keyseed, + sm->PTK.ltf_keyseed_len)) { + wpa_printf(MSG_ERROR, + "WPA: Failed to set LTF keyseed to driver"); + wpa_sta_disconnect(sm->wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; + } +#endif /* CONFIG_PASN */ + /* WPA2 send GTK in the 4-way handshake */ secure = 1; gtk = gsm->GTK[gsm->GN - 1]; @@ -3598,6 +4793,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) secure = 0; gtk = NULL; gtk_len = 0; + gtkidx = 0; _rsc = NULL; if (sm->rx_eapol_key_secure) { /* @@ -3608,7 +4804,8 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) * by setting the Secure bit here even in the case of * WPA if the supplicant used it first. */ - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround"); secure = 1; } @@ -3640,20 +4837,32 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) kde_len += 2 + RSN_SELECTOR_LEN + 2; #endif /* CONFIG_DPP2 */ + kde_len += wpa_auth_ml_kdes_len(sm); + + if (sm->ssid_protection) + kde_len += 2 + conf->ssid_len; + +#ifdef CONFIG_TESTING_OPTIONS + if (conf->eapol_m3_elements) + kde_len += wpabuf_len(conf->eapol_m3_elements); +#endif /* CONFIG_TESTING_OPTIONS */ + kde = os_malloc(kde_len); if (!kde) goto done; pos = kde; - os_memcpy(pos, wpa_ie, wpa_ie_len); - pos += wpa_ie_len; + if (!is_mld) { + os_memcpy(pos, wpa_ie, wpa_ie_len); + pos += wpa_ie_len; + } #ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { int res; size_t elen; elen = pos - kde; - res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name); + res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name, true); if (res < 0) { wpa_printf(MSG_ERROR, "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data"); @@ -3670,7 +4879,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0); } - if (gtk) { + if (gtk && !is_mld) { hdr[0] = gtkidx & 0x03; pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gtk_len); @@ -3689,9 +4898,8 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) 2 + sm->assoc_resp_ftie[1]); res = 2 + sm->assoc_resp_ftie[1]; } else { - int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); - - res = wpa_write_ftie(conf, use_sha384, + res = wpa_write_ftie(conf, sm->wpa_key_mgmt, + sm->xxkey_len, conf->r0_key_holder, conf->r0_key_holder_len, NULL, NULL, pos, @@ -3751,6 +4959,26 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) } #endif /* CONFIG_DPP2 */ + pos = wpa_auth_ml_kdes(sm, pos); + + if (sm->ssid_protection) { + *pos++ = WLAN_EID_SSID; + *pos++ = conf->ssid_len; + os_memcpy(pos, conf->ssid, conf->ssid_len); + pos += conf->ssid_len; + } + +#ifdef CONFIG_TESTING_OPTIONS + if (conf->eapol_m3_elements) { + os_memcpy(pos, wpabuf_head(conf->eapol_m3_elements), + wpabuf_len(conf->eapol_m3_elements)); + pos += wpabuf_len(conf->eapol_m3_elements); + } + + if (conf->eapol_m3_no_encrypt) + encr = 0; +#endif /* CONFIG_TESTING_OPTIONS */ + wpa_send_eapol(sm->wpa_auth, sm, (secure ? WPA_KEY_INFO_SECURE : 0) | (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ? @@ -3763,16 +4991,74 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) P2P_INTERFACE_STATE_4WAY_HANDSHAKE_3, P2P_CHR_DEFAULT_REASON_CODE); #endif done: - os_free(kde); + bin_clear_free(kde, kde_len); os_free(wpa_ie_buf); os_free(wpa_ie_buf2); } +static int wpa_auth_validate_ml_kdes_m4(struct wpa_state_machine *sm) +{ +#ifdef CONFIG_IEEE80211BE + const struct ieee802_1x_hdr *hdr; + const struct wpa_eapol_key *key; + struct wpa_eapol_ie_parse kde; + const u8 *key_data, *mic; + u16 key_data_length; + size_t mic_len; + + if (sm->mld_assoc_link_id < 0) + return 0; + + /* + * Note: last_rx_eapol_key length fields have already been validated in + * wpa_receive(). + */ + mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len); + + hdr = (const struct ieee802_1x_hdr *) sm->last_rx_eapol_key; + key = (const struct wpa_eapol_key *) (hdr + 1); + mic = (const u8 *) (key + 1); + key_data = mic + mic_len + 2; + key_data_length = WPA_GET_BE16(mic + mic_len); + if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) - + sizeof(*key) - mic_len - 2) + return -1; + + if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) { + wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, + "received EAPOL-Key msg 4/4 with invalid Key Data contents"); + return -1; + } + + /* MLD MAC address must be the same */ + if (!kde.mac_addr || + !ether_addr_equal(kde.mac_addr, sm->peer_mld_addr)) { + wpa_printf(MSG_DEBUG, + "MLD: Mismatching or missing MLD address in EAPOL-Key msg 4/4"); + return -1; + } + + wpa_printf(MSG_DEBUG, "MLD: MLD address in EAPOL-Key msg 4/4: " MACSTR, + MAC2STR(kde.mac_addr)); +#endif /* CONFIG_IEEE80211BE */ + + return 0; +} + + SM_STATE(WPA_PTK, PTKINITDONE) { SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk); sm->EAPOLKeyReceived = false; + + if (wpa_auth_validate_ml_kdes_m4(sm) < 0) { + wpa_sta_disconnect(sm->wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; + } + if (sm->Pair) { enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise); int klen = wpa_cipher_key_len(sm->pairwise); @@ -3796,6 +5082,22 @@ SM_STATE(WPA_PTK, PTKINITDONE) WLAN_REASON_PREV_AUTH_NOT_VALID); return; } + +#ifdef CONFIG_PASN + if (sm->wpa_auth->conf.secure_ltf && + ieee802_11_rsnx_capab(sm->rsnxe, + WLAN_RSNX_CAPAB_SECURE_LTF) && + wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr, + sm->PTK.ltf_keyseed, + sm->PTK.ltf_keyseed_len)) { + wpa_printf(MSG_ERROR, + "WPA: Failed to set LTF keyseed to driver"); + wpa_sta_disconnect(sm->wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; + } +#endif /* CONFIG_PASN */ + /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ sm->pairwise_set = true; @@ -3828,15 +5130,17 @@ SM_STATE(WPA_PTK, PTKINITDONE) sm->PInitAKeys = true; else sm->has_GTK = true; - wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "pairwise key handshake completed (%s)", sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN"); wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO, "EAPOL-4WAY-HS-COMPLETED " MACSTR, MAC2STR(sm->addr)); #ifdef CONFIG_IEEE80211R_AP - wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr); + wpa_ft_push_pmk_r1(sm->wpa_auth, wpa_auth_get_spa(sm)); #endif /* CONFIG_IEEE80211R_AP */ + + sm->ptkstart_without_success = 0; } @@ -3849,7 +5153,7 @@ SM_STEP(WPA_PTK) SM_ENTER(WPA_PTK, INITIALIZE); else if (sm->Disconnect /* || FIX: dot11RSNAConfigSALifetime timeout */) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "WPA_PTK: sm->Disconnect"); SM_ENTER(WPA_PTK, DISCONNECT); } @@ -3898,7 +5202,8 @@ SM_STEP(WPA_PTK) #endif /* CONFIG_DPP */ } else { wpa_auth->dot11RSNA4WayHandshakeFailures++; - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "INITPMK - keyAvailable = false"); SM_ENTER(WPA_PTK, DISCONNECT); } @@ -3911,8 +5216,14 @@ SM_STEP(WPA_PTK) } else if (wpa_auth_uses_sae(sm) && sm->pmksa) { SM_ENTER(WPA_PTK, PTKSTART); #endif /* CONFIG_SAE */ + } else if (wpa_key_mgmt_wpa_psk_no_sae(sm->wpa_key_mgmt) && + wpa_auth->conf.radius_psk) { + wpa_printf(MSG_DEBUG, + "INITPSK: No PSK yet available for STA - use RADIUS later"); + SM_ENTER(WPA_PTK, PTKSTART); } else { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "no PSK configured for the STA"); wpa_auth->dot11RSNA4WayHandshakeFailures++; SM_ENTER(WPA_PTK, DISCONNECT); @@ -3924,7 +5235,8 @@ SM_STEP(WPA_PTK) SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); else if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) { wpa_auth->dot11RSNA4WayHandshakeFailures++; - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, "PTKSTART: Retry limit %u reached", conf->wpa_pairwise_update_count); sm->disconnect_reason = @@ -3956,7 +5268,8 @@ SM_STEP(WPA_PTK) (conf->wpa_disable_eapol_key_retries && sm->TimeoutCtr > 1)) { wpa_auth->dot11RSNA4WayHandshakeFailures++; - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, "PTKINITNEGOTIATING: Retry limit %u reached", conf->wpa_pairwise_update_count); sm->disconnect_reason = @@ -3987,11 +5300,16 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) { u8 rsc[WPA_KEY_RSC_LEN]; struct wpa_group *gsm = sm->group; - const u8 *kde; + const u8 *kde = NULL; u8 *kde_buf = NULL, *pos, hdr[2]; - size_t kde_len; + size_t kde_len = 0; u8 *gtk, stub_gtk[32]; struct wpa_auth_config *conf = &sm->wpa_auth->conf; + bool is_mld = false; + +#ifdef CONFIG_IEEE80211BE + is_mld = sm->mld_assoc_link_id >= 0; +#endif /* CONFIG_IEEE80211BE */ SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group); @@ -4013,7 +5331,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) os_memset(rsc, 0, WPA_KEY_RSC_LEN); if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE) wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc); - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "sending 1/2 msg of Group Key Handshake"); gtk = gsm->GTK[gsm->GN - 1]; @@ -4026,7 +5344,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) return; gtk = stub_gtk; } - if (sm->wpa == WPA_VERSION_WPA2) { + + if (sm->wpa == WPA_VERSION_WPA2 && !is_mld) { kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm); kde_buf = os_malloc(kde_len); @@ -4045,6 +5364,19 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) return; } kde_len = pos - kde; +#ifdef CONFIG_IEEE80211BE + } else if (sm->wpa == WPA_VERSION_WPA2 && is_mld) { + kde_len = wpa_auth_ml_group_kdes_len(sm); + if (kde_len) { + kde_buf = os_malloc(kde_len); + if (!kde_buf) + return; + + kde = pos = kde_buf; + pos = wpa_auth_ml_group_kdes(sm, pos); + kde_len = pos - kde_buf; + } +#endif /* CONFIG_IEEE80211BE */ } else { kde = gtk; kde_len = gsm->GTK_len; @@ -4058,7 +5390,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0), rsc, NULL, kde, kde_len, gsm->GN, 1); - os_free(kde_buf); + bin_clear_free(kde_buf, kde_len); } @@ -4094,7 +5426,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED) return; if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "received EAPOL-Key group msg 2/2 with invalid Key Data contents"); return; } @@ -4105,7 +5437,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED) int tx_seg1_idx; if (wpa_channel_info(wpa_auth, &ci) != 0) { - wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), + LOGGER_INFO, "Failed to get channel info to validate received OCI in EAPOL-Key group 2/2"); return; } @@ -4119,24 +5452,25 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED) if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci, tx_chanwidth, tx_seg1_idx) != OCI_SUCCESS) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), + 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); + MAC2STR(wpa_auth_get_spa(sm)), + ocv_errorstr); return; } } #endif /* CONFIG_OCV */ if (sm->GUpdateStationKeys) - sm->group->GKeyDoneStations--; - sm->GUpdateStationKeys = false; + wpa_gkeydone_sta(sm); sm->GTimeoutCtr = 0; /* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */ - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "group key handshake completed (%s)", sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN"); sm->has_GTK = true; @@ -4147,11 +5481,18 @@ SM_STATE(WPA_PTK_GROUP, KEYERROR) { SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group); if (sm->GUpdateStationKeys) - sm->group->GKeyDoneStations--; - sm->GUpdateStationKeys = false; + wpa_gkeydone_sta(sm); + if (sm->wpa_auth->conf.no_disconnect_on_group_keyerror && + sm->wpa == WPA_VERSION_WPA2) { + wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, + "group key handshake failed after %u tries - allow STA to remain connected", + sm->wpa_auth->conf.wpa_group_update_count); + return; + } sm->Disconnect = true; sm->disconnect_reason = WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT; - wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO, "group key handshake failed (%s) after %u tries", sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN", sm->wpa_auth->conf.wpa_group_update_count); @@ -4219,19 +5560,30 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, group->IGTK[group->GN_igtk - 4], len); } - if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION && - conf->beacon_prot) { - len = wpa_cipher_key_len(conf->group_mgmt_cipher); - os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); - inc_byte_array(group->Counter, WPA_NONCE_LEN); - if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion", - wpa_auth->addr, group->GNonce, - group->BIGTK[group->GN_bigtk - 6], len) < 0) - ret = -1; - wpa_hexdump_key(MSG_DEBUG, "BIGTK", - group->BIGTK[group->GN_bigtk - 6], len); + if (!wpa_auth->non_tx_beacon_prot && + conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) + return ret; + if (!conf->beacon_prot) + return ret; + + if (wpa_auth->conf.tx_bss_auth) { + group = wpa_auth->conf.tx_bss_auth->group; + if (group->bigtk_set) + return ret; + wpa_printf(MSG_DEBUG, "Set up BIGTK for TX BSS"); } + len = wpa_cipher_key_len(conf->group_mgmt_cipher); + os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); + inc_byte_array(group->Counter, WPA_NONCE_LEN); + if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion", + wpa_auth->addr, group->GNonce, + group->BIGTK[group->GN_bigtk - 6], len) < 0) + return -1; + group->bigtk_set = true; + wpa_hexdump_key(MSG_DEBUG, "BIGTK", + group->BIGTK[group->GN_bigtk - 6], len); + return ret; } @@ -4264,7 +5616,8 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) return 0; if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, "Not in PTKINITDONE; skip Group Key update"); sm->GUpdateStationKeys = false; return 0; @@ -4275,7 +5628,8 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) * Since we clear the GKeyDoneStations before the loop, the * station needs to be counted here anyway. */ - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, "GUpdateStationKeys was already set when marking station for GTK rekeying"); } @@ -4390,9 +5744,10 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos) int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos) { - struct wpa_group *gsm = sm->group; + struct wpa_authenticator *wpa_auth = sm->wpa_auth; + struct wpa_group *gsm = wpa_auth->group; u8 *start = pos; - size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + size_t len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); /* * BIGTK subelement: @@ -4402,7 +5757,7 @@ int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos) *pos++ = 2 + 6 + len; WPA_PUT_LE16(pos, gsm->GN_bigtk); pos += 2; - if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0) + if (wpa_auth_get_seqnum(wpa_auth, NULL, gsm->GN_bigtk, pos) != 0) return 0; pos += 6; @@ -4428,17 +5783,11 @@ int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos) #endif /* CONFIG_WNM_AP */ -static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, - struct wpa_group *group) +static void wpa_group_update_gtk(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) { int tmp; - wpa_printf(MSG_EXCESSIVE, - "WPA: group state machine entering state SETKEYS (VLAN-ID %d)", - group->vlan_id); - group->changed = true; - group->wpa_group_state = WPA_GROUP_SETKEYS; - group->GTKReKey = false; tmp = group->GM; group->GM = group->GN; group->GN = tmp; @@ -4452,6 +5801,25 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, * counting the STAs that are marked with GUpdateStationKeys instead of * including all STAs that could be in not-yet-completed state. */ wpa_gtk_update(wpa_auth, group); +} + + +static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, + struct wpa_group *group) +{ + wpa_printf(MSG_EXCESSIVE, + "WPA: group state machine entering state SETKEYS (VLAN-ID %d)", + group->vlan_id); + group->changed = true; + group->wpa_group_state = WPA_GROUP_SETKEYS; + group->GTKReKey = false; + +#ifdef CONFIG_IEEE80211BE + if (wpa_auth->is_ml) + goto skip_update; +#endif /* CONFIG_IEEE80211BE */ + + wpa_group_update_gtk(wpa_auth, group); if (group->GKeyDoneStations) { wpa_printf(MSG_DEBUG, @@ -4459,6 +5827,10 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, group->GKeyDoneStations); group->GKeyDoneStations = 0; } + +#ifdef CONFIG_IEEE80211BE +skip_update: +#endif /* CONFIG_IEEE80211BE */ wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group); wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d", group->GKeyDoneStations); @@ -4492,12 +5864,21 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, KEY_FLAG_GROUP_TX_DEFAULT) < 0) ret = -1; - if (ret == 0 && conf->beacon_prot && - wpa_auth_set_key(wpa_auth, group->vlan_id, alg, + if (ret || !conf->beacon_prot) + return ret; + if (wpa_auth->conf.tx_bss_auth) { + wpa_auth = wpa_auth->conf.tx_bss_auth; + group = wpa_auth->group; + if (!group->bigtk_set || group->bigtk_configured) + return ret; + } + if (wpa_auth_set_key(wpa_auth, group->vlan_id, alg, broadcast_ether_addr, group->GN_bigtk, group->BIGTK[group->GN_bigtk - 6], len, KEY_FLAG_GROUP_TX_DEFAULT) < 0) ret = -1; + else + group->bigtk_configured = true; } return ret; @@ -4509,7 +5890,7 @@ static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx) if (sm->group == ctx) { wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR_SEC " for disconnection due to fatal failure", - MAC2STR_SEC(sm->addr)); + MAC2STR_SEC(wpa_auth_get_spa(sm))); sm->Disconnect = true; } @@ -4568,6 +5949,61 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, } +static void wpa_clear_changed(struct wpa_state_machine *sm) +{ +#ifdef CONFIG_IEEE80211BE + int link_id; +#endif /* CONFIG_IEEE80211BE */ + + sm->changed = false; + sm->wpa_auth->group->changed = false; + +#ifdef CONFIG_IEEE80211BE + for_each_sm_auth(sm, link_id) + sm->mld_links[link_id].wpa_auth->group->changed = false; +#endif /* CONFIG_IEEE80211BE */ +} + + +static void wpa_group_sm_step_links(struct wpa_state_machine *sm) +{ +#ifdef CONFIG_IEEE80211BE + int link_id; +#endif /* CONFIG_IEEE80211BE */ + + if (!sm || !sm->wpa_auth) + return; + wpa_group_sm_step(sm->wpa_auth, sm->wpa_auth->group); + +#ifdef CONFIG_IEEE80211BE + for_each_sm_auth(sm, link_id) { + wpa_group_sm_step(sm->mld_links[link_id].wpa_auth, + sm->mld_links[link_id].wpa_auth->group); + } +#endif /* CONFIG_IEEE80211BE */ +} + + +static bool wpa_group_sm_changed(struct wpa_state_machine *sm) +{ +#ifdef CONFIG_IEEE80211BE + int link_id; +#endif /* CONFIG_IEEE80211BE */ + bool changed; + + if (!sm || !sm->wpa_auth) + return false; + changed = sm->wpa_auth->group->changed; + +#ifdef CONFIG_IEEE80211BE + for_each_sm_auth(sm, link_id) + changed |= sm->mld_links[link_id].wpa_auth->group->changed; +#endif /* CONFIG_IEEE80211BE */ + + return changed; +} + + static int wpa_sm_step(struct wpa_state_machine *sm) { if (!sm) @@ -4586,8 +6022,7 @@ static int wpa_sm_step(struct wpa_state_machine *sm) if (sm->pending_deinit) break; - sm->changed = false; - sm->wpa_auth->group->changed = false; + wpa_clear_changed(sm); SM_STEP_RUN(WPA_PTK); if (sm->pending_deinit) @@ -4595,14 +6030,14 @@ static int wpa_sm_step(struct wpa_state_machine *sm) SM_STEP_RUN(WPA_PTK_GROUP); if (sm->pending_deinit) break; - wpa_group_sm_step(sm->wpa_auth, sm->group); - } while (sm->changed || sm->wpa_auth->group->changed); + wpa_group_sm_step_links(sm); + } while (sm->changed || wpa_group_sm_changed(sm)); sm->in_step_loop = 0; if (sm->pending_deinit) { wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state machine deinit for " - MACSTR_SEC, MAC2STR_SEC(sm->addr)); + MACSTR_SEC, MAC2STR_SEC(wpa_auth_get_spa(sm))); wpa_free_sta_sm(sm); return 1; } @@ -4642,9 +6077,11 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth) tmp = group->GM_igtk; group->GM_igtk = group->GN_igtk; group->GN_igtk = tmp; - tmp = group->GM_bigtk; - group->GM_bigtk = group->GN_bigtk; - group->GN_bigtk = tmp; + if (!wpa_auth->conf.tx_bss_auth) { + tmp = group->GM_bigtk; + group->GM_bigtk = group->GN_bigtk; + group->GN_bigtk = tmp; + } wpa_gtk_update(wpa_auth, group); wpa_group_config_group_keys(wpa_auth, group); } @@ -4795,11 +6232,13 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen) "wpa=%d\n" "AKMSuiteSelector=" RSN_SUITE "\n" "hostapdWPAPTKState=%d\n" - "hostapdWPAPTKGroupState=%d\n", + "hostapdWPAPTKGroupState=%d\n" + "hostapdMFPR=%d\n", sm->wpa, RSN_SUITE_ARG(wpa_akm_to_suite(sm->wpa_key_mgmt)), sm->wpa_ptk_state, - sm->wpa_ptk_group_state); + sm->wpa_ptk_group_state, + sm->mfpr); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; @@ -4836,6 +6275,14 @@ const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len) } +const u8 * wpa_auth_get_dpp_pkhash(struct wpa_state_machine *sm) +{ + if (!sm || !sm->pmksa) + return NULL; + return sm->pmksa->dpp_pkhash; +} + + int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm) { if (!sm) @@ -4928,7 +6375,8 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len); if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL, sm->PTK.kck, sm->PTK.kck_len, - sm->wpa_auth->addr, sm->addr, session_timeout, + wpa_auth_get_aa(sm), + wpa_auth_get_spa(sm), session_timeout, eapol, sm->wpa_key_mgmt)) return 0; @@ -4983,18 +6431,24 @@ void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid) int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *pmk, size_t pmk_len, const u8 *pmkid, - int session_timeout, int akmp) + int session_timeout, int akmp, const u8 *dpp_pkhash) { + struct rsn_pmksa_cache_entry *entry; + if (!wpa_auth || wpa_auth->conf.disable_pmksa_caching) return -1; - wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN); - if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid, + wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (3)", pmk, PMK_LEN); + entry = pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid, NULL, 0, wpa_auth->addr, addr, session_timeout, - NULL, akmp)) - return 0; + NULL, akmp); + if (!entry) + return -1; - return -1; + if (dpp_pkhash) + entry->dpp_pkhash = os_memdup(dpp_pkhash, SHA256_MAC_LEN); + + return 0; } @@ -5083,6 +6537,15 @@ int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth, #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */ +struct rsn_pmksa_cache * +wpa_auth_get_pmksa_cache(struct wpa_authenticator *wpa_auth) +{ + if (!wpa_auth || !wpa_auth->pmksa) + return NULL; + return wpa_auth->pmksa; +} + + struct rsn_pmksa_cache_entry * wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, const u8 *pmkid) @@ -5096,13 +6559,14 @@ wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa, struct wpa_state_machine *sm, struct wpa_authenticator *wpa_auth, - u8 *pmkid, u8 *pmk) + u8 *pmkid, u8 *pmk, size_t *pmk_len) { if (!sm) return; sm->pmksa = pmksa; - os_memcpy(pmk, pmksa->pmk, PMK_LEN); + os_memcpy(pmk, pmksa->pmk, pmksa->pmk_len); + *pmk_len = pmksa->pmk_len; os_memcpy(pmkid, pmksa->pmkid, PMKID_LEN); os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmksa->pmkid, PMKID_LEN); } @@ -5306,7 +6770,7 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR_SEC " to use group state machine for VLAN ID %d", - MAC2STR_SEC(sm->addr), vlan_id); + MAC2STR_SEC(wpa_auth_get_spa(sm)), vlan_id); wpa_group_get(sm->wpa_auth, group); wpa_group_put(sm->wpa_auth, sm->group); @@ -5322,7 +6786,7 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, if (!wpa_auth || !sm) return; wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR_SEC - " ack=%d", MAC2STR_SEC(sm->addr), ack); + " ack=%d", MAC2STR_SEC(wpa_auth_get_spa(sm)), ack); if (sm->pending_1_of_4_timeout && ack) { /* * Some deployed supplicant implementations update their SNonce @@ -5366,7 +6830,8 @@ int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm) { if (!sm) return 0; - return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE; + return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE || + sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY; } @@ -5442,13 +6907,14 @@ wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth, #ifdef CONFIG_IEEE80211R_AP -int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384, +int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, u8 *buf, size_t len) { struct wpa_auth_config *conf = &wpa_auth->conf; - return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder, - conf->r0_key_holder_len, + return wpa_write_ftie(conf, sm->wpa_key_mgmt, sm->xxkey_len, + conf->r0_key_holder, conf->r0_key_holder_len, NULL, NULL, buf, len, NULL, 0, 0); } #endif /* CONFIG_IEEE80211R_AP */ @@ -5495,6 +6961,13 @@ void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z) #endif /* CONFIG_DPP2 */ +void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val) +{ + if (sm) + sm->ssid_protection = val; +} + + void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth, u8 val) { @@ -5518,7 +6991,7 @@ int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce, anonce = anonce_buf; } - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "sending 1/4 msg of 4-Way Handshake (TESTING)"); wpa_send_eapol(sm->wpa_auth, sm, WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL, @@ -5560,7 +7033,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, wpa_ie = wpa_ie + wpa_ie[1] + 2; wpa_ie_len = wpa_ie[1] + 2; } - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "sending 3/4 msg of 4-Way Handshake (TESTING)"); if (sm->wpa == WPA_VERSION_WPA2) { /* WPA2 send GTK in the 4-way handshake */ @@ -5585,7 +7058,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, * by setting the Secure bit here even in the case of * WPA if the supplicant used it first. */ - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), + LOGGER_DEBUG, "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround"); secure = 1; } @@ -5617,7 +7091,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, size_t elen; elen = pos - kde; - res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name); + res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name, true); if (res < 0) { wpa_printf(MSG_ERROR, "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data"); @@ -5662,9 +7136,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, 2 + sm->assoc_resp_ftie[1]); res = 2 + sm->assoc_resp_ftie[1]; } else { - int use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); - - res = wpa_write_ftie(conf, use_sha384, + res = wpa_write_ftie(conf, sm->wpa_key_mgmt, + sm->xxkey_len, conf->r0_key_holder, conf->r0_key_holder_len, NULL, NULL, pos, @@ -5702,7 +7175,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_KEY_TYPE, _rsc, sm->ANonce, kde, pos - kde, 0, encr); - os_free(kde); + bin_clear_free(kde, kde_len); return 0; } @@ -5723,7 +7196,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm, /* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */ os_memset(rsc, 0, WPA_KEY_RSC_LEN); /* Use 0 RSC */ - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, "sending 1/2 msg of Group Key Handshake (TESTING)"); gtk = gsm->GTK[gsm->GN - 1]; @@ -5770,7 +7243,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm, (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0), rsc, NULL, kde, kde_len, gsm->GN, 1); - os_free(kde_buf); + bin_clear_free(kde_buf, kde_len); return 0; } @@ -5779,8 +7252,10 @@ int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth) { if (!wpa_auth) return -1; - eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); - return eloop_register_timeout(0, 0, wpa_rekey_gtk, wpa_auth, NULL); + eloop_cancel_timeout(wpa_rekey_gtk, + wpa_get_primary_auth(wpa_auth), NULL); + return eloop_register_timeout(0, 0, wpa_rekey_gtk, + wpa_get_primary_auth(wpa_auth), NULL); } @@ -5826,3 +7301,91 @@ void wpa_auth_set_ocv_override_freq(struct wpa_authenticator *wpa_auth, } #endif /* CONFIG_TESTING_OPTIONS */ + + +void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success) +{ + if (!sm->waiting_radius_psk) { + wpa_printf(MSG_DEBUG, + "Ignore RADIUS PSK response for " MACSTR + " that did not wait one", + MAC2STR(sm->addr)); + return; + } + + wpa_printf(MSG_DEBUG, "RADIUS PSK response for " MACSTR " (%s)", + MAC2STR(sm->addr), success ? "success" : "fail"); + sm->waiting_radius_psk = 0; + + if (success) { + /* Try to process the EAPOL-Key msg 2/4 again */ + sm->EAPOLKeyReceived = true; + } else { + sm->Disconnect = true; + } + + eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL); +} + + +void wpa_auth_set_ml_info(struct wpa_state_machine *sm, + u8 mld_assoc_link_id, struct mld_info *info) +{ +#ifdef CONFIG_IEEE80211BE + unsigned int link_id; + + if (!info) + return; + + os_memset(sm->mld_links, 0, sizeof(sm->mld_links)); + sm->n_mld_affiliated_links = 0; + + wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm), LOGGER_DEBUG, + "MLD: Initialization"); + + os_memcpy(sm->peer_mld_addr, info->common_info.mld_addr, ETH_ALEN); + + sm->mld_assoc_link_id = mld_assoc_link_id; + + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + struct mld_link_info *link = &info->links[link_id]; + struct mld_link *sm_link = &sm->mld_links[link_id]; + struct wpa_get_link_auth_ctx ctx; + + sm_link->valid = link->valid; + if (!link->valid) + continue; + + os_memcpy(sm_link->peer_addr, link->peer_addr, ETH_ALEN); + + wpa_printf(MSG_DEBUG, + "WPA_AUTH: MLD: id=%u, peer=" MACSTR, + link_id, + MAC2STR(sm_link->peer_addr)); + + if (link_id != mld_assoc_link_id) { + sm->n_mld_affiliated_links++; + ctx.addr = link->local_addr; + ctx.mld_addr = NULL; + ctx.link_id = -1; + ctx.wpa_auth = NULL; + wpa_auth_for_each_auth(sm->wpa_auth, + wpa_get_link_sta_auth, &ctx); + if (ctx.wpa_auth) { + sm_link->wpa_auth = ctx.wpa_auth; + wpa_group_get(sm_link->wpa_auth, + sm_link->wpa_auth->group); + } + } else { + sm_link->wpa_auth = sm->wpa_auth; + } + + if (!sm_link->wpa_auth) + wpa_printf(MSG_ERROR, + "Unable to find authenticator object for ML STA " + MACSTR " on link id %d", + MAC2STR(sm->wpa_auth->mld_addr), + link_id); + } +#endif /* CONFIG_IEEE80211BE */ +} diff --git a/wpa_supplicant-2.9_standard/src/ap/wpa_auth.h b/wpa_supplicant-2.9_standard/src/ap/wpa_auth.h index aaa7e02f45d1a9a27867ce9dbecce22b1a2ce1c2..4e727b9be34d7a1d3181b8557aadeb7349284cc5 100644 --- a/wpa_supplicant-2.9_standard/src/ap/wpa_auth.h +++ b/wpa_supplicant-2.9_standard/src/ap/wpa_auth.h @@ -1,6 +1,6 @@ /* * hostapd - IEEE 802.11i-2004 / WPA Authenticator - * Copyright (c) 2004-2017, Jouni Malinen + * Copyright (c) 2004-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -15,6 +15,7 @@ #include "common/ieee802_11_defs.h" struct vlan_description; +struct mld_info; #define MAX_OWN_IE_OVERRIDE 256 @@ -197,9 +198,9 @@ struct wpa_auth_config { #ifdef CONFIG_OCV int ocv; /* Operating Channel Validation */ #endif /* CONFIG_OCV */ -#ifdef CONFIG_IEEE80211R_AP u8 ssid[SSID_MAX_LEN]; size_t ssid_len; +#ifdef CONFIG_IEEE80211R_AP u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; u8 r0_key_holder[FT_R0KH_ID_MAX_LEN]; size_t r0_key_holder_len; @@ -240,6 +241,10 @@ struct wpa_auth_config { unsigned int gtk_rsc_override_set:1; unsigned int igtk_rsc_override_set:1; int ft_rsnxe_used; + bool delay_eapol_tx; + struct wpabuf *eapol_m1_elements; + struct wpabuf *eapol_m3_elements; + bool eapol_m3_no_encrypt; #endif /* CONFIG_TESTING_OPTIONS */ unsigned int oci_freq_override_eapol_m3; unsigned int oci_freq_override_eapol_g1; @@ -255,7 +260,7 @@ struct wpa_auth_config { unsigned int fils_cache_id_set:1; u8 fils_cache_id[FILS_CACHE_ID_LEN]; #endif /* CONFIG_FILS */ - int sae_pwe; + enum sae_pwe sae_pwe; bool sae_pk; unsigned int secure_ltf:1; @@ -273,6 +278,23 @@ struct wpa_auth_config { * PTK derivation regardless of advertised capabilities. */ bool force_kdk_derivation; + + bool radius_psk; + + bool no_disconnect_on_group_keyerror; + + /* Pointer to Multi-BSSID transmitted BSS authenticator instance. + * Set only in nontransmitted BSSs, i.e., is NULL for transmitted BSS + * and in BSSs that are not part of a Multi-BSSID set. */ + struct wpa_authenticator *tx_bss_auth; + +#ifdef CONFIG_IEEE80211BE + const u8 *mld_addr; + int link_id; + struct wpa_authenticator *first_link_auth; +#endif /* CONFIG_IEEE80211BE */ + + bool ssid_protection; }; typedef enum { @@ -285,6 +307,30 @@ typedef enum { WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx } wpa_eapol_variable; +struct wpa_auth_ml_key_info { + unsigned int n_mld_links; + bool mgmt_frame_prot; + bool beacon_prot; + + struct wpa_auth_ml_link_key_info { + u8 link_id; + + u8 gtkidx; + u8 gtk_len; + u8 pn[6]; + const u8 *gtk; + + u8 igtkidx; + u8 igtk_len; + const u8 *igtk; + u8 ipn[6]; + + u8 bigtkidx; + const u8 *bigtk; + u8 bipn[6]; + } links[MAX_NUM_MLD_LINKS]; +}; + struct wpa_auth_callbacks { void (*logger)(void *ctx, const u8 *addr, logger_level level, const char *txt); @@ -304,6 +350,7 @@ struct wpa_auth_callbacks { int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq); int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data, size_t data_len, int encrypt); + int (*get_sta_count)(void *ctx); int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx), void *cb_ctx); int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a, @@ -320,6 +367,9 @@ struct wpa_auth_callbacks { void (*store_ptksa)(void *ctx, const u8 *addr, int cipher, u32 life_time, const struct wpa_ptk *ptk); void (*clear_ptksa)(void *ctx, const u8 *addr, int cipher); + void (*request_radius_psk)(void *ctx, const u8 *addr, int key_mgmt, + const u8 *anonce, + const u8 *eapol, size_t eapol_len); #ifdef CONFIG_IEEE80211R_AP struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr); int (*add_sta_ft)(void *ctx, const u8 *sta_addr); @@ -345,6 +395,14 @@ struct wpa_auth_callbacks { #ifdef CONFIG_MESH int (*start_ampe)(void *ctx, const u8 *sta_addr); #endif /* CONFIG_MESH */ +#ifdef CONFIG_PASN + int (*set_ltf_keyseed)(void *ctx, const u8 *addr, const u8 *ltf_keyseed, + size_t ltf_keyseed_len); +#endif /* CONFIG_PASN */ +#ifdef CONFIG_IEEE80211BE + int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info); +#endif /* CONFIG_IEEE80211BE */ + int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2); }; struct wpa_authenticator * wpa_init(const u8 *addr, @@ -370,7 +428,8 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, const u8 *wpa_ie, size_t wpa_ie_len, const u8 *rsnxe, size_t rsnxe_len, const u8 *mdie, size_t mdie_len, - const u8 *owe_dh, size_t owe_dh_len); + const u8 *owe_dh, size_t owe_dh_len, + struct wpa_state_machine *assoc_sm); int wpa_validate_osen(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, const u8 *osen_ie, size_t osen_ie_len); @@ -401,6 +460,7 @@ void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth); int wpa_auth_pairwise_set(struct wpa_state_machine *sm); int wpa_auth_get_pairwise(struct wpa_state_machine *sm); const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len); +const u8 * wpa_auth_get_dpp_pkhash(struct wpa_state_machine *sm); int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm); int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm); int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm); @@ -425,7 +485,7 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr, void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid); int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *pmk, size_t pmk_len, const u8 *pmkid, - int session_timeout, int akmp); + int session_timeout, int akmp, const u8 *dpp_pkhash); void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, const u8 *sta_addr); int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf, @@ -439,6 +499,8 @@ wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk, const u8 *pmkid, int expiration); int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth, struct rsn_pmksa_cache_entry *entry); +struct rsn_pmksa_cache * +wpa_auth_get_pmksa_cache(struct wpa_authenticator *wpa_auth); struct rsn_pmksa_cache_entry * wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, const u8 *pmkid); @@ -448,7 +510,7 @@ wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth, void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa, struct wpa_state_machine *sm, struct wpa_authenticator *wpa_auth, - u8 *pmkid, u8 *pmk); + u8 *pmkid, u8 *pmk, size_t *pmk_len); int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id); void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int ack); @@ -458,9 +520,9 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, size_t max_len, int auth_alg, const u8 *req_ies, size_t req_ies_len, int omit_rsnxe); -void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, +void wpa_ft_process_auth(struct wpa_state_machine *sm, u16 auth_transaction, const u8 *ies, size_t ies_len, - void (*cb)(void *ctx, const u8 *dst, const u8 *bssid, + void (*cb)(void *ctx, const u8 *dst, u16 auth_transaction, u16 resp, const u8 *ies, size_t ies_len), void *ctx); @@ -526,7 +588,8 @@ int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies, int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth, int ap_seg1_idx, int *bandwidth, int *seg1_idx); -int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384, +int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, u8 *buf, size_t len); void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm, u8 *fils_anonce, u8 *fils_snonce, @@ -543,6 +606,7 @@ bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth, u8 *fd_rsn_info); void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg); void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z); +void wpa_auth_set_ssid_protection(struct wpa_state_machine *sm, bool val); void wpa_auth_set_transition_disable(struct wpa_authenticator *wpa_auth, u8 val); @@ -579,4 +643,21 @@ int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, int vlan_id, void wpa_auth_store_ptksa(struct wpa_authenticator *wpa_auth, const u8 *addr, int cipher, u32 life_time, const struct wpa_ptk *ptk); +void wpa_auth_sta_radius_psk_resp(struct wpa_state_machine *sm, bool success); + +void wpa_auth_set_ml_info(struct wpa_state_machine *sm, + u8 mld_assoc_link_id, struct mld_info *info); +void wpa_auth_ml_get_key_info(struct wpa_authenticator *a, + struct wpa_auth_ml_link_key_info *info, + bool mgmt_frame_prot, bool beacon_prot); + +void wpa_release_link_auth_ref(struct wpa_state_machine *sm, + int release_link_id); + +#define for_each_sm_auth(sm, link_id) \ + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) \ + if (sm->mld_links[link_id].valid && \ + sm->mld_links[link_id].wpa_auth && \ + sm->wpa_auth != sm->mld_links[link_id].wpa_auth) + #endif /* WPA_AUTH_H */ diff --git a/wpa_supplicant-2.9_standard/src/ap/wpa_auth_ft.c b/wpa_supplicant-2.9_standard/src/ap/wpa_auth_ft.c index 0d03fcb2a9f0f6806529a68a22a0937cf75d47ee..24b5d389b7ae5a0e754d891f42361988fc8b1ec5 100644 --- a/wpa_supplicant-2.9_standard/src/ap/wpa_auth_ft.c +++ b/wpa_supplicant-2.9_standard/src/ap/wpa_auth_ft.c @@ -20,6 +20,7 @@ #include "crypto/aes_siv.h" #include "crypto/aes_wrap.h" #include "crypto/sha384.h" +#include "crypto/sha512.h" #include "crypto/random.h" #include "ap_config.h" #include "ieee802_11.h" @@ -34,6 +35,9 @@ const unsigned int ftRRBseqTimeout = 10; const unsigned int ftRRBmaxQueueLen = 100; +/* TODO: make these configurable */ +static const int dot11RSNAConfigPMKLifetime = 43200; + static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm, const u8 *current_ap, const u8 *sta_addr, @@ -805,15 +809,29 @@ int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len) } -int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384, +int wpa_write_ftie(struct wpa_auth_config *conf, int key_mgmt, size_t key_len, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *anonce, const u8 *snonce, u8 *buf, size_t len, const u8 *subelem, size_t subelem_len, int rsnxe_used) { u8 *pos = buf, *ielen; - size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) : - sizeof(struct rsn_ftie); + size_t hdrlen; + u16 mic_control = rsnxe_used ? FTE_MIC_CTRL_RSNXE_USED : 0; + + if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + key_len == SHA256_MAC_LEN) + hdrlen = sizeof(struct rsn_ftie); + else if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + key_len == SHA384_MAC_LEN) + hdrlen = sizeof(struct rsn_ftie_sha384); + else if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + key_len == SHA512_MAC_LEN) + hdrlen = sizeof(struct rsn_ftie_sha512); + else if (wpa_key_mgmt_sha384(key_mgmt)) + hdrlen = sizeof(struct rsn_ftie_sha384); + else + hdrlen = sizeof(struct rsn_ftie); if (len < 2 + hdrlen + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len + subelem_len) @@ -822,12 +840,27 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384, *pos++ = WLAN_EID_FAST_BSS_TRANSITION; ielen = pos++; - if (use_sha384) { + if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + key_len == SHA512_MAC_LEN) { + struct rsn_ftie_sha512 *hdr = (struct rsn_ftie_sha512 *) pos; + + os_memset(hdr, 0, sizeof(*hdr)); + pos += sizeof(*hdr); + mic_control |= FTE_MIC_LEN_32 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + WPA_PUT_LE16(hdr->mic_control, mic_control); + if (anonce) + os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); + if (snonce) + os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN); + } else if ((key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + key_len == SHA384_MAC_LEN) || + wpa_key_mgmt_sha384(key_mgmt)) { struct rsn_ftie_sha384 *hdr = (struct rsn_ftie_sha384 *) pos; os_memset(hdr, 0, sizeof(*hdr)); pos += sizeof(*hdr); - WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used); + mic_control |= FTE_MIC_LEN_24 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + WPA_PUT_LE16(hdr->mic_control, mic_control); if (anonce) os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); if (snonce) @@ -837,7 +870,8 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384, os_memset(hdr, 0, sizeof(*hdr)); pos += sizeof(*hdr); - WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used); + mic_control |= FTE_MIC_LEN_16 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + WPA_PUT_LE16(hdr->mic_control, mic_control); if (anonce) os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); if (snonce) @@ -1393,7 +1427,7 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth, os_get_reltime(&now); dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) { - if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 && + if (ether_addr_equal(r0->spa, spa) && os_memcmp_const(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN) == 0) { *r0_out = r0; @@ -1488,7 +1522,7 @@ int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth, os_get_reltime(&now); dl_list_for_each(r1, &cache->pmk_r1, struct wpa_ft_pmk_r1_sa, list) { - if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 && + if (ether_addr_equal(r1->spa, spa) && os_memcmp_const(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN) == 0) { os_memcpy(pmk_r1, r1->pmk_r1, r1->pmk_r1_len); @@ -1990,7 +2024,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, sm->r0kh_id, sm->r0kh_id_len); return -1; } - if (os_memcmp(r0kh->addr, sm->wpa_auth->addr, ETH_ALEN) == 0) { + if (ether_addr_equal(r0kh->addr, sm->wpa_auth->addr)) { wpa_printf(MSG_DEBUG, "FT: R0KH-ID points to self - no matching key available"); return -1; @@ -2078,13 +2112,11 @@ int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, } -int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) +int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk, + u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name, + size_t *key_len, size_t kdk_len) { - u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN]; - size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ? - SHA384_MAC_LEN : PMK_LEN; - size_t pmk_r1_len = pmk_r0_len; - u8 pmk_r1[PMK_LEN_MAX]; + size_t pmk_r0_len, pmk_r1_len; u8 ptk_name[WPA_PMK_NAME_LEN]; const u8 *mdid = sm->wpa_auth->conf.mobility_domain; const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder; @@ -2092,15 +2124,20 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder; const u8 *ssid = sm->wpa_auth->conf.ssid; size_t ssid_len = sm->wpa_auth->conf.ssid_len; - int psk_local = sm->wpa_auth->conf.ft_psk_generate_local; - int expires_in = sm->wpa_auth->conf.r0_key_lifetime; - struct vlan_description vlan; - const u8 *identity, *radius_cui; - size_t identity_len, radius_cui_len; - int session_timeout; const u8 *mpmk; size_t mpmk_len; + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + (sm->xxkey_len == SHA256_MAC_LEN || + sm->xxkey_len == SHA384_MAC_LEN || + sm->xxkey_len == SHA512_MAC_LEN)) + pmk_r0_len = sm->xxkey_len; + else if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) + pmk_r0_len = SHA384_MAC_LEN; + else + pmk_r0_len = PMK_LEN; + *key_len = pmk_r1_len = pmk_r0_len; + if (sm->xxkey_len > 0) { mpmk = sm->xxkey; mpmk_len = sm->xxkey_len; @@ -2113,10 +2150,39 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) return -1; } + if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid, + r0kh, r0kh_len, sm->addr, + pmk_r0, pmk_r0_name, + sm->wpa_key_mgmt) < 0 || + wpa_derive_pmk_r1(pmk_r0, pmk_r0_len, pmk_r0_name, r1kh, sm->addr, + pmk_r1, sm->pmk_r1_name) < 0) + return -1; + + 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, + kdk_len); +} + + +void wpa_auth_ft_store_keys(struct wpa_state_machine *sm, const u8 *pmk_r0, + const u8 *pmk_r1, const u8 *pmk_r0_name, + size_t key_len) +{ + int psk_local = sm->wpa_auth->conf.ft_psk_generate_local; + int expires_in = sm->wpa_auth->conf.r0_key_lifetime; + struct vlan_description vlan; + const u8 *identity, *radius_cui; + size_t identity_len, radius_cui_len; + int session_timeout; + + if (psk_local && wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) + return; + if (wpa_ft_get_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) { wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " MACSTR_SEC, MAC2STR_SEC(sm->addr)); - return -1; + return; } identity_len = wpa_ft_get_identity(sm->wpa_auth, sm->addr, &identity); @@ -2124,31 +2190,16 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) &radius_cui); session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr); - if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid, - r0kh, r0kh_len, sm->addr, - pmk_r0, pmk_r0_name, - wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0) - return -1; - 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, - sm->pairwise, &vlan, expires_in, - session_timeout, identity, identity_len, - radius_cui, radius_cui_len); - - 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; - 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, - expires_in, session_timeout, identity, - identity_len, radius_cui, radius_cui_len); - 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, - 0); + wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, key_len, + pmk_r0_name, + sm->pairwise, &vlan, expires_in, + session_timeout, identity, identity_len, + radius_cui, radius_cui_len); + wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, key_len, + sm->pmk_r1_name, sm->pairwise, &vlan, + expires_in, session_timeout, identity, + identity_len, radius_cui, radius_cui_len); } @@ -2240,6 +2291,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len) wpa_printf(MSG_DEBUG, "FT: GTK subelem encryption failed: kek_len=%d", (int) kek_len); + forced_memzero(keybuf, sizeof(keybuf)); os_free(subelem); return NULL; } @@ -2314,7 +2366,8 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len) { u8 *subelem, *pos; - struct wpa_group *gsm = sm->group; + struct wpa_authenticator *wpa_auth = sm->wpa_auth; + struct wpa_group *gsm = wpa_auth->group; size_t subelem_len; const u8 *kek, *bigtk; size_t kek_len; @@ -2329,7 +2382,7 @@ static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len) kek_len = sm->PTK.kek_len; } - bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + bigtk_len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); /* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] | * Key[16+8] */ @@ -2343,10 +2396,10 @@ static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len) *pos++ = subelem_len - 2; WPA_PUT_LE16(pos, gsm->GN_bigtk); pos += 2; - wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos); + wpa_auth_get_seqnum(wpa_auth, NULL, gsm->GN_bigtk, pos); pos += 6; *pos++ = bigtk_len; - bigtk = gsm->IGTK[gsm->GN_bigtk - 6]; + bigtk = gsm->BIGTK[gsm->GN_bigtk - 6]; if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { /* * Provide unique random BIGTK to each OSEN STA to prevent use @@ -2520,12 +2573,11 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, u8 *anonce, *snonce; const u8 *kck; size_t kck_len; - int use_sha384; + size_t key_len; if (sm == NULL) return pos; - use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); conf = &sm->wpa_auth->conf; if (!wpa_key_mgmt_ft(sm->wpa_key_mgmt)) @@ -2696,7 +2748,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, snonce = NULL; } rsnxe_used = (auth_alg == WLAN_AUTH_FT) && - (conf->sae_pwe == 1 || conf->sae_pwe == 2); + (conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || + conf->sae_pwe == SAE_PWE_BOTH); #ifdef CONFIG_TESTING_OPTIONS if (sm->wpa_auth->conf.ft_rsnxe_used) { rsnxe_used = sm->wpa_auth->conf.ft_rsnxe_used == 1; @@ -2704,7 +2757,20 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, rsnxe_used); } #endif /* CONFIG_TESTING_OPTIONS */ - res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len, + key_len = sm->xxkey_len; + if (!key_len) + key_len = sm->pmk_r1_len; + if (!key_len && sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + sm->wpa_auth->cb->get_psk) { + size_t psk_len; + + if (sm->wpa_auth->cb->get_psk(sm->wpa_auth->cb_ctx, + sm->addr, sm->p2p_dev_addr, + NULL, &psk_len, NULL)) + key_len = psk_len; + } + res = wpa_write_ftie(conf, sm->wpa_key_mgmt, key_len, + r0kh_id, r0kh_id_len, anonce, snonce, pos, end - pos, subelem, subelem_len, rsnxe_used); os_free(subelem); @@ -2714,7 +2780,16 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, ftie_len = res; pos += res; - if (use_sha384) { + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + key_len == SHA512_MAC_LEN) { + struct rsn_ftie_sha512 *_ftie = + (struct rsn_ftie_sha512 *) (ftie + 2); + + fte_mic = _ftie->mic; + elem_count = &_ftie->mic_control[1]; + } else if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + key_len == SHA384_MAC_LEN) || + wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) { struct rsn_ftie_sha384 *_ftie = (struct rsn_ftie_sha384 *) (ftie + 2); @@ -2730,8 +2805,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, *elem_count = 3; /* Information element count */ ric_start = pos; - if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse, use_sha384) == 0 - && parse.ric) { + if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse, + sm->wpa_key_mgmt, false) == 0 && parse.ric) { pos = wpa_ft_process_ric(sm, pos, end, parse.ric, parse.ric_len); if (auth_alg == WLAN_AUTH_FT) @@ -2747,8 +2822,10 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, } else { res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe, sizeof(rsnxe_buf)); - if (res < 0) - return NULL; + if (res < 0) { + pos = NULL; + goto fail; + } rsnxe_len = res; } #ifdef CONFIG_TESTING_OPTIONS @@ -2771,22 +2848,29 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, kck_len = sm->PTK.kck_len; } if (auth_alg == WLAN_AUTH_FT && - wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 6, + wpa_ft_mic(sm->wpa_key_mgmt, kck, kck_len, + sm->addr, sm->wpa_auth->addr, 6, mdie, mdie_len, ftie, ftie_len, rsnie, rsnie_len, ric_start, ric_start ? pos - ric_start : 0, rsnxe_len ? rsnxe : NULL, rsnxe_len, + NULL, fte_mic) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); - return NULL; + pos = NULL; + goto fail; } os_free(sm->assoc_resp_ftie); sm->assoc_resp_ftie = os_malloc(ftie_len); - if (!sm->assoc_resp_ftie) - return NULL; + if (!sm->assoc_resp_ftie) { + pos = NULL; + goto fail; + } os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len); +fail: + wpa_ft_parse_ies_free(&parse); return pos; } @@ -2804,6 +2888,20 @@ static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, } +#ifdef CONFIG_PASN +static inline int wpa_auth_set_ltf_keyseed(struct wpa_authenticator *wpa_auth, + const u8 *peer_addr, + const u8 *ltf_keyseed, + size_t ltf_keyseed_len) +{ + if (!wpa_auth->cb->set_ltf_keyseed) + return -1; + return wpa_auth->cb->set_ltf_keyseed(wpa_auth->cb_ctx, peer_addr, + ltf_keyseed, ltf_keyseed_len); +} +#endif /* CONFIG_PASN */ + + static inline int wpa_auth_add_sta_ft(struct wpa_authenticator *wpa_auth, const u8 *addr) { @@ -2848,9 +2946,24 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry) sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) return; +#ifdef CONFIG_PASN + if (sm->wpa_auth->conf.secure_ltf && + ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) && + wpa_auth_set_ltf_keyseed(sm->wpa_auth, sm->addr, + sm->PTK.ltf_keyseed, + sm->PTK.ltf_keyseed_len)) { + wpa_printf(MSG_ERROR, + "FT: Failed to set LTF keyseed to driver"); + return; + } +#endif /* CONFIG_PASN */ + /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ sm->pairwise_set = true; sm->tk_already_set = true; + + wpa_auth_store_ptksa(sm->wpa_auth, sm->addr, sm->pairwise, + dot11RSNAConfigPMKLifetime, &sm->PTK); } @@ -2886,7 +2999,8 @@ static int wpa_ft_psk_pmk_r1(struct wpa_state_machine *sm, if (wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh, r0kh_len, sm->addr, - pmk_r0, pmk_r0_name, 0) < 0 || + pmk_r0, pmk_r0_name, + WPA_KEY_MGMT_FT_PSK) < 0 || wpa_derive_pmk_r1(pmk_r0, PMK_LEN, pmk_r0_name, r1kh, sm->addr, pmk_r1, pmk_r1_name) < 0 || os_memcmp_const(pmk_r1_name, req_pmk_r1_name, @@ -2980,17 +3094,17 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *req_pmk_r0_name, - const u8 *req_pmk_r1_name, + u8 *out_pmk_r1_name, u8 *out_pmk_r1, int *out_pairwise, struct vlan_description *vlan, const u8 **identity, size_t *identity_len, const u8 **radius_cui, size_t *radius_cui_len, - int *out_session_timeout) + int *out_session_timeout, + size_t *pmk_r1_len) { struct wpa_auth_config *conf = &wpa_auth->conf; const struct wpa_ft_pmk_r0_sa *r0; - u8 pmk_r1_name[WPA_PMK_NAME_LEN]; int expires_in = 0; int session_timeout = 0; struct os_reltime now; @@ -3009,7 +3123,7 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth, if (wpa_derive_pmk_r1(r0->pmk_r0, r0->pmk_r0_len, r0->pmk_r0_name, conf->r1_key_holder, - sm->addr, out_pmk_r1, pmk_r1_name) < 0) + sm->addr, out_pmk_r1, out_pmk_r1_name) < 0) return -1; os_get_reltime(&now); @@ -3020,7 +3134,7 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth, session_timeout = r0->session_timeout - now.sec; wpa_ft_store_pmk_r1(wpa_auth, sm->addr, out_pmk_r1, r0->pmk_r0_len, - pmk_r1_name, + out_pmk_r1_name, sm->pairwise, r0->vlan, expires_in, session_timeout, r0->identity, r0->identity_len, r0->radius_cui, r0->radius_cui_len); @@ -3045,6 +3159,8 @@ static int wpa_ft_local_derive_pmk_r1(struct wpa_authenticator *wpa_auth, *out_session_timeout = session_timeout; + *pmk_r1_len = r0->pmk_r0_len; + return 0; } @@ -3065,8 +3181,8 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, struct vlan_description vlan; const u8 *identity, *radius_cui; size_t identity_len = 0, radius_cui_len = 0; - int use_sha384; - size_t pmk_r1_len, kdk_len; + size_t pmk_r1_len, kdk_len, len; + int retval = WLAN_STATUS_UNSPECIFIED_FAILURE; *resp_ies = NULL; *resp_ies_len = 0; @@ -3077,12 +3193,10 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs", ies, ies_len); - if (wpa_ft_parse_ies(ies, ies_len, &parse, -1)) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, 0, false)) { wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } - use_sha384 = wpa_key_mgmt_sha384(parse.key_mgmt); - pmk_r1_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; mdie = (struct rsn_mdie *) parse.mdie; if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || @@ -3090,34 +3204,20 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, sm->wpa_auth->conf.mobility_domain, MOBILITY_DOMAIN_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); - return WLAN_STATUS_INVALID_MDIE; + retval = WLAN_STATUS_INVALID_MDIE; + goto out; } - if (use_sha384) { - struct rsn_ftie_sha384 *ftie; - - ftie = (struct rsn_ftie_sha384 *) parse.ftie; - if (!ftie || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return WLAN_STATUS_INVALID_FTIE; - } - - os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN); - } else { - struct rsn_ftie *ftie; - - ftie = (struct rsn_ftie *) parse.ftie; - if (!ftie || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return WLAN_STATUS_INVALID_FTIE; - } - - os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN); + if (!parse.ftie || parse.ftie_len < sizeof(struct rsn_ftie)) { + wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } if (parse.r0kh_id == NULL) { wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID"); - return WLAN_STATUS_INVALID_FTIE; + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID", @@ -3127,57 +3227,86 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, if (parse.rsn_pmkid == NULL) { wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE"); - return WLAN_STATUS_INVALID_PMKID; + retval = WLAN_STATUS_INVALID_PMKID; + goto out; } if (wpa_ft_set_key_mgmt(sm, &parse) < 0) - return WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name", parse.rsn_pmkid, WPA_PMK_NAME_LEN); - if (wpa_derive_pmk_r1_name(parse.rsn_pmkid, - sm->wpa_auth->conf.r1_key_holder, sm->addr, - pmk_r1_name, use_sha384) < 0) - return WLAN_STATUS_UNSPECIFIED_FAILURE; if (conf->ft_psk_generate_local && wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) { + if (wpa_derive_pmk_r1_name(parse.rsn_pmkid, + sm->wpa_auth->conf.r1_key_holder, + sm->addr, pmk_r1_name, PMK_LEN) < 0) + goto out; if (wpa_ft_psk_pmk_r1(sm, pmk_r1_name, pmk_r1, &pairwise, &vlan, &identity, &identity_len, &radius_cui, &radius_cui_len, - &session_timeout) < 0) - return WLAN_STATUS_INVALID_PMKID; + &session_timeout) < 0) { + retval = WLAN_STATUS_INVALID_PMKID; + goto out; + } + pmk_r1_len = PMK_LEN; wpa_printf(MSG_DEBUG, "FT: Generated PMK-R1 for FT-PSK locally"); - } else if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, - pmk_r1, &pmk_r1_len, &pairwise, &vlan, - &identity, &identity_len, &radius_cui, - &radius_cui_len, &session_timeout) < 0) { - wpa_printf(MSG_DEBUG, - "FT: No PMK-R1 available in local cache for the requested PMKR1Name"); - if (wpa_ft_local_derive_pmk_r1(sm->wpa_auth, sm, - parse.r0kh_id, parse.r0kh_id_len, - parse.rsn_pmkid, - pmk_r1_name, pmk_r1, &pairwise, - &vlan, &identity, &identity_len, - &radius_cui, &radius_cui_len, - &session_timeout) == 0) { + goto pmk_r1_derived; + } + + /* Need to test all possible hash algorithms for FT-SAE-EXT-KEY since + * the key length is not yet known. For other AKMs, only the length + * identified by the AKM is used. */ + for (len = SHA256_MAC_LEN; len <= SHA512_MAC_LEN; len += 16) { + if (parse.key_mgmt != WPA_KEY_MGMT_FT_SAE_EXT_KEY && + ((wpa_key_mgmt_sha384(parse.key_mgmt) && + len != SHA384_MAC_LEN) || + (!wpa_key_mgmt_sha384(parse.key_mgmt) && + len != SHA256_MAC_LEN))) + continue; + if (wpa_derive_pmk_r1_name(parse.rsn_pmkid, + sm->wpa_auth->conf.r1_key_holder, + sm->addr, pmk_r1_name, len) < 0) + continue; + + if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, + pmk_r1, &pmk_r1_len, &pairwise, &vlan, + &identity, &identity_len, &radius_cui, + &radius_cui_len, + &session_timeout) == 0) { wpa_printf(MSG_DEBUG, - "FT: Generated PMK-R1 based on local PMK-R0"); + "FT: Found PMKR1Name (using SHA%zu) from local cache", + pmk_r1_len * 8); goto pmk_r1_derived; } + } - if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) { - wpa_printf(MSG_DEBUG, - "FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH"); - return WLAN_STATUS_INVALID_PMKID; - } + wpa_printf(MSG_DEBUG, + "FT: No PMK-R1 available in local cache for the requested PMKR1Name"); + if (wpa_ft_local_derive_pmk_r1(sm->wpa_auth, sm, + parse.r0kh_id, parse.r0kh_id_len, + parse.rsn_pmkid, + pmk_r1_name, pmk_r1, &pairwise, + &vlan, &identity, &identity_len, + &radius_cui, &radius_cui_len, + &session_timeout, &pmk_r1_len) == 0) { + wpa_printf(MSG_DEBUG, + "FT: Generated PMK-R1 based on local PMK-R0"); + goto pmk_r1_derived; + } - return -1; /* Status pending */ - } else { - wpa_printf(MSG_DEBUG, "FT: Found PMKR1Name from local cache"); + if (wpa_ft_pull_pmk_r1(sm, ies, ies_len, parse.rsn_pmkid) < 0) { + wpa_printf(MSG_DEBUG, + "FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH"); + retval = WLAN_STATUS_INVALID_PMKID; + goto out; } + retval = -1; /* Status pending */ + goto out; + pmk_r1_derived: wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, pmk_r1_len); sm->pmk_r1_name_valid = 1; @@ -3188,7 +3317,44 @@ pmk_r1_derived: if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) { wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " "ANonce"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; + } + + /* Now that we know the correct PMK-R1 length and as such, the length + * of the MIC field, fetch the SNonce. */ + if (pmk_r1_len == SHA512_MAC_LEN) { + const struct rsn_ftie_sha512 *ftie; + + ftie = (const struct rsn_ftie_sha512 *) parse.ftie; + if (!ftie || parse.ftie_len < sizeof(*ftie)) { + wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); + retval = WLAN_STATUS_INVALID_FTIE; + goto out; + } + + os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN); + } else if (pmk_r1_len == SHA384_MAC_LEN) { + const struct rsn_ftie_sha384 *ftie; + + ftie = (const struct rsn_ftie_sha384 *) parse.ftie; + if (!ftie || parse.ftie_len < sizeof(*ftie)) { + wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); + retval = WLAN_STATUS_INVALID_FTIE; + goto out; + } + + os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN); + } else { + const struct rsn_ftie *ftie; + + ftie = (const struct rsn_ftie *) parse.ftie; + if (!ftie || parse.ftie_len < sizeof(*ftie)) { + wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); + retval = WLAN_STATUS_INVALID_FTIE; + goto out; + } + + os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN); } wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", @@ -3205,9 +3371,18 @@ pmk_r1_derived: 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, + &sm->PTK, ptk_name, parse.key_mgmt, pairwise, kdk_len) < 0) - return WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; + +#ifdef CONFIG_PASN + if (sm->wpa_auth->conf.secure_ltf && + ieee802_11_rsnx_capab(sm->rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) && + wpa_ltf_keyseed(&sm->PTK, parse.key_mgmt, pairwise)) { + wpa_printf(MSG_DEBUG, "FT: Failed to derive LTF keyseed"); + goto out; + } +#endif /* CONFIG_PASN */ sm->pairwise = pairwise; sm->PTK_valid = true; @@ -3216,14 +3391,14 @@ pmk_r1_derived: if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; } if (wpa_ft_set_identity(sm->wpa_auth, sm->addr, identity, identity_len) < 0 || wpa_ft_set_radius_cui(sm->wpa_auth, sm->addr, radius_cui, radius_cui_len) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to configure identity/CUI"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; } wpa_ft_set_session_timeout(sm->wpa_auth, sm->addr, session_timeout); @@ -3246,7 +3421,8 @@ pmk_r1_derived: goto fail; pos += ret; - ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len, + ret = wpa_write_ftie(conf, parse.key_mgmt, pmk_r1_len, + parse.r0kh_id, parse.r0kh_id_len, sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0, 0); if (ret < 0) @@ -3255,17 +3431,20 @@ pmk_r1_derived: *resp_ies_len = pos - *resp_ies; - return WLAN_STATUS_SUCCESS; + retval = WLAN_STATUS_SUCCESS; + goto out; fail: os_free(*resp_ies); *resp_ies = NULL; - return WLAN_STATUS_UNSPECIFIED_FAILURE; +out: + wpa_ft_parse_ies_free(&parse); + return retval; } -void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, +void wpa_ft_process_auth(struct wpa_state_machine *sm, u16 auth_transaction, const u8 *ies, size_t ies_len, - void (*cb)(void *ctx, const u8 *dst, const u8 *bssid, + void (*cb)(void *ctx, const u8 *dst, u16 auth_transaction, u16 status, const u8 *ies, size_t ies_len), void *ctx) @@ -3283,7 +3462,8 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR_SEC " BSSID=" MACSTR_SEC " transaction=%d", - MAC2STR_SEC(sm->addr), MAC2STR_SEC(bssid), auth_transaction); + MAC2STR_SEC(sm->addr), MAC2STR_SEC(sm->wpa_auth->addr), + auth_transaction); sm->ft_pending_cb = cb; sm->ft_pending_cb_ctx = ctx; sm->ft_pending_auth_transaction = auth_transaction; @@ -3301,8 +3481,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, MAC2STR_SEC(sm->addr), auth_transaction + 1, status, status2str(status)); wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len); - cb(ctx, sm->addr, bssid, auth_transaction + 1, status, - resp_ies, resp_ies_len); + cb(ctx, sm->addr, auth_transaction + 1, status, resp_ies, resp_ies_len); os_free(resp_ies); } @@ -3313,44 +3492,43 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, struct wpa_ft_ies parse; struct rsn_mdie *mdie; u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN]; - size_t mic_len = 16; + size_t mic_len; unsigned int count; const u8 *kck; size_t kck_len; - int use_sha384; - const u8 *anonce, *snonce, *fte_mic; - u8 fte_elem_count; - int rsnxe_used; struct wpa_auth_config *conf; + int retval = WLAN_STATUS_UNSPECIFIED_FAILURE; if (sm == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; conf = &sm->wpa_auth->conf; - use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len); - if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, sm->wpa_key_mgmt, + false) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs"); return WLAN_STATUS_UNSPECIFIED_FAILURE; } if (parse.rsn == NULL) { wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; } if (parse.rsn_pmkid == NULL) { wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE"); - return WLAN_STATUS_INVALID_PMKID; + retval = WLAN_STATUS_INVALID_PMKID; + goto out; } if (os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match " "with the PMKR1Name derived from auth request"); - return WLAN_STATUS_INVALID_PMKID; + retval = WLAN_STATUS_INVALID_PMKID; + goto out; } mdie = (struct rsn_mdie *) parse.mdie; @@ -3358,61 +3536,53 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, os_memcmp(mdie->mobility_domain, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); - return WLAN_STATUS_INVALID_MDIE; + retval = WLAN_STATUS_INVALID_MDIE; + goto out; } - if (use_sha384) { - struct rsn_ftie_sha384 *ftie; - - ftie = (struct rsn_ftie_sha384 *) parse.ftie; - if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return WLAN_STATUS_INVALID_FTIE; - } - - anonce = ftie->anonce; - snonce = ftie->snonce; - rsnxe_used = ftie->mic_control[0] & 0x01; - fte_elem_count = ftie->mic_control[1]; - fte_mic = ftie->mic; - } else { - struct rsn_ftie *ftie; - - ftie = (struct rsn_ftie *) parse.ftie; - if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return WLAN_STATUS_INVALID_FTIE; - } + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + sm->pmk_r1_len == SHA512_MAC_LEN) + mic_len = 32; + else if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + sm->pmk_r1_len == SHA384_MAC_LEN) || + wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) + mic_len = 24; + else + mic_len = 16; - anonce = ftie->anonce; - snonce = ftie->snonce; - rsnxe_used = ftie->mic_control[0] & 0x01; - fte_elem_count = ftie->mic_control[1]; - fte_mic = ftie->mic; + if (!parse.ftie || !parse.fte_anonce || !parse.fte_snonce || + parse.fte_mic_len != mic_len) { + wpa_printf(MSG_DEBUG, + "FT: Invalid FTE (fte_mic_len=%zu mic_len=%zu)", + parse.fte_mic_len, mic_len); + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } - if (os_memcmp(snonce, sm->SNonce, WPA_NONCE_LEN) != 0) { + if (os_memcmp(parse.fte_snonce, sm->SNonce, WPA_NONCE_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", - snonce, WPA_NONCE_LEN); + parse.fte_snonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", sm->SNonce, WPA_NONCE_LEN); - return WLAN_STATUS_INVALID_FTIE; + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } - if (os_memcmp(anonce, sm->ANonce, WPA_NONCE_LEN) != 0) { + if (os_memcmp(parse.fte_anonce, sm->ANonce, WPA_NONCE_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", - anonce, WPA_NONCE_LEN); + parse.fte_anonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", sm->ANonce, WPA_NONCE_LEN); - return WLAN_STATUS_INVALID_FTIE; + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } - if (parse.r0kh_id == NULL) { wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); - return WLAN_STATUS_INVALID_FTIE; + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } if (parse.r0kh_id_len != sm->r0kh_id_len || @@ -3424,12 +3594,14 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, parse.r0kh_id, parse.r0kh_id_len); wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", sm->r0kh_id, sm->r0kh_id_len); - return WLAN_STATUS_INVALID_FTIE; + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } if (parse.r1kh_id == NULL) { wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); - return WLAN_STATUS_INVALID_FTIE; + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } if (os_memcmp_const(parse.r1kh_id, conf->r1_key_holder, @@ -3440,7 +3612,8 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, parse.r1kh_id, FT_R1KH_ID_LEN); wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID", conf->r1_key_holder, FT_R1KH_ID_LEN); - return WLAN_STATUS_INVALID_FTIE; + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } if (parse.rsn_pmkid == NULL || @@ -3448,7 +3621,8 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, { wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); - return WLAN_STATUS_INVALID_PMKID; + retval = WLAN_STATUS_INVALID_PMKID; + goto out; } count = 3; @@ -3456,11 +3630,11 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, count += ieee802_11_ie_count(parse.ric, parse.ric_len); if (parse.rsnxe) count++; - if (fte_elem_count != count) { + if (parse.fte_elem_count != count) { wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " "Control: received %u expected %u", - fte_elem_count, count); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + parse.fte_elem_count, count); + goto out; } if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) { @@ -3470,24 +3644,26 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, kck = sm->PTK.kck; kck_len = sm->PTK.kck_len; } - if (wpa_ft_mic(kck, kck_len, sm->addr, sm->wpa_auth->addr, 5, + if (wpa_ft_mic(sm->wpa_key_mgmt, kck, kck_len, + sm->addr, sm->wpa_auth->addr, 5, parse.mdie - 2, parse.mdie_len + 2, parse.ftie - 2, parse.ftie_len + 2, parse.rsn - 2, parse.rsn_len + 2, parse.ric, parse.ric_len, parse.rsnxe ? parse.rsnxe - 2 : NULL, parse.rsnxe ? parse.rsnxe_len + 2 : 0, + NULL, mic) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; } - if (os_memcmp_const(mic, fte_mic, mic_len) != 0) { + if (os_memcmp_const(mic, parse.fte_mic, mic_len) != 0) { wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR_SEC " auth_addr=" MACSTR_SEC, MAC2STR_SEC(sm->addr), MAC2STR_SEC(sm->wpa_auth->addr)); wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", - fte_mic, mic_len); + parse.fte_mic, mic_len); wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len); wpa_hexdump(MSG_MSGDUMP, "FT: MDIE", parse.mdie - 2, parse.mdie_len + 2); @@ -3498,14 +3674,18 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, wpa_hexdump(MSG_MSGDUMP, "FT: RSNXE", parse.rsnxe ? parse.rsnxe - 2 : NULL, parse.rsnxe ? parse.rsnxe_len + 2 : 0); - return WLAN_STATUS_INVALID_FTIE; + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } - if (rsnxe_used && (conf->sae_pwe == 1 || conf->sae_pwe == 2) && + if (parse.fte_rsnxe_used && + (conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || + conf->sae_pwe == SAE_PWE_BOTH) && !parse.rsnxe) { wpa_printf(MSG_INFO, "FT: FTE indicated that STA uses RSNXE, but RSNXE was not included"); - return -1; /* discard request */ + retval = -1; /* discard request */ + goto out; } #ifdef CONFIG_OCV @@ -3518,14 +3698,14 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, if (wpa_channel_info(sm->wpa_auth, &ci) != 0) { wpa_printf(MSG_WARNING, "Failed to get channel info to validate received OCI in (Re)Assoc Request"); - return WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; } if (get_sta_tx_parameters(sm, channel_width_to_int(ci.chanwidth), ci.seg1_idx, &tx_chanwidth, &tx_seg1_idx) < 0) - return WLAN_STATUS_UNSPECIFIED_FAILURE; + goto out; res = ocv_verify_tx_params(parse.oci, parse.oci_len, &ci, tx_chanwidth, tx_seg1_idx); @@ -3541,12 +3721,16 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, OCV_FAILURE "addr=" MACSTR " frame=ft-reassoc-req error=%s", MAC2STR(sm->addr), ocv_errorstr); - return WLAN_STATUS_INVALID_FTIE; + retval = WLAN_STATUS_INVALID_FTIE; + goto out; } } #endif /* CONFIG_OCV */ - return WLAN_STATUS_SUCCESS; + retval = WLAN_STATUS_SUCCESS; +out: + wpa_ft_parse_ies_free(&parse); + return retval; } @@ -3582,7 +3766,7 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len) " Target AP=" MACSTR_SEC " Action=%d)", MAC2STR_SEC(sta_addr), MAC2STR_SEC(target_ap), action); - if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(sta_addr, sm->addr)) { wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: " "STA=" MACSTR_SEC " STA-Address=" MACSTR_SEC, MAC2STR_SEC(sm->addr), MAC2STR_SEC(sta_addr)); @@ -3595,7 +3779,7 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len) * APs in the MD (if such a list were configured). */ if ((target_ap[0] & 0x01) || - os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) { + ether_addr_equal(target_ap, sm->wpa_auth->addr)) { wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action " "frame"); return -1; @@ -3626,7 +3810,7 @@ int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len) } -static void wpa_ft_rrb_rx_request_cb(void *ctx, const u8 *dst, const u8 *bssid, +static void wpa_ft_rrb_rx_request_cb(void *ctx, const u8 *dst, u16 auth_transaction, u16 resp, const u8 *ies, size_t ies_len) { @@ -3853,7 +4037,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, seq_ret = wpa_ft_rrb_seq_chk(r1kh->seq, src_addr, enc, enc_len, auth, auth_len, msgtype, no_defer); if (!no_defer && r1kh_wildcard && - (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0)) { + (!r1kh || !ether_addr_equal(r1kh->addr, src_addr))) { /* wildcard: r1kh-id unknown or changed addr -> do a seq req */ seq_ret = FT_RRB_SEQ_DEFER; } @@ -4020,7 +4204,7 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, cb ? 0 : 1); } if (cb && r0kh_wildcard && - (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0)) { + (!r0kh || !ether_addr_equal(r0kh->addr, src_addr))) { /* wildcard: r0kh-id unknown or changed addr -> do a seq req */ seq_ret = FT_RRB_SEQ_DEFER; } @@ -4069,7 +4253,8 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, pmk_r1_len = PMK_LEN; if (wpa_ft_rrb_get_tlv(plain, plain_len, FT_RRB_PMK_R1, &f_pmk_r1_len, &f_pmk_r1) == 0 && - (f_pmk_r1_len == PMK_LEN || f_pmk_r1_len == SHA384_MAC_LEN)) + (f_pmk_r1_len == PMK_LEN || f_pmk_r1_len == SHA384_MAC_LEN || + f_pmk_r1_len == SHA512_MAC_LEN)) pmk_r1_len = f_pmk_r1_len; RRB_GET(FT_RRB_PMK_R1, pmk_r1, msgtype, pmk_r1_len); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f_pmk_r1, pmk_r1_len); @@ -4154,7 +4339,7 @@ static void ft_finish_pull(struct wpa_state_machine *sm) wpa_printf(MSG_DEBUG, "FT: Postponed auth callback result for " MACSTR_SEC " - status %u", MAC2STR_SEC(sm->addr), status); - sm->ft_pending_cb(sm->ft_pending_cb_ctx, sm->addr, sm->wpa_auth->addr, + sm->ft_pending_cb(sm->ft_pending_cb_ctx, sm->addr, sm->ft_pending_auth_transaction + 1, status, resp_ies, resp_ies_len); os_free(resp_ies); @@ -4173,7 +4358,7 @@ static int ft_get_sta_cb(struct wpa_state_machine *sm, void *ctx) struct ft_get_sta_ctx *info = ctx; if ((info->s1kh_id && - os_memcmp(info->s1kh_id, sm->addr, ETH_ALEN) != 0) || + !ether_addr_equal(info->s1kh_id, sm->addr)) || os_memcmp(info->nonce, sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) != 0 || sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL) @@ -4298,7 +4483,7 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth, wpa_ft_rrb_lookup_r0kh(wpa_auth, f_r0kh_id, f_r0kh_id_len, &r0kh, &r0kh_wildcard); if (!r0kh_wildcard && - (!r0kh || os_memcmp(r0kh->addr, src_addr, ETH_ALEN) != 0)) { + (!r0kh || !ether_addr_equal(r0kh->addr, src_addr))) { wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID", f_r0kh_id, f_r0kh_id_len); goto out; @@ -4316,7 +4501,7 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth, wpa_ft_rrb_lookup_r1kh(wpa_auth, f_r1kh_id, &r1kh, &r1kh_wildcard); if (!r1kh_wildcard && - (!r1kh || os_memcmp(r1kh->addr, src_addr, ETH_ALEN) != 0)) { + (!r1kh || !ether_addr_equal(r1kh->addr, src_addr))) { wpa_hexdump(MSG_DEBUG, "FT: Did not find R1KH-ID", f_r1kh_id, FT_R1KH_ID_LEN); goto out; @@ -4622,7 +4807,7 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, return -1; } - if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(target_ap_addr, wpa_auth->addr)) { wpa_printf(MSG_DEBUG, "FT: Target AP address in the " "RRB Request does not match with own " "address"); @@ -4785,7 +4970,7 @@ void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr) return; dl_list_for_each(r0, &cache->pmk_r0, struct wpa_ft_pmk_r0_sa, list) { - if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0) { + if (ether_addr_equal(r0->spa, addr)) { r0found = r0; break; } diff --git a/wpa_supplicant-2.9_standard/src/ap/wpa_auth_glue.c b/wpa_supplicant-2.9_standard/src/ap/wpa_auth_glue.c index 890c95938dc284b4790d89f85a1b10ab085a45f2..e25056451c477bf12fc4771b7e4a6e003a728b06 100644 --- a/wpa_supplicant-2.9_standard/src/ap/wpa_auth_glue.c +++ b/wpa_supplicant-2.9_standard/src/ap/wpa_auth_glue.c @@ -1,6 +1,6 @@ /* * hostapd / WPA authenticator glue code - * Copyright (c) 2002-2012, Jouni Malinen + * Copyright (c) 2002-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -29,6 +29,7 @@ #include "ap_drv_ops.h" #include "ap_config.h" #include "ieee802_11.h" +#include "ieee802_11_auth.h" #include "pmksa_cache_auth.h" #include "wpa_auth.h" #include "wpa_auth_glue.h" @@ -74,11 +75,12 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->beacon_prot = conf->beacon_prot; wconf->group_mgmt_cipher = conf->group_mgmt_cipher; wconf->sae_require_mfp = conf->sae_require_mfp; -#ifdef CONFIG_IEEE80211R_AP + wconf->ssid_protection = conf->ssid_protection; wconf->ssid_len = conf->ssid.ssid_len; if (wconf->ssid_len > SSID_MAX_LEN) wconf->ssid_len = SSID_MAX_LEN; os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len); +#ifdef CONFIG_IEEE80211R_AP os_memcpy(wconf->mobility_domain, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN); if (conf->nas_identifier && @@ -118,6 +120,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, #ifdef CONFIG_TESTING_OPTIONS wconf->corrupt_gtk_rekey_mic_probability = iconf->corrupt_gtk_rekey_mic_probability; + wconf->delay_eapol_tx = iconf->delay_eapol_tx; if (conf->own_ie_override && wpabuf_len(conf->own_ie_override) <= MAX_OWN_IE_OVERRIDE) { wconf->own_ie_override_len = wpabuf_len(conf->own_ie_override); @@ -183,6 +186,12 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->oci_freq_override_ft_assoc = conf->oci_freq_override_ft_assoc; wconf->oci_freq_override_fils_assoc = conf->oci_freq_override_fils_assoc; + + if (conf->eapol_m1_elements) + wconf->eapol_m1_elements = wpabuf_dup(conf->eapol_m1_elements); + if (conf->eapol_m3_elements) + wconf->eapol_m3_elements = wpabuf_dup(conf->eapol_m3_elements); + wconf->eapol_m3_no_encrypt = conf->eapol_m3_no_encrypt; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_P2P os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4); @@ -197,10 +206,10 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, #endif /* CONFIG_FILS */ wconf->sae_pwe = conf->sae_pwe; sae_pw_id = hostapd_sae_pw_id_in_use(conf); - if (sae_pw_id == 2 && wconf->sae_pwe != 3) - wconf->sae_pwe = 1; - else if (sae_pw_id == 1 && wconf->sae_pwe == 0) - wconf->sae_pwe = 2; + if (sae_pw_id == 2 && wconf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) + wconf->sae_pwe = SAE_PWE_HASH_TO_ELEMENT; + else if (sae_pw_id == 1 && wconf->sae_pwe == SAE_PWE_HUNT_AND_PECK) + wconf->sae_pwe = SAE_PWE_BOTH; #ifdef CONFIG_SAE_PK wconf->sae_pk = hostapd_sae_pk_in_use(conf); #endif /* CONFIG_SAE_PK */ @@ -216,6 +225,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->force_kdk_derivation = conf->force_kdk_derivation; #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_PASN */ + + wconf->radius_psk = conf->wpa_psk_radius == PSK_RADIUS_DURING_4WAY_HS; + wconf->no_disconnect_on_group_keyerror = + conf->bss_max_idle && conf->ap_max_inactivity && + conf->no_disconnect_on_group_keyerror; } @@ -405,10 +419,14 @@ static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, psk = sta->psk->psk; for (pos = sta->psk; pos; pos = pos->next) { if (pos->is_passphrase) { - pbkdf2_sha1(pos->passphrase, - hapd->conf->ssid.ssid, - hapd->conf->ssid.ssid_len, 4096, - pos->psk, PMK_LEN); + if (pbkdf2_sha1(pos->passphrase, + hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len, 4096, + pos->psk, PMK_LEN) != 0) { + wpa_printf(MSG_WARNING, + "Error in pbkdf2_sha1()"); + continue; + } pos->is_passphrase = 0; } if (pos->psk == prev_psk) { @@ -518,7 +536,14 @@ static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx, u8 *seq) { struct hostapd_data *hapd = ctx; - return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq); + int link_id = -1; + +#ifdef CONFIG_IEEE80211BE + if (hapd->conf->mld_ap && idx) + link_id = hapd->mld_link_id; +#endif /* CONFIG_IEEE80211BE */ + return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, link_id, + seq); } @@ -529,6 +554,11 @@ int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, struct hostapd_data *hapd = ctx; struct sta_info *sta; u32 flags = 0; + int link_id = -1; + +#ifdef CONFIG_IEEE80211BE + link_id = hapd->conf->mld_ap ? hapd->mld_link_id : -1; +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_TESTING_OPTIONS if (hapd->ext_eapol_frame_io) { @@ -546,11 +576,25 @@ int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, #endif /* CONFIG_TESTING_OPTIONS */ sta = ap_get_sta(hapd, addr); - if (sta) + if (sta) { flags = hostapd_sta_flags_to_drv(sta->flags); +#ifdef CONFIG_IEEE80211BE + if (ap_sta_is_mld(hapd, sta) && + (sta->flags & WLAN_STA_AUTHORIZED)) + link_id = -1; +#endif /* CONFIG_IEEE80211BE */ + } return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len, - encrypt, flags); + encrypt, flags, link_id); +} + + +static int hostapd_wpa_auth_get_sta_count(void *ctx) +{ + struct hostapd_data *hapd = ctx; + + return hapd->num_sta; } @@ -649,7 +693,7 @@ static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx) hapd = iface->bss[j]; if (hapd == idata->src_hapd || !hapd->wpa_auth || - os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) != 0) + !ether_addr_equal(hapd->own_addr, idata->dst)) continue; wpa_printf(MSG_DEBUG, @@ -839,7 +883,7 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx) MOBILITY_DOMAIN_ID_LEN) != 0) continue; /* no matching FT SSID/mobility domain */ if (!is_multicast_ether_addr(idata->dst_addr) && - os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0) + !ether_addr_equal(hapd->own_addr, idata->dst_addr)) continue; /* destination address does not match */ /* defer eth_p_oui_deliver until next eloop step as this is @@ -942,7 +986,8 @@ static void hostapd_store_ptksa(void *ctx, const u8 *addr,int cipher, { struct hostapd_data *hapd = ctx; - ptksa_cache_add(hapd->ptksa, addr, cipher, life_time, ptk); + ptksa_cache_add(hapd->ptksa, hapd->own_addr, addr, cipher, life_time, + ptk, NULL, NULL, 0); } @@ -1136,17 +1181,25 @@ static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr, if (!sta || !sta->wpa_sm) return -1; - if (vlan->notempty && - !hostapd_vlan_valid(hapd->conf->vlan, vlan)) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, - "Invalid VLAN %d%s received from FT", - vlan->untagged, vlan->tagged[0] ? "+" : ""); - return -1; - } + if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) { + if (vlan->notempty && + !hostapd_vlan_valid(hapd->conf->vlan, vlan)) { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "Invalid VLAN %d%s received from FT", + vlan->untagged, vlan->tagged[0] ? + "+" : ""); + return -1; + } - if (ap_sta_set_vlan(hapd, sta, vlan) < 0) - return -1; + if (ap_sta_set_vlan(hapd, sta, vlan) < 0) + return -1; + + } else { + if (vlan->notempty) + sta->vlan_id = vlan->untagged; + } /* Configure wpa_group for GTK but ignore error due to driver not * knowing this STA. */ ap_sta_bind_vlan(hapd, sta); @@ -1169,10 +1222,15 @@ static int hostapd_wpa_auth_get_vlan(void *ctx, const u8 *sta_addr, if (!sta) return -1; - if (sta->vlan_desc) + if (sta->vlan_desc) { *vlan = *sta->vlan_desc; - else + } else if ((hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) && + sta->vlan_id) { + vlan->notempty = 1; + vlan->untagged = sta->vlan_id; + } else { os_memset(vlan, 0, sizeof(*vlan)); + } return 0; } @@ -1375,7 +1433,7 @@ static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf, wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR_SEC " -> " MACSTR_SEC, MAC2STR_SEC(ethhdr->h_source), MAC2STR_SEC(ethhdr->h_dest)); if (!is_multicast_ether_addr(ethhdr->h_dest) && - os_memcmp(hapd->own_addr, ethhdr->h_dest, ETH_ALEN) != 0) + !ether_addr_equal(hapd->own_addr, ethhdr->h_dest)) return; wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr), len - sizeof(*ethhdr)); @@ -1391,7 +1449,7 @@ static void hostapd_rrb_oui_receive(void *ctx, const u8 *src_addr, wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR_SEC " -> " MACSTR_SEC, MAC2STR_SEC(src_addr), MAC2STR_SEC(dst_addr)); if (!is_multicast_ether_addr(dst_addr) && - os_memcmp(hapd->own_addr, dst_addr, ETH_ALEN) != 0) + !ether_addr_equal(hapd->own_addr, dst_addr)) return; wpa_ft_rrb_oui_rx(hapd->wpa_auth, src_addr, dst_addr, oui_suffix, buf, len); @@ -1460,6 +1518,106 @@ static void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd) #endif /* CONFIG_IEEE80211R_AP */ +#ifndef CONFIG_NO_RADIUS +static void hostapd_request_radius_psk(void *ctx, const u8 *addr, int key_mgmt, + const u8 *anonce, + const u8 *eapol, size_t eapol_len) +{ + struct hostapd_data *hapd = ctx; + + wpa_printf(MSG_DEBUG, "RADIUS PSK request for " MACSTR " key_mgmt=0x%x", + MAC2STR(addr), key_mgmt); + wpa_hexdump(MSG_DEBUG, "ANonce", anonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "EAPOL", eapol, eapol_len); + hostapd_acl_req_radius_psk(hapd, addr, key_mgmt, anonce, eapol, + eapol_len); +} +#endif /* CONFIG_NO_RADIUS */ + + +#ifdef CONFIG_PASN +static int hostapd_set_ltf_keyseed(void *ctx, const u8 *peer_addr, + const u8 *ltf_keyseed, + size_t ltf_keyseed_len) +{ + struct hostapd_data *hapd = ctx; + + return hostapd_drv_set_secure_ranging_ctx(hapd, hapd->own_addr, + peer_addr, 0, 0, NULL, + ltf_keyseed_len, + ltf_keyseed, 0); +} +#endif /* CONFIG_PASN */ + + +#ifdef CONFIG_IEEE80211BE + +static int hostapd_wpa_auth_get_ml_key_info(void *ctx, + struct wpa_auth_ml_key_info *info) +{ + struct hostapd_data *hapd = ctx; + unsigned int i; + + wpa_printf(MSG_DEBUG, "WPA_AUTH: MLD: Get key info CB: n_mld_links=%u", + info->n_mld_links); + + if (!hapd->conf->mld_ap || !hapd->iface || !hapd->iface->interfaces) + return -1; + + for (i = 0; i < info->n_mld_links; i++) { + struct hostapd_data *bss; + u8 link_id = info->links[i].link_id; + bool link_bss_found = false; + + wpa_printf(MSG_DEBUG, + "WPA_AUTH: MLD: Get link info CB: link_id=%u", + link_id); + + if (hapd->mld_link_id == link_id) { + wpa_auth_ml_get_key_info(hapd->wpa_auth, + &info->links[i], + info->mgmt_frame_prot, + info->beacon_prot); + continue; + } + + for_each_mld_link(bss, hapd) { + if (bss == hapd || bss->mld_link_id != link_id) + continue; + + wpa_auth_ml_get_key_info(bss->wpa_auth, + &info->links[i], + info->mgmt_frame_prot, + info->beacon_prot); + link_bss_found = true; + break; + } + + if (!link_bss_found) + wpa_printf(MSG_DEBUG, + "WPA_AUTH: MLD: link=%u not found", link_id); + } + + return 0; +} + +#endif /* CONFIG_IEEE80211BE */ + + +static int hostapd_wpa_auth_get_drv_flags(void *ctx, + u64 *drv_flags, u64 *drv_flags2) +{ + struct hostapd_data *hapd = ctx; + + if (drv_flags) + *drv_flags = hapd->iface->drv_flags; + if (drv_flags2) + *drv_flags2 = hapd->iface->drv_flags2; + + return 0; +} + + int hostapd_setup_wpa(struct hostapd_data *hapd) { struct wpa_auth_config _conf; @@ -1475,6 +1633,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) .set_key = hostapd_wpa_auth_set_key, .get_seqnum = hostapd_wpa_auth_get_seqnum, .send_eapol = hostapd_wpa_auth_send_eapol, + .get_sta_count = hostapd_wpa_auth_get_sta_count, .for_each_sta = hostapd_wpa_auth_for_each_sta, .for_each_auth = hostapd_wpa_auth_for_each_auth, .send_ether = hostapd_wpa_auth_send_ether, @@ -1503,12 +1662,26 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) .set_session_timeout = hostapd_wpa_auth_set_session_timeout, .get_session_timeout = hostapd_wpa_auth_get_session_timeout, #endif /* CONFIG_IEEE80211R_AP */ +#ifndef CONFIG_NO_RADIUS + .request_radius_psk = hostapd_request_radius_psk, +#endif /* CONFIG_NO_RADIUS */ +#ifdef CONFIG_PASN + .set_ltf_keyseed = hostapd_set_ltf_keyseed, +#endif /* CONFIG_PASN */ +#ifdef CONFIG_IEEE80211BE + .get_ml_key_info = hostapd_wpa_auth_get_ml_key_info, +#endif /* CONFIG_IEEE80211BE */ + .get_drv_flags = hostapd_wpa_auth_get_drv_flags, }; const u8 *wpa_ie; size_t wpa_ie_len; + struct hostapd_data *tx_bss; hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf); _conf.msg_ctx = hapd->msg_ctx; + tx_bss = hostapd_mbssid_get_tx_bss(hapd); + if (tx_bss != hapd) + _conf.tx_bss_auth = tx_bss->wpa_auth; if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS) _conf.tx_status = 1; if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME) @@ -1539,11 +1712,33 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) #endif /* CONFIG_OCV */ _conf.secure_ltf = - !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF); + !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_AP); _conf.secure_rtt = - !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT); + !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_AP); _conf.prot_range_neg = - !!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG); + !!(hapd->iface->drv_flags2 & + WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP); + +#ifdef CONFIG_IEEE80211BE + _conf.mld_addr = NULL; + _conf.link_id = -1; + _conf.first_link_auth = NULL; + + if (hapd->conf->mld_ap) { + struct hostapd_data *lhapd; + + _conf.mld_addr = hapd->mld->mld_addr; + _conf.link_id = hapd->mld_link_id; + + for_each_mld_link(lhapd, hapd) { + if (lhapd == hapd) + continue; + + if (lhapd->wpa_auth) + _conf.first_link_auth = lhapd->wpa_auth; + } + } +#endif /* CONFIG_IEEE80211BE */ hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd); if (hapd->wpa_auth == NULL) { @@ -1648,4 +1843,10 @@ void hostapd_deinit_wpa(struct hostapd_data *hapd) hapd->l2 = NULL; hostapd_wpa_unregister_ft_oui(hapd); #endif /* CONFIG_IEEE80211R_AP */ + +#ifdef CONFIG_TESTING_OPTIONS + forced_memzero(hapd->last_gtk, WPA_GTK_MAX_LEN); + forced_memzero(hapd->last_igtk, WPA_IGTK_MAX_LEN); + forced_memzero(hapd->last_bigtk, WPA_BIGTK_MAX_LEN); +#endif /* CONFIG_TESTING_OPTIONS */ } diff --git a/wpa_supplicant-2.9_standard/src/ap/wpa_auth_i.h b/wpa_supplicant-2.9_standard/src/ap/wpa_auth_i.h index a6dc1a59185d4756e3600e371eb2ca5f46517940..4e5ba3e2ed6f2d9223c81b384800aee04c24c20f 100644 --- a/wpa_supplicant-2.9_standard/src/ap/wpa_auth_i.h +++ b/wpa_supplicant-2.9_standard/src/ap/wpa_auth_i.h @@ -86,9 +86,11 @@ struct wpa_state_machine { unsigned int pending_deinit:1; unsigned int started:1; unsigned int mgmt_frame_prot:1; + unsigned int mfpr:1; unsigned int rx_eapol_key_secure:1; unsigned int update_snonce:1; unsigned int alt_snonce_valid:1; + unsigned int waiting_radius_psk:1; #ifdef CONFIG_IEEE80211R_AP unsigned int ft_completed:1; unsigned int pmk_r1_name_valid:1; @@ -96,6 +98,8 @@ struct wpa_state_machine { unsigned int is_wnmsleep:1; unsigned int pmkid_set:1; + unsigned int ptkstart_without_success; + #ifdef CONFIG_OCV int ocv_enabled; #endif /* CONFIG_OCV */ @@ -130,11 +134,9 @@ struct wpa_state_machine { * Request */ u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */ size_t r0kh_id_len; - u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key - * message 2/4 */ u8 *assoc_resp_ftie; - void (*ft_pending_cb)(void *ctx, const u8 *dst, const u8 *bssid, + void (*ft_pending_cb)(void *ctx, const u8 *dst, u16 auth_transaction, u16 status, const u8 *ies, size_t ies_len); void *ft_pending_cb_ctx; @@ -149,6 +151,7 @@ struct wpa_state_machine { #ifdef CONFIG_P2P u8 ip_addr[4]; + unsigned int ip_addr_bit; #endif /* CONFIG_P2P */ #ifdef CONFIG_FILS @@ -167,6 +170,21 @@ struct wpa_state_machine { void *eapol_status_cb_ctx1; void *eapol_status_cb_ctx2; #endif /* CONFIG_TESTING_OPTIONS */ + +#ifdef CONFIG_IEEE80211BE + u8 peer_mld_addr[ETH_ALEN]; + s8 mld_assoc_link_id; + u8 n_mld_affiliated_links; + + struct mld_link { + bool valid; + u8 peer_addr[ETH_ALEN]; + + struct wpa_authenticator *wpa_auth; + } mld_links[MAX_NUM_MLD_LINKS]; +#endif /* CONFIG_IEEE80211BE */ + + bool ssid_protection; }; @@ -199,6 +217,8 @@ struct wpa_group { u8 BIGTK[2][WPA_IGTK_MAX_LEN]; int GN_igtk, GM_igtk; int GN_bigtk, GM_bigtk; + bool bigtk_set; + bool bigtk_configured; /* Number of references except those in struct wpa_group->next */ unsigned int references; unsigned int num_setup_iface; @@ -234,9 +254,18 @@ struct wpa_authenticator { struct rsn_pmksa_cache *pmksa; struct wpa_ft_pmk_cache *ft_pmk_cache; + bool non_tx_beacon_prot; + #ifdef CONFIG_P2P struct bitfield *ip_pool; #endif /* CONFIG_P2P */ + +#ifdef CONFIG_IEEE80211BE + bool is_ml; + u8 mld_addr[ETH_ALEN]; + u8 link_id; + bool primary_auth; +#endif /* CONFIG_IEEE80211BE */ }; @@ -291,15 +320,23 @@ int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, int (*cb)(struct wpa_authenticator *a, void *ctx), void *cb_ctx); +void wpa_auth_store_ptksa(struct wpa_authenticator *wpa_auth, + const u8 *addr, int cipher, + u32 life_time, const struct wpa_ptk *ptk); #ifdef CONFIG_IEEE80211R_AP int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len); -int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384, +int wpa_write_ftie(struct wpa_auth_config *conf, int key_mgmt, size_t key_len, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *anonce, const u8 *snonce, u8 *buf, size_t len, const u8 *subelem, size_t subelem_len, int rsnxe_used); -int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk); +int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk, + u8 *pmk_r0, u8 *pmk_r1, u8 *pmk_r0_name, + size_t *key_len, size_t kdk_len); +void wpa_auth_ft_store_keys(struct wpa_state_machine *sm, const u8 *pmk_r0, + const u8 *pmk_r1, const u8 *pmk_r0_name, + size_t key_len); struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void); void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache); void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry); diff --git a/wpa_supplicant-2.9_standard/src/ap/wpa_auth_ie.c b/wpa_supplicant-2.9_standard/src/ap/wpa_auth_ie.c index 11f05b17ff7179c399b86d903604e700f494e14b..2a64cea48e18b21772b19c08ddf40f92c51e8473 100644 --- a/wpa_supplicant-2.9_standard/src/ap/wpa_auth_ie.c +++ b/wpa_supplicant-2.9_standard/src/ap/wpa_auth_ie.c @@ -10,6 +10,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" +#include "drivers/driver.h" #include "eapol_auth/eapol_auth_sm.h" #include "ap_config.h" #include "ieee802_11.h" @@ -212,6 +213,13 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, num_suites++; } #endif /* CONFIG_IEEE80211R_AP */ +#ifdef CONFIG_SHA384 + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA384); + pos += RSN_SELECTOR_LEN; + num_suites++; + } +#endif /* CONFIG_SHA384 */ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); pos += RSN_SELECTOR_LEN; @@ -238,6 +246,11 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, pos += RSN_SELECTOR_LEN; num_suites++; } + if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY); + pos += RSN_SELECTOR_LEN; + num_suites++; + } #endif /* CONFIG_SAE */ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B); @@ -396,11 +409,12 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len) { u8 *pos = buf; - u16 capab = 0; + u32 capab = 0, tmp; size_t flen; if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) && - (conf->sae_pwe == 1 || conf->sae_pwe == 2 || conf->sae_pk || + (conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || + conf->sae_pwe == SAE_PWE_BOTH || conf->sae_pk || wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt))) { capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); #ifdef CONFIG_SAE_PK @@ -414,21 +428,28 @@ int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len) if (conf->secure_rtt) capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT); if (conf->prot_range_neg) - capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG); + capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR); + if (conf->ssid_protection) + capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION); - flen = (capab & 0xff00) ? 2 : 1; if (!capab) return 0; /* no supported extended RSN capabilities */ + tmp = capab; + flen = 0; + while (tmp) { + flen++; + tmp >>= 8; + } if (len < 2 + flen) return -1; capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ *pos++ = WLAN_EID_RSNX; *pos++ = flen; - *pos++ = capab & 0x00ff; - capab >>= 8; - if (capab) - *pos++ = capab; + while (capab) { + *pos++ = capab & 0xff; + capab >>= 8; + } return pos - buf; } @@ -594,7 +615,8 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, const u8 *wpa_ie, size_t wpa_ie_len, const u8 *rsnxe, size_t rsnxe_len, const u8 *mdie, size_t mdie_len, - const u8 *owe_dh, size_t owe_dh_len) + const u8 *owe_dh, size_t owe_dh_len, + struct wpa_state_machine *assoc_sm) { struct wpa_auth_config *conf = &wpa_auth->conf; struct wpa_ie_data data; @@ -680,6 +702,8 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, selector = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY; else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) selector = RSN_AUTH_KEY_MGMT_FT_SAE; + else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) + selector = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY; #endif /* CONFIG_SAE */ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; @@ -697,6 +721,10 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, else if (data.key_mgmt & WPA_KEY_MGMT_OSEN) selector = RSN_AUTH_KEY_MGMT_OSEN; #endif /* CONFIG_HS20 */ +#ifdef CONFIG_SHA384 + else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) + selector = RSN_AUTH_KEY_MGMT_802_1X_SHA384; +#endif /* CONFIG_SHA384 */ wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector; selector = wpa_cipher_to_suite(WPA_PROTO_RSN, @@ -779,6 +807,10 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, else if (key_mgmt & WPA_KEY_MGMT_FT_PSK) sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK; #endif /* CONFIG_IEEE80211R_AP */ +#ifdef CONFIG_SHA384 + else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) + sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA384; +#endif /* CONFIG_SHA384 */ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256; else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256) @@ -790,6 +822,8 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY; else if (key_mgmt & WPA_KEY_MGMT_FT_SAE) sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE; + else if (key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) + sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY; #endif /* CONFIG_SAE */ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X) sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X; @@ -874,6 +908,7 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, sm->mgmt_frame_prot = 0; else sm->mgmt_frame_prot = 1; + sm->mfpr = !!(data.capabilities & WPA_CAPABILITY_MFPR); if (sm->mgmt_frame_prot && (ciphers & WPA_CIPHER_TKIP)) { wpa_printf(MSG_DEBUG, @@ -929,6 +964,15 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, else sm->wpa = WPA_VERSION_WPA; + if (assoc_sm) { + /* For ML association link STA cannot choose a different + * AKM or pairwise cipher from association STA */ + if (sm->wpa_key_mgmt != assoc_sm->wpa_key_mgmt) + return WPA_INVALID_AKMP; + if (sm->pairwise != assoc_sm->pairwise) + return WPA_INVALID_PAIRWISE; + } + #if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS) if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 || sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) && @@ -987,11 +1031,24 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } #ifdef CONFIG_SAE - if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid && - !sm->pmksa) { - wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "No PMKSA cache entry found for SAE"); - return WPA_INVALID_PMKID; + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE || + sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE_EXT_KEY) { + u64 drv_flags = 0; + u64 drv_flags2 = 0; + bool ap_sae_offload = false; + + if (wpa_auth->cb->get_drv_flags && + wpa_auth->cb->get_drv_flags(wpa_auth->cb_ctx, &drv_flags, + &drv_flags2) == 0) + ap_sae_offload = + !!(drv_flags2 & + WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP); + + if (!ap_sae_offload && data.num_pmkid && !sm->pmksa) { + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, + "No PMKSA cache entry found for SAE"); + return WPA_INVALID_PMKID; + } } #endif /* CONFIG_SAE */ diff --git a/wpa_supplicant-2.9_standard/src/ap/wpa_auth_kay.c b/wpa_supplicant-2.9_standard/src/ap/wpa_auth_kay.c index a7916b29851d7e8e299f30d4924e70ad03e8287c..8d07c1b3f8be30a24add6a313f51486627132c5b 100644 --- a/wpa_supplicant-2.9_standard/src/ap/wpa_auth_kay.c +++ b/wpa_supplicant-2.9_standard/src/ap/wpa_auth_kay.c @@ -138,7 +138,6 @@ static unsigned int conf_offset_val(enum confidentiality_offset co) switch (co) { case CONFIDENTIALITY_OFFSET_30: return 30; - break; case CONFIDENTIALITY_OFFSET_50: return 50; default: @@ -328,8 +327,11 @@ int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd, res = ieee802_1x_kay_init(kay_ctx, policy, hapd->conf->macsec_replay_protect, hapd->conf->macsec_replay_window, + hapd->conf->macsec_offload, hapd->conf->macsec_port, - hapd->conf->mka_priority, hapd->conf->iface, + hapd->conf->mka_priority, + hapd->conf->macsec_csindex, + hapd->conf->iface, hapd->own_addr); /* ieee802_1x_kay_init() frees kay_ctx on failure */ if (!res) @@ -351,33 +353,6 @@ void ieee802_1x_dealloc_kay_sm_hapd(struct hostapd_data *hapd) } -static int ieee802_1x_auth_get_session_id(struct hostapd_data *hapd, - struct sta_info *sta, u8 *sid, - size_t *len) -{ - const u8 *session_id; - size_t id_len, need_len; - - session_id = ieee802_1x_get_session_id(sta->eapol_sm, &id_len); - if (!session_id) { - wpa_printf(MSG_DEBUG, - "MACsec: Failed to get SessionID from EAPOL state machines"); - return -1; - } - - need_len = 1 + 2 * 32 /* random size */; - if (need_len > id_len) { - wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough"); - return -1; - } - - os_memcpy(sid, session_id, need_len); - *len = need_len; - - return 0; -} - - static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd, struct sta_info *sta, u8 *msk, size_t *len) { @@ -409,8 +384,8 @@ static int ieee802_1x_auth_get_msk(struct hostapd_data *hapd, void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd, struct sta_info *sta) { - u8 *sid; - size_t sid_len = 128; + const u8 *sid; + size_t sid_len; struct mka_key_name *ckn; struct mka_key *cak; struct mka_key *msk; @@ -424,10 +399,9 @@ void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd, MACSTR_SEC, MAC2STR_SEC(sta->addr)); msk = os_zalloc(sizeof(*msk)); - sid = os_zalloc(sid_len); ckn = os_zalloc(sizeof(*ckn)); cak = os_zalloc(sizeof(*cak)); - if (!msk || !sid || !ckn || !cak) + if (!msk || !ckn || !cak) goto fail; msk->len = DEFAULT_KEY_LEN; @@ -436,8 +410,8 @@ void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd, goto fail; } - if (ieee802_1x_auth_get_session_id(hapd, sta, sid, &sid_len)) - { + sid = ieee802_1x_get_session_id(sta->eapol_sm, &sid_len); + if (!sid) { wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get EAP Session Id"); goto fail; @@ -469,7 +443,6 @@ void * ieee802_1x_notify_create_actor_hapd(struct hostapd_data *hapd, fail: bin_clear_free(msk, sizeof(*msk)); - os_free(sid); os_free(ckn); bin_clear_free(cak, sizeof(*cak)); diff --git a/wpa_supplicant-2.9_standard/src/ap/wps_hostapd.c b/wpa_supplicant-2.9_standard/src/ap/wps_hostapd.c index 0a40dce443cd6b3730ed005771969fff1da17a5e..6514a260fefc9e5bf2ca60127c6f948bde0acf37 100644 --- a/wpa_supplicant-2.9_standard/src/ap/wps_hostapd.c +++ b/wpa_supplicant-2.9_standard/src/ap/wps_hostapd.c @@ -289,7 +289,7 @@ static int hostapd_wps_lookup_pskfile_cb(void *ctx, const u8 *mac_addr, any_psk = wpa_psk->psk; if (mac_addr && !dev_psk && - os_memcmp(mac_addr, wpa_psk->addr, ETH_ALEN) == 0) { + ether_addr_equal(mac_addr, wpa_psk->addr)) { dev_psk = wpa_psk->psk; break; } @@ -1070,10 +1070,11 @@ static void hostapd_free_wps(struct wps_context *wps) for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) wpabuf_free(wps->dev.vendor_ext[i]); wps_device_data_free(&wps->dev); - os_free(wps->network_key); + bin_clear_free(wps->network_key, wps->network_key_len); hostapd_wps_nfc_clear(wps); wpabuf_free(wps->dh_pubkey); wpabuf_free(wps->dh_privkey); + forced_memzero(wps->psk, sizeof(wps->psk)); os_free(wps); } diff --git a/wpa_supplicant-2.9_standard/src/ap/x_snoop.c b/wpa_supplicant-2.9_standard/src/ap/x_snoop.c index 5bf3e9cb61c2113358e59a8cca60d5e35ff4c429..73fc0dbf6dfb92526e399a9f5824c848a182886a 100644 --- a/wpa_supplicant-2.9_standard/src/ap/x_snoop.c +++ b/wpa_supplicant-2.9_standard/src/ap/x_snoop.c @@ -31,6 +31,8 @@ int x_snoop_init(struct hostapd_data *hapd) return -1; } + hapd->x_snoop_initialized = true; + if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 1)) { wpa_printf(MSG_DEBUG, @@ -125,7 +127,10 @@ void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd, void x_snoop_deinit(struct hostapd_data *hapd) { + if (!hapd->x_snoop_initialized) + return; hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0); hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0); hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0); + hapd->x_snoop_initialized = false; } diff --git a/wpa_supplicant-2.9_standard/src/build.rules b/wpa_supplicant-2.9_standard/src/build.rules index acda8847284d7d3fb1b704a17e385409f66d508d..c756ccb84e8ced5c431b548d0179158c9389ea25 100644 --- a/wpa_supplicant-2.9_standard/src/build.rules +++ b/wpa_supplicant-2.9_standard/src/build.rules @@ -80,7 +80,7 @@ endif _DIRS := $(BUILDDIR)/$(PROJ) .PHONY: _make_dirs _make_dirs: - @mkdir -p $(_DIRS) + @mkdir -p $(sort $(_DIRS)) $(BUILDDIR)/$(PROJ)/src/%.o: $(ROOTDIR)src/%.c $(CONFIG_FILE) | _make_dirs $(Q)$(CC) -c -o $@ $(CFLAGS) $< diff --git a/wpa_supplicant-2.9_standard/src/common/brcm_vendor.h b/wpa_supplicant-2.9_standard/src/common/brcm_vendor.h index f163dea73768ff78fa37321e29196251c5e365e7..c42ed7e8bc3ba244388d2f7474b9218e5b3a3ff5 100644 --- a/wpa_supplicant-2.9_standard/src/common/brcm_vendor.h +++ b/wpa_supplicant-2.9_standard/src/common/brcm_vendor.h @@ -40,15 +40,15 @@ * @BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS: Set some connect parameters. * Used for the case that FW handle SAE. * - * @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP paramters. + * @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP parameters. * Used for the case that FW handle SAE. * * @BRCM_VENDOR_SCMD_ACS: ACS command/event which is used to * invoke the ACS function in device and pass selected channels to * hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes. * - * @BRCM_VENDOR_SCMD_MAX: This acts as a the tail of cmds list. - * Make sure it located at the end of the list. + * @BRCM_VENDOR_SCMD_MAX: This acts as a tail of cmds list. + * Make sure it is located at the end of the list. * */ enum brcm_nl80211_vendor_subcmds { @@ -66,7 +66,7 @@ enum brcm_nl80211_vendor_subcmds { }; /** - * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchoronous event identifiers + * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchronous event identifiers * * @BRCM_VENDOR_EVENT_UNSPEC: Reserved value 0 * diff --git a/wpa_supplicant-2.9_standard/src/common/common_module_tests.c b/wpa_supplicant-2.9_standard/src/common/common_module_tests.c index 05c8e0eac8ccd42ef4dd0dad25aa07e29fbbe989..a95ae36dc078194039923380da27487e7eae98f7 100644 --- a/wpa_supplicant-2.9_standard/src/common/common_module_tests.c +++ b/wpa_supplicant-2.9_standard/src/common/common_module_tests.c @@ -428,11 +428,7 @@ static int sae_tests(void) } if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL, - NULL, 0 -#ifdef CONFIG_MLD_PATCH - , NULL -#endif - ) != 0 || + NULL, 0, NULL) != 0 || sae_process_commit(&sae) < 0) goto fail; diff --git a/wpa_supplicant-2.9_standard/src/common/defs.h b/wpa_supplicant-2.9_standard/src/common/defs.h index 2396429eef7cc93303155475fd4b47bd76b9596b..5819d0dbfbe47ec1995ce03e028cedb409e7fca4 100644 --- a/wpa_supplicant-2.9_standard/src/common/defs.h +++ b/wpa_supplicant-2.9_standard/src/common/defs.h @@ -64,12 +64,14 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean; #define WPA_KEY_MGMT_PASN BIT(25) #define WPA_KEY_MGMT_SAE_EXT_KEY BIT(26) #define WPA_KEY_MGMT_FT_SAE_EXT_KEY BIT(27) +#define WPA_KEY_MGMT_IEEE8021X_SHA384 BIT(28) #define WPA_KEY_MGMT_FT (WPA_KEY_MGMT_FT_PSK | \ WPA_KEY_MGMT_FT_IEEE8021X | \ WPA_KEY_MGMT_FT_IEEE8021X_SHA384 | \ WPA_KEY_MGMT_FT_SAE | \ + WPA_KEY_MGMT_FT_SAE_EXT_KEY | \ WPA_KEY_MGMT_FT_FILS_SHA256 | \ WPA_KEY_MGMT_FT_FILS_SHA384) @@ -90,7 +92,8 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm) WPA_KEY_MGMT_FILS_SHA256 | WPA_KEY_MGMT_FILS_SHA384 | WPA_KEY_MGMT_FT_FILS_SHA256 | - WPA_KEY_MGMT_FT_FILS_SHA384)); + WPA_KEY_MGMT_FT_FILS_SHA384 | + WPA_KEY_MGMT_IEEE8021X_SHA384)); } static inline int wpa_key_mgmt_wpa_psk_no_sae(int akm) @@ -107,7 +110,8 @@ static inline int wpa_key_mgmt_wpa_psk(int akm) WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY | - WPA_KEY_MGMT_FT_SAE)); + WPA_KEY_MGMT_FT_SAE | + WPA_KEY_MGMT_FT_SAE_EXT_KEY)); } static inline int wpa_key_mgmt_ft(int akm) @@ -131,12 +135,14 @@ static inline int wpa_key_mgmt_sae(int akm) { return !!(akm & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY | - WPA_KEY_MGMT_FT_SAE)); + WPA_KEY_MGMT_FT_SAE | + WPA_KEY_MGMT_FT_SAE_EXT_KEY)); } static inline int wpa_key_mgmt_sae_ext_key(int akm) { - return !!(akm & WPA_KEY_MGMT_SAE_EXT_KEY); + return !!(akm & (WPA_KEY_MGMT_SAE_EXT_KEY | + WPA_KEY_MGMT_FT_SAE_EXT_KEY)); } static inline int wpa_key_mgmt_fils(int akm) @@ -149,7 +155,8 @@ static inline int wpa_key_mgmt_fils(int akm) static inline int wpa_key_mgmt_sha256(int akm) { - return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 | + return !!(akm & (WPA_KEY_MGMT_FT_IEEE8021X | + WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE | @@ -164,7 +171,8 @@ static inline int wpa_key_mgmt_sha384(int akm) return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 | WPA_KEY_MGMT_FT_IEEE8021X_SHA384 | WPA_KEY_MGMT_FILS_SHA384 | - WPA_KEY_MGMT_FT_FILS_SHA384)); + WPA_KEY_MGMT_FT_FILS_SHA384 | + WPA_KEY_MGMT_IEEE8021X_SHA384)); } static inline int wpa_key_mgmt_suite_b(int akm) @@ -193,6 +201,13 @@ static inline int wpa_key_mgmt_cckm(int akm) return akm == WPA_KEY_MGMT_CCKM; } +static inline int wpa_key_mgmt_cross_akm(int akm) +{ + return !!(akm & (WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_PSK_SHA256 | + WPA_KEY_MGMT_SAE | + WPA_KEY_MGMT_SAE_EXT_KEY)); +} #define WPA_PROTO_WPA BIT(0) #define WPA_PROTO_RSN BIT(1) @@ -454,9 +469,26 @@ enum chan_width { CHAN_WIDTH_4320, CHAN_WIDTH_6480, CHAN_WIDTH_8640, + CHAN_WIDTH_320, CHAN_WIDTH_UNKNOWN }; +/* VHT/EDMG/etc. channel widths + * Note: The first four values are used in hostapd.conf and as such, must + * maintain their defined values. Other values are used internally. */ +enum oper_chan_width { + CONF_OPER_CHWIDTH_USE_HT = 0, + CONF_OPER_CHWIDTH_80MHZ = 1, + CONF_OPER_CHWIDTH_160MHZ = 2, + CONF_OPER_CHWIDTH_80P80MHZ = 3, + CONF_OPER_CHWIDTH_2160MHZ, + CONF_OPER_CHWIDTH_4320MHZ, + CONF_OPER_CHWIDTH_6480MHZ, + CONF_OPER_CHWIDTH_8640MHZ, + CONF_OPER_CHWIDTH_40MHZ_6GHZ, + CONF_OPER_CHWIDTH_320MHZ, +}; + enum key_flag { KEY_FLAG_MODIFY = BIT(0), KEY_FLAG_DEFAULT = BIT(1), @@ -500,9 +532,13 @@ enum ptk0_rekey_handling { PTK0_REKEY_ALLOW_NEVER }; -#ifdef CONFIG_MLD_PATCH +enum frame_encryption { + FRAME_ENCRYPTION_UNKNOWN = -1, + FRAME_NOT_ENCRYPTED = 0, + FRAME_ENCRYPTED = 1 +}; + #define MAX_NUM_MLD_LINKS 15 -#endif enum sae_pwe { SAE_PWE_HUNT_AND_PECK = 0, diff --git a/wpa_supplicant-2.9_standard/src/common/dpp.c b/wpa_supplicant-2.9_standard/src/common/dpp.c index 5e15a99c1007a99d2002805e8a929969a068da02..fe75aa66f217da8b6ed80338bc530d59135ba0c4 100644 --- a/wpa_supplicant-2.9_standard/src/common/dpp.c +++ b/wpa_supplicant-2.9_standard/src/common/dpp.c @@ -2,6 +2,7 @@ * DPP functionality shared between hostapd and wpa_supplicant * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -12,6 +13,7 @@ #include "utils/common.h" #include "utils/base64.h" #include "utils/json.h" +#include "utils/ip_addr.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" #include "common/gas.h" @@ -25,8 +27,6 @@ #include "dpp_i.h" -static const char * dpp_netrole_str(enum dpp_netrole netrole); - #ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_DPP3 int dpp_version_override = 3; @@ -163,6 +163,7 @@ void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info) os_free(info->uri); os_free(info->info); os_free(info->chan); + os_free(info->host); os_free(info->pk); crypto_ec_key_deinit(info->pubkey); str_clear_free(info->configurator_params); @@ -346,12 +347,94 @@ static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info) } +static int dpp_parse_uri_supported_curves(struct dpp_bootstrap_info *bi, + const char *txt) +{ + int val; + + if (!txt) + return 0; + + val = hex2num(txt[0]); + if (val < 0) + return -1; + bi->supported_curves = val; + + val = hex2num(txt[1]); + if (val > 0) + bi->supported_curves |= val << 4; + + wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x", + bi->supported_curves); + + return 0; +} + + +static int dpp_parse_uri_host(struct dpp_bootstrap_info *bi, const char *txt) +{ + const char *end; + char *port; + struct hostapd_ip_addr addr; + char buf[100], *pos; + + if (!txt) + return 0; + + end = os_strchr(txt, ';'); + if (!end) + end = txt + os_strlen(txt); + if (end - txt > (int) sizeof(buf) - 1) + return -1; + os_memcpy(buf, txt, end - txt); + buf[end - txt] = '\0'; + + bi->port = DPP_TCP_PORT; + + pos = buf; + if (*pos == '[') { + pos = &buf[1]; + port = os_strchr(pos, ']'); + if (!port) + return -1; + *port++ = '\0'; + if (*port == ':') + bi->port = atoi(port + 1); + } + + if (hostapd_parse_ip_addr(pos, &addr) < 0) { + if (buf[0] != '[') { + port = os_strrchr(pos, ':'); + if (port) { + *port++ = '\0'; + bi->port = atoi(port); + } + } + if (hostapd_parse_ip_addr(pos, &addr) < 0) { + wpa_printf(MSG_INFO, + "DPP: Invalid IP address in URI host entry: %s", + pos); + return -1; + } + } + os_free(bi->host); + bi->host = os_memdup(&addr, sizeof(addr)); + if (!bi->host) + return -1; + + wpa_printf(MSG_DEBUG, "DPP: host: %s port: %u", + hostapd_ip_txt(bi->host, buf, sizeof(buf)), bi->port); + + return 0; +} + + static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) { const char *pos = uri; const char *end; const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL; - const char *version = NULL; + const char *version = NULL, *supported_curves = NULL, *host = NULL; struct dpp_bootstrap_info *bi; wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri)); @@ -384,6 +467,10 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) pk = pos + 2; else if (pos[0] == 'V' && pos[1] == ':' && !version) version = pos + 2; + else if (pos[0] == 'B' && pos[1] == ':' && !supported_curves) + supported_curves = pos + 2; + else if (pos[0] == 'H' && pos[1] == ':' && !host) + host = pos + 2; else wpa_hexdump_ascii(MSG_DEBUG, "DPP: Ignore unrecognized URI parameter", @@ -405,6 +492,8 @@ static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) dpp_parse_uri_mac(bi, mac) < 0 || dpp_parse_uri_info(bi, info) < 0 || dpp_parse_uri_version(bi, version) < 0 || + dpp_parse_uri_supported_curves(bi, supported_curves) < 0 || + dpp_parse_uri_host(bi, host) < 0 || dpp_parse_uri_pk(bi, pk) < 0) { dpp_bootstrap_info_free(bi); bi = NULL; @@ -605,6 +694,8 @@ int dpp_gen_uri(struct dpp_bootstrap_info *bi) { char macstr[ETH_ALEN * 2 + 10]; size_t len; + char supp_curves[10]; + char host[100]; len = 4; /* "DPP:" */ if (bi->chan) @@ -622,11 +713,44 @@ int dpp_gen_uri(struct dpp_bootstrap_info *bi) #endif /* CONFIG_DPP2 */ len += 4 + os_strlen(bi->pk); /* K:...;; */ + if (bi->supported_curves) { + u8 val = bi->supported_curves; + + if (val & 0xf0) { + val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); + len += os_snprintf(supp_curves, sizeof(supp_curves), + "B:%02x;", val); + } else { + len += os_snprintf(supp_curves, sizeof(supp_curves), + "B:%x;", val); + } + } else { + supp_curves[0] = '\0'; + } + + host[0] = '\0'; + if (bi->host) { + char buf[100]; + const char *addr; + + addr = hostapd_ip_txt(bi->host, buf, sizeof(buf)); + if (!addr) + return -1; + if (bi->port == DPP_TCP_PORT) + len += os_snprintf(host, sizeof(host), "H:%s;", addr); + else if (bi->host->af == AF_INET) + len += os_snprintf(host, sizeof(host), "H:%s:%u;", + addr, bi->port); + else + len += os_snprintf(host, sizeof(host), "H:[%s]:%u;", + addr, bi->port); + } + os_free(bi->uri); bi->uri = os_malloc(len + 1); if (!bi->uri) return -1; - os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%sK:%s;;", + os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%s%sK:%s;;", bi->chan ? "C:" : "", bi->chan ? bi->chan : "", bi->chan ? ";" : "", macstr, @@ -634,6 +758,8 @@ int dpp_gen_uri(struct dpp_bootstrap_info *bi) bi->info ? ";" : "", DPP_VERSION == 3 ? "V:3;" : (DPP_VERSION == 2 ? "V:2;" : ""), + supp_curves, + host, bi->pk); return 0; } @@ -659,9 +785,12 @@ static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth, { size_t nonce_len; size_t json_len, clear_len; - struct wpabuf *clear = NULL, *msg = NULL; + struct wpabuf *clear = NULL, *msg = NULL, *pe = NULL; u8 *wrapped; size_t attr_len; +#ifdef CONFIG_DPP3 + u8 auth_i[DPP_MAX_HASH_LEN]; +#endif /* CONFIG_DPP3 */ wpa_printf(MSG_DEBUG, "DPP: Build configuration request"); @@ -676,6 +805,18 @@ static struct wpabuf * dpp_build_conf_req_attr(struct dpp_authentication *auth, /* { E-nonce, configAttrib }ke */ clear_len = 4 + nonce_len + 4 + json_len; +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key) { + pe = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); + if (!pe) + goto fail; + clear_len += 4 + wpabuf_len(pe); + + if (dpp_derive_auth_i(auth, auth_i) < 0) + goto fail; + clear_len += 4 + auth->curve->hash_len; + } +#endif /* CONFIG_DPP3 */ clear = wpabuf_alloc(clear_len); attr_len = 4 + clear_len + AES_BLOCK_SIZE; #ifdef CONFIG_TESTING_OPTIONS @@ -717,6 +858,21 @@ skip_e_nonce: } #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef CONFIG_DPP3 + if (pe) { + wpa_printf(MSG_DEBUG, "DPP: Pe"); + wpabuf_put_le16(clear, DPP_ATTR_I_PROTOCOL_KEY); + wpabuf_put_le16(clear, wpabuf_len(pe)); + wpabuf_put_buf(clear, pe); + } + if (auth->waiting_new_key) { + wpa_printf(MSG_DEBUG, "DPP: Initiator Authentication Tag"); + wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG); + wpabuf_put_le16(clear, auth->curve->hash_len); + wpabuf_put_data(clear, auth_i, auth->curve->hash_len); + } +#endif /* CONFIG_DPP3 */ + /* configAttrib */ wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ); wpabuf_put_le16(clear, json_len); @@ -749,13 +905,15 @@ skip_wrapped_data: wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Request frame attributes", msg); +out: wpabuf_free(clear); + wpabuf_free(pe); return msg; fail: - wpabuf_free(clear); wpabuf_free(msg); - return NULL; + msg = NULL; + goto out; } @@ -811,12 +969,14 @@ struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth, struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth, const char *name, enum dpp_netrole netrole, - const char *mud_url, int *opclasses) + const char *mud_url, int *opclasses, + const char *extra_name, + const char *extra_value) { size_t len, name_len; const char *tech = "infra"; const char *dpp_name; - struct wpabuf *buf, *json; + struct wpabuf *buf = NULL, *json = NULL; char *csr = NULL; #ifdef CONFIG_TESTING_OPTIONS @@ -834,6 +994,8 @@ 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); + if (extra_name && extra_value && extra_name[0] && extra_value[0]) + len += 10 + os_strlen(extra_name) + os_strlen(extra_value); #ifdef CONFIG_DPP2 if (auth->csr) { size_t csr_len; @@ -841,19 +1003,17 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth, csr = base64_encode_no_lf(wpabuf_head(auth->csr), wpabuf_len(auth->csr), &csr_len); if (!csr) - return NULL; + goto fail; len += 30 + csr_len; } #endif /* CONFIG_DPP2 */ json = wpabuf_alloc(len); if (!json) - return NULL; + goto fail; json_start_object(json, NULL); - if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) { - wpabuf_free(json); - return NULL; - } + if (json_add_string_escape(json, "name", dpp_name, name_len) < 0) + goto fail; json_value_sep(json); json_add_string(json, "wi-fi_tech", tech); json_value_sep(json); @@ -875,9 +1035,14 @@ struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth, json_value_sep(json); json_add_string(json, "pkcs10", csr); } + if (extra_name && extra_value && extra_name[0] && extra_value[0]) { + json_value_sep(json); + wpabuf_printf(json, "\"%s\":%s", extra_name, extra_value); + } json_end_object(json); buf = dpp_build_conf_req(auth, wpabuf_head(json)); +fail: wpabuf_free(json); os_free(csr); @@ -987,6 +1152,8 @@ void dpp_configuration_free(struct dpp_configuration *conf) str_clear_free(conf->passphrase); os_free(conf->group_id); os_free(conf->csrattrs); + os_free(conf->extra_name); + os_free(conf->extra_value); bin_clear_free(conf, sizeof(*conf)); } @@ -1113,6 +1280,29 @@ static int dpp_configuration_parse_helper(struct dpp_authentication *auth, os_memcpy(conf->csrattrs, pos, len); } + pos = os_strstr(cmd, " conf_extra_name="); + if (pos) { + pos += 17; + end = os_strchr(pos, ' '); + len = end ? (size_t) (end - pos) : os_strlen(pos); + conf->extra_name = os_zalloc(len + 1); + if (!conf->extra_name) + goto fail; + os_memcpy(conf->extra_name, pos, len); + } + + pos = os_strstr(cmd, " conf_extra_value="); + if (pos) { + pos += 18; + end = os_strchr(pos, ' '); + len = end ? (size_t) (end - pos) : os_strlen(pos); + len /= 2; + conf->extra_value = os_zalloc(len + 1); + if (!conf->extra_value || + hexstr2bin(pos, (u8 *) conf->extra_value, len) < 0) + goto fail; + } + if (!dpp_configuration_valid(conf)) goto fail; @@ -1120,8 +1310,14 @@ static int dpp_configuration_parse_helper(struct dpp_authentication *auth, auth->conf_sta = conf_sta; auth->conf_ap = conf_ap; } else if (idx == 1) { - auth->conf2_sta = conf_sta; - auth->conf2_ap = conf_ap; + if (!auth->conf_sta) + auth->conf_sta = conf_sta; + else + auth->conf2_sta = conf_sta; + if (!auth->conf_ap) + auth->conf_ap = conf_ap; + else + auth->conf2_ap = conf_ap; } else { goto fail; } @@ -1152,7 +1348,7 @@ static int dpp_configuration_parse(struct dpp_authentication *auth, goto fail; os_memcpy(tmp, cmd, len); tmp[len] = '\0'; - res = dpp_configuration_parse_helper(auth, cmd, 0); + res = dpp_configuration_parse_helper(auth, tmp, 0); str_clear_free(tmp); if (res) goto fail; @@ -1210,6 +1406,13 @@ int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd) wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd); + if (os_strstr(cmd, " conf=query")) { + auth->configurator_set = 0; + auth->use_config_query = true; + ret = 0; + goto fail; + } + pos = os_strstr(cmd, " configurator="); if (!auth->conf && pos) { pos += 14; @@ -1290,6 +1493,9 @@ void dpp_auth_deinit(struct dpp_authentication *auth) dl_list_del(&auth->tmp_peer_bi->list); dpp_bootstrap_info_free(auth->tmp_peer_bi); } + os_free(auth->e_name); + os_free(auth->e_mud_url); + os_free(auth->e_band_support); #ifdef CONFIG_TESTING_OPTIONS os_free(auth->config_obj_override); os_free(auth->discovery_override); @@ -1400,7 +1606,7 @@ static void dpp_build_legacy_cred_params(struct wpabuf *buf, } -static const char * dpp_netrole_str(enum dpp_netrole netrole) +const char * dpp_netrole_str(enum dpp_netrole netrole) { switch (netrole) { case DPP_NETROLE_STA: @@ -1415,6 +1621,32 @@ static const char * dpp_netrole_str(enum dpp_netrole netrole) } +static bool dpp_supports_curve(const char *curve, struct dpp_bootstrap_info *bi) +{ + enum dpp_bootstrap_supported_curves idx; + + if (!bi || !bi->supported_curves) + return true; /* no support indication available */ + + if (os_strcmp(curve, "prime256v1") == 0) + idx = DPP_BOOTSTRAP_CURVE_P_256; + else if (os_strcmp(curve, "secp384r1") == 0) + idx = DPP_BOOTSTRAP_CURVE_P_384; + else if (os_strcmp(curve, "secp521r1") == 0) + idx = DPP_BOOTSTRAP_CURVE_P_521; + else if (os_strcmp(curve, "brainpoolP256r1") == 0) + idx = DPP_BOOTSTRAP_CURVE_BP_256; + else if (os_strcmp(curve, "brainpoolP384r1") == 0) + idx = DPP_BOOTSTRAP_CURVE_BP_384; + else if (os_strcmp(curve, "brainpoolP512r1") == 0) + idx = DPP_BOOTSTRAP_CURVE_BP_512; + else + return true; + + return bi->supported_curves & BIT(idx); +} + + static struct wpabuf * dpp_build_conf_obj_dpp(struct dpp_authentication *auth, struct dpp_configuration *conf) @@ -1422,7 +1654,8 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, struct wpabuf *buf = NULL; char *signed_conn = NULL; size_t tailroom; - const struct dpp_curve_params *curve; + const struct dpp_curve_params *curve; /* C-sign-key curve */ + const struct dpp_curve_params *nak_curve; /* netAccessKey curve */ struct wpabuf *dppcon = NULL; size_t extra_len = 1000; int incl_legacy; @@ -1435,6 +1668,23 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, goto fail; } curve = auth->conf->curve; + if (dpp_akm_dpp(conf->akm) && + !dpp_supports_curve(curve->name, auth->peer_bi)) { + wpa_printf(MSG_DEBUG, + "DPP: Enrollee does not support C-sign-key curve (%s) - cannot generate config object", + curve->name); + goto fail; + } + if (auth->new_curve && auth->new_key_received) + nak_curve = auth->new_curve; + else + nak_curve = auth->curve; + if (!dpp_supports_curve(nak_curve->name, auth->peer_bi)) { + wpa_printf(MSG_DEBUG, + "DPP: Enrollee does not support netAccessKey curve (%s) - cannot generate config object", + nak_curve->name); + goto fail; + } akm = conf->akm; if (dpp_akm_ver2(akm) && auth->peer_version < 2) { @@ -1452,7 +1702,7 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, extra_len += os_strlen(conf->group_id); /* Connector (JSON dppCon object) */ - dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3); + dppcon = wpabuf_alloc(extra_len + 2 * nak_curve->prime_len * 4 / 3); if (!dppcon) goto fail; #ifdef CONFIG_TESTING_OPTIONS @@ -1482,9 +1732,38 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, #ifdef CONFIG_TESTING_OPTIONS skip_groups: #endif /* CONFIG_TESTING_OPTIONS */ - if (!auth->peer_protocol_key || - dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL, - auth->curve) < 0) { + if (!auth->peer_protocol_key) { + wpa_printf(MSG_DEBUG, + "DPP: No peer protocol key available to build netAccessKey JWK"); + goto fail; + } +#ifdef CONFIG_DPP3 + if (auth->conf->net_access_key_curve && + auth->curve != auth->conf->net_access_key_curve && + !auth->new_key_received) { + if (!dpp_supports_curve(auth->conf->net_access_key_curve->name, + auth->peer_bi)) { + wpa_printf(MSG_DEBUG, + "DPP: Enrollee does not support the required netAccessKey curve (%s) - cannot generate config object", + auth->conf->net_access_key_curve->name); + goto fail; + } + wpa_printf(MSG_DEBUG, + "DPP: Peer protocol key curve (%s) does not match the required netAccessKey curve (%s) - %s", + auth->curve->name, + auth->conf->net_access_key_curve->name, + auth->waiting_new_key ? + "the required key not received" : + "request a new key"); + if (auth->waiting_new_key) + auth->waiting_new_key = false; /* failed */ + else + auth->waiting_new_key = true; + goto fail; + } +#endif /* CONFIG_DPP3 */ + if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL, + nak_curve) < 0) { wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK"); goto fail; } @@ -1531,6 +1810,9 @@ skip_groups: tailroom += os_strlen(auth->trusted_eap_server_name); tailroom += 1000; } + if (conf->extra_name && conf->extra_value) + tailroom += 10 + os_strlen(conf->extra_name) + + os_strlen(conf->extra_value); buf = dpp_build_conf_start(auth, conf, tailroom); if (!buf) goto fail; @@ -1591,11 +1873,30 @@ skip_groups: #endif /* CONFIG_DPP2 */ json_end_object(buf); + if (conf->extra_name && conf->extra_value) { + json_value_sep(buf); + wpabuf_printf(buf, "\"%s\":%s", conf->extra_name, + conf->extra_value); + } json_end_object(buf); wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object", wpabuf_head(buf), wpabuf_len(buf)); +#ifdef CONFIG_DPP3 + if (!auth->conf->net_access_key_curve) { + /* All netAccessKey values used in the network will have to be + * from the same curve for network introduction to work, so + * hardcode the first used netAccessKey curve for consecutive + * operations if there was no explicit configuration of which + * curve to use. */ + wpa_printf(MSG_DEBUG, + "DPP: Update Configurator to require netAccessKey curve %s based on first provisioning", + nak_curve->name); + auth->conf->net_access_key_curve = nak_curve; + } +#endif /* CONFIG_DPP3 */ + out: os_free(signed_conn); wpabuf_free(dppcon); @@ -1614,8 +1915,12 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth, { struct wpabuf *buf; const char *akm_str; + size_t len = 1000; - buf = dpp_build_conf_start(auth, conf, 1000); + if (conf->extra_name && conf->extra_value) + len += 10 + os_strlen(conf->extra_name) + + os_strlen(conf->extra_value); + buf = dpp_build_conf_start(auth, conf, len); if (!buf) return NULL; @@ -1628,6 +1933,11 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth, json_value_sep(buf); dpp_build_legacy_cred_params(buf, conf); json_end_object(buf); + if (conf->extra_name && conf->extra_value) { + json_value_sep(buf); + wpabuf_printf(buf, "\"%s\":%s", conf->extra_name, + conf->extra_value); + } json_end_object(buf); wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)", @@ -1637,6 +1947,25 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth, } +static int dpp_get_peer_bi_id(struct dpp_authentication *auth) +{ + struct dpp_bootstrap_info *bi; + + if (auth->peer_bi) + return auth->peer_bi->id; + if (auth->tmp_peer_bi) + return auth->tmp_peer_bi->id; + + bi = os_zalloc(sizeof(*bi)); + if (!bi) + return -1; + bi->id = dpp_next_id(auth->global); + dl_list_add(&auth->global->bootstrap, &bi->list); + auth->tmp_peer_bi = bi; + return bi->id; +} + + static struct wpabuf * dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole, int idx, bool cert_req) @@ -1665,10 +1994,19 @@ dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole, conf = auth->conf2_ap; } if (!conf) { - if (idx == 0) + if (idx == 0) { + if (auth->use_config_query) { + wpa_printf(MSG_DEBUG, + "DPP: No configuration available for Enrollee(%s) - waiting for configuration", + dpp_netrole_str(netrole)); + auth->waiting_config = true; + dpp_get_peer_bi_id(auth); + return NULL; + } wpa_printf(MSG_DEBUG, "DPP: No configuration available for Enrollee(%s) - reject configuration request", dpp_netrole_str(netrole)); + } return NULL; } @@ -1695,7 +2033,7 @@ 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 *conf = NULL, *conf2 = NULL, *env_data = NULL; + struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL, *pc = NULL; size_t clear_len, attr_len; struct wpabuf *clear = NULL, *msg = NULL; u8 *wrapped; @@ -1722,11 +2060,17 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, } } + if (!conf && auth->waiting_config) + return NULL; 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; +#ifdef CONFIG_DPP3 + else if (auth->waiting_new_key) + status = DPP_STATUS_NEW_KEY_NEEDED; +#endif /* CONFIG_DPP3 */ else status = DPP_STATUS_CONFIGURE_FAILURE; forced_status: @@ -1746,6 +2090,31 @@ forced_status: if (status == DPP_STATUS_CSR_NEEDED && auth->conf_sta && auth->conf_sta->csrattrs) clear_len += 4 + os_strlen(auth->conf_sta->csrattrs); +#ifdef CONFIG_DPP3 + if (status == DPP_STATUS_NEW_KEY_NEEDED) { + struct crypto_ec_key *new_pc; + + clear_len += 6; /* Finite Cyclic Group attribute */ + + wpa_printf(MSG_DEBUG, + "DPP: Generate a new own protocol key for the curve %s", + auth->conf->net_access_key_curve->name); + new_pc = dpp_gen_keypair(auth->conf->net_access_key_curve); + if (!new_pc) { + wpa_printf(MSG_DEBUG, "DPP: Failed to generate new Pc"); + return NULL; + } + pc = crypto_ec_key_get_pubkey_point(new_pc, 0); + if (!pc) { + crypto_ec_key_deinit(new_pc); + return NULL; + } + crypto_ec_key_deinit(auth->own_protocol_key); + auth->own_protocol_key = new_pc; + auth->new_curve = auth->conf->net_access_key_curve; + clear_len += 4 + wpabuf_len(pc); + } +#endif /* CONFIG_DPP3 */ clear = wpabuf_alloc(clear_len); attr_len = 4 + 1 + 4 + clear_len + AES_BLOCK_SIZE; #ifdef CONFIG_TESTING_OPTIONS @@ -1823,6 +2192,27 @@ skip_e_nonce: wpabuf_put_str(clear, auth->conf_sta->csrattrs); } +#ifdef CONFIG_DPP3 + if (status == DPP_STATUS_NEW_KEY_NEEDED && auth->conf && + auth->conf->net_access_key_curve) { + u16 ike_group = auth->conf->net_access_key_curve->ike_group; + + /* Finite Cyclic Group attribute */ + wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u", + ike_group); + wpabuf_put_le16(clear, DPP_ATTR_FINITE_CYCLIC_GROUP); + wpabuf_put_le16(clear, 2); + wpabuf_put_le16(clear, ike_group); + + if (pc) { + wpa_printf(MSG_DEBUG, "DPP: Pc"); + wpabuf_put_le16(clear, DPP_ATTR_R_PROTOCOL_KEY); + wpabuf_put_le16(clear, wpabuf_len(pc)); + wpabuf_put_buf(clear, pc); + } + } +#endif /* CONFIG_DPP3 */ + #ifdef CONFIG_TESTING_OPTIONS skip_config_obj: if (dpp_test == DPP_TEST_NO_STATUS_CONF_RESP) { @@ -1873,6 +2263,7 @@ out: wpabuf_clear_free(conf2); wpabuf_clear_free(env_data); wpabuf_clear_free(clear); + wpabuf_free(pc); return msg; fail: @@ -1894,6 +2285,10 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, struct json_token *root = NULL, *token; enum dpp_netrole netrole; struct wpabuf *cert_req = NULL; +#ifdef CONFIG_DPP3 + const u8 *i_proto; + u16 i_proto_len; +#endif /* CONFIG_DPP3 */ #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_STOP_AT_CONF_REQ) { @@ -1947,6 +2342,59 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); os_memcpy(auth->e_nonce, e_nonce, e_nonce_len); +#ifdef CONFIG_DPP3 + i_proto = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_I_PROTOCOL_KEY, &i_proto_len); + if (i_proto && !auth->waiting_new_key) { + dpp_auth_fail(auth, + "Enrollee included a new protocol key even though one was not expected"); + goto fail; + } + if (i_proto) { + struct crypto_ec_key *pe; + u8 auth_i[DPP_MAX_HASH_LEN]; + const u8 *rx_auth_i; + u16 rx_auth_i_len; + + wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key (new Pe)", + i_proto, i_proto_len); + + pe = dpp_set_pubkey_point(auth->own_protocol_key, + i_proto, i_proto_len); + if (!pe) { + dpp_auth_fail(auth, + "Invalid Initiator Protocol Key (Pe)"); + goto fail; + } + dpp_debug_print_key("New Peer Protocol Key (Pe)", pe); + crypto_ec_key_deinit(auth->peer_protocol_key); + auth->peer_protocol_key = pe; + auth->new_key_received = true; + auth->waiting_new_key = false; + + if (dpp_derive_auth_i(auth, auth_i) < 0) + goto fail; + + rx_auth_i = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_I_AUTH_TAG, &rx_auth_i_len); + if (!rx_auth_i) { + dpp_auth_fail(auth, + "Missing Initiator Authentication Tag"); + goto fail; + } + if (rx_auth_i_len != auth->curve->hash_len || + os_memcmp(rx_auth_i, auth_i, auth->curve->hash_len) != 0) { + dpp_auth_fail(auth, + "Mismatch in Initiator Authenticating Tag"); + wpa_hexdump(MSG_DEBUG, "DPP: Received Auth-I", + rx_auth_i, rx_auth_i_len); + wpa_hexdump(MSG_DEBUG, "DPP: Derived Auth-I'", + auth_i, auth->curve->hash_len); + goto fail; + } + } +#endif /* CONFIG_DPP3 */ + config_attr = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_ATTR_OBJ, &config_attr_len); @@ -1970,6 +2418,8 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, goto fail; } wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string); + os_free(auth->e_name); + auth->e_name = os_strdup(token->string); token = json_get_member(root, "wi-fi_tech"); if (!token || token->type != JSON_STRING) { @@ -2009,6 +2459,8 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, wpa_printf(MSG_DEBUG, "DPP: mudurl = '%s'", token->string); wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_MUD_URL "%s", token->string); + os_free(auth->e_mud_url); + auth->e_mud_url = os_strdup(token->string); } token = json_get_member(root, "bandSupport"); @@ -2044,7 +2496,8 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, } pos += res; } - os_free(opclass); + os_free(auth->e_band_support); + auth->e_band_support = opclass; wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_BAND_SUPPORT "%s", txt); } @@ -2062,21 +2515,9 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, 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; - } + id = dpp_get_peer_bi_id(auth); + if (id < 0) + goto fail; wpa_printf(MSG_DEBUG, "DPP: CSR is valid - forward to CA/RA"); txt = base64_encode_no_lf(wpabuf_head(cert_req), @@ -2952,6 +3393,72 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth, goto fail; } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + if (status[0] == DPP_STATUS_NEW_KEY_NEEDED) { + const u8 *fcgroup, *r_proto; + u16 fcgroup_len, r_proto_len; + u16 group; + const struct dpp_curve_params *curve; + struct crypto_ec_key *new_pe; + struct crypto_ec_key *pc; + + fcgroup = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_FINITE_CYCLIC_GROUP, + &fcgroup_len); + if (!fcgroup || fcgroup_len != 2) { + dpp_auth_fail(auth, + "Missing or invalid required Finite Cyclic Group attribute"); + goto fail; + } + group = WPA_GET_LE16(fcgroup); + + wpa_printf(MSG_DEBUG, + "DPP: Configurator requested a new protocol key from group %u", + group); + curve = dpp_get_curve_ike_group(group); + if (!curve) { + dpp_auth_fail(auth, + "Unsupported group for new protocol key"); + goto fail; + } + + new_pe = dpp_gen_keypair(curve); + if (!new_pe) { + dpp_auth_fail(auth, + "Failed to generate a new protocol key"); + goto fail; + } + + crypto_ec_key_deinit(auth->own_protocol_key); + auth->own_protocol_key = new_pe; + auth->new_curve = curve; + + r_proto = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_R_PROTOCOL_KEY, + &r_proto_len); + if (!r_proto) { + dpp_auth_fail(auth, + "Missing required Responder Protocol Key attribute (Pc)"); + goto fail; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key (new Pc)", + r_proto, r_proto_len); + + pc = dpp_set_pubkey_point(new_pe, r_proto, r_proto_len); + if (!pc) { + dpp_auth_fail(auth, "Invalid Responder Protocol Key (Pc)"); + goto fail; + } + dpp_debug_print_key("New Peer Protocol Key (Pc)", pc); + + crypto_ec_key_deinit(auth->peer_protocol_key); + auth->peer_protocol_key = pc; + + auth->waiting_new_key = true; + ret = -3; + goto fail; + } +#endif /* CONFIG_DPP3 */ if (status[0] != DPP_STATUS_OK) { dpp_auth_fail(auth, "Configurator rejected configuration"); goto fail; @@ -3640,12 +4147,12 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, const u8 *net_access_key, size_t net_access_key_len, const u8 *csign_key, size_t csign_key_len, const u8 *peer_connector, size_t peer_connector_len, - os_time_t *expiry) + os_time_t *expiry, u8 *peer_key_hash) { struct json_token *root = NULL, *netkey, *token; struct json_token *own_root = NULL; enum dpp_status_error ret = 255, res; - struct crypto_ec_key *own_key = NULL, *peer_key = NULL; + struct crypto_ec_key *own_key = NULL; struct wpabuf *own_key_pub = NULL; const struct dpp_curve_params *curve, *own_curve; struct dpp_signed_connector_info info; @@ -3718,12 +4225,12 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, goto fail; } - peer_key = dpp_parse_jwk(netkey, &curve); - if (!peer_key) { + intro->peer_key = dpp_parse_jwk(netkey, &curve); + if (!intro->peer_key) { ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } - dpp_debug_print_key("DPP: Received netAccessKey", peer_key); + dpp_debug_print_key("DPP: Received netAccessKey", intro->peer_key); if (own_curve != curve) { wpa_printf(MSG_DEBUG, @@ -3734,7 +4241,7 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, } /* ECDH: N = nk * PK */ - if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0) + if (dpp_ecdh(own_key, intro->peer_key, Nx, &Nx_len) < 0) goto fail; wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)", @@ -3748,26 +4255,48 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, intro->pmk_len = curve->hash_len; /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */ - if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) { + if (dpp_derive_pmkid(curve, own_key, intro->peer_key, intro->pmkid) < + 0) { wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID"); goto fail; } +#ifdef CONFIG_DPP3 + if (dpp_hpke_suite(curve->ike_group, &intro->kem_id, &intro->kdf_id, + &intro->aead_id) < 0) { + wpa_printf(MSG_ERROR, "DPP: Unsupported group %d", + curve->ike_group); + goto fail; + } +#endif /* CONFIG_DPP3 */ + + if (peer_key_hash) + dpp_get_pubkey_hash(intro->peer_key, peer_key_hash); + ret = DPP_STATUS_OK; fail: if (ret != DPP_STATUS_OK) - os_memset(intro, 0, sizeof(*intro)); + dpp_peer_intro_deinit(intro); os_memset(Nx, 0, sizeof(Nx)); os_free(info.payload); crypto_ec_key_deinit(own_key); wpabuf_free(own_key_pub); - crypto_ec_key_deinit(peer_key); json_free(root); json_free(own_root); return ret; } +void dpp_peer_intro_deinit(struct dpp_introduction *intro) +{ + if (!intro) + return; + + crypto_ec_key_deinit(intro->peer_key); + os_memset(intro, 0, sizeof(*intro)); +} + + #ifdef CONFIG_DPP3 int dpp_get_connector_version(const char *connector) { @@ -3866,10 +4395,47 @@ struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp, } +static int dpp_parse_supported_curves_list(struct dpp_bootstrap_info *bi, + char *txt) +{ + char *token, *context = NULL; + u8 curves = 0; + + if (!txt) + return 0; + + while ((token = str_token(txt, ":", &context))) { + if (os_strcmp(token, "P-256") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_P_256); + } else if (os_strcmp(token, "P-384") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_P_384); + } else if (os_strcmp(token, "P-521") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_P_521); + } else if (os_strcmp(token, "BP-256") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_256); + } else if (os_strcmp(token, "BP-384") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_384); + } else if (os_strcmp(token, "BP-512") == 0) { + curves |= BIT(DPP_BOOTSTRAP_CURVE_BP_512); + } else { + wpa_printf(MSG_DEBUG, "DPP: Unsupported curve '%s'", + token); + return -1; + } + } + bi->supported_curves = curves; + + wpa_printf(MSG_DEBUG, "DPP: URI supported curves: 0x%x", + bi->supported_curves); + + return 0; +} + + int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) { char *mac = NULL, *info = NULL, *curve = NULL; - char *key = NULL; + char *key = NULL, *supported_curves = NULL, *host = NULL; u8 *privkey = NULL; size_t privkey_len = 0; int ret = -1; @@ -3896,6 +4462,8 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) info = get_param(cmd, " info="); curve = get_param(cmd, " curve="); key = get_param(cmd, " key="); + supported_curves = get_param(cmd, " supported_curves="); + host = get_param(cmd, " host="); if (key) { privkey_len = os_strlen(key) / 2; @@ -3909,6 +4477,8 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) dpp_parse_uri_chan_list(bi, bi->chan) < 0 || dpp_parse_uri_mac(bi, mac) < 0 || dpp_parse_uri_info(bi, info) < 0 || + dpp_parse_supported_curves_list(bi, supported_curves) < 0 || + dpp_parse_uri_host(bi, host) < 0 || dpp_gen_uri(bi) < 0) goto fail; @@ -3921,6 +4491,8 @@ fail: os_free(mac); os_free(info); str_clear_free(key); + os_free(supported_curves); + os_free(host); bin_clear_free(privkey, privkey_len); dpp_bootstrap_info_free(bi); return ret; @@ -3975,12 +4547,55 @@ int dpp_bootstrap_info(struct dpp_global *dpp, int id, { struct dpp_bootstrap_info *bi; char pkhash[2 * SHA256_MAC_LEN + 1]; + char supp_curves[100]; + char host[100]; + int ret; bi = dpp_bootstrap_get_id(dpp, id); if (!bi) return -1; wpa_snprintf_hex(pkhash, sizeof(pkhash), bi->pubkey_hash, SHA256_MAC_LEN); + + supp_curves[0] = '\0'; + if (bi->supported_curves) { + size_t i; + char *pos = supp_curves; + char *end = &supp_curves[sizeof(supp_curves)]; + const char *curve[6] = { "P-256", "P-384", "P-521", + "BP-256", "BP-384", "BP-512" }; + + ret = os_snprintf(pos, end - pos, "supp_curves="); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + + for (i = 0; i < ARRAY_SIZE(curve); i++) { + if (!(bi->supported_curves & BIT(i))) + continue; + ret = os_snprintf(pos, end - pos, "%s:", curve[i]); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + + if (pos[-1] == ':') + pos[-1] = '\n'; + else + supp_curves[0] = '\0'; + } + + host[0] = '\0'; + if (bi->host) { + char buf[100]; + + ret = os_snprintf(host, sizeof(host), "host=%s %u\n", + hostapd_ip_txt(bi->host, buf, sizeof(buf)), + bi->port); + if (os_snprintf_error(sizeof(host), ret)) + return -1; + } + return os_snprintf(reply, reply_size, "type=%s\n" "mac_addr=" MACSTR "\n" "info=%s\n" @@ -3988,7 +4603,7 @@ int dpp_bootstrap_info(struct dpp_global *dpp, int id, "use_freq=%u\n" "curve=%s\n" "pkhash=%s\n" - "version=%d\n", + "version=%d\n%s%s", dpp_bootstrap_type_txt(bi->type), MAC2STR(bi->mac_addr), bi->info ? bi->info : "", @@ -3996,7 +4611,9 @@ int dpp_bootstrap_info(struct dpp_global *dpp, int id, bi->num_freq == 1 ? bi->freq[0] : 0, bi->curve->name, pkhash, - bi->version); + bi->version, + supp_curves, + host); } @@ -4173,12 +4790,25 @@ 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 *curve; 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; + const struct dpp_curve_params *net_access_key_curve = NULL; + + curve = get_param(cmd, " net_access_key_curve="); + if (curve) { + net_access_key_curve = dpp_get_curve_name(curve); + if (!net_access_key_curve) { + wpa_printf(MSG_DEBUG, + "DPP: Unsupported net_access_key_curve: %s", + curve); + goto fail; + } + os_free(curve); + } curve = get_param(cmd, " curve="); key = get_param(cmd, " key="); @@ -4205,6 +4835,7 @@ int dpp_configurator_add(struct dpp_global *dpp, const char *cmd) if (!conf) goto fail; + conf->net_access_key_curve = net_access_key_curve; conf->id = dpp_next_configurator_id(dpp); dl_list_add(&dpp->configurator, &conf->list); ret = conf->id; @@ -4220,6 +4851,32 @@ fail: } +int dpp_configurator_set(struct dpp_global *dpp, const char *cmd) +{ + unsigned int id; + struct dpp_configurator *conf; + char *curve; + + id = atoi(cmd); + conf = dpp_configurator_get_id(dpp, id); + if (!conf) + return -1; + + curve = get_param(cmd, " net_access_key_curve="); + if (curve) { + const struct dpp_curve_params *net_access_key_curve; + + net_access_key_curve = dpp_get_curve_name(curve); + os_free(curve); + if (!net_access_key_curve) + return -1; + conf->net_access_key_curve = net_access_key_curve; + } + + return 0; +} + + static int dpp_configurator_del(struct dpp_global *dpp, unsigned int id) { struct dpp_configurator *conf, *tmp; @@ -4357,6 +5014,7 @@ struct dpp_global * dpp_global_init(struct dpp_global_config *config) #ifdef CONFIG_DPP2 dl_list_init(&dpp->controllers); dl_list_init(&dpp->tcp_init); + dpp->relay_sock = -1; #endif /* CONFIG_DPP2 */ return dpp; @@ -4385,6 +5043,24 @@ void dpp_global_deinit(struct dpp_global *dpp) } +void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator) +{ + u8 hash[SHA256_MAC_LEN]; + char hex[SHA256_MAC_LEN * 2 + 1]; + + if (auth->peer_protocol_key) { + dpp_get_pubkey_hash(auth->peer_protocol_key, hash); + wpa_snprintf_hex(hex, sizeof(hex), hash, sizeof(hash)); + } else { + hex[0] = '\0'; + } + wpa_msg(auth->msg_ctx, MSG_INFO, + DPP_EVENT_AUTH_SUCCESS "init=%d pkhash=%s own=%d peer=%d", + initiator, hex, auth->own_bi ? (int) auth->own_bi->id : -1, + auth->peer_bi ? (int) auth->peer_bi->id : -1); +} + + #ifdef CONFIG_DPP2 struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi) @@ -4417,3 +5093,98 @@ void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src, } #endif /* CONFIG_DPP2 */ + + +#ifdef CONFIG_DPP3 + +struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi) +{ + struct wpabuf *msg; + const u8 *r_hash = bi->pubkey_hash_chirp; +#ifdef CONFIG_TESTING_OPTIONS + u8 test_hash[SHA256_MAC_LEN]; +#endif /* CONFIG_TESTING_OPTIONS */ + + wpa_printf(MSG_DEBUG, + "DPP: Build Push Button Presence Announcement frame"); + + msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT, + 4 + SHA256_MAC_LEN); + if (!msg) + return NULL; + +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ) { + wpa_printf(MSG_INFO, + "DPP: TESTING - invalid R-Bootstrap Key Hash"); + os_memcpy(test_hash, r_hash, SHA256_MAC_LEN); + test_hash[SHA256_MAC_LEN - 1] ^= 0x01; + r_hash = test_hash; + } +#endif /* CONFIG_TESTING_OPTIONS */ + + /* Responder Bootstrapping Key Hash */ + dpp_build_attr_r_bootstrap_key_hash(msg, r_hash); + wpa_hexdump_buf(MSG_DEBUG, + "DPP: Push Button Presence Announcement frame attributes", + msg); + return msg; +} + + +struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi, + const u8 *e_hash, + const u8 *c_nonce, + size_t c_nonce_len) +{ + struct wpabuf *msg; + const u8 *i_hash = bi->pubkey_hash_chirp; +#ifdef CONFIG_TESTING_OPTIONS + u8 test_hash[SHA256_MAC_LEN]; +#endif /* CONFIG_TESTING_OPTIONS */ + + wpa_printf(MSG_DEBUG, + "DPP: Build Push Button Presence Announcement Response frame"); + + msg = dpp_alloc_msg(DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP, + 2 * (4 + SHA256_MAC_LEN) + 4 + c_nonce_len); + if (!msg) + return NULL; + +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP) { + wpa_printf(MSG_INFO, + "DPP: TESTING - invalid I-Bootstrap Key Hash"); + os_memcpy(test_hash, i_hash, SHA256_MAC_LEN); + test_hash[SHA256_MAC_LEN - 1] ^= 0x01; + i_hash = test_hash; + } else if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP) { + wpa_printf(MSG_INFO, + "DPP: TESTING - invalid R-Bootstrap Key Hash"); + os_memcpy(test_hash, e_hash, SHA256_MAC_LEN); + test_hash[SHA256_MAC_LEN - 1] ^= 0x01; + e_hash = test_hash; + } +#endif /* CONFIG_TESTING_OPTIONS */ + + /* Initiator Bootstrapping Key Hash */ + wpa_printf(MSG_DEBUG, "DPP: I-Bootstrap Key Hash"); + wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH); + wpabuf_put_le16(msg, SHA256_MAC_LEN); + wpabuf_put_data(msg, i_hash, SHA256_MAC_LEN); + + /* Responder Bootstrapping Key Hash */ + dpp_build_attr_r_bootstrap_key_hash(msg, e_hash); + + /* Configurator Nonce */ + wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE); + wpabuf_put_le16(msg, c_nonce_len); + wpabuf_put_data(msg, c_nonce, c_nonce_len); + + wpa_hexdump_buf(MSG_DEBUG, + "DPP: Push Button Presence Announcement Response frame attributes", + msg); + return msg; +} + +#endif /* CONFIG_DPP3 */ diff --git a/wpa_supplicant-2.9_standard/src/common/dpp.h b/wpa_supplicant-2.9_standard/src/common/dpp.h index 8d62a0e2ac3b7cfb573dbaa0cf5b6f7aba7c9a60..0f843da6a394fd449f2defd8a918f5a7897bab49 100644 --- a/wpa_supplicant-2.9_standard/src/common/dpp.h +++ b/wpa_supplicant-2.9_standard/src/common/dpp.h @@ -2,6 +2,7 @@ * DPP functionality shared between hostapd and wpa_supplicant * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -55,6 +56,11 @@ enum dpp_public_action_frame_type { DPP_PA_RECONFIG_AUTH_RESP = 16, DPP_PA_RECONFIG_AUTH_CONF = 17, DPP_PA_PKEX_EXCHANGE_REQ = 18, + DPP_PA_PB_PRESENCE_ANNOUNCEMENT = 19, + DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP = 20, + DPP_PA_PRIV_PEER_INTRO_QUERY = 21, + DPP_PA_PRIV_PEER_INTRO_NOTIFY = 22, + DPP_PA_PRIV_PEER_INTRO_UPDATE = 23, }; enum dpp_attribute_id { @@ -109,6 +115,7 @@ enum dpp_status_error { DPP_STATUS_CONFIGURE_PENDING = 11, DPP_STATUS_CSR_NEEDED = 12, DPP_STATUS_CSR_BAD = 13, + DPP_STATUS_NEW_KEY_NEEDED = 14, }; /* DPP Reconfig Flags object - connectorKey values */ @@ -144,6 +151,15 @@ enum dpp_bootstrap_type { DPP_BOOTSTRAP_NFC_URI, }; +enum dpp_bootstrap_supported_curves { + DPP_BOOTSTRAP_CURVE_P_256 = 0, + DPP_BOOTSTRAP_CURVE_P_384 = 1, + DPP_BOOTSTRAP_CURVE_P_521 = 2, + DPP_BOOTSTRAP_CURVE_BP_256 = 3, + DPP_BOOTSTRAP_CURVE_BP_384 = 4, + DPP_BOOTSTRAP_CURVE_BP_512 = 5, +}; + struct dpp_bootstrap_info { struct dl_list list; unsigned int id; @@ -152,11 +168,14 @@ struct dpp_bootstrap_info { u8 mac_addr[ETH_ALEN]; char *chan; char *info; + struct hostapd_ip_addr *host; + unsigned int port; char *pk; unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ]; unsigned int num_freq; bool channels_listed; u8 version; + u8 supported_curves; /* enum dpp_bootstrap_supported_curves bitmap */ int own; struct crypto_ec_key *pubkey; u8 pubkey_hash[SHA256_MAC_LEN]; @@ -167,21 +186,32 @@ struct dpp_bootstrap_info { int nfc_negotiated; /* whether this has been used in NFC negotiated * connection handover */ char *configurator_params; + u8 peer_pubkey_hash[SHA256_MAC_LEN]; /* for enforcing a specific + * peer bootstrapping key with + * PKEX */ }; #define PKEX_COUNTER_T_LIMIT 5 +enum dpp_pkex_ver { + PKEX_VER_AUTO, + PKEX_VER_ONLY_1, + PKEX_VER_ONLY_2, +}; + struct dpp_pkex { void *msg_ctx; unsigned int initiator:1; unsigned int exchange_done:1; unsigned int failed:1; unsigned int v2:1; + unsigned int forced_ver:1; struct dpp_bootstrap_info *own_bi; u8 own_mac[ETH_ALEN]; u8 peer_mac[ETH_ALEN]; char *identifier; char *code; + size_t code_len; struct crypto_ec_key *x; struct crypto_ec_key *y; u8 Mx[DPP_MAX_SHARED_SECRET_LEN]; @@ -195,6 +225,7 @@ struct dpp_pkex { unsigned int exch_req_tries; unsigned int freq; u8 peer_version; + struct wpabuf *enc_key; }; enum dpp_akm { @@ -233,6 +264,8 @@ struct dpp_configuration { int psk_set; char *csrattrs; + char *extra_name; + char *extra_value; }; struct dpp_asymmetric_key { @@ -250,6 +283,7 @@ struct dpp_authentication { void *msg_ctx; u8 peer_version; const struct dpp_curve_params *curve; + const struct dpp_curve_params *new_curve; struct dpp_bootstrap_info *peer_bi; struct dpp_bootstrap_info *own_bi; struct dpp_bootstrap_info *tmp_own_bi; @@ -350,8 +384,15 @@ struct dpp_authentication { char *trusted_eap_server_name; struct wpabuf *cacert; struct wpabuf *certbag; - void *cert_resp_ctx; + bool waiting_new_key; + bool new_key_received; + void *config_resp_ctx; void *gas_server_ctx; + bool use_config_query; + bool waiting_config; + char *e_name; + char *e_mud_url; + int *e_band_support; #ifdef CONFIG_TESTING_OPTIONS char *config_obj_override; char *discovery_override; @@ -368,6 +409,7 @@ struct dpp_configurator { u8 kid_hash[SHA256_MAC_LEN]; char *kid; const struct dpp_curve_params *curve; + const struct dpp_curve_params *net_access_key_curve; char *connector; /* own Connector for reconfiguration */ struct crypto_ec_key *connector_key; struct crypto_ec_key *pp_key; @@ -378,6 +420,10 @@ struct dpp_introduction { u8 pmk[PMK_LEN_MAX]; size_t pmk_len; int peer_version; + struct crypto_ec_key *peer_key; + enum hpke_kem_id kem_id; + enum hpke_kdf_id kdf_id; + enum hpke_aead_id aead_id; }; struct dpp_relay_config { @@ -401,6 +447,14 @@ struct dpp_controller_config { void *msg_ctx; void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); + bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); +}; + +#define DPP_PB_INFO_COUNT 2 + +struct dpp_pb_info { + u8 hash[SHA256_MAC_LEN]; + struct os_reltime rx_time; }; #ifdef CONFIG_TESTING_OPTIONS @@ -499,6 +553,13 @@ enum dpp_test_behavior { DPP_TEST_REJECT_CONFIG = 91, DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_REQ = 92, DPP_TEST_NO_PROTOCOL_VERSION_PEER_DISC_RESP = 93, + DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_REQ = 94, + DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_RESP = 95, + DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 96, + DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ = 97, + DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ = 98, + DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_PB_RESP = 99, + DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_RESP = 100, }; extern enum dpp_test_behavior dpp_test; @@ -520,6 +581,7 @@ int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac); int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info); int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi, struct dpp_bootstrap_info *peer_bi); +const char * dpp_netrole_str(enum dpp_netrole netrole); struct dpp_authentication * dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx); struct hostapd_hw_modes; @@ -544,11 +606,18 @@ struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth, struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth, const char *name, enum dpp_netrole netrole, - const char *mud_url, int *opclasses); + const char *mud_url, int *opclasses, + const char *extra_name, + const char *extra_value); int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, const u8 *attr_start, size_t attr_len); int dpp_notify_new_qr_code(struct dpp_authentication *auth, struct dpp_bootstrap_info *peer_bi); +void dpp_controller_pkex_add(struct dpp_global *dpp, + struct dpp_bootstrap_info *bi, + const char *code, const char *identifier); +bool dpp_controller_is_own_pkex_req(struct dpp_global *dpp, + const u8 *buf, size_t len); struct dpp_configuration * dpp_configuration_alloc(const char *type); int dpp_akm_psk(enum dpp_akm akm); int dpp_akm_sae(enum dpp_akm akm); @@ -600,18 +669,19 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, const u8 *net_access_key, size_t net_access_key_len, const u8 *csign_key, size_t csign_key_len, const u8 *peer_connector, size_t peer_connector_len, - os_time_t *expiry); + os_time_t *expiry, u8 *peer_key_hash); +void dpp_peer_intro_deinit(struct dpp_introduction *intro); int dpp_get_connector_version(const char *connector); struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, const u8 *own_mac, const char *identifier, const char *code, - bool v2); + size_t code_len, bool v2); struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, struct dpp_bootstrap_info *bi, const u8 *own_mac, const u8 *peer_mac, const char *identifier, - const char *code, + const char *code, size_t code_len, const u8 *buf, size_t len, bool v2); struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, const u8 *peer_mac, @@ -638,6 +708,11 @@ struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key, int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len); void dpp_pfs_free(struct dpp_pfs *pfs); +struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve, + const u8 *privkey, size_t privkey_len); +int dpp_hpke_suite(int iana_group, enum hpke_kem_id *kem_id, + enum hpke_kdf_id *kdf_id, enum hpke_aead_id *aead_id); + struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name); int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr); @@ -664,6 +739,7 @@ void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap, struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp, const u8 *hash); int dpp_configurator_add(struct dpp_global *dpp, const char *cmd); +int dpp_configurator_set(struct dpp_global *dpp, const char *cmd); int dpp_configurator_remove(struct dpp_global *dpp, const char *id); int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id, char *buf, size_t buflen); @@ -673,31 +749,69 @@ struct dpp_configurator * dpp_configurator_find_kid(struct dpp_global *dpp, const u8 *kid); int dpp_relay_add_controller(struct dpp_global *dpp, struct dpp_relay_config *config); +void dpp_relay_remove_controller(struct dpp_global *dpp, + const struct hostapd_ip_addr *addr); +int dpp_relay_listen(struct dpp_global *dpp, int port, + struct dpp_relay_config *config); +void dpp_relay_stop_listen(struct dpp_global *dpp); int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, const u8 *buf, size_t len, unsigned int freq, const u8 *i_bootstrap, const u8 *r_bootstrap, void *cb_ctx); int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data, size_t data_len); +bool dpp_relay_controller_available(struct dpp_global *dpp); int dpp_controller_start(struct dpp_global *dpp, struct dpp_controller_config *config); +int dpp_controller_set_params(struct dpp_global *dpp, + const char *configurator_params); void dpp_controller_stop(struct dpp_global *dpp); void dpp_controller_stop_for_ctx(struct dpp_global *dpp, void *cb_ctx); struct dpp_authentication * dpp_controller_get_auth(struct dpp_global *dpp, unsigned int id); void dpp_controller_new_qr_code(struct dpp_global *dpp, struct dpp_bootstrap_info *bi); +int dpp_tcp_pkex_init(struct dpp_global *dpp, struct dpp_pkex *pkex, + const struct hostapd_ip_addr *addr, int port, + void *msg_ctx, void *cb_ctx, + int (*pkex_done)(void *ctx, void *conn, + struct dpp_bootstrap_info *bi)); int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth, const struct hostapd_ip_addr *addr, int port, - const char *name, enum dpp_netrole netrole, void *msg_ctx, - void *cb_ctx, + const char *name, enum dpp_netrole netrole, + const char *mud_url, + const char *extra_conf_req_name, + const char *extra_conf_req_value, + void *msg_ctx, void *cb_ctx, int (*process_conf_obj)(void *ctx, - struct dpp_authentication *auth)); + struct dpp_authentication *auth), + bool (*tcp_msg_sent)(void *ctx, + struct dpp_authentication *auth)); +int dpp_tcp_auth(struct dpp_global *dpp, void *_conn, + struct dpp_authentication *auth, const char *name, + enum dpp_netrole netrole, const char *mud_url, + const char *extra_conf_req_name, + const char *extra_conf_req_value, + int (*process_conf_obj)(void *ctx, + struct dpp_authentication *auth), + bool (*tcp_msg_sent)(void *ctx, + struct dpp_authentication *auth)); +bool dpp_tcp_conn_status_requested(struct dpp_global *dpp); +void dpp_tcp_send_conn_status(struct dpp_global *dpp, + enum dpp_status_error result, + const u8 *ssid, size_t ssid_len, + const char *channel_list); struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi); void dpp_notify_chirp_received(void *msg_ctx, int id, const u8 *src, unsigned int freq, const u8 *hash); +struct wpabuf * dpp_build_pb_announcement(struct dpp_bootstrap_info *bi); +struct wpabuf * dpp_build_pb_announcement_resp(struct dpp_bootstrap_info *bi, + const u8 *e_hash, + const u8 *c_nonce, + size_t c_nonce_len); + struct dpp_global_config { void *cb_ctx; void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi); @@ -706,6 +820,7 @@ struct dpp_global_config { struct dpp_global * dpp_global_init(struct dpp_global_config *config); void dpp_global_clear(struct dpp_global *dpp); void dpp_global_deinit(struct dpp_global *dpp); +void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator); /* dpp_reconfig.c */ @@ -738,6 +853,7 @@ struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key, size_t pp_key_len); int dpp_update_reconfig_id(struct dpp_reconfig_id *id); void dpp_free_reconfig_id(struct dpp_reconfig_id *id); +int dpp_get_pubkey_hash(struct crypto_ec_key *key, u8 *hash); #endif /* CONFIG_DPP */ #endif /* DPP_H */ diff --git a/wpa_supplicant-2.9_standard/src/common/dpp_crypto.c b/wpa_supplicant-2.9_standard/src/common/dpp_crypto.c index 500f473cf1e0086bf003e1ea6064bf37e9121392..e4dc61dc75e711bb7c957c7e0a39dd549826134d 100644 --- a/wpa_supplicant-2.9_standard/src/common/dpp_crypto.c +++ b/wpa_supplicant-2.9_standard/src/common/dpp_crypto.c @@ -246,6 +246,27 @@ struct crypto_ec_key * dpp_set_pubkey_point(struct crypto_ec_key *group_key, } +int dpp_get_pubkey_hash(struct crypto_ec_key *key, u8 *hash) +{ + struct wpabuf *uncomp; + const u8 *addr[1]; + size_t len[1]; + int res; + + if (!key) + return -1; + + uncomp = crypto_ec_key_get_pubkey_point(key, 1); + if (!uncomp) + return -1; + addr[0] = wpabuf_head(uncomp); + len[0] = wpabuf_len(uncomp); + res = sha256_vector(1, addr, len, hash); + wpabuf_free(uncomp); + return res; +} + + struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve) { struct crypto_ec_key *key; @@ -1035,10 +1056,9 @@ fail: int dpp_auth_derive_l_responder(struct dpp_authentication *auth) { struct crypto_ec *ec; - struct crypto_ec_point *L = NULL; - const struct crypto_ec_point *BI; - const struct crypto_bignum *bR, *pR, *q; - struct crypto_bignum *sum = NULL, *lx = NULL; + struct crypto_ec_point *L = NULL, *BI = NULL; + const struct crypto_bignum *q; + struct crypto_bignum *sum = NULL, *lx = NULL, *bR = NULL, *pR = NULL; int ret = -1; /* L = ((bR + pR) modulo q) * BI */ @@ -1068,7 +1088,10 @@ int dpp_auth_derive_l_responder(struct dpp_authentication *auth) fail: crypto_bignum_deinit(lx, 1); crypto_bignum_deinit(sum, 1); + crypto_bignum_deinit(bR, 1); + crypto_bignum_deinit(pR, 1); crypto_ec_point_deinit(L, 1); + crypto_ec_point_deinit(BI, 1); crypto_ec_deinit(ec); return ret; } @@ -1077,10 +1100,8 @@ fail: int dpp_auth_derive_l_initiator(struct dpp_authentication *auth) { struct crypto_ec *ec; - struct crypto_ec_point *L = NULL, *sum = NULL; - const struct crypto_ec_point *BR, *PR; - const struct crypto_bignum *bI; - struct crypto_bignum *lx = NULL; + struct crypto_ec_point *L = NULL, *sum = NULL, *BR = NULL, *PR = NULL; + struct crypto_bignum *lx = NULL, *bI = NULL; int ret = -1; /* L = bI * (BR + PR) */ @@ -1108,8 +1129,11 @@ int dpp_auth_derive_l_initiator(struct dpp_authentication *auth) ret = 0; fail: crypto_bignum_deinit(lx, 1); + crypto_bignum_deinit(bI, 1); crypto_ec_point_deinit(sum, 1); crypto_ec_point_deinit(L, 1); + crypto_ec_point_deinit(BR, 1); + crypto_ec_point_deinit(PR, 1); crypto_ec_deinit(ec); return ret; } @@ -1434,16 +1458,15 @@ dpp_pkex_get_role_elem(const struct dpp_curve_params *curve, int init) struct crypto_ec_point * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init, - const char *code, const char *identifier, + const char *code, size_t code_len, const char *identifier, struct crypto_ec **ret_ec) { u8 hash[DPP_MAX_HASH_LEN]; const u8 *addr[3]; size_t len[3]; unsigned int num_elem = 0; - struct crypto_ec_point *Qi = NULL; + struct crypto_ec_point *Qi = NULL, *Pi = NULL; struct crypto_ec_key *Pi_key = NULL; - const struct crypto_ec_point *Pi = NULL; struct crypto_bignum *hash_bn = NULL; struct crypto_ec *ec = NULL; @@ -1463,9 +1486,9 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init, len[num_elem] = os_strlen(identifier); num_elem++; } - wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code)); + wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, code_len); addr[num_elem] = (const u8 *) code; - len[num_elem] = os_strlen(code); + len[num_elem] = code_len; num_elem++; if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0) goto fail; @@ -1494,6 +1517,7 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init, crypto_ec_point_debug_print(ec, Qi, "DPP: Qi"); out: crypto_ec_key_deinit(Pi_key); + crypto_ec_point_deinit(Pi, 1); crypto_bignum_deinit(hash_bn, 1); if (ret_ec && Qi) *ret_ec = ec; @@ -1509,16 +1533,15 @@ fail: struct crypto_ec_point * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp, - const char *code, const char *identifier, + const char *code, size_t code_len, const char *identifier, struct crypto_ec **ret_ec) { u8 hash[DPP_MAX_HASH_LEN]; const u8 *addr[3]; size_t len[3]; unsigned int num_elem = 0; - struct crypto_ec_point *Qr = NULL; + struct crypto_ec_point *Qr = NULL, *Pr = NULL; struct crypto_ec_key *Pr_key = NULL; - const struct crypto_ec_point *Pr = NULL; struct crypto_bignum *hash_bn = NULL; struct crypto_ec *ec = NULL; @@ -1538,9 +1561,9 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp, len[num_elem] = os_strlen(identifier); num_elem++; } - wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code)); + wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, code_len); addr[num_elem] = (const u8 *) code; - len[num_elem] = os_strlen(code); + len[num_elem] = code_len; num_elem++; if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0) goto fail; @@ -1570,6 +1593,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp, out: crypto_ec_key_deinit(Pr_key); + crypto_ec_point_deinit(Pr, 1); crypto_bignum_deinit(hash_bn, 1); if (ret_ec && Qr) *ret_ec = ec; @@ -1587,7 +1611,7 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, u8 ver_init, u8 ver_resp, const u8 *Mx, size_t Mx_len, const u8 *Nx, size_t Nx_len, - const char *code, + const char *code, size_t code_len, const u8 *Kx, size_t Kx_len, u8 *z, unsigned int hash_len) { @@ -1612,7 +1636,7 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, info_len = 2 * ETH_ALEN; else info_len = 2; - info_len += Mx_len + Nx_len + os_strlen(code); + info_len += Mx_len + Nx_len + code_len; info = os_malloc(info_len); if (!info) return -1; @@ -1630,7 +1654,7 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, pos += Mx_len; os_memcpy(pos, Nx, Nx_len); pos += Nx_len; - os_memcpy(pos, code, os_strlen(code)); + os_memcpy(pos, code, code_len); /* HKDF-Expand(PRK, info, L) */ if (hash_len == 32) @@ -1661,11 +1685,10 @@ int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth, struct json_token *peer_net_access_key) { struct crypto_ec_key *own_key = NULL, *peer_key = NULL; - struct crypto_bignum *sum = NULL; - const struct crypto_bignum *q, *cR, *pR; + struct crypto_bignum *sum = NULL, *cR = NULL, *pR = NULL; + const struct crypto_bignum *q; struct crypto_ec *ec = NULL; - struct crypto_ec_point *M = NULL; - const struct crypto_ec_point *CI; + struct crypto_ec_point *M = NULL, *CI = NULL; u8 Mx[DPP_MAX_SHARED_SECRET_LEN]; u8 prk[DPP_MAX_HASH_LEN]; const struct dpp_curve_params *curve; @@ -1748,7 +1771,10 @@ fail: forced_memzero(prk, sizeof(prk)); forced_memzero(Mx, sizeof(Mx)); crypto_ec_point_deinit(M, 1); + crypto_ec_point_deinit(CI, 1); crypto_bignum_deinit(sum, 1); + crypto_bignum_deinit(cR, 1); + crypto_bignum_deinit(pR, 1); crypto_ec_key_deinit(own_key); crypto_ec_key_deinit(peer_key); crypto_ec_deinit(ec); @@ -1761,10 +1787,9 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth, struct json_token *net_access_key) { struct crypto_ec_key *pr = NULL, *peer_key = NULL; - const struct crypto_ec_point *CR, *PR; - const struct crypto_bignum *cI; + struct crypto_bignum *cI = NULL; struct crypto_ec *ec = NULL; - struct crypto_ec_point *sum = NULL, *M = NULL; + struct crypto_ec_point *sum = NULL, *M = NULL, *CR = NULL, *PR = NULL; u8 Mx[DPP_MAX_SHARED_SECRET_LEN]; u8 prk[DPP_MAX_HASH_LEN]; int res = -1; @@ -1835,10 +1860,13 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth, fail: forced_memzero(prk, sizeof(prk)); forced_memzero(Mx, sizeof(Mx)); + crypto_bignum_deinit(cI, 1); crypto_ec_key_deinit(pr); crypto_ec_key_deinit(peer_key); crypto_ec_point_deinit(sum, 1); crypto_ec_point_deinit(M, 1); + crypto_ec_point_deinit(CR, 1); + crypto_ec_point_deinit(PR, 1); crypto_ec_deinit(ec); return res; } @@ -2059,7 +2087,7 @@ struct wpabuf * dpp_build_csr(struct dpp_authentication *auth, const char *name) struct wpabuf *priv_key; u8 cp[DPP_CP_LEN]; char *password = NULL; - size_t password_len; + size_t password_len = 0; int hash_sign_algo; /* TODO: use auth->csrattrs */ @@ -2259,8 +2287,8 @@ int dpp_update_reconfig_id(struct dpp_reconfig_id *id) { const struct crypto_bignum *q; struct crypto_bignum *bn; - const struct crypto_ec_point *pp, *generator; - struct crypto_ec_point *e_prime_id, *a_nonce; + const struct crypto_ec_point *generator; + struct crypto_ec_point *e_prime_id, *a_nonce, *pp; int ret = -1; pp = crypto_ec_key_get_public_key(id->pp_key); @@ -2297,6 +2325,7 @@ int dpp_update_reconfig_id(struct dpp_reconfig_id *id) fail: crypto_ec_point_deinit(e_prime_id, 1); crypto_ec_point_deinit(a_nonce, 1); + crypto_ec_point_deinit(pp, 1); crypto_bignum_deinit(bn, 1); return ret; } @@ -2321,9 +2350,9 @@ struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey, struct crypto_ec_key *e_prime_id) { struct crypto_ec *ec; - const struct crypto_bignum *pp; + struct crypto_bignum *pp = NULL; struct crypto_ec_point *e_id = NULL; - const struct crypto_ec_point *a_nonce_point, *e_prime_id_point; + struct crypto_ec_point *a_nonce_point, *e_prime_id_point; if (!ppkey) return NULL; @@ -2348,6 +2377,9 @@ struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey, crypto_ec_point_debug_print(ec, e_id, "DPP: Decrypted E-id"); fail: + crypto_ec_point_deinit(a_nonce_point, 1); + crypto_ec_point_deinit(e_prime_id_point, 1); + crypto_bignum_deinit(pp, 1); crypto_ec_deinit(ec); return e_id; } @@ -2355,6 +2387,139 @@ fail: #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + +int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i) +{ + int ret = -1, res; + u8 Sx[DPP_MAX_SHARED_SECRET_LEN]; + size_t Sx_len; + unsigned int hash_len; + const char *info = "New DPP Protocol Key"; + const u8 *addr[3]; + size_t len[3]; + u8 tmp[DPP_MAX_HASH_LEN], k[DPP_MAX_HASH_LEN]; + struct wpabuf *pcx = NULL, *pex = NULL; + + hash_len = auth->curve->hash_len; + + /* + * Configurator: S = pc * Pe + * Enrollee: S = pe * Pc + * k = HKDF(bk, "New DPP Protocol Key", S.x) + * = HKDF-Expand(HKDF-Extract(bk, S.X), "New DPP Protocol Key", + * len(new-curve-hash-out)) + * Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x) + * + * auth->own_protocol_key and auth->peer_protocol_key have already been + * updated to use the new keys. The new curve determines the size of + * the (new) protocol keys and S.x. The other parameters (bk, hash + * algorithm, k) are determined based on the initially determined curve + * during the (re)authentication exchange. + */ + + if (dpp_ecdh(auth->own_protocol_key, auth->peer_protocol_key, + Sx, &Sx_len) < 0) + goto fail; + + wpa_hexdump_key(MSG_DEBUG, "DPP: S.x", Sx, Sx_len); + + /* tmp = HKDF-Extract(bk, S.x) */ + addr[0] = Sx; + len[0] = Sx_len; + res = dpp_hmac_vector(hash_len, auth->bk, hash_len, 1, addr, len, tmp); + if (res < 0) + goto fail; + wpa_hexdump_key(MSG_DEBUG, "DPP: HKDF-Extract(bk, S.x)", + tmp, hash_len); + /* k = HKDF-Expand(tmp, "New DPP Protocol Key", len(hash-output)) + */ + res = dpp_hkdf_expand(hash_len, tmp, hash_len, info, k, hash_len); + if (res < 0) + return -1; + + wpa_hexdump_key(MSG_DEBUG, + "DPP: k = HKDF-Expand(\"New DPP Protocol Key\")", + k, hash_len); + + /* Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x) */ + addr[0] = auth->e_nonce; + len[0] = auth->curve->nonce_len; + + if (auth->configurator) { + pcx = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); + pex = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key, + 0); + } else { + pcx = crypto_ec_key_get_pubkey_point(auth->peer_protocol_key, + 0); + pex = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); + } + if (!pcx || !pex) + goto fail; + addr[1] = wpabuf_head(pcx); + len[1] = wpabuf_len(pcx) / 2; + addr[2] = wpabuf_head(pex); + len[2] = wpabuf_len(pex) / 2; + + if (dpp_hmac_vector(hash_len, k, hash_len, 3, addr, len, auth_i) < 0) + goto fail; + wpa_hexdump_key(MSG_DEBUG, + "DPP: Auth-I = HMAC(k, E-nonce | Pc.x | Pe.x)", + auth_i, hash_len); + ret = 0; +fail: + forced_memzero(Sx, sizeof(Sx)); + forced_memzero(tmp, sizeof(tmp)); + forced_memzero(k, sizeof(k)); + wpabuf_free(pcx); + wpabuf_free(pex); + return ret; +} + + +int dpp_hpke_suite(int iana_group, enum hpke_kem_id *kem_id, + enum hpke_kdf_id *kdf_id, enum hpke_aead_id *aead_id) +{ + switch (iana_group) { + case 19: + *kem_id = HPKE_DHKEM_P256_HKDF_SHA256; + *kdf_id = HPKE_KDF_HKDF_SHA256; + *aead_id = HPKE_AEAD_AES_128_GCM; + return 0; + case 20: + *kem_id = HPKE_DHKEM_P384_HKDF_SHA384; + *kdf_id = HPKE_KDF_HKDF_SHA384; + *aead_id = HPKE_AEAD_AES_256_GCM; + return 0; + case 21: + *kem_id = HPKE_DHKEM_P521_HKDF_SHA512; + *kdf_id = HPKE_KDF_HKDF_SHA512; + *aead_id = HPKE_AEAD_AES_256_GCM; + return 0; + case 28: + *kem_id = HPKE_DHKEM_P256_HKDF_SHA256; + *kdf_id = HPKE_KDF_HKDF_SHA256; + *aead_id = HPKE_AEAD_AES_128_GCM; + return 0; + case 29: + *kem_id = HPKE_DHKEM_P384_HKDF_SHA384; + *kdf_id = HPKE_KDF_HKDF_SHA384; + *aead_id = HPKE_AEAD_AES_256_GCM; + return 0; + case 30: + *kem_id = HPKE_DHKEM_P521_HKDF_SHA512; + *kdf_id = HPKE_KDF_HKDF_SHA512; + *aead_id = HPKE_AEAD_AES_256_GCM; + return 0; + } + + return -1; +} + +#endif /* CONFIG_DPP3 */ + + #ifdef CONFIG_TESTING_OPTIONS int dpp_test_gen_invalid_key(struct wpabuf *msg, @@ -2362,8 +2527,7 @@ int dpp_test_gen_invalid_key(struct wpabuf *msg, { struct crypto_ec *ec; struct crypto_ec_key *key = NULL; - const struct crypto_ec_point *pub_key; - struct crypto_ec_point *p = NULL; + struct crypto_ec_point *p = NULL, *pub_key = NULL; u8 *x, *y; int ret = -1; @@ -2381,11 +2545,9 @@ retry: /* Retrieve public key coordinates */ pub_key = crypto_ec_key_get_public_key(key); - if (!pub_key) + if (!pub_key || crypto_ec_point_to_bin(ec, pub_key, x, y)) goto fail; - crypto_ec_point_to_bin(ec, pub_key, x, y); - /* And corrupt them */ y[curve->prime_len - 1] ^= 0x01; p = crypto_ec_point_from_bin(ec, x); @@ -2398,6 +2560,7 @@ retry: ret = 0; fail: crypto_ec_point_deinit(p, 0); + crypto_ec_point_deinit(pub_key, 0); crypto_ec_key_deinit(key); crypto_ec_deinit(ec); return ret; diff --git a/wpa_supplicant-2.9_standard/src/common/dpp_i.h b/wpa_supplicant-2.9_standard/src/common/dpp_i.h index c00b1ee41240184668478121e783ad5c4921a606..dfa4a3cb866f6ad5dbb4b142e038b55438bf0e76 100644 --- a/wpa_supplicant-2.9_standard/src/common/dpp_i.h +++ b/wpa_supplicant-2.9_standard/src/common/dpp_i.h @@ -2,6 +2,7 @@ * DPP module internal definitions * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -18,10 +19,19 @@ struct dpp_global { struct dl_list configurator; /* struct dpp_configurator */ #ifdef CONFIG_DPP2 struct dl_list controllers; /* struct dpp_relay_controller */ + struct dpp_relay_controller *tmp_controller; struct dpp_controller *controller; struct dl_list tcp_init; /* struct dpp_connection */ + int relay_sock; + void *relay_msg_ctx; + void *relay_cb_ctx; + void (*relay_tx)(void *ctx, const u8 *addr, unsigned int freq, + const u8 *msg, size_t len); + void (*relay_gas_resp_tx)(void *ctx, const u8 *addr, u8 dialog_token, + int prot, struct wpabuf *buf); void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); + bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi); #endif /* CONFIG_DPP2 */ }; @@ -95,8 +105,6 @@ int dpp_get_subject_public_key(struct dpp_bootstrap_info *bi, int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi); int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, const u8 *privkey, size_t privkey_len); -struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve, - const u8 *privkey, size_t privkey_len); struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve); int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len); int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len); @@ -111,17 +119,17 @@ int dpp_derive_pmkid(const struct dpp_curve_params *curve, struct crypto_ec_key *peer_key, u8 *pmkid); struct crypto_ec_point * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init, - const char *code, const char *identifier, + const char *code, size_t code_len, const char *identifier, struct crypto_ec **ret_ec); struct crypto_ec_point * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp, - const char *code, const char *identifier, + const char *code, size_t code_len, const char *identifier, struct crypto_ec **ret_ec); int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, u8 ver_init, u8 ver_resp, const u8 *Mx, size_t Mx_len, const u8 *Nx, size_t Nx_len, - const char *code, + const char *code, size_t code_len, const u8 *Kx, size_t Kx_len, u8 *z, unsigned int hash_len); int dpp_reconfig_derive_ke_responder(struct dpp_authentication *auth, @@ -134,6 +142,7 @@ int dpp_reconfig_derive_ke_initiator(struct dpp_authentication *auth, struct crypto_ec_point * dpp_decrypt_e_id(struct crypto_ec_key *ppkey, struct crypto_ec_key *a_nonce, struct crypto_ec_key *e_prime_id); +int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i); char * dpp_sign_connector(struct dpp_configurator *conf, const struct wpabuf *dppcon); int dpp_test_gen_invalid_key(struct wpabuf *msg, diff --git a/wpa_supplicant-2.9_standard/src/common/dpp_pkex.c b/wpa_supplicant-2.9_standard/src/common/dpp_pkex.c index b9494dbfce244e134de8e299da370b6ee4acf1c8..017e05d9e0753a9ff91960655d2c6d6e9b409c07 100644 --- a/wpa_supplicant-2.9_standard/src/common/dpp_pkex.c +++ b/wpa_supplicant-2.9_standard/src/common/dpp_pkex.c @@ -30,8 +30,7 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex, bool v2) { struct crypto_ec *ec = NULL; - const struct crypto_ec_point *X; - struct crypto_ec_point *Qi = NULL, *M = NULL; + struct crypto_ec_point *Qi = NULL, *M = NULL, *X = NULL; u8 *Mx, *My; struct wpabuf *msg = NULL; size_t attr_len; @@ -42,7 +41,7 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex, /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */ Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code, - pkex->identifier, &ec); + pkex->code_len, pkex->identifier, &ec); if (!Qi) goto fail; @@ -146,10 +145,13 @@ skip_finite_cyclic_group: My = wpabuf_put(msg, curve->prime_len); if (crypto_ec_point_to_bin(ec, M, Mx, My)) goto fail; + wpabuf_free(pkex->enc_key); + pkex->enc_key = wpabuf_alloc_copy(Mx, 2 * curve->prime_len); os_memcpy(pkex->Mx, Mx, curve->prime_len); out: + crypto_ec_point_deinit(X, 1); crypto_ec_point_deinit(M, 1); crypto_ec_point_deinit(Qi, 1); crypto_ec_deinit(ec); @@ -171,7 +173,7 @@ static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt) struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, const u8 *own_mac, const char *identifier, const char *code, - bool v2) + size_t code_len, bool v2) { struct dpp_pkex *pkex; @@ -196,9 +198,10 @@ struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, if (!pkex->identifier) goto fail; } - pkex->code = os_strdup(code); + pkex->code = os_memdup(code, code_len); if (!pkex->code) goto fail; + pkex->code_len = code_len; pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2); if (!pkex->exchange_req) goto fail; @@ -340,7 +343,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, const u8 *own_mac, const u8 *peer_mac, const char *identifier, - const char *code, + const char *code, size_t code_len, const u8 *buf, size_t len, bool v2) { const u8 *attr_group, *attr_id, *attr_key; @@ -349,9 +352,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, u16 ike_group; struct dpp_pkex *pkex = NULL; struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, - *N = NULL; + *N = NULL, *Y = NULL; struct crypto_ec *ec = NULL; - const struct crypto_ec_point *Y; u8 *x_coord = NULL, *y_coord = NULL; u8 Kx[DPP_MAX_SHARED_SECRET_LEN]; size_t Kx_len; @@ -438,8 +440,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, } /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */ - Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, identifier, - &ec); + Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, code_len, + identifier, &ec); if (!Qi) goto fail; @@ -469,16 +471,19 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, pkex->t = bi->pkex_t; pkex->msg_ctx = msg_ctx; pkex->own_bi = bi; - os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); - os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); + if (own_mac) + os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); + if (peer_mac) + os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); if (identifier) { pkex->identifier = os_strdup(identifier); if (!pkex->identifier) goto fail; } - pkex->code = os_strdup(code); + pkex->code = os_memdup(code, code_len); if (!pkex->code) goto fail; + pkex->code_len = code_len; os_memcpy(pkex->Mx, attr_key, attr_key_len / 2); @@ -494,8 +499,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, goto fail; /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */ - Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, identifier, - NULL); + Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, code_len, + identifier, NULL); if (!Qr) goto fail; @@ -549,7 +554,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, pkex->peer_version, DPP_VERSION, pkex->Mx, curve->prime_len, pkex->Nx, curve->prime_len, pkex->code, - Kx, Kx_len, pkex->z, curve->hash_len); + pkex->code_len, Kx, Kx_len, pkex->z, + curve->hash_len); os_memset(Kx, 0, Kx_len); if (res < 0) goto fail; @@ -564,6 +570,7 @@ out: crypto_ec_point_deinit(M, 1); crypto_ec_point_deinit(N, 1); crypto_ec_point_deinit(X, 1); + crypto_ec_point_deinit(Y, 1); crypto_ec_deinit(ec); return pkex; fail: @@ -742,7 +749,8 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, } #endif /* CONFIG_DPP2 */ - os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); + if (peer_mac) + os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS, &attr_status_len); @@ -788,7 +796,8 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */ Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac, - pkex->code, pkex->identifier, &ec); + pkex->code, pkex->code_len, pkex->identifier, + &ec); if (!Qr) goto fail; @@ -866,7 +875,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, DPP_VERSION, pkex->peer_version, pkex->Mx, curve->prime_len, attr_key /* N.x */, attr_key_len / 2, - pkex->code, Kx, Kx_len, + pkex->code, pkex->code_len, Kx, Kx_len, pkex->z, curve->hash_len); os_memset(Kx, 0, Kx_len); if (res < 0) @@ -1341,9 +1350,12 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer, return NULL; bi->id = dpp_next_id(dpp); bi->type = DPP_BOOTSTRAP_PKEX; - os_memcpy(bi->mac_addr, peer, ETH_ALEN); - bi->num_freq = 1; - bi->freq[0] = freq; + if (peer) + os_memcpy(bi->mac_addr, peer, ETH_ALEN); + if (freq) { + bi->num_freq = 1; + bi->freq[0] = freq; + } bi->curve = pkex->own_bi->curve; bi->pubkey = pkex->peer_bootstrap_key; pkex->peer_bootstrap_key = NULL; @@ -1351,6 +1363,8 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer, dpp_bootstrap_info_free(bi); return NULL; } + os_memcpy(pkex->own_bi->peer_pubkey_hash, bi->pubkey_hash, + SHA256_MAC_LEN); dpp_pkex_free(pkex); dl_list_add(&dpp->bootstrap, &bi->list); return bi; @@ -1369,5 +1383,6 @@ void dpp_pkex_free(struct dpp_pkex *pkex) crypto_ec_key_deinit(pkex->peer_bootstrap_key); wpabuf_free(pkex->exchange_req); wpabuf_free(pkex->exchange_resp); + wpabuf_free(pkex->enc_key); os_free(pkex); } diff --git a/wpa_supplicant-2.9_standard/src/common/dpp_reconfig.c b/wpa_supplicant-2.9_standard/src/common/dpp_reconfig.c index 7137bc5fdd431268bb7208e9a70bcc0385a2e365..452c502475126739220d77d6930fd6eab25a2070 100644 --- a/wpa_supplicant-2.9_standard/src/common/dpp_reconfig.c +++ b/wpa_supplicant-2.9_standard/src/common/dpp_reconfig.c @@ -131,6 +131,7 @@ static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth) { struct wpabuf *msg; size_t attr_len; + u8 ver = DPP_VERSION; /* Build DPP Reconfig Authentication Request frame attributes */ attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) + @@ -144,10 +145,25 @@ static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth) wpabuf_put_le16(msg, 1); wpabuf_put_u8(msg, auth->transaction_id); +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version"); + goto skip_proto_ver; + } + if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version"); + ver = 1; + } +#endif /* CONFIG_TESTING_OPTIONS */ + /* Protocol Version */ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); wpabuf_put_le16(msg, 1); - wpabuf_put_u8(msg, DPP_VERSION); + wpabuf_put_u8(msg, ver); + +#ifdef CONFIG_TESTING_OPTIONS +skip_proto_ver: +#endif /* CONFIG_TESTING_OPTIONS */ /* DPP Connector */ wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); diff --git a/wpa_supplicant-2.9_standard/src/common/dpp_tcp.c b/wpa_supplicant-2.9_standard/src/common/dpp_tcp.c index c9cf814e9f553b4fcfe6c054a39745d35128d723..70b6e023e77acea32b9a330475ad84b63184cf8f 100644 --- a/wpa_supplicant-2.9_standard/src/common/dpp_tcp.c +++ b/wpa_supplicant-2.9_standard/src/common/dpp_tcp.c @@ -1,6 +1,7 @@ /* * DPP over TCP * Copyright (c) 2019-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -24,10 +25,13 @@ struct dpp_connection { struct dpp_controller *ctrl; struct dpp_relay_controller *relay; struct dpp_global *global; + struct dpp_pkex *pkex; struct dpp_authentication *auth; void *msg_ctx; void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); + int (*pkex_done)(void *ctx, void *conn, struct dpp_bootstrap_info *bi); + bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); int sock; u8 mac_addr[ETH_ALEN]; unsigned int freq; @@ -44,6 +48,9 @@ struct dpp_connection { unsigned int gas_comeback_in_progress:1; u8 gas_dialog_token; char *name; + char *mud_url; + char *extra_conf_req_name; + char *extra_conf_req_value; enum dpp_netrole netrole; }; @@ -71,9 +78,13 @@ struct dpp_controller { struct dl_list conn; /* struct dpp_connection */ char *configurator_params; enum dpp_netrole netrole; + struct dpp_bootstrap_info *pkex_bi; + char *pkex_code; + char *pkex_identifier; void *msg_ctx; void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); + bool (*tcp_msg_sent)(void *ctx, struct dpp_authentication *auth); }; static void dpp_controller_rx(int sd, void *eloop_ctx, void *sock_ctx); @@ -81,6 +92,9 @@ 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); +#ifdef CONFIG_DPP3 +static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx); +#endif /* CONFIG_DPP3 */ static void dpp_tcp_gas_query_comeback(void *eloop_ctx, void *timeout_ctx); static void dpp_relay_conn_timeout(void *eloop_ctx, void *timeout_ctx); @@ -99,10 +113,17 @@ static void dpp_connection_free(struct dpp_connection *conn) eloop_cancel_timeout(dpp_tcp_build_csr, conn, NULL); eloop_cancel_timeout(dpp_tcp_gas_query_comeback, conn, NULL); eloop_cancel_timeout(dpp_relay_conn_timeout, conn, NULL); +#ifdef CONFIG_DPP3 + eloop_cancel_timeout(dpp_tcp_build_new_key, conn, NULL); +#endif /* CONFIG_DPP3 */ wpabuf_free(conn->msg); wpabuf_free(conn->msg_out); dpp_auth_deinit(conn->auth); + dpp_pkex_free(conn->pkex); os_free(conn->name); + os_free(conn->mud_url); + os_free(conn->extra_conf_req_name); + os_free(conn->extra_conf_req_value); os_free(conn); } @@ -118,6 +139,7 @@ int dpp_relay_add_controller(struct dpp_global *dpp, struct dpp_relay_config *config) { struct dpp_relay_controller *ctrl; + char txt[100]; if (!dpp) return -1; @@ -133,6 +155,8 @@ int dpp_relay_add_controller(struct dpp_global *dpp, ctrl->cb_ctx = config->cb_ctx; ctrl->tx = config->tx; ctrl->gas_resp_tx = config->gas_resp_tx; + wpa_printf(MSG_DEBUG, "DPP: Add Relay connection to Controller %s", + hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt))); dl_list_add(&dpp->controllers, &ctrl->list); return 0; } @@ -174,6 +198,31 @@ dpp_relay_controller_get_ctx(struct dpp_global *dpp, void *cb_ctx) } +static struct dpp_relay_controller * +dpp_relay_controller_get_addr(struct dpp_global *dpp, + const struct sockaddr_in *addr) +{ + struct dpp_relay_controller *ctrl; + + if (!dpp) + return NULL; + + dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, + list) { + if (ctrl->ipaddr.af == AF_INET && + addr->sin_addr.s_addr == ctrl->ipaddr.u.v4.s_addr) + return ctrl; + } + + if (dpp->tmp_controller && + dpp->tmp_controller->ipaddr.af == AF_INET && + addr->sin_addr.s_addr == dpp->tmp_controller->ipaddr.u.v4.s_addr) + return dpp->tmp_controller; + + return NULL; +} + + static void dpp_controller_gas_done(struct dpp_connection *conn) { struct dpp_authentication *auth = conn->auth; @@ -184,6 +233,14 @@ static void dpp_controller_gas_done(struct dpp_connection *conn) return; } +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key) { + wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key"); + conn->on_tcp_tx_complete_gas_done = 0; + return; + } +#endif /* CONFIG_DPP3 */ + if (auth->peer_version >= 2 && auth->conf_resp_status == DPP_STATUS_OK) { wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result"); @@ -191,7 +248,8 @@ static void dpp_controller_gas_done(struct dpp_connection *conn) return; } - wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT); + wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT "conf_status=%d", + auth->conf_resp_status); dpp_connection_remove(conn); } @@ -239,6 +297,10 @@ static int dpp_tcp_send(struct dpp_connection *conn) dpp_controller_rx, conn, NULL) == 0) conn->read_eloop = 1; if (conn->on_tcp_tx_complete_remove) { + if (conn->auth && conn->auth->connect_on_tx_status && + conn->tcp_msg_sent && + conn->tcp_msg_sent(conn->cb_ctx, conn->auth)) + return 0; dpp_connection_remove(conn); } else if (conn->auth && (conn->ctrl || conn->auth->configurator) && conn->on_tcp_tx_complete_gas_done) { @@ -285,8 +347,10 @@ static void dpp_controller_start_gas_client(struct dpp_connection *conn) const char *dpp_name; dpp_name = conn->name ? conn->name : "Test"; - buf = dpp_build_conf_req_helper(auth, dpp_name, conn->netrole, NULL, - NULL); + buf = dpp_build_conf_req_helper(auth, dpp_name, conn->netrole, + conn->mud_url, NULL, + conn->extra_conf_req_name, + conn->extra_conf_req_value); if (!buf) { wpa_printf(MSG_DEBUG, "DPP: No configuration request data available"); @@ -307,8 +371,7 @@ static void dpp_controller_auth_success(struct dpp_connection *conn, return; wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded"); - wpa_msg(conn->msg_ctx, MSG_INFO, - DPP_EVENT_AUTH_SUCCESS "init=%d", initiator); + dpp_notify_auth_success(auth, initiator); #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) { wpa_printf(MSG_INFO, @@ -493,6 +556,31 @@ static int dpp_relay_tx(struct dpp_connection *conn, const u8 *hdr, } +static struct dpp_connection * +dpp_relay_match_ctrl(struct dpp_relay_controller *ctrl, const u8 *src, + unsigned int freq, u8 type) +{ + struct dpp_connection *conn; + + dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) { + if (ether_addr_equal(src, conn->mac_addr)) + return conn; + if ((type == DPP_PA_PKEX_EXCHANGE_RESP || + type == DPP_PA_AUTHENTICATION_RESP) && + conn->freq == 0 && + is_broadcast_ether_addr(conn->mac_addr)) { + wpa_printf(MSG_DEBUG, + "DPP: Associate this peer to the new Controller initiated connection"); + os_memcpy(conn->mac_addr, src, ETH_ALEN); + conn->freq = freq; + return conn; + } + } + + return NULL; +} + + int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, const u8 *buf, size_t len, unsigned int freq, const u8 *i_bootstrap, const u8 *r_bootstrap, @@ -511,12 +599,16 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, type != DPP_PA_RECONFIG_ANNOUNCEMENT) { dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, list) { - dl_list_for_each(conn, &ctrl->conn, - struct dpp_connection, list) { - if (os_memcmp(src, conn->mac_addr, - ETH_ALEN) == 0) - return dpp_relay_tx(conn, hdr, buf, len); - } + conn = dpp_relay_match_ctrl(ctrl, src, freq, type); + if (conn) + return dpp_relay_tx(conn, hdr, buf, len); + } + + if (dpp->tmp_controller) { + conn = dpp_relay_match_ctrl(dpp->tmp_controller, src, + freq, type); + if (conn) + return dpp_relay_tx(conn, hdr, buf, len); } } @@ -525,6 +617,8 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, /* TODO: Could send this to all configured Controllers. For now, * only the first Controller is supported. */ ctrl = dpp_relay_controller_get_ctx(dpp, cb_ctx); + } else if (type == DPP_PA_PKEX_EXCHANGE_REQ) { + ctrl = dpp_relay_controller_get_ctx(dpp, cb_ctx); } else { if (!r_bootstrap) return -1; @@ -533,6 +627,17 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, if (!ctrl) return -1; + if (type == DPP_PA_PRESENCE_ANNOUNCEMENT || + type == DPP_PA_RECONFIG_ANNOUNCEMENT) { + conn = dpp_relay_match_ctrl(ctrl, src, freq, type); + if (conn && + (!conn->auth || conn->auth->waiting_auth_resp)) { + wpa_printf(MSG_DEBUG, + "DPP: Use existing TCP connection to Controller since no Auth Resp seen on it yet"); + return dpp_relay_tx(conn, hdr, buf, len); + } + } + wpa_printf(MSG_DEBUG, "DPP: Authentication Request for a configured Controller"); conn = dpp_relay_new_conn(ctrl, src, freq); @@ -550,11 +655,25 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, } +static struct dpp_connection * +dpp_relay_find_conn(struct dpp_relay_controller *ctrl, const u8 *src) +{ + struct dpp_connection *conn; + + dl_list_for_each(conn, &ctrl->conn, struct dpp_connection, list) { + if (ether_addr_equal(src, conn->mac_addr)) + return conn; + } + + return NULL; +} + + int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data, size_t data_len) { struct dpp_relay_controller *ctrl; - struct dpp_connection *conn, *found = NULL; + struct dpp_connection *conn = NULL; struct wpabuf *msg; /* Check if there is a successfully completed authentication for this @@ -562,19 +681,15 @@ int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data, */ dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, list) { - if (found) + conn = dpp_relay_find_conn(ctrl, src); + if (conn) break; - dl_list_for_each(conn, &ctrl->conn, - struct dpp_connection, list) { - if (os_memcmp(src, conn->mac_addr, - ETH_ALEN) == 0) { - found = conn; - break; - } - } } - if (!found) + if (!conn && dpp->tmp_controller) + conn = dpp_relay_find_conn(dpp->tmp_controller, src); + + if (!conn) return -1; msg = wpabuf_alloc(4 + 1 + data_len); @@ -593,6 +708,12 @@ int dpp_relay_rx_gas_req(struct dpp_global *dpp, const u8 *src, const u8 *data, } +bool dpp_relay_controller_available(struct dpp_global *dpp) +{ + return dpp && dl_list_len(&dpp->controllers) > 0; +} + + static void dpp_controller_free(struct dpp_controller *ctrl) { struct dpp_connection *conn, *tmp; @@ -609,6 +730,8 @@ static void dpp_controller_free(struct dpp_controller *ctrl) eloop_unregister_sock(ctrl->sock, EVENT_TYPE_READ); } os_free(ctrl->configurator_params); + os_free(ctrl->pkex_code); + os_free(ctrl->pkex_identifier); os_free(ctrl); } @@ -768,9 +891,11 @@ static int dpp_controller_rx_conf_result(struct dpp_connection *conn, status = dpp_conf_result_rx(auth, hdr, buf, len); if (status == DPP_STATUS_OK && auth->send_conn_status) { - wpa_msg(msg_ctx, MSG_INFO, - DPP_EVENT_CONF_SENT "wait_conn_status=1"); + wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT + "wait_conn_status=1 conf_resp_status=%d", + auth->conf_resp_status); wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result"); + auth->waiting_conn_status_result = 1; eloop_cancel_timeout( dpp_controller_conn_status_result_wait_timeout, conn, NULL); @@ -780,7 +905,8 @@ static int dpp_controller_rx_conf_result(struct dpp_connection *conn, return 0; } if (status == DPP_STATUS_OK) - wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT); + wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT + "conf_resp_status=%d", auth->conf_resp_status); else wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); return -1; /* to remove the completed connection */ @@ -833,12 +959,6 @@ static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn, struct dpp_authentication *auth; struct dpp_global *dpp = conn->ctrl->global; - if (conn->auth) { - wpa_printf(MSG_DEBUG, - "DPP: Ignore Presence Announcement during ongoing Authentication"); - return -1; - } - wpa_printf(MSG_DEBUG, "DPP: Presence Announcement"); r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, @@ -857,6 +977,12 @@ static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn, return -1; } + if (conn->auth) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore Presence Announcement during ongoing Authentication"); + return 0; + } + auth = dpp_auth_init(dpp, conn->msg_ctx, peer_bi, NULL, DPP_CAPAB_CONFIGURATOR, -1, NULL, 0); if (!auth) @@ -959,6 +1085,144 @@ static int dpp_controller_rx_reconfig_auth_resp(struct dpp_connection *conn, } +static int dpp_controller_rx_pkex_exchange_req(struct dpp_connection *conn, + const u8 *hdr, const u8 *buf, + size_t len) +{ + struct dpp_controller *ctrl = conn->ctrl; + + if (!ctrl) + return 0; + + wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request"); + + /* TODO: Support multiple PKEX codes by iterating over all the enabled + * values here */ + + if (!ctrl->pkex_code || !ctrl->pkex_bi) { + wpa_printf(MSG_DEBUG, + "DPP: No PKEX code configured - ignore request"); + return 0; + } + + if (conn->pkex || conn->auth) { + wpa_printf(MSG_DEBUG, + "DPP: Already in PKEX/Authentication session - ignore new PKEX request"); + return 0; + } + + conn->pkex = dpp_pkex_rx_exchange_req(conn->msg_ctx, ctrl->pkex_bi, + NULL, NULL, + ctrl->pkex_identifier, + ctrl->pkex_code, + os_strlen(ctrl->pkex_code), + buf, len, true); + if (!conn->pkex) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to process the request"); + return -1; + } + + return dpp_tcp_send_msg(conn, conn->pkex->exchange_resp); +} + + +static int dpp_controller_rx_pkex_exchange_resp(struct dpp_connection *conn, + const u8 *hdr, const u8 *buf, + size_t len) +{ + struct dpp_pkex *pkex = conn->pkex; + struct wpabuf *msg; + int res; + + wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response"); + + if (!pkex || !pkex->initiator || pkex->exchange_done) { + wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); + return 0; + } + + msg = dpp_pkex_rx_exchange_resp(pkex, NULL, buf, len); + if (!msg) { + wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); + return -1; + } + + wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Request"); + res = dpp_tcp_send_msg(conn, msg); + wpabuf_free(msg); + return res; +} + + +static int dpp_controller_rx_pkex_commit_reveal_req(struct dpp_connection *conn, + const u8 *hdr, + const u8 *buf, size_t len) +{ + struct dpp_pkex *pkex = conn->pkex; + struct wpabuf *msg; + int res; + struct dpp_bootstrap_info *bi; + + wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Request"); + + if (!pkex || pkex->initiator || !pkex->exchange_done) { + wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); + return 0; + } + + msg = dpp_pkex_rx_commit_reveal_req(pkex, hdr, buf, len); + if (!msg) { + wpa_printf(MSG_DEBUG, "DPP: Failed to process the request"); + return -1; + } + + wpa_printf(MSG_DEBUG, "DPP: Send PKEX Commit-Reveal Response"); + res = dpp_tcp_send_msg(conn, msg); + wpabuf_free(msg); + if (res < 0) + return res; + bi = dpp_pkex_finish(conn->global, pkex, NULL, 0); + if (!bi) + return -1; + conn->pkex = NULL; + return 0; +} + + +static int +dpp_controller_rx_pkex_commit_reveal_resp(struct dpp_connection *conn, + const u8 *hdr, + const u8 *buf, size_t len) +{ + struct dpp_pkex *pkex = conn->pkex; + int res; + struct dpp_bootstrap_info *bi; + + wpa_printf(MSG_DEBUG, "DPP: PKEX Commit-Reveal Response"); + + if (!pkex || !pkex->initiator || !pkex->exchange_done) { + wpa_printf(MSG_DEBUG, "DPP: No matching PKEX session"); + return 0; + } + + res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len); + if (res < 0) { + wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); + return res; + } + + bi = dpp_pkex_finish(conn->global, pkex, NULL, 0); + if (!bi) + return -1; + conn->pkex = NULL; + + if (!conn->pkex_done) + return -1; + return conn->pkex_done(conn->cb_ctx, conn, bi); +} + + static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg, size_t len) { @@ -1018,6 +1282,22 @@ static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg, case DPP_PA_RECONFIG_AUTH_RESP: return dpp_controller_rx_reconfig_auth_resp(conn, msg, pos, end - pos); + case DPP_PA_PKEX_V1_EXCHANGE_REQ: + wpa_printf(MSG_DEBUG, + "DPP: Ignore PKEXv1 Exchange Request - not supported over TCP"); + return -1; + case DPP_PA_PKEX_EXCHANGE_REQ: + return dpp_controller_rx_pkex_exchange_req(conn, msg, pos, + end - pos); + case DPP_PA_PKEX_EXCHANGE_RESP: + return dpp_controller_rx_pkex_exchange_resp(conn, msg, pos, + end - pos); + case DPP_PA_PKEX_COMMIT_REVEAL_REQ: + return dpp_controller_rx_pkex_commit_reveal_req(conn, msg, pos, + end - pos); + case DPP_PA_PKEX_COMMIT_REVEAL_RESP: + return dpp_controller_rx_pkex_commit_reveal_resp(conn, msg, pos, + end - pos); default: /* TODO: missing messages types */ wpa_printf(MSG_DEBUG, @@ -1126,6 +1406,8 @@ static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg, return -1; } + wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_REQ_RX); + pos = msg; end = msg + len; @@ -1161,6 +1443,52 @@ static int dpp_controller_rx_gas_req(struct dpp_connection *conn, const u8 *msg, WLAN_PA_GAS_INITIAL_RESP); } + if (!resp && auth->waiting_config && auth->peer_bi) { + char *buf = NULL, *name = ""; + char band[200], *b_pos, *b_end; + int i, res, *opclass = auth->e_band_support; + char *mud_url = "N/A"; + + wpa_printf(MSG_DEBUG, "DPP: Configuration not yet ready"); + if (auth->e_name) { + size_t e_len = os_strlen(auth->e_name); + + buf = os_malloc(e_len * 4 + 1); + if (buf) { + printf_encode(buf, len * 4 + 1, + (const u8 *) auth->e_name, e_len); + name = buf; + } + } + band[0] = '\0'; + b_pos = band; + b_end = band + sizeof(band); + for (i = 0; opclass && opclass[i]; i++) { + res = os_snprintf(b_pos, b_end - b_pos, "%s%d", + b_pos == band ? "" : ",", opclass[i]); + if (os_snprintf_error(b_end - b_pos, res)) { + *b_pos = '\0'; + break; + } + b_pos += res; + } + if (auth->e_mud_url) { + size_t e_len = os_strlen(auth->e_mud_url); + + if (!has_ctrl_char((const u8 *) auth->e_mud_url, e_len)) + mud_url = auth->e_mud_url; + } + wpa_msg(conn->msg_ctx, MSG_INFO, DPP_EVENT_CONF_NEEDED + "peer=%d net_role=%s name=\"%s\" opclass=%s mud_url=%s", + auth->peer_bi->id, dpp_netrole_str(auth->e_netrole), + name, band, mud_url); + os_free(buf); + + 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); } @@ -1227,6 +1555,21 @@ static void dpp_tcp_build_csr(void *eloop_ctx, void *timeout_ctx) } +#ifdef CONFIG_DPP3 +static void dpp_tcp_build_new_key(void *eloop_ctx, void *timeout_ctx) +{ + struct dpp_connection *conn = eloop_ctx; + struct dpp_authentication *auth = conn->auth; + + if (!auth || !auth->waiting_new_key) + return; + + wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key"); + dpp_controller_start_gas_client(conn); +} +#endif /* CONFIG_DPP3 */ + + static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp) { struct dpp_authentication *auth = conn->auth; @@ -1247,6 +1590,14 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp) eloop_register_timeout(0, 0, dpp_tcp_build_csr, conn, NULL); return 0; } +#ifdef CONFIG_DPP3 + if (res == -3) { + wpa_printf(MSG_DEBUG, "DPP: New protocol key needed"); + eloop_register_timeout(0, 0, dpp_tcp_build_new_key, conn, + NULL); + return 0; + } +#endif /* CONFIG_DPP3 */ if (res < 0) { wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); return -1; @@ -1538,6 +1889,7 @@ static void dpp_controller_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx) conn->msg_ctx = ctrl->msg_ctx; conn->cb_ctx = ctrl->cb_ctx; conn->process_conf_obj = ctrl->process_conf_obj; + conn->tcp_msg_sent = ctrl->tcp_msg_sent; conn->sock = fd; conn->netrole = ctrl->netrole; @@ -1563,16 +1915,115 @@ fail: } +int dpp_tcp_pkex_init(struct dpp_global *dpp, struct dpp_pkex *pkex, + const struct hostapd_ip_addr *addr, int port, + void *msg_ctx, void *cb_ctx, + int (*pkex_done)(void *ctx, void *conn, + struct dpp_bootstrap_info *bi)) +{ + struct dpp_connection *conn; + struct sockaddr_storage saddr; + socklen_t addrlen; + const u8 *hdr, *pos, *end; + char txt[100]; + + wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d", + anonymize_ip(hostapd_ip_txt(addr, txt, sizeof(txt))), port); + if (dpp_ipaddr_to_sockaddr((struct sockaddr *) &saddr, &addrlen, + addr, port) < 0) { + dpp_pkex_free(pkex); + return -1; + } + + conn = os_zalloc(sizeof(*conn)); + if (!conn) { + dpp_pkex_free(pkex); + return -1; + } + + conn->msg_ctx = msg_ctx; + conn->cb_ctx = cb_ctx; + conn->pkex_done = pkex_done; + conn->global = dpp; + conn->pkex = pkex; + conn->sock = socket(AF_INET, SOCK_STREAM, 0); + if (conn->sock < 0) + goto fail; + + if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { + wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", + strerror(errno)); + goto fail; + } + + if (connect(conn->sock, (struct sockaddr *) &saddr, addrlen) < 0) { + if (errno != EINPROGRESS) { + wpa_printf(MSG_DEBUG, "DPP: Failed to connect: %s", + strerror(errno)); + goto fail; + } + + /* + * Continue connecting in the background; eloop will call us + * once the connection is ready (or failed). + */ + } + + if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, + dpp_conn_tx_ready, conn, NULL) < 0) + goto fail; + conn->write_eloop = 1; + + hdr = wpabuf_head(pkex->exchange_req); + end = hdr + wpabuf_len(pkex->exchange_req); + hdr += 2; /* skip Category and Actiom */ + pos = hdr + DPP_HDR_LEN; + conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos); + if (!conn->msg_out) + goto fail; + /* Message will be sent in dpp_conn_tx_ready() */ + + /* TODO: eloop timeout to clear a connection if it does not complete + * properly */ + dl_list_add(&dpp->tcp_init, &conn->list); + return 0; +fail: + dpp_connection_free(conn); + return -1; +} + + +static int dpp_tcp_auth_start(struct dpp_connection *conn, + struct dpp_authentication *auth) +{ + const u8 *hdr, *pos, *end; + + hdr = wpabuf_head(auth->req_msg); + end = hdr + wpabuf_len(auth->req_msg); + hdr += 2; /* skip Category and Actiom */ + pos = hdr + DPP_HDR_LEN; + conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos); + if (!conn->msg_out) + return -1; + /* Message will be sent in dpp_conn_tx_ready() */ + return 0; +} + + int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth, const struct hostapd_ip_addr *addr, int port, const char *name, - enum dpp_netrole netrole, void *msg_ctx, void *cb_ctx, + enum dpp_netrole netrole, const char *mud_url, + const char *extra_conf_req_name, + const char *extra_conf_req_value, + void *msg_ctx, void *cb_ctx, int (*process_conf_obj)(void *ctx, - struct dpp_authentication *auth)) + struct dpp_authentication *auth), + bool (*tcp_msg_sent)(void *ctx, + struct dpp_authentication *auth)) { struct dpp_connection *conn; struct sockaddr_storage saddr; socklen_t addrlen; - const u8 *hdr, *pos, *end; char txt[100]; wpa_printf(MSG_DEBUG, "DPP: Initialize TCP connection to %s port %d", @@ -1592,7 +2043,14 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth, conn->msg_ctx = msg_ctx; conn->cb_ctx = cb_ctx; conn->process_conf_obj = process_conf_obj; + conn->tcp_msg_sent = tcp_msg_sent; conn->name = os_strdup(name ? name : "Test"); + if (mud_url) + conn->mud_url = os_strdup(mud_url); + if (extra_conf_req_name) + conn->extra_conf_req_name = os_strdup(extra_conf_req_name); + if (extra_conf_req_value) + conn->extra_conf_req_value = os_strdup(extra_conf_req_value); conn->netrole = netrole; conn->global = dpp; conn->auth = auth; @@ -1624,14 +2082,8 @@ int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth, goto fail; conn->write_eloop = 1; - hdr = wpabuf_head(auth->req_msg); - end = hdr + wpabuf_len(auth->req_msg); - hdr += 2; /* skip Category and Actiom */ - pos = hdr + DPP_HDR_LEN; - conn->msg_out = dpp_tcp_encaps(hdr, pos, end - pos); - if (!conn->msg_out) + if (dpp_tcp_auth_start(conn, auth) < 0) goto fail; - /* Message will be sent in dpp_conn_tx_ready() */ /* TODO: eloop timeout to clear a connection if it does not complete * properly */ @@ -1643,6 +2095,42 @@ fail: } +int dpp_tcp_auth(struct dpp_global *dpp, void *_conn, + struct dpp_authentication *auth, const char *name, + enum dpp_netrole netrole, const char *mud_url, + const char *extra_conf_req_name, + const char *extra_conf_req_value, + int (*process_conf_obj)(void *ctx, + struct dpp_authentication *auth), + bool (*tcp_msg_sent)(void *ctx, + struct dpp_authentication *auth)) +{ + struct dpp_connection *conn = _conn; + + /* Continue with Authentication exchange on an existing TCP connection. + */ + conn->process_conf_obj = process_conf_obj; + conn->tcp_msg_sent = tcp_msg_sent; + os_free(conn->name); + conn->name = os_strdup(name ? name : "Test"); + os_free(conn->mud_url); + conn->mud_url = mud_url ? os_strdup(mud_url) : NULL; + os_free(conn->extra_conf_req_name); + conn->extra_conf_req_name = extra_conf_req_name ? + os_strdup(extra_conf_req_name) : NULL; + conn->extra_conf_req_value = extra_conf_req_value ? + os_strdup(extra_conf_req_value) : NULL; + conn->netrole = netrole; + conn->auth = auth; + + if (dpp_tcp_auth_start(conn, auth) < 0) + return -1; + + dpp_conn_tx_ready(conn->sock, conn, NULL); + return 0; +} + + int dpp_controller_start(struct dpp_global *dpp, struct dpp_controller_config *config) { @@ -1668,6 +2156,7 @@ int dpp_controller_start(struct dpp_global *dpp, ctrl->msg_ctx = config->msg_ctx; ctrl->cb_ctx = config->cb_ctx; ctrl->process_conf_obj = config->process_conf_obj; + ctrl->tcp_msg_sent = config->tcp_msg_sent; ctrl->sock = socket(AF_INET, SOCK_STREAM, 0); if (ctrl->sock < 0) @@ -1714,6 +2203,29 @@ fail: } +int dpp_controller_set_params(struct dpp_global *dpp, + const char *configurator_params) +{ + + if (!dpp || !dpp->controller) + return -1; + + if (configurator_params) { + char *val = os_strdup(configurator_params); + + if (!val) + return -1; + os_free(dpp->controller->configurator_params); + dpp->controller->configurator_params = val; + } else { + os_free(dpp->controller->configurator_params); + dpp->controller->configurator_params = NULL; + } + + return 0; +} + + void dpp_controller_stop(struct dpp_global *dpp) { if (dpp) { @@ -1793,6 +2305,52 @@ void dpp_controller_new_qr_code(struct dpp_global *dpp, } +void dpp_controller_pkex_add(struct dpp_global *dpp, + struct dpp_bootstrap_info *bi, + const char *code, const char *identifier) +{ + struct dpp_controller *ctrl = dpp->controller; + + if (!ctrl) + return; + + ctrl->pkex_bi = bi; + os_free(ctrl->pkex_code); + ctrl->pkex_code = code ? os_strdup(code) : NULL; + os_free(ctrl->pkex_identifier); + ctrl->pkex_identifier = identifier ? os_strdup(identifier) : NULL; +} + + +bool dpp_controller_is_own_pkex_req(struct dpp_global *dpp, + const u8 *buf, size_t len) +{ + struct dpp_connection *conn; + const u8 *attr_key = NULL; + u16 attr_key_len = 0; + + dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) { + if (!conn->pkex || !conn->pkex->enc_key) + continue; + + if (!attr_key) { + attr_key = dpp_get_attr(buf, len, + DPP_ATTR_ENCRYPTED_KEY, + &attr_key_len); + if (!attr_key) + return false; + } + + if (attr_key_len == wpabuf_len(conn->pkex->enc_key) && + os_memcmp(attr_key, wpabuf_head(conn->pkex->enc_key), + attr_key_len) == 0) + return true; + } + + return false; +} + + void dpp_tcp_init_flush(struct dpp_global *dpp) { struct dpp_connection *conn, *tmp; @@ -1806,6 +2364,10 @@ void dpp_tcp_init_flush(struct dpp_global *dpp) static void dpp_relay_controller_free(struct dpp_relay_controller *ctrl) { struct dpp_connection *conn, *tmp; + char txt[100]; + + wpa_printf(MSG_DEBUG, "DPP: Remove Relay connection to Controller %s", + hostapd_ip_txt(&ctrl->ipaddr, txt, sizeof(txt))); dl_list_for_each_safe(conn, tmp, &ctrl->conn, struct dpp_connection, list) @@ -1826,6 +2388,278 @@ void dpp_relay_flush_controllers(struct dpp_global *dpp) dl_list_del(&ctrl->list); dpp_relay_controller_free(ctrl); } + + if (dpp->tmp_controller) { + dpp_relay_controller_free(dpp->tmp_controller); + dpp->tmp_controller = NULL; + } +} + + +void dpp_relay_remove_controller(struct dpp_global *dpp, + const struct hostapd_ip_addr *addr) +{ + struct dpp_relay_controller *ctrl; + + if (!dpp) + return; + + dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, + list) { + if (hostapd_ip_equal(&ctrl->ipaddr, addr)) { + dl_list_del(&ctrl->list); + dpp_relay_controller_free(ctrl); + return; + } + } + + if (dpp->tmp_controller && + hostapd_ip_equal(&dpp->tmp_controller->ipaddr, addr)) { + dpp_relay_controller_free(dpp->tmp_controller); + dpp->tmp_controller = NULL; + } +} + + +static void dpp_relay_tcp_cb(int sd, void *eloop_ctx, void *sock_ctx) +{ + struct dpp_global *dpp = eloop_ctx; + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + int fd; + struct dpp_relay_controller *ctrl; + struct dpp_connection *conn = NULL; + + wpa_printf(MSG_DEBUG, "DPP: New TCP connection (Relay)"); + + fd = accept(dpp->relay_sock, (struct sockaddr *) &addr, &addr_len); + if (fd < 0) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to accept new connection: %s", + strerror(errno)); + return; + } + wpa_printf(MSG_DEBUG, "DPP: Connection from %s:%d", + inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + ctrl = dpp_relay_controller_get_addr(dpp, &addr); + if (!ctrl && dpp->tmp_controller && + dl_list_len(&dpp->tmp_controller->conn)) { + char txt[100]; + + wpa_printf(MSG_DEBUG, + "DPP: Remove a temporaty Controller entry for %s", + hostapd_ip_txt(&dpp->tmp_controller->ipaddr, + txt, sizeof(txt))); + dpp_relay_controller_free(dpp->tmp_controller); + dpp->tmp_controller = NULL; + } + if (!ctrl && !dpp->tmp_controller) { + wpa_printf(MSG_DEBUG, "DPP: Add a temporary Controller entry"); + ctrl = os_zalloc(sizeof(*ctrl)); + if (!ctrl) + goto fail; + dl_list_init(&ctrl->conn); + ctrl->global = dpp; + ctrl->ipaddr.af = AF_INET; + ctrl->ipaddr.u.v4.s_addr = addr.sin_addr.s_addr; + ctrl->msg_ctx = dpp->relay_msg_ctx; + ctrl->cb_ctx = dpp->relay_cb_ctx; + ctrl->tx = dpp->relay_tx; + ctrl->gas_resp_tx = dpp->relay_gas_resp_tx; + dpp->tmp_controller = ctrl; + } + if (!ctrl) { + wpa_printf(MSG_DEBUG, + "DPP: No Controller found for that address"); + goto fail; + } + + if (dl_list_len(&ctrl->conn) >= 15) { + wpa_printf(MSG_DEBUG, + "DPP: Too many ongoing Relay connections to the Controller - cannot start a new one"); + goto fail; + } + + conn = os_zalloc(sizeof(*conn)); + if (!conn) + goto fail; + + conn->global = ctrl->global; + conn->relay = ctrl; + conn->msg_ctx = ctrl->msg_ctx; + conn->cb_ctx = ctrl->global->cb_ctx; + os_memset(conn->mac_addr, 0xff, ETH_ALEN); + conn->sock = fd; + + if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) != 0) { + wpa_printf(MSG_DEBUG, "DPP: fnctl(O_NONBLOCK) failed: %s", + strerror(errno)); + goto fail; + } + + if (eloop_register_sock(conn->sock, EVENT_TYPE_READ, + dpp_controller_rx, conn, NULL) < 0) + goto fail; + conn->read_eloop = 1; + + /* TODO: eloop timeout to expire connections that do not complete in + * reasonable time */ + dl_list_add(&ctrl->conn, &conn->list); + return; + +fail: + close(fd); + os_free(conn); +} + + +int dpp_relay_listen(struct dpp_global *dpp, int port, + struct dpp_relay_config *config) +{ + int s; + int on = 1; + struct sockaddr_in sin; + + if (dpp->relay_sock >= 0) { + wpa_printf(MSG_INFO, "DPP: %s(%d) - relay port already opened", + __func__, port); + return -1; + } + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + wpa_printf(MSG_INFO, + "DPP: socket(SOCK_STREAM) failed: %s", + strerror(errno)); + return -1; + } + + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { + wpa_printf(MSG_DEBUG, + "DPP: setsockopt(SO_REUSEADDR) failed: %s", + strerror(errno)); + /* try to continue anyway */ + } + + if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) { + wpa_printf(MSG_INFO, "DPP: fnctl(O_NONBLOCK) failed: %s", + strerror(errno)); + close(s); + return -1; + } + + /* TODO: IPv6 */ + os_memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons(port); + if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { + wpa_printf(MSG_INFO, + "DPP: Failed to bind Relay TCP port: %s", + strerror(errno)); + close(s); + return -1; + } + if (listen(s, 10 /* max backlog */) < 0 || + fcntl(s, F_SETFL, O_NONBLOCK) < 0 || + eloop_register_sock(s, EVENT_TYPE_READ, dpp_relay_tcp_cb, dpp, + NULL)) { + close(s); + return -1; + } + + dpp->relay_sock = s; + dpp->relay_msg_ctx = config->msg_ctx; + dpp->relay_cb_ctx = config->cb_ctx; + dpp->relay_tx = config->tx; + dpp->relay_gas_resp_tx = config->gas_resp_tx; + wpa_printf(MSG_DEBUG, "DPP: Relay started on TCP port %d", port); + return 0; +} + + +void dpp_relay_stop_listen(struct dpp_global *dpp) +{ + if (!dpp || dpp->relay_sock < 0) + return; + eloop_unregister_sock(dpp->relay_sock, EVENT_TYPE_READ); + close(dpp->relay_sock); + dpp->relay_sock = -1; +} + + +bool dpp_tcp_conn_status_requested(struct dpp_global *dpp) +{ + struct dpp_connection *conn; + + if (!dpp) + return false; + + dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) { + if (conn->auth && conn->auth->conn_status_requested) + return true; + } + + return false; +} + + +static void dpp_tcp_send_conn_status_msg(struct dpp_global *dpp, + struct dpp_connection *conn, + enum dpp_status_error result, + const u8 *ssid, size_t ssid_len, + const char *channel_list) +{ + struct dpp_authentication *auth = conn->auth; + int res; + struct wpabuf *msg; + struct dpp_connection *c; + + auth->conn_status_requested = 0; + + msg = dpp_build_conn_status_result(auth, result, ssid, ssid_len, + channel_list); + if (!msg) { + dpp_connection_remove(conn); + return; + } + + res = dpp_tcp_send_msg(conn, msg); + wpabuf_free(msg); + + if (res < 0) { + dpp_connection_remove(conn); + return; + } + + /* conn might have been removed during the dpp_tcp_send_msg() call, so + * need to check that it is still present before modifying it. */ + dl_list_for_each(c, &dpp->tcp_init, struct dpp_connection, list) { + if (conn == c) { + /* This exchange will be terminated in the TX status + * handler */ + conn->on_tcp_tx_complete_remove = 1; + break; + } + } +} + + +void dpp_tcp_send_conn_status(struct dpp_global *dpp, + enum dpp_status_error result, + const u8 *ssid, size_t ssid_len, + const char *channel_list) +{ + struct dpp_connection *conn; + + dl_list_for_each(conn, &dpp->tcp_init, struct dpp_connection, list) { + if (conn->auth && conn->auth->conn_status_requested) { + dpp_tcp_send_conn_status_msg(dpp, conn, result, ssid, + ssid_len, channel_list); + break; + } + } } #endif /* CONFIG_DPP2 */ diff --git a/wpa_supplicant-2.9_standard/src/common/dragonfly.c b/wpa_supplicant-2.9_standard/src/common/dragonfly.c index 1e842716668e139634593f1f8dfdbcd0a3717484..d039e5f9eb39f4e0229aaa0283444916d9274698 100644 --- a/wpa_supplicant-2.9_standard/src/common/dragonfly.c +++ b/wpa_supplicant-2.9_standard/src/common/dragonfly.c @@ -67,12 +67,15 @@ int dragonfly_get_random_qr_qnr(const struct crypto_bignum *prime, } res = crypto_bignum_legendre(tmp, prime); - if (res == 1 && !(*qr)) + if (res == 1 && !(*qr)) { *qr = tmp; - else if (res == -1 && !(*qnr)) + } else if (res == -1 && !(*qnr)) { *qnr = tmp; - else + } else { crypto_bignum_deinit(tmp, 0); + if (res == -2) + break; + } } if (*qr && *qnr) diff --git a/wpa_supplicant-2.9_standard/src/common/gas_server.c b/wpa_supplicant-2.9_standard/src/common/gas_server.c index 15b2a84ad2bde8db4f4d059ef1b345572c9deb1b..77a850486d6380622f23ae59186af2ff7d869b77 100644 --- a/wpa_supplicant-2.9_standard/src/common/gas_server.c +++ b/wpa_supplicant-2.9_standard/src/common/gas_server.c @@ -2,6 +2,7 @@ * Generic advertisement service (GAS) server * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2020, The Linux Foundation + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -18,7 +19,7 @@ #define MAX_ADV_PROTO_ID_LEN 10 -#define GAS_QUERY_TIMEOUT 10 +#define GAS_QUERY_TIMEOUT 60 struct gas_server_handler { struct dl_list list; @@ -26,7 +27,7 @@ struct gas_server_handler { u8 adv_proto_id_len; struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa, const u8 *query, size_t query_len, - u16 *comeback_delay); + int *comeback_delay); void (*status_cb)(void *ctx, struct wpabuf *resp, int ok); void *ctx; struct gas_server *gas; @@ -42,6 +43,7 @@ struct gas_server_response { u8 dialog_token; struct gas_server_handler *handler; u16 comeback_delay; + bool initial_resp_sent; }; struct gas_server { @@ -86,25 +88,22 @@ static void gas_server_free_response(struct gas_server_response *response) static void -gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler, +gas_server_send_resp(struct gas_server *gas, struct gas_server_response *response, - const u8 *da, int freq, u8 dialog_token, struct wpabuf *query_resp, u16 comeback_delay) { - size_t max_len = (freq > 56160) ? 928 : 1400; + struct gas_server_handler *handler = response->handler; + size_t max_len = (response->freq > 56160) ? 928 : 1400; size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2; size_t resp_frag_len; struct wpabuf *resp; if (comeback_delay == 0 && !query_resp) { + dl_list_del(&response->list); gas_server_free_response(response); return; } - response->freq = freq; - response->handler = handler; - os_memcpy(response->dst, da, ETH_ALEN); - response->dialog_token = dialog_token; if (comeback_delay) { /* Need more time to prepare the response */ resp_frag_len = 0; @@ -119,12 +118,14 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler, resp_frag_len = wpabuf_len(query_resp); } - resp = gas_build_initial_resp(dialog_token, WLAN_STATUS_SUCCESS, + resp = gas_build_initial_resp(response->dialog_token, + WLAN_STATUS_SUCCESS, comeback_delay, handler->adv_proto_id_len + resp_frag_len); if (!resp) { wpabuf_free(query_resp); + dl_list_del(&response->list); gas_server_free_response(response); return; } @@ -152,8 +153,9 @@ gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler, } response->offset = resp_frag_len; response->resp = query_resp; - dl_list_add(&gas->responses, &response->list); - gas->tx(gas->ctx, freq, da, resp, comeback_delay ? 2000 : 0); + response->initial_resp_sent = true; + gas->tx(gas->ctx, response->freq, response->dst, resp, + comeback_delay ? 2000 : 0); wpabuf_free(resp); eloop_register_timeout(GAS_QUERY_TIMEOUT, 0, gas_server_response_timeout, response, NULL); @@ -223,25 +225,35 @@ gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa, wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response); dl_list_for_each(handler, &gas->handlers, struct gas_server_handler, list) { - u16 comeback_delay = 0; + int comeback_delay = 0; if (adv_proto_len < 1 + handler->adv_proto_id_len || os_memcmp(adv_proto + 1, handler->adv_proto_id, handler->adv_proto_id_len) != 0) continue; + response->freq = freq; + response->handler = handler; + os_memcpy(response->dst, sa, ETH_ALEN); + response->dialog_token = dialog_token; + dl_list_add(&gas->responses, &response->list); + wpa_printf(MSG_DEBUG, "GAS: Calling handler for the requested Advertisement Protocol ID"); resp = handler->req_cb(handler->ctx, response, sa, query_req, query_req_len, &comeback_delay); wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler", resp); + if (comeback_delay < 0) { + wpa_printf(MSG_DEBUG, + "GAS: Handler requested short delay before sending out the initial response"); + return 0; + } if (comeback_delay) wpa_printf(MSG_DEBUG, "GAS: Handler requested comeback delay: %u TU", comeback_delay); - gas_server_send_resp(gas, handler, response, sa, freq, - dialog_token, resp, comeback_delay); + gas_server_send_resp(gas, response, resp, comeback_delay); return 0; } @@ -340,7 +352,7 @@ gas_server_rx_comeback_req(struct gas_server *gas, const u8 *da, const u8 *sa, dl_list_for_each(response, &gas->responses, struct gas_server_response, list) { if (response->dialog_token != dialog_token || - os_memcmp(sa, response->dst, ETH_ALEN) != 0) + !ether_addr_equal(sa, response->dst)) continue; gas_server_handle_rx_comeback_req(response); return 0; @@ -458,7 +470,7 @@ void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data, dl_list_for_each(response, &gas->responses, struct gas_server_response, list) { if (response->dialog_token != dialog_token || - os_memcmp(dst, response->dst, ETH_ALEN) != 0) + !ether_addr_equal(dst, response->dst)) continue; gas_server_handle_tx_status(response, ack); return; @@ -484,11 +496,42 @@ int gas_server_set_resp(struct gas_server *gas, void *resp_ctx, if (!response || response->resp) return -1; + if (!response->initial_resp_sent) { + wpa_printf(MSG_DEBUG, "GAS: Send the delayed initial response"); + gas_server_send_resp(gas, response, resp, 0); + return 0; + } + response->resp = resp; return 0; } +int gas_server_set_comeback_delay(struct gas_server *gas, void *resp_ctx, + u16 comeback_delay) +{ + struct gas_server_response *tmp, *response = NULL; + + dl_list_for_each(tmp, &gas->responses, struct gas_server_response, + list) { + if (tmp == resp_ctx) { + response = tmp; + break; + } + } + + if (!response || response->initial_resp_sent) + return -1; + + wpa_printf(MSG_DEBUG, + "GAS: Send the delayed initial response with comeback delay %u", + comeback_delay); + gas_server_send_resp(gas, response, NULL, comeback_delay); + + return 0; +} + + bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx) { struct gas_server_response *tmp; @@ -552,7 +595,7 @@ int gas_server_register(struct gas_server *gas, struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa, const u8 *query, size_t query_len, - u16 *comeback_delay), + int *comeback_delay), void (*status_cb)(void *ctx, struct wpabuf *resp, int ok), void *ctx) diff --git a/wpa_supplicant-2.9_standard/src/common/gas_server.h b/wpa_supplicant-2.9_standard/src/common/gas_server.h index db00f87e8de1097fe0a31925a381afd9b586b723..8d5eaa256bac29fbddc4718431f3a5f2cfbad0aa 100644 --- a/wpa_supplicant-2.9_standard/src/common/gas_server.h +++ b/wpa_supplicant-2.9_standard/src/common/gas_server.h @@ -2,6 +2,7 @@ * Generic advertisement service (GAS) server * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2020, The Linux Foundation + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -25,7 +26,7 @@ int gas_server_register(struct gas_server *gas, struct wpabuf * (*req_cb)(void *ctx, void *resp_ctx, const u8 *sa, const u8 *query, size_t query_len, - u16 *comeback_delay), + int *comeback_delay), void (*status_cb)(void *ctx, struct wpabuf *resp, int ok), void *ctx); @@ -34,6 +35,8 @@ int gas_server_rx(struct gas_server *gas, const u8 *da, const u8 *sa, int freq); void gas_server_tx_status(struct gas_server *gas, const u8 *dst, const u8 *data, size_t data_len, int ack); +int gas_server_set_comeback_delay(struct gas_server *gas, void *resp_ctx, + u16 comeback_delay); int gas_server_set_resp(struct gas_server *gas, void *resp_ctx, struct wpabuf *resp); bool gas_server_response_sent(struct gas_server *gas, void *resp_ctx); diff --git a/wpa_supplicant-2.9_standard/src/common/hw_features_common.c b/wpa_supplicant-2.9_standard/src/common/hw_features_common.c index b302b498524579205568a3621ba2c53b1f004663..604ea8b200506966b836ba785bc2e391aa012e1f 100644 --- a/wpa_supplicant-2.9_standard/src/common/hw_features_common.c +++ b/wpa_supplicant-2.9_standard/src/common/hw_features_common.c @@ -183,8 +183,8 @@ void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan) *pri_chan = *sec_chan = 0; - ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); - if (elems.ht_operation) { + if (ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0) != + ParseFailed && elems.ht_operation) { oper = (struct ieee80211_ht_operation *) elems.ht_operation; *pri_chan = oper->primary_chan; if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) { @@ -273,7 +273,10 @@ static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, if (bss->freq < start || bss->freq > end || bss->freq == pri_freq) return 0; - ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0); + if (ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0) == + ParseFailed) + return 0; + if (!elems.ht_capabilities) { wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: " MACSTR_SEC " freq=%d", MAC2STR_SEC(bss->bssid), bss->freq); @@ -357,9 +360,9 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode, } } - ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, - 0); - if (elems.ht_capabilities) { + if (ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, + &elems, 0) != ParseFailed && + elems.ht_capabilities) { struct ieee80211_ht_capabilities *ht_cap = (struct ieee80211_ht_capabilities *) elems.ht_capabilities; @@ -378,18 +381,95 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode, } +static void punct_update_legacy_bw_80(u8 bitmap, u8 pri_chan, u8 *seg0) +{ + u8 first_chan = *seg0 - 6, sec_chan; + + switch (bitmap) { + case 0x6: + *seg0 = 0; + return; + case 0x8: + case 0x4: + case 0x2: + case 0x1: + case 0xC: + case 0x3: + if (pri_chan < *seg0) + *seg0 -= 4; + else + *seg0 += 4; + break; + } + + if (pri_chan < *seg0) + sec_chan = pri_chan + 4; + else + sec_chan = pri_chan - 4; + + if (bitmap & BIT((sec_chan - first_chan) / 4)) + *seg0 = 0; +} + + +static void punct_update_legacy_bw_160(u8 bitmap, u8 pri, + enum oper_chan_width *width, u8 *seg0) +{ + if (pri < *seg0) { + *seg0 -= 8; + if (bitmap & 0x0F) { + *width = 0; + punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0); + } + } else { + *seg0 += 8; + if (bitmap & 0xF0) { + *width = 0; + punct_update_legacy_bw_80((bitmap & 0xF0) >> 4, pri, + seg0); + } + } +} + + +void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width, + u8 *seg0, u8 *seg1) +{ + if (*width == CONF_OPER_CHWIDTH_80MHZ && (bitmap & 0xF)) { + *width = CONF_OPER_CHWIDTH_USE_HT; + punct_update_legacy_bw_80(bitmap & 0xF, pri, seg0); + } + + if (*width == CONF_OPER_CHWIDTH_160MHZ && (bitmap & 0xFF)) { + *width = CONF_OPER_CHWIDTH_80MHZ; + *seg1 = 0; + punct_update_legacy_bw_160(bitmap & 0xFF, pri, width, seg0); + } + + /* TODO: 320 MHz */ +} + + int hostapd_set_freq_params(struct hostapd_freq_params *data, enum hostapd_hw_mode mode, int freq, int channel, int enable_edmg, u8 edmg_channel, int ht_enabled, int vht_enabled, int he_enabled, - int sec_channel_offset, - int oper_chwidth, int center_segment0, + bool eht_enabled, int sec_channel_offset, + enum oper_chan_width oper_chwidth, + int center_segment0, int center_segment1, u32 vht_caps, - struct he_capabilities *he_cap) + struct he_capabilities *he_cap, + struct eht_capabilities *eht_cap, + u16 punct_bitmap) { + enum oper_chan_width oper_chwidth_legacy; + u8 seg0_legacy, seg1_legacy; + if (!he_cap || !he_cap->he_supported) he_enabled = 0; + if (!eht_cap || !eht_cap->eht_supported) + eht_enabled = 0; os_memset(data, 0, sizeof(*data)); data->mode = mode; data->freq = freq; @@ -397,14 +477,17 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, data->ht_enabled = ht_enabled; data->vht_enabled = vht_enabled; data->he_enabled = he_enabled; + data->eht_enabled = eht_enabled; data->sec_channel_offset = sec_channel_offset; data->center_freq1 = freq + sec_channel_offset * 10; data->center_freq2 = 0; - if (oper_chwidth == CHANWIDTH_80MHZ) + if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ) data->bandwidth = 80; - else if (oper_chwidth == CHANWIDTH_160MHZ || - oper_chwidth == CHANWIDTH_80P80MHZ) + else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ || + oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) data->bandwidth = 160; + else if (oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) + data->bandwidth = 320; else if (sec_channel_offset) data->bandwidth = 40; else @@ -415,9 +498,9 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, &data->edmg); if (is_6ghz_freq(freq)) { - if (!data->he_enabled) { + if (!data->he_enabled && !data->eht_enabled) { wpa_printf(MSG_ERROR, - "Can't set 6 GHz mode - HE isn't enabled"); + "Can't set 6 GHz mode - HE or EHT aren't enabled"); return -1; } @@ -438,6 +521,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, } else { int freq1, freq2 = 0; int bw = center_idx_to_bw_6ghz(center_segment0); + int opclass; if (bw < 0) { wpa_printf(MSG_ERROR, @@ -445,7 +529,10 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, return -1; } - freq1 = ieee80211_chan_to_freq(NULL, 131, + /* The 6 GHz channel 2 uses a different operating class + */ + opclass = center_segment0 == 2 ? 136 : 131; + freq1 = ieee80211_chan_to_freq(NULL, opclass, center_segment0); if (freq1 < 0) { wpa_printf(MSG_ERROR, @@ -480,13 +567,27 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, return 0; } - if (data->he_enabled) switch (oper_chwidth) { - case CHANWIDTH_USE_HT: + if (data->eht_enabled) switch (oper_chwidth) { + case CONF_OPER_CHWIDTH_320MHZ: + if (!(eht_cap->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] & + EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) { + wpa_printf(MSG_ERROR, + "320 MHz channel width is not supported in 5 or 6 GHz"); + return -1; + } + break; + default: + break; + } + + if (data->he_enabled || data->eht_enabled) switch (oper_chwidth) { + case CONF_OPER_CHWIDTH_USE_HT: if (sec_channel_offset == 0) break; if (mode == HOSTAPD_MODE_IEEE80211G) { - if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + if (he_cap && + !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) { wpa_printf(MSG_ERROR, "40 MHz channel width is not supported in 2.4 GHz"); @@ -494,10 +595,11 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, } break; } - /* fall through */ - case CHANWIDTH_80MHZ: + __attribute__((fallthrough)); + case CONF_OPER_CHWIDTH_80MHZ: if (mode == HOSTAPD_MODE_IEEE80211A) { - if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + if (he_cap && + !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) { wpa_printf(MSG_ERROR, "40/80 MHz channel width is not supported in 5/6 GHz"); @@ -505,35 +607,39 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, } } break; - case CHANWIDTH_80P80MHZ: - if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + case CONF_OPER_CHWIDTH_80P80MHZ: + if (he_cap && + !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) { wpa_printf(MSG_ERROR, "80+80 MHz channel width is not supported in 5/6 GHz"); return -1; } break; - case CHANWIDTH_160MHZ: - if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + case CONF_OPER_CHWIDTH_160MHZ: + if (he_cap && + !(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) { wpa_printf(MSG_ERROR, "160 MHz channel width is not supported in 5 / 6GHz"); return -1; } break; + default: + break; } else if (data->vht_enabled) switch (oper_chwidth) { - case CHANWIDTH_USE_HT: + case CONF_OPER_CHWIDTH_USE_HT: break; - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) { wpa_printf(MSG_ERROR, "80+80 channel width is not supported!"); return -1; } - /* fall through */ - case CHANWIDTH_80MHZ: + __attribute__((fallthrough)); + case CONF_OPER_CHWIDTH_80MHZ: break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { wpa_printf(MSG_ERROR, @@ -541,10 +647,21 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, return -1; } break; + default: + break; } - if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) { - case CHANWIDTH_USE_HT: + oper_chwidth_legacy = oper_chwidth; + seg0_legacy = center_segment0; + seg1_legacy = center_segment1; + if (punct_bitmap) + punct_update_legacy_bw(punct_bitmap, channel, + &oper_chwidth_legacy, + &seg0_legacy, &seg1_legacy); + + if (data->eht_enabled || data->he_enabled || + data->vht_enabled) switch (oper_chwidth) { + case CONF_OPER_CHWIDTH_USE_HT: if (center_segment1 || (center_segment0 != 0 && 5000 + center_segment0 * 5 != data->center_freq1 && @@ -555,7 +672,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, return -1; } break; - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: if (center_segment1 == center_segment0 + 4 || center_segment1 == center_segment0 - 4) { wpa_printf(MSG_ERROR, @@ -563,20 +680,23 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, return -1; } data->center_freq2 = 5000 + center_segment1 * 5; - /* fall through */ - case CHANWIDTH_80MHZ: + __attribute__((fallthrough)); + case CONF_OPER_CHWIDTH_80MHZ: data->bandwidth = 80; - if (!sec_channel_offset) { + if (!sec_channel_offset && + oper_chwidth_legacy != CONF_OPER_CHWIDTH_USE_HT) { wpa_printf(MSG_ERROR, "80/80+80 MHz: no second channel offset"); return -1; } - if (oper_chwidth == CHANWIDTH_80MHZ && center_segment1) { + if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ && + center_segment1) { wpa_printf(MSG_ERROR, "80 MHz: center segment 1 configured"); return -1; } - if (oper_chwidth == CHANWIDTH_80P80MHZ && !center_segment1) { + if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ && + !center_segment1) { wpa_printf(MSG_ERROR, "80+80 MHz: center segment 1 not configured"); return -1; @@ -615,14 +735,15 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, } } break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: data->bandwidth = 160; if (center_segment1) { wpa_printf(MSG_ERROR, "160 MHz: center segment 1 should not be set"); return -1; } - if (!sec_channel_offset) { + if (!sec_channel_offset && + oper_chwidth_legacy != CONF_OPER_CHWIDTH_USE_HT) { wpa_printf(MSG_ERROR, "160 MHz: second channel offset not set"); return -1; @@ -646,6 +767,43 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, return -1; } break; + case CONF_OPER_CHWIDTH_320MHZ: + data->bandwidth = 320; + if (!data->eht_enabled || !is_6ghz_freq(freq)) { + wpa_printf(MSG_ERROR, + "320 MHz: EHT not enabled or not a 6 GHz channel"); + return -1; + } + if (center_segment1) { + wpa_printf(MSG_ERROR, + "320 MHz: center segment 1 should not be set"); + return -1; + } + if (center_segment0 == channel + 30 || + center_segment0 == channel + 26 || + center_segment0 == channel + 22 || + center_segment0 == channel + 18 || + center_segment0 == channel + 14 || + center_segment0 == channel + 10 || + center_segment0 == channel + 6 || + center_segment0 == channel + 2 || + center_segment0 == channel - 2 || + center_segment0 == channel - 6 || + center_segment0 == channel - 10 || + center_segment0 == channel - 14 || + center_segment0 == channel - 18 || + center_segment0 == channel - 22 || + center_segment0 == channel - 26 || + center_segment0 == channel - 30) + data->center_freq1 = 5000 + center_segment0 * 5; + else { + wpa_printf(MSG_ERROR, + "320 MHz: wrong center segment 0"); + return -1; + } + break; + default: + break; } return 0; @@ -756,6 +914,7 @@ u32 num_chan_to_bw(int num_chans) case 2: case 4: case 8: + case 16: return num_chans * 20; default: return 20; @@ -789,6 +948,9 @@ int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw, case 160: bw_mask = HOSTAPD_CHAN_WIDTH_160; break; + case 320: + bw_mask = HOSTAPD_CHAN_WIDTH_320; + break; default: bw_mask = 0; break; @@ -804,3 +966,70 @@ int chan_pri_allowed(const struct hostapd_channel_data *chan) return !(chan->flag & HOSTAPD_CHAN_DISABLED) && (chan->allowed_bw & HOSTAPD_CHAN_WIDTH_20); } + + +/* IEEE P802.11be/D3.0, Table 36-30 - Definition of the Punctured Channel + * Information field in the U-SIG for an EHT MU PPDU using non-OFDMA + * transmissions */ +static const u16 punct_bitmap_80[] = { 0xF, 0xE, 0xD, 0xB, 0x7 }; +static const u16 punct_bitmap_160[] = { + 0xFF, 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, + 0x7F, 0xFC, 0xF3, 0xCF, 0x3F +}; +static const u16 punct_bitmap_320[] = { + 0xFFFF, 0xFFFC, 0xFFF3, 0xFFCF, 0xFF3F, 0xFCFF, 0xF3FF, 0xCFFF, + 0x3FFF, 0xFFF0, 0xFF0F, 0xF0FF, 0x0FFF, 0xFFC0, 0xFF30, 0xFCF0, + 0xF3F0, 0xCFF0, 0x3FF0, 0x0FFC, 0x0FF3, 0x0FCF, 0x0F3F, 0x0CFF, + 0x03FF +}; + + +bool is_punct_bitmap_valid(u16 bw, u16 pri_ch_bit_pos, u16 punct_bitmap) +{ + u8 i, count; + u16 bitmap; + const u16 *valid_bitmaps; + + if (!punct_bitmap) /* All channels active */ + return true; + + bitmap = ~punct_bitmap; + + switch (bw) { + case 80: + bitmap &= 0xF; + valid_bitmaps = punct_bitmap_80; + count = ARRAY_SIZE(punct_bitmap_80); + break; + + case 160: + bitmap &= 0xFF; + valid_bitmaps = punct_bitmap_160; + count = ARRAY_SIZE(punct_bitmap_160); + break; + + case 320: + bitmap &= 0xFFFF; + valid_bitmaps = punct_bitmap_320; + count = ARRAY_SIZE(punct_bitmap_320); + break; + + default: + return false; + } + + if (!bitmap) /* No channel active */ + return false; + + if (!(bitmap & BIT(pri_ch_bit_pos))) { + wpa_printf(MSG_DEBUG, "Primary channel cannot be punctured"); + return false; + } + + for (i = 0; i < count; i++) { + if (valid_bitmaps[i] == bitmap) + return true; + } + + return false; +} diff --git a/wpa_supplicant-2.9_standard/src/common/hw_features_common.h b/wpa_supplicant-2.9_standard/src/common/hw_features_common.h index 0e92aa0f2bc5e6bdf58db849f0051ea33b74455d..e791c33f1736ef836d8a2266a73239f63a6c2d52 100644 --- a/wpa_supplicant-2.9_standard/src/common/hw_features_common.h +++ b/wpa_supplicant-2.9_standard/src/common/hw_features_common.h @@ -35,15 +35,20 @@ int check_40mhz_5g(struct wpa_scan_results *scan_res, int check_40mhz_2g4(struct hostapd_hw_modes *mode, struct wpa_scan_results *scan_res, int pri_chan, int sec_chan); +void punct_update_legacy_bw(u16 bitmap, u8 pri_chan, + enum oper_chan_width *width, u8 *seg0, u8 *seg1); int hostapd_set_freq_params(struct hostapd_freq_params *data, enum hostapd_hw_mode mode, int freq, int channel, int edmg, u8 edmg_channel, int ht_enabled, int vht_enabled, int he_enabled, - int sec_channel_offset, - int oper_chwidth, int center_segment0, + bool eht_enabled, int sec_channel_offset, + enum oper_chan_width oper_chwidth, + int center_segment0, int center_segment1, u32 vht_caps, - struct he_capabilities *he_caps); + struct he_capabilities *he_caps, + struct eht_capabilities *eht_cap, + u16 punct_bitmap); void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps, int disabled); int ieee80211ac_cap_check(u32 hw, u32 conf); @@ -52,5 +57,6 @@ u32 num_chan_to_bw(int num_chans); int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw, int ht40_plus, int pri); int chan_pri_allowed(const struct hostapd_channel_data *chan); +bool is_punct_bitmap_valid(u16 bw, u16 pri_ch_bit_pos, u16 punct_bitmap); #endif /* HW_FEATURES_COMMON_H */ diff --git a/wpa_supplicant-2.9_standard/src/common/ieee802_11_common.c b/wpa_supplicant-2.9_standard/src/common/ieee802_11_common.c index 3b76fbf3c5abc4ac262b3ab97ca896e396549eb7..f4fc8b1078ec479010bb51ca478c873fa975064f 100644 --- a/wpa_supplicant-2.9_standard/src/common/ieee802_11_common.c +++ b/wpa_supplicant-2.9_standard/src/common/ieee802_11_common.c @@ -207,7 +207,7 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, return 0; } -#ifdef CONFIG_MLD_PATCH + static int ieee802_11_parse_mle(const u8 *pos, size_t elen, size_t **total_len, struct ieee802_11_elems *elems, int show_errors) @@ -269,19 +269,16 @@ static size_t ieee802_11_fragments_length(struct ieee802_11_elems *elems, return frags_len; } -#endif + static int ieee802_11_parse_extension(const u8 *pos, size_t elen, struct ieee802_11_elems *elems, -#ifdef CONFIG_MLD_PATCH const u8 *start, size_t len, -#endif int show_errors) { u8 ext_id; -#ifdef CONFIG_MLD_PATCH size_t *total_len = NULL; -#endif + if (elen < 1) { if (show_errors) { wpa_printf(MSG_MSGDUMP, @@ -292,9 +289,7 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, ext_id = *pos++; elen--; -#ifndef CONFIG_MLD_PATCH - elems->frag_ies.last_eid_ext = 0; -#endif + switch (ext_id) { case WLAN_EID_EXT_ASSOC_DELAY_INFO: if (elen != 1) @@ -321,9 +316,7 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, break; elems->fils_hlp = pos; elems->fils_hlp_len = elen; -#ifdef CONFIG_MLD_PATCH total_len = &elems->fils_hlp_len; -#endif break; case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN: if (elen < 1) @@ -340,9 +333,7 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, case WLAN_EID_EXT_WRAPPED_DATA: elems->wrapped_data = pos; elems->wrapped_data_len = elen; -#ifdef CONFIG_MLD_PATCH total_len = &elems->wrapped_data_len; -#endif break; case WLAN_EID_EXT_FILS_PUBLIC_KEY: if (elen < 1) @@ -390,7 +381,6 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, elems->pasn_params = pos; elems->pasn_params_len = elen; break; -#ifdef CONFIG_MLD_PATCH case WLAN_EID_EXT_EHT_CAPABILITIES: if (elen < EHT_CAPABILITIES_IE_MIN_LEN) break; @@ -414,10 +404,6 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, elems->mbssid_known_bss = pos; elems->mbssid_known_bss_len = elen; break; - case WLAN_EID_EXT_AKM_SUITE_SELECTOR: - // MLD AKM24 Ap auth frame contains AKM_SUITE_SELECTOR IE - break; -#endif default: if (show_errors) { wpa_printf(MSG_MSGDUMP, @@ -426,68 +412,28 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, } return -1; } -#ifdef CONFIG_MLD_PATCH + if (elen == 254 && total_len) *total_len += ieee802_11_fragments_length( elems, pos + elen, (start + len) - (pos + elen)); -#else - if (elen == 254) - elems->frag_ies.last_eid_ext = ext_id; -#endif + return 0; } -#ifndef CONFIG_MLD_PATCH -static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies, - const u8 *pos, u8 elen) -{ - if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) { - wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip"); - return; - } - - /* - * Note: while EID == 0 is a valid ID (SSID IE), it should not be - * fragmented. - */ - if (!frag_ies->last_eid) { - wpa_printf(MSG_MSGDUMP, - "Fragment without a valid last element - skip"); - return; - } - - frag_ies->frags[frag_ies->n_frags].ie = pos; - frag_ies->frags[frag_ies->n_frags].ie_len = elen; - frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid; - frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext; - frag_ies->n_frags++; -} -#endif -/** - * ieee802_11_parse_elems - Parse information elements in management frames - * @start: Pointer to the start of IEs - * @len: Length of IE buffer in octets - * @elems: Data structure for parsed elements - * @show_errors: Whether to show parsing errors in debug log - * Returns: Parsing result - */ -ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, - struct ieee802_11_elems *elems, - int show_errors) +static ParseRes __ieee802_11_parse_elems(const u8 *start, size_t len, + struct ieee802_11_elems *elems, + int show_errors) { const struct element *elem; int unknown = 0; - os_memset(elems, 0, sizeof(*elems)); - if (!start) return ParseOK; for_each_element(elem, start, len) { u8 id = elem->id, elen = elem->datalen; const u8 *pos = elem->data; -#ifdef CONFIG_MLD_PATCH size_t *total_len = NULL; if (id == WLAN_EID_FRAGMENT && elems->num_frag_elems > 0) { @@ -495,7 +441,7 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, continue; } elems->num_frag_elems = 0; -#endif + switch (id) { case WLAN_EID_SSID: if (elen > SSID_MAX_LEN) { @@ -572,10 +518,8 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, break; elems->ftie = pos; elems->ftie_len = elen; -#ifdef CONFIG_MLD_PATCH elems->fte_defrag_len = elen; total_len = &elems->fte_defrag_len; -#endif break; case WLAN_EID_TIMEOUT_INTERVAL: if (elen != 5) @@ -614,10 +558,10 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, break; elems->vht_operation = pos; break; - case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION: + case WLAN_EID_OPERATING_MODE_NOTIFICATION: if (elen != 1) break; - elems->vht_opmode_notif = pos; + elems->opmode_notif = pos; break; case WLAN_EID_LINK_ID: if (elen < 18) @@ -676,6 +620,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elems->rrm_enabled = pos; elems->rrm_enabled_len = elen; break; + case WLAN_EID_MULTIPLE_BSSID: + if (elen < 1) + break; + elems->mbssid = pos; + elems->mbssid_len = elen; + break; case WLAN_EID_CAG_NUMBER: elems->cag_number = pos; elems->cag_number_len = elen; @@ -703,19 +653,13 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elems->s1g_capab = pos; break; case WLAN_EID_FRAGMENT: -#ifdef CONFIG_MLD_PATCH wpa_printf(MSG_MSGDUMP, "Fragment without a valid last element - skip"); -#else - ieee802_11_parse_fragment(&elems->frag_ies, pos, elen); -#endif + break; case WLAN_EID_EXTENSION: - if (ieee802_11_parse_extension(pos, elen, elems, -#ifdef CONFIG_MLD_PATCH - start, len, -#endif - show_errors)) + if (ieee802_11_parse_extension(pos, elen, elems, start, + len, show_errors)) unknown++; break; default: @@ -727,18 +671,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, id, elen); break; } -#ifdef CONFIG_MLD_PATCH + if (elen == 255 && total_len) *total_len += ieee802_11_fragments_length( elems, pos + elen, (start + len) - (pos + elen)); -#else - if (id != WLAN_EID_FRAGMENT && elen == 255) - elems->frag_ies.last_eid = id; - if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext) - elems->frag_ies.last_eid = 0; -#endif } if (!for_each_element_completed(elem, start, len)) { @@ -756,6 +694,432 @@ done: } +/** + * ieee802_11_parse_elems - Parse information elements in management frames + * @start: Pointer to the start of IEs + * @len: Length of IE buffer in octets + * @elems: Data structure for parsed elements + * @show_errors: Whether to show parsing errors in debug log + * Returns: Parsing result + */ +ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, + struct ieee802_11_elems *elems, + int show_errors) +{ + os_memset(elems, 0, sizeof(*elems)); + + return __ieee802_11_parse_elems(start, len, elems, show_errors); +} + + +/** + * ieee802_11_elems_clear_ids - Clear the data for the given element IDs + * @ids: Array of element IDs for which data should be cleared. + * @num: The number of entries in the array + */ +void ieee802_11_elems_clear_ids(struct ieee802_11_elems *elems, + const u8 *ids, size_t num) +{ + size_t i; + + for (i = 0; i < num; i++) { + switch (ids[i]) { + case WLAN_EID_SSID: + elems->ssid = NULL; + elems->ssid_len = 0; + break; + case WLAN_EID_SUPP_RATES: + elems->supp_rates = NULL; + elems->supp_rates_len = 0; + break; + case WLAN_EID_DS_PARAMS: + elems->ds_params = NULL; + break; + case WLAN_EID_CHALLENGE: + elems->challenge = NULL; + elems->challenge_len = 0; + break; + case WLAN_EID_ERP_INFO: + elems->erp_info = NULL; + break; + case WLAN_EID_EXT_SUPP_RATES: + elems->ext_supp_rates = NULL; + elems->ext_supp_rates_len = 0; + break; + case WLAN_EID_RSN: + elems->rsn_ie = NULL; + elems->rsn_ie_len = 0; + break; + case WLAN_EID_RSNX: + elems->rsnxe = NULL; + elems->rsnxe_len = 0; + break; + case WLAN_EID_PWR_CAPABILITY: + elems->power_capab = NULL; + elems->power_capab_len = 0; + break; + case WLAN_EID_SUPPORTED_CHANNELS: + elems->supp_channels = NULL; + elems->supp_channels_len = 0; + break; + case WLAN_EID_MOBILITY_DOMAIN: + elems->mdie = NULL; + elems->mdie_len = 0; + break; + case WLAN_EID_FAST_BSS_TRANSITION: + elems->ftie = NULL; + elems->ftie_len = 0; + break; + case WLAN_EID_TIMEOUT_INTERVAL: + elems->timeout_int = NULL; + break; + case WLAN_EID_HT_CAP: + elems->ht_capabilities = NULL; + break; + case WLAN_EID_HT_OPERATION: + elems->ht_operation = NULL; + break; + case WLAN_EID_MESH_CONFIG: + elems->mesh_config = NULL; + elems->mesh_config_len = 0; + break; + case WLAN_EID_MESH_ID: + elems->mesh_id = NULL; + elems->mesh_id_len = 0; + break; + case WLAN_EID_PEER_MGMT: + elems->peer_mgmt = NULL; + elems->peer_mgmt_len = 0; + break; + case WLAN_EID_VHT_CAP: + elems->vht_capabilities = NULL; + break; + case WLAN_EID_VHT_OPERATION: + elems->vht_operation = NULL; + break; + case WLAN_EID_OPERATING_MODE_NOTIFICATION: + elems->opmode_notif = NULL; + break; + case WLAN_EID_LINK_ID: + elems->link_id = NULL; + break; + case WLAN_EID_INTERWORKING: + elems->interworking = NULL; + elems->interworking_len = 0; + break; + case WLAN_EID_QOS_MAP_SET: + elems->qos_map_set = NULL; + elems->qos_map_set_len = 0; + break; + case WLAN_EID_EXT_CAPAB: + elems->ext_capab = NULL; + elems->ext_capab_len = 0; + break; + case WLAN_EID_BSS_MAX_IDLE_PERIOD: + elems->bss_max_idle_period = NULL; + break; + case WLAN_EID_SSID_LIST: + elems->ssid_list = NULL; + elems->ssid_list_len = 0; + break; + case WLAN_EID_AMPE: + elems->ampe = NULL; + elems->ampe_len = 0; + break; + case WLAN_EID_MIC: + elems->mic = NULL; + elems->mic_len = 0; + break; + case WLAN_EID_MULTI_BAND: + os_memset(&elems->mb_ies, 0, sizeof(elems->mb_ies)); + elems->mb_ies.nof_ies = 0; + break; + case WLAN_EID_SUPPORTED_OPERATING_CLASSES: + elems->supp_op_classes = NULL; + elems->supp_op_classes_len = 0; + break; + case WLAN_EID_RRM_ENABLED_CAPABILITIES: + elems->rrm_enabled = NULL; + elems->rrm_enabled_len = 0; + break; + case WLAN_EID_CAG_NUMBER: + elems->cag_number = NULL; + elems->cag_number_len = 0; + break; + case WLAN_EID_AP_CSN: + elems->ap_csn = NULL; + break; + case WLAN_EID_FILS_INDICATION: + elems->fils_indic = NULL; + elems->fils_indic_len = 0; + break; + case WLAN_EID_DILS: + elems->dils = NULL; + elems->dils_len = 0; + break; + case WLAN_EID_S1G_CAPABILITIES: + elems->s1g_capab = NULL; + break; + } + } +} + + +/** + * ieee802_11_elems_clear_ext_ids - Clear the data for the given element + * extension IDs + * @ids: Array of element extension IDs for which data should be cleared. + * @num: The number of entries in the array + */ +void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems, + const u8 *ids, size_t num) +{ + size_t i; + + for (i = 0; i < num; i++) { + switch (ids[i]) { + case WLAN_EID_EXT_ASSOC_DELAY_INFO: + elems->assoc_delay_info = NULL; + break; + case WLAN_EID_EXT_FILS_REQ_PARAMS: + elems->fils_req_params = NULL; + elems->fils_req_params_len = 0; + break; + case WLAN_EID_EXT_FILS_KEY_CONFIRM: + elems->fils_key_confirm = NULL; + elems->fils_key_confirm_len = 0; + break; + case WLAN_EID_EXT_FILS_SESSION: + elems->fils_session = NULL; + break; + case WLAN_EID_EXT_FILS_HLP_CONTAINER: + elems->fils_hlp = NULL; + elems->fils_hlp_len = 0; + break; + case WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN: + elems->fils_ip_addr_assign = NULL; + elems->fils_ip_addr_assign_len = 0; + break; + case WLAN_EID_EXT_KEY_DELIVERY: + elems->key_delivery = NULL; + elems->key_delivery_len = 0; + break; + case WLAN_EID_EXT_WRAPPED_DATA: + elems->wrapped_data = NULL; + elems->wrapped_data_len = 0; + break; + case WLAN_EID_EXT_FILS_PUBLIC_KEY: + elems->fils_pk = NULL; + elems->fils_pk_len = 0; + break; + case WLAN_EID_EXT_FILS_NONCE: + elems->fils_nonce = NULL; + break; + case WLAN_EID_EXT_OWE_DH_PARAM: + elems->owe_dh = NULL; + elems->owe_dh_len = 0; + break; + case WLAN_EID_EXT_PASSWORD_IDENTIFIER: + elems->password_id = NULL; + elems->password_id_len = 0; + break; + case WLAN_EID_EXT_HE_CAPABILITIES: + elems->he_capabilities = NULL; + elems->he_capabilities_len = 0; + break; + case WLAN_EID_EXT_HE_OPERATION: + elems->he_operation = NULL; + elems->he_operation_len = 0; + break; + case WLAN_EID_EXT_OCV_OCI: + elems->oci = NULL; + elems->oci_len = 0; + break; + case WLAN_EID_EXT_SHORT_SSID_LIST: + elems->short_ssid_list = NULL; + elems->short_ssid_list_len = 0; + break; + case WLAN_EID_EXT_HE_6GHZ_BAND_CAP: + elems->he_6ghz_band_cap = NULL; + break; + case WLAN_EID_EXT_PASN_PARAMS: + elems->pasn_params = NULL; + elems->pasn_params_len = 0; + break; + case WLAN_EID_EXT_MULTI_LINK: + elems->basic_mle = NULL; + elems->probe_req_mle = NULL; + elems->reconf_mle = NULL; + elems->tdls_mle = NULL; + elems->prior_access_mle = NULL; + + elems->basic_mle_len = 0; + elems->probe_req_mle_len = 0; + elems->reconf_mle_len = 0; + elems->tdls_mle_len = 0; + elems->prior_access_mle_len = 0; + break; + case WLAN_EID_EXT_EHT_CAPABILITIES: + elems->eht_capabilities = NULL; + elems->eht_capabilities_len = 0; + break; + case WLAN_EID_EXT_EHT_OPERATION: + elems->eht_operation = NULL; + elems->eht_operation_len = 0; + break; + } + } +} + + +ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len, + struct ieee802_11_elems *elems, + struct wpabuf *mlbuf, + u8 link_id, bool show_errors) +{ + const struct ieee80211_eht_ml *ml; + const u8 *pos; + ParseRes res = ParseFailed; + + pos = wpabuf_head(mlbuf); + len = wpabuf_len(mlbuf); + + /* Must have control and common info length */ + if (len < sizeof(*ml) + 1 || len < sizeof(*ml) + pos[sizeof(*ml)]) + goto out; + + ml = (const struct ieee80211_eht_ml *) pos; + + /* As we are interested with the Per-STA profile, ignore other types */ + if ((le_to_host16(ml->ml_control) & MULTI_LINK_CONTROL_TYPE_MASK) != + MULTI_LINK_CONTROL_TYPE_BASIC) + goto out; + + /* Skip the common info */ + len -= sizeof(*ml) + pos[sizeof(*ml)]; + pos += sizeof(*ml) + pos[sizeof(*ml)]; + + while (len > 2) { + size_t sub_elem_len = *(pos + 1); + size_t sta_info_len; + u16 link_info_control; + const u8 *non_inherit; + + wpa_printf(MSG_DEBUG, + "MLD: sub element: len=%zu, sub_elem_len=%zu", + len, sub_elem_len); + + if (2 + sub_elem_len > len) { + if (show_errors) + wpa_printf(MSG_DEBUG, + "MLD: error: len=%zu, sub_elem_len=%zu", + len, sub_elem_len); + goto out; + } + + if (*pos != 0) { + pos += 2 + sub_elem_len; + len -= 2 + sub_elem_len; + continue; + } + + if (sub_elem_len < 5) { + if (show_errors) + wpa_printf(MSG_DEBUG, + "MLD: error: sub_elem_len=%zu < 5", + sub_elem_len); + goto out; + } + + link_info_control = WPA_GET_LE16(pos + 2); + if ((link_info_control & BASIC_MLE_STA_CTRL_LINK_ID_MASK) != + link_id) { + pos += 2 + sub_elem_len; + len -= 2 + sub_elem_len; + continue; + } + + sta_info_len = *(pos + 4); + if (sub_elem_len < sta_info_len + 3 || sta_info_len < 1) { + if (show_errors) + wpa_printf(MSG_DEBUG, + "MLD: error: sub_elem_len=%zu, sta_info_len=%zu", + sub_elem_len, sta_info_len); + goto out; + } + + pos += sta_info_len + 4; + sub_elem_len -= sta_info_len + 2; + + if (sub_elem_len < 2) { + if (show_errors) + wpa_printf(MSG_DEBUG, + "MLD: missing capability info"); + goto out; + } + + pos += 2; + sub_elem_len -= 2; + + /* Handle non-inheritance */ + non_inherit = get_ie_ext(pos, sub_elem_len, + WLAN_EID_EXT_NON_INHERITANCE); + if (non_inherit && non_inherit[1] > 1) { + u8 non_inherit_len = non_inherit[1] - 1; + + /* + * Do not include the Non-Inheritance element when + * parsing below. It should be the last element in the + * subelement. + */ + if (3U + non_inherit_len > sub_elem_len) + goto out; + sub_elem_len -= 3 + non_inherit_len; + + /* Skip the ID, length and extension ID */ + non_inherit += 3; + + if (non_inherit_len < 1UL + non_inherit[0]) { + if (show_errors) + wpa_printf(MSG_DEBUG, + "MLD: Invalid inheritance"); + goto out; + } + + ieee802_11_elems_clear_ids(elems, &non_inherit[1], + non_inherit[0]); + + non_inherit_len -= 1 + non_inherit[0]; + non_inherit += 1 + non_inherit[0]; + + if (non_inherit_len < 1UL || + non_inherit_len < 1UL + non_inherit[0]) { + if (show_errors) + wpa_printf(MSG_DEBUG, + "MLD: Invalid inheritance"); + goto out; + } + + ieee802_11_elems_clear_ext_ids(elems, &non_inherit[1], + non_inherit[0]); + } + + wpa_printf(MSG_DEBUG, "MLD: link: sub_elem_len=%zu", + sub_elem_len); + + if (sub_elem_len) + res = __ieee802_11_parse_elems(pos, sub_elem_len, + elems, show_errors); + else + res = ParseOK; + break; + } + +out: + return res; +} + + int ieee802_11_ie_count(const u8 *ies, size_t ies_len) { const struct element *elem; @@ -1013,7 +1377,7 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) { u8 op_class; - return ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT, + return ieee80211_freq_to_channel_ext(freq, 0, CONF_OPER_CHWIDTH_USE_HT, &op_class, channel); } @@ -1023,15 +1387,15 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel) * 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_*) + * @chanwidth: VHT/EDMG/etc. channel width * @op_class: Buffer for returning operating class * @channel: Buffer for returning channel number * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure */ -enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, - int sec_channel, - int chanwidth, - u8 *op_class, u8 *channel) +enum hostapd_hw_mode +ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel, + enum oper_chan_width chanwidth, + u8 *op_class, u8 *channel) { u8 vht_opclass; @@ -1079,13 +1443,13 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, } switch (chanwidth) { - case CHANWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: vht_opclass = 128; break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: vht_opclass = 129; break; - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: vht_opclass = 130; break; default: @@ -1142,8 +1506,6 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, *op_class = 126; else if (sec_channel == -1) *op_class = 127; - else if (freq <= 5805) - *op_class = 124; else *op_class = 125; @@ -1184,15 +1546,18 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, return NUM_HOSTAPD_MODES; switch (chanwidth) { - case CHANWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: *op_class = 133; break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: *op_class = 134; break; - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: *op_class = 135; break; + case CONF_OPER_CHWIDTH_320MHZ: + *op_class = 137; + break; default: if (sec_channel) *op_class = 132; @@ -1217,12 +1582,12 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, return NUM_HOSTAPD_MODES; switch (chanwidth) { - case CHANWIDTH_USE_HT: - case CHANWIDTH_2160MHZ: + case CONF_OPER_CHWIDTH_USE_HT: + case CONF_OPER_CHWIDTH_2160MHZ: *channel = (freq - 56160) / 2160; *op_class = 180; break; - case CHANWIDTH_4320MHZ: + case CONF_OPER_CHWIDTH_4320MHZ: /* EDMG channels 9 - 13 */ if (freq > 56160 + 2160 * 5) return NUM_HOSTAPD_MODES; @@ -1230,7 +1595,7 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, *channel = (freq - 56160) / 2160 + 8; *op_class = 181; break; - case CHANWIDTH_6480MHZ: + case CONF_OPER_CHWIDTH_6480MHZ: /* EDMG channels 17 - 20 */ if (freq > 56160 + 2160 * 4) return NUM_HOSTAPD_MODES; @@ -1238,7 +1603,7 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq, *channel = (freq - 56160) / 2160 + 16; *op_class = 182; break; - case CHANWIDTH_8640MHZ: + case CONF_OPER_CHWIDTH_8640MHZ: /* EDMG channels 25 - 27 */ if (freq > 56160 + 2160 * 3) return NUM_HOSTAPD_MODES; @@ -1267,28 +1632,31 @@ int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth, case CHAN_WIDTH_20_NOHT: case CHAN_WIDTH_20: case CHAN_WIDTH_40: - cw = CHANWIDTH_USE_HT; + cw = CONF_OPER_CHWIDTH_USE_HT; break; case CHAN_WIDTH_80: - cw = CHANWIDTH_80MHZ; + cw = CONF_OPER_CHWIDTH_80MHZ; break; case CHAN_WIDTH_80P80: - cw = CHANWIDTH_80P80MHZ; + cw = CONF_OPER_CHWIDTH_80P80MHZ; break; case CHAN_WIDTH_160: - cw = CHANWIDTH_160MHZ; + cw = CONF_OPER_CHWIDTH_160MHZ; break; case CHAN_WIDTH_2160: - cw = CHANWIDTH_2160MHZ; + cw = CONF_OPER_CHWIDTH_2160MHZ; break; case CHAN_WIDTH_4320: - cw = CHANWIDTH_4320MHZ; + cw = CONF_OPER_CHWIDTH_4320MHZ; break; case CHAN_WIDTH_6480: - cw = CHANWIDTH_6480MHZ; + cw = CONF_OPER_CHWIDTH_6480MHZ; break; case CHAN_WIDTH_8640: - cw = CHANWIDTH_8640MHZ; + cw = CONF_OPER_CHWIDTH_8640MHZ; + break; + case CHAN_WIDTH_320: + cw = CONF_OPER_CHWIDTH_320MHZ; break; } @@ -1390,8 +1758,9 @@ static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan) if (chan < 25 || chan > 29) return -1; return 56160 + 2160 * (chan - 24); + default: + return -1; } - return -1; } @@ -1440,13 +1809,15 @@ static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan) if (chan != 25) return -1; return 56160 + 2160 * (chan - 24); + default: + return -1; } - return -1; } static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan) { + /* Table E-3 in IEEE Std 802.11-2020 - Operating classes in Japan */ switch (op_class) { case 30: /* channels 1..13 */ case 56: /* channels 1..9; 40 MHz */ @@ -1470,14 +1841,14 @@ static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan) if (chan < 34 || chan > 64) return -1; return 5000 + 5 * chan; - case 34: /* channels 100-140 */ - case 35: /* channels 100-140 */ - case 39: /* channels 100-132; 40 MHz */ - case 40: /* channels 100-132; 40 MHz */ - case 44: /* channels 104-136; 40 MHz */ - case 45: /* channels 104-136; 40 MHz */ - case 58: /* channels 100-140 */ - if (chan < 100 || chan > 140) + case 34: /* channels 100-144 */ + case 35: /* reserved */ + case 39: /* channels 100-140; 40 MHz */ + case 40: /* reserved */ + case 44: /* channels 104-144; 40 MHz */ + case 45: /* reserved */ + case 58: /* channels 100-144 */ + if (chan < 100 || chan > 144) return -1; return 5000 + 5 * chan; case 59: /* 60 GHz band, channels 1..6 */ @@ -1496,8 +1867,9 @@ static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan) if (chan != 25) return -1; return 56160 + 2160 * (chan - 24); + default: + return -1; } - return -1; } @@ -1522,14 +1894,15 @@ static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan) if (chan < 149 || chan > 165) return -1; return 5000 + 5 * chan; + default: + return -1; } - return -1; } static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) { - /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */ + /* Table E-4 in IEEE Std 802.11-2020 - Global operating classes */ switch (op_class) { case 81: /* channels 1..13 */ @@ -1555,10 +1928,10 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) if (chan < 36 || chan > 64) return -1; return 5000 + 5 * chan; - case 121: /* channels 100-140 */ - case 122: /* channels 100-142; 40 MHz */ - case 123: /* channels 104-136; 40 MHz */ - if (chan < 100 || chan > 140) + case 121: /* channels 100-144 */ + case 122: /* channels 100-140; 40 MHz */ + case 123: /* channels 104-144; 40 MHz */ + if (chan < 100 || chan > 144) return -1; return 5000 + 5 * chan; case 124: /* channels 149,153,157,161 */ @@ -1585,6 +1958,7 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */ case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */ + case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */ if (chan < 1 || chan > 233) return -1; return 5950 + chan * 5; @@ -1608,8 +1982,9 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan) if (chan < 25 || chan > 29) return -1; return 56160 + 2160 * (chan - 24); + default: + return -1; } - return -1; } /** @@ -1658,7 +2033,7 @@ int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, if (!modes || !num_modes) return (freq >= 5260 && freq <= 5320) || - (freq >= 5500 && freq <= 5700); + (freq >= 5500 && freq <= 5720); for (i = 0; i < num_modes; i++) { for (j = 0; j < modes[i].num_channels; j++) { @@ -1682,6 +2057,13 @@ int is_dfs_global_op_class(u8 op_class) } +bool is_80plus_op_class(u8 op_class) +{ + /* Operating classes with "80+" behavior indication in Table E-4 */ + return op_class == 130 || op_class == 135; +} + + static int is_11b(u8 rate) { return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16; @@ -1948,6 +2330,9 @@ const char * status2str(u16 status) S2S(DENIED_HE_NOT_SUPPORTED) S2S(SAE_HASH_TO_ELEMENT) S2S(SAE_PK) + S2S(INVALID_PUBLIC_KEY) + S2S(PASN_BASE_AKMP_FAILED) + S2S(OCI_MISMATCH) } return "UNKNOWN"; #undef S2S @@ -2031,24 +2416,35 @@ const struct oper_class_map global_op_class[] = { { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 121, 100, 140, 4, BW20, NO_P2P_SUPP }, - { 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, 121, 100, 144, 4, BW20, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 122, 100, 140, 8, BW40PLUS, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 123, 104, 144, 8, BW40MINUS, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, 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.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 + * IEEE Std 802.11ax-2021, Table E-4 actually talks about channel center + * frequency index for operation classes 128, 129, 130, 132, 133, 134, + * and 135, but currently use the lowest 20 MHz channel for simplicity * (these center frequencies are not actual channels, which makes - * wpas_p2p_verify_channel() fail). wpas_p2p_verify_80mhz() should take - * care of removing invalid channels. + * wpas_p2p_verify_channel() fail). + * Specially for the operation class 136, it is also defined to use the + * channel center frequency index value, but it happens to be a 20 MHz + * channel and the channel number in the channel set would match the + * value in for the frequency center. + * + * Operating class value pair 128 and 130 is used to describe a 80+80 + * MHz channel on the 5 GHz band. 130 is identified with "80+", so this + * is encoded with two octets 130 and 128. Similarly, operating class + * value pair 133 and 135 is used to describe a 80+80 MHz channel on + * the 6 GHz band (135 being the one with "80+" indication). All other + * operating classes listed here are used as 1-octet values. */ { HOSTAPD_MODE_IEEE80211A, 128, 36, 177, 4, BW80, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 129, 36, 177, 4, BW160, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 130, 36, 177, 4, BW80P80, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 132, 1, 233, 8, BW40, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 133, 1, 233, 16, BW80, P2P_SUPP }, @@ -2056,6 +2452,9 @@ const struct oper_class_map global_op_class[] = { { HOSTAPD_MODE_IEEE80211A, 135, 1, 233, 16, BW80P80, NO_P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 136, 2, 2, 4, BW20, NO_P2P_SUPP }, + /* IEEE P802.11be/D5.0, Table E-4 (Global operating classes) */ + { HOSTAPD_MODE_IEEE80211A, 137, 31, 191, 32, BW320, NO_P2P_SUPP }, + /* * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes. * Class 180 has the legacy channels 1-6. Classes 181-183 include @@ -2066,11 +2465,6 @@ const struct oper_class_map global_op_class[] = { { 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 } }; @@ -2155,7 +2549,6 @@ size_t global_op_class_size = ARRAY_SIZE(global_op_class_data); size_t global_op_class_size = ARRAY_SIZE(global_op_class); #endif - /** * get_ie - Fetch a specified information element from IEs buffer * @ies: Information elements buffer @@ -2242,21 +2635,141 @@ size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len) } -size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value) +u16 check_multi_ap_ie(const u8 *multi_ap_ie, size_t multi_ap_len, + struct multi_ap_params *multi_ap) +{ + const struct element *elem; + bool ext_present = false; + unsigned int vlan_id; + + os_memset(multi_ap, 0, sizeof(*multi_ap)); + + /* Default profile is 1, when Multi-AP profile subelement is not + * present in the element. */ + multi_ap->profile = 1; + + for_each_element(elem, multi_ap_ie, multi_ap_len) { + u8 id = elem->id, elen = elem->datalen; + const u8 *pos = elem->data; + + switch (id) { + case MULTI_AP_SUB_ELEM_TYPE: + if (elen >= 1) { + multi_ap->capability = *pos; + ext_present = true; + } else { + wpa_printf(MSG_DEBUG, + "Multi-AP invalid Multi-AP subelement"); + return WLAN_STATUS_INVALID_IE; + } + break; + case MULTI_AP_PROFILE_SUB_ELEM_TYPE: + if (elen < 1) { + wpa_printf(MSG_DEBUG, + "Multi-AP IE invalid Multi-AP profile subelement"); + return WLAN_STATUS_INVALID_IE; + } + + multi_ap->profile = *pos; + if (multi_ap->profile > MULTI_AP_PROFILE_MAX) { + wpa_printf(MSG_DEBUG, + "Multi-AP IE with invalid profile 0x%02x", + multi_ap->profile); + return WLAN_STATUS_ASSOC_DENIED_UNSPEC; + } + break; + case MULTI_AP_VLAN_SUB_ELEM_TYPE: + if (multi_ap->profile < MULTI_AP_PROFILE_2) { + wpa_printf(MSG_DEBUG, + "Multi-AP IE invalid profile to read VLAN IE"); + return WLAN_STATUS_INVALID_IE; + } + if (elen < 2) { + wpa_printf(MSG_DEBUG, + "Multi-AP IE invalid Multi-AP VLAN subelement"); + return WLAN_STATUS_INVALID_IE; + } + + vlan_id = WPA_GET_LE16(pos); + if (vlan_id < 1 || vlan_id > 4094) { + wpa_printf(MSG_INFO, + "Multi-AP IE invalid Multi-AP VLAN ID %d", + vlan_id); + return WLAN_STATUS_INVALID_IE; + } + multi_ap->vlanid = vlan_id; + break; + default: + wpa_printf(MSG_DEBUG, + "Ignore unknown subelement %u in Multi-AP IE", + id); + break; + } + } + + if (!for_each_element_completed(elem, multi_ap_ie, multi_ap_len)) { + wpa_printf(MSG_DEBUG, "Multi AP IE parse failed @%d", + (int) (multi_ap_ie + multi_ap_len - + (const u8 *) elem)); + wpa_hexdump(MSG_MSGDUMP, "IEs", multi_ap_ie, multi_ap_len); + } + + if (!ext_present) { + wpa_printf(MSG_DEBUG, + "Multi-AP element without Multi-AP Extension subelement"); + return WLAN_STATUS_INVALID_IE; + } + + return WLAN_STATUS_SUCCESS; +} + + +size_t add_multi_ap_ie(u8 *buf, size_t len, + const struct multi_ap_params *multi_ap) { u8 *pos = buf; + u8 *len_ptr; - if (len < 9) + if (len < 6) return 0; *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 7; /* len */ + len_ptr = pos; /* Length field to be set at the end */ + pos++; WPA_PUT_BE24(pos, OUI_WFA); pos += 3; *pos++ = MULTI_AP_OUI_TYPE; + + /* Multi-AP Extension subelement */ + if (buf + len - pos < 3) + return 0; *pos++ = MULTI_AP_SUB_ELEM_TYPE; *pos++ = 1; /* len */ - *pos++ = value; + *pos++ = multi_ap->capability; + + /* Add Multi-AP Profile subelement only for R2 or newer configuration */ + if (multi_ap->profile >= MULTI_AP_PROFILE_2) { + if (buf + len - pos < 3) + return 0; + *pos++ = MULTI_AP_PROFILE_SUB_ELEM_TYPE; + *pos++ = 1; + *pos++ = multi_ap->profile; + } + + /* Add Multi-AP Default 802.1Q Setting subelement only for backhaul BSS + */ + if (multi_ap->vlanid && + multi_ap->profile >= MULTI_AP_PROFILE_2 && + (multi_ap->capability & MULTI_AP_BACKHAUL_BSS)) { + if (buf + len - pos < 4) + return 0; + *pos++ = MULTI_AP_VLAN_SUB_ELEM_TYPE; + *pos++ = 2; + WPA_PUT_LE16(pos, multi_ap->vlanid); + pos += 2; + } + + *len_ptr = pos - len_ptr - 1; return pos - buf; } @@ -2421,6 +2934,8 @@ int oper_class_bw_to_int(const struct oper_class_map *map) case BW80P80: case BW160: return 160; + case BW320: + return 320; case BW2160: return 2160; default: @@ -2446,6 +2961,9 @@ int center_idx_to_bw_6ghz(u8 idx) /* channels 15, 47, 79...*/ if ((idx & 0x1f) == 0xf) return 3; /* 160 MHz */ + /* channels 31, 63, 95, 127, 159, 191 */ + if ((idx & 0x1f) == 0x1f && idx < 192) + return 4; /* 320 MHz */ return -1; } @@ -2468,7 +2986,7 @@ bool is_6ghz_freq(int freq) bool is_6ghz_op_class(u8 op_class) { - return op_class >= 131 && op_class <= 136; + return op_class >= 131 && op_class <= 137; } @@ -2516,6 +3034,21 @@ int get_6ghz_sec_channel(int channel) } +bool is_same_band(int freq1, int freq2) +{ + if (IS_2P4GHZ(freq1) && IS_2P4GHZ(freq2)) + return true; + + if (IS_5GHZ(freq1) && IS_5GHZ(freq2)) + return true; + + if (is_6ghz_freq(freq1) && is_6ghz_freq(freq2)) + return true; + + return false; +} + + int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, size_t nei_rep_len) { @@ -2644,7 +3177,7 @@ bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len, for (i = 0; i < flen; i++) capabs |= rsnxe[i] << (8 * i); - return capabs & BIT(capab); + return !!(capabs & BIT(capab)); } @@ -2746,10 +3279,10 @@ int op_class_to_bandwidth(u8 op_class) case 119: /* channels 52,60; 40 MHz; dfs */ case 120: /* channels 56,64; 40 MHz; dfs */ return 40; - case 121: /* channels 100-140 */ + case 121: /* channels 100-144 */ return 20; - case 122: /* channels 100-142; 40 MHz */ - case 123: /* channels 104-136; 40 MHz */ + case 122: /* channels 100-140; 40 MHz */ + case 123: /* channels 104-144; 40 MHz */ return 40; case 124: /* channels 149,153,157,161 */ case 125: /* channels 149,153,157,161,165,169,173,177 */ @@ -2774,6 +3307,8 @@ int op_class_to_bandwidth(u8 op_class) return 160; case 136: /* UHB channels, 20 MHz: 2 */ return 20; + case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */ + return 320; case 180: /* 60 GHz band, channels 1..8 */ return 2160; case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */ @@ -2782,73 +3317,109 @@ int op_class_to_bandwidth(u8 op_class) return 6480; case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */ return 8640; + default: + return 20; } - - return 20; } -int op_class_to_ch_width(u8 op_class) +enum oper_chan_width op_class_to_ch_width(u8 op_class) { switch (op_class) { case 81: case 82: - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; case 83: /* channels 1..9; 40 MHz */ case 84: /* channels 5..13; 40 MHz */ - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; case 115: /* channels 36,40,44,48; indoor only */ - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; case 116: /* channels 36,44; 40 MHz; indoor only */ case 117: /* channels 40,48; 40 MHz; indoor only */ - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; case 118: /* channels 52,56,60,64; dfs */ - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; case 119: /* channels 52,60; 40 MHz; dfs */ case 120: /* channels 56,64; 40 MHz; dfs */ - return CHANWIDTH_USE_HT; - case 121: /* channels 100-140 */ - return CHANWIDTH_USE_HT; - case 122: /* channels 100-142; 40 MHz */ - case 123: /* channels 104-136; 40 MHz */ - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; + case 121: /* channels 100-144 */ + return CONF_OPER_CHWIDTH_USE_HT; + case 122: /* channels 100-140; 40 MHz */ + case 123: /* channels 104-144; 40 MHz */ + return CONF_OPER_CHWIDTH_USE_HT; case 124: /* channels 149,153,157,161 */ case 125: /* channels 149,153,157,161,165,169,171 */ - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; case 126: /* channels 149,157,165, 173; 40 MHz */ case 127: /* channels 153,161,169,177; 40 MHz */ - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; case 128: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80 MHz */ - return CHANWIDTH_80MHZ; + return CONF_OPER_CHWIDTH_80MHZ; case 129: /* center freqs 50, 114, 163; 160 MHz */ - return CHANWIDTH_160MHZ; + return CONF_OPER_CHWIDTH_160MHZ; case 130: /* center freqs 42, 58, 106, 122, 138, 155, 171; 80+80 MHz */ - return CHANWIDTH_80P80MHZ; + return CONF_OPER_CHWIDTH_80P80MHZ; case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */ - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */ - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */ - return CHANWIDTH_80MHZ; + return CONF_OPER_CHWIDTH_80MHZ; case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */ - return CHANWIDTH_160MHZ; + return CONF_OPER_CHWIDTH_160MHZ; case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */ - return CHANWIDTH_80P80MHZ; + return CONF_OPER_CHWIDTH_80P80MHZ; case 136: /* UHB channels, 20 MHz: 2 */ - return CHANWIDTH_USE_HT; + return CONF_OPER_CHWIDTH_USE_HT; + case 137: /* UHB channels, 320 MHz: 31, 63, 95, 127, 159, 191 */ + return CONF_OPER_CHWIDTH_320MHZ; case 180: /* 60 GHz band, channels 1..8 */ - return CHANWIDTH_2160MHZ; + return CONF_OPER_CHWIDTH_2160MHZ; case 181: /* 60 GHz band, EDMG CB2, channels 9..15 */ - return CHANWIDTH_4320MHZ; + return CONF_OPER_CHWIDTH_4320MHZ; case 182: /* 60 GHz band, EDMG CB3, channels 17..22 */ - return CHANWIDTH_6480MHZ; + return CONF_OPER_CHWIDTH_6480MHZ; case 183: /* 60 GHz band, EDMG CB4, channel 25..29 */ - return CHANWIDTH_8640MHZ; + return CONF_OPER_CHWIDTH_8640MHZ; + default: + return CONF_OPER_CHWIDTH_USE_HT; } - return CHANWIDTH_USE_HT; } -#ifdef CONFIG_MLD_PATCH -struct wpabuf * ieee802_11_defrag_data(const u8 *data, size_t len, bool ext_elem) + + +/** + * chwidth_freq2_to_ch_width - Determine channel width as enum oper_chan_width + * @chwidth: Channel width integer + * @freq2: Value for frequency 2. 0 is not used + * Returns: enum oper_chan_width, -1 on failure + */ +int chwidth_freq2_to_ch_width(int chwidth, int freq2) +{ + if (freq2 < 0) + return -1; + if (freq2) + return CONF_OPER_CHWIDTH_80P80MHZ; + + switch (chwidth) { + case 0: + case 20: + case 40: + return CONF_OPER_CHWIDTH_USE_HT; + case 80: + return CONF_OPER_CHWIDTH_80MHZ; + case 160: + return CONF_OPER_CHWIDTH_160MHZ; + case 320: + return CONF_OPER_CHWIDTH_320MHZ; + default: + wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d", + chwidth); + return -1; + } +} + + +struct wpabuf * ieee802_11_defrag(const u8 *data, size_t len, bool ext_elem) { struct wpabuf *buf; const u8 *pos, *end = data + len; @@ -2886,82 +3457,41 @@ struct wpabuf * ieee802_11_defrag_data(const u8 *data, size_t len, bool ext_elem return buf; } -#else -struct wpabuf * ieee802_11_defrag_data(const struct ieee802_11_elems *elems, - u8 eid, u8 eid_ext, - const u8 *data, u8 len) -{ - const struct frag_ies_info *frag_ies = &elems->frag_ies; - struct wpabuf *buf; - unsigned int i; - if (!elems || !data || !len) - return NULL; - buf = wpabuf_alloc_copy(data, len); - if (!buf) - return NULL; - - for (i = 0; i < frag_ies->n_frags; i++) { - int ret; - - if (frag_ies->frags[i].eid != eid || - frag_ies->frags[i].eid_ext != eid_ext) - continue; +const u8 * get_ml_ie(const u8 *ies, size_t len, u8 type) +{ + const struct element *elem; - ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len); - if (ret < 0) { - wpabuf_free(buf); - return NULL; - } + if (!ies) + return NULL; - /* Copy only the fragment data (without the EID and length) */ - wpabuf_put_data(buf, frag_ies->frags[i].ie, - frag_ies->frags[i].ie_len); + for_each_element_extid(elem, WLAN_EID_EXT_MULTI_LINK, ies, len) { + if (elem->datalen >= 2 && + (elem->data[1] & MULTI_LINK_CONTROL_TYPE_MASK) == type) + return &elem->id; } - return buf; + return NULL; } -#endif -struct wpabuf * ieee802_11_defrag(const struct ieee802_11_elems *elems, - u8 eid, u8 eid_ext) + +const u8 * get_basic_mle_mld_addr(const u8 *buf, size_t len) { - const u8 *data; - u8 len; + const size_t mld_addr_pos = + 2 /* Control field */ + + 1 /* Common Info Length field */; + const size_t fixed_len = mld_addr_pos + + ETH_ALEN /* MLD MAC Address field */; - /* - * TODO: Defragmentation mechanism can be supported for all IEs. For now - * handle only those that are used (or use ieee802_11_defrag_data()). - */ - switch (eid) { - case WLAN_EID_EXTENSION: - switch (eid_ext) { - case WLAN_EID_EXT_FILS_HLP_CONTAINER: - data = elems->fils_hlp; - len = elems->fils_hlp_len; - break; - case WLAN_EID_EXT_WRAPPED_DATA: - data = elems->wrapped_data; - len = elems->wrapped_data_len; - break; - default: - wpa_printf(MSG_DEBUG, - "Defragmentation not supported. eid_ext=%u", - eid_ext); - return NULL; - } - break; - default: - wpa_printf(MSG_DEBUG, - "Defragmentation not supported. eid=%u", eid); + if (len < fixed_len) return NULL; - } -#ifdef CONFIG_MLD_PATCH - return ieee802_11_defrag_data(data, len, true); -#else - return ieee802_11_defrag_data(elems, eid, eid_ext, data, len); -#endif + + if ((buf[0] & MULTI_LINK_CONTROL_TYPE_MASK) != + MULTI_LINK_CONTROL_TYPE_BASIC) + return NULL; + + return &buf[mld_addr_pos]; } static int parse_oh_ht_mcs_for_max_noss( @@ -3231,72 +3761,3 @@ enum chan_width get_oh_sta_oper_chan_width( } return ap_oper_chan_width; } -#ifdef CONFIG_MLD_PATCH -const u8 * get_ml_ie(const u8 *ies, size_t len, u8 type) -{ - const struct element *elem; - - if (!ies) - return NULL; - - for_each_element_extid(elem, WLAN_EID_EXT_MULTI_LINK, ies, len) { - if (elem->datalen >= 2 && - (elem->data[1] & MULTI_LINK_CONTROL_TYPE_MASK) == type) - return &elem->id; - } - - return NULL; -} - -const u8 * get_basic_mle_mld_addr(const u8 *buf, size_t len) -{ - const size_t mld_addr_pos = - 2 /* Control field */ + - 1 /* Common Info Length field */; - const size_t fixed_len = mld_addr_pos + - ETH_ALEN /* MLD MAC Address field */; - - if (len < fixed_len) - return NULL; - - if ((buf[0] & MULTI_LINK_CONTROL_TYPE_MASK) != - MULTI_LINK_CONTROL_TYPE_BASIC) - return NULL; - - return &buf[mld_addr_pos]; -} - -struct wpabuf * ieee802_11_defrag_mle(struct ieee802_11_elems *elems, u8 type) -{ - const u8 *data; - size_t len; - - switch (type) { - case MULTI_LINK_CONTROL_TYPE_BASIC: - data = elems->basic_mle; - len = elems->basic_mle_len; - break; - case MULTI_LINK_CONTROL_TYPE_PROBE_REQ: - data = elems->probe_req_mle; - len = elems->probe_req_mle_len; - break; - case MULTI_LINK_CONTROL_TYPE_RECONF: - data = elems->reconf_mle; - len = elems->reconf_mle_len; - break; - case MULTI_LINK_CONTROL_TYPE_TDLS: - data = elems->tdls_mle; - len = elems->tdls_mle_len; - break; - case MULTI_LINK_CONTROL_TYPE_PRIOR_ACCESS: - data = elems->prior_access_mle; - len = elems->prior_access_mle_len; - break; - default: - wpa_printf(MSG_DEBUG, "Defragmentation not supported for multilink element type=%u", type); - return NULL; - } - - return ieee802_11_defrag_data(data, len, true); -} -#endif \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/src/common/ieee802_11_common.h b/wpa_supplicant-2.9_standard/src/common/ieee802_11_common.h index 2f9b0c67a235ef637ed4935a1e3c5b06b9d5ebb7..5ba914ced34ffcdf8a731fd364a598da837ddc01 100644 --- a/wpa_supplicant-2.9_standard/src/common/ieee802_11_common.h +++ b/wpa_supplicant-2.9_standard/src/common/ieee802_11_common.h @@ -21,7 +21,6 @@ struct element { struct hostapd_hw_modes; #define MAX_NOF_MB_IES_SUPPORTED 5 -#define MAX_NUM_FRAG_IES_SUPPORTED 3 #define MAX_NOSS_RX_LENGTH 4 #define CHAN_CENTER_FREQ_VALUE 8 @@ -40,19 +39,10 @@ struct mb_ies_info { u8 nof_ies; }; -struct frag_ies_info { - struct { - u8 eid; - u8 eid_ext; - const u8 *ie; - u8 ie_len; - } frags[MAX_NUM_FRAG_IES_SUPPORTED]; - - u8 n_frags; - - /* the last parsed element ID and element extension ID */ - u8 last_eid; - u8 last_eid_ext; +struct multi_ap_params { + u8 capability; + u8 profile; + u16 vlanid; }; /* Parsed Information Elements */ @@ -80,7 +70,7 @@ struct ieee802_11_elems { const u8 *peer_mgmt; const u8 *vht_capabilities; const u8 *vht_operation; - const u8 *vht_opmode_notif; + const u8 *opmode_notif; const u8 *vendor_ht_cap; const u8 *vendor_vht; const u8 *p2p; @@ -131,7 +121,6 @@ struct ieee802_11_elems { const u8 *sae_pk; const u8 *s1g_capab; const u8 *pasn_params; -#ifdef CONFIG_MLD_PATCH const u8 *eht_capabilities; const u8 *eht_operation; const u8 *basic_mle; @@ -140,7 +129,8 @@ struct ieee802_11_elems { const u8 *tdls_mle; const u8 *prior_access_mle; const u8 *mbssid_known_bss; -#endif + const u8 *mbssid; + u8 ssid_len; u8 supp_rates_len; u8 challenge_len; @@ -178,18 +168,10 @@ struct ieee802_11_elems { u8 dils_len; u8 fils_req_params_len; u8 fils_key_confirm_len; -#ifdef CONFIG_MLD_PATCH size_t fils_hlp_len; -#else - u8 fils_hlp_len; -#endif u8 fils_ip_addr_assign_len; u8 key_delivery_len; -#ifdef CONFIG_MLD_PATCH size_t wrapped_data_len; -#else - u8 wrapped_data_len; -#endif u8 fils_pk_len; u8 owe_dh_len; u8 power_capab_len; @@ -202,7 +184,6 @@ struct ieee802_11_elems { u8 short_ssid_list_len; u8 sae_pk_len; u8 pasn_params_len; -#ifdef CONFIG_MLD_PATCH u8 eht_capabilities_len; u8 eht_operation_len; size_t basic_mle_len; @@ -211,9 +192,10 @@ struct ieee802_11_elems { size_t tdls_mle_len; size_t prior_access_mle_len; u8 mbssid_known_bss_len; -#endif + u8 mbssid_len; + struct mb_ies_info mb_ies; -#ifdef CONFIG_MLD_PATCH + size_t fte_defrag_len; /* @@ -221,9 +203,6 @@ struct ieee802_11_elems { * fragmented element. */ unsigned int num_frag_elems; -#else - struct frag_ies_info frag_ies; -#endif }; typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; @@ -231,6 +210,14 @@ typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, struct ieee802_11_elems *elems, int show_errors); +void ieee802_11_elems_clear_ids(struct ieee802_11_elems *elems, + const u8 *ids, size_t num); +void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems, + const u8 *ids, size_t num); +ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len, + struct ieee802_11_elems *elems, + struct wpabuf *mlbuf, + u8 link_id, bool show_errors); int ieee802_11_ie_count(const u8 *ies, size_t ies_len); struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len, u32 oui_type); @@ -261,14 +248,16 @@ 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, - int sec_channel, int vht, - u8 *op_class, u8 *channel); +enum hostapd_hw_mode +ieee80211_freq_to_channel_ext(unsigned int freq, int sec_channel, + enum oper_chan_width chanwidth, + u8 *op_class, u8 *channel); int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth, int sec_channel, u8 *op_class, u8 *channel); int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, u16 num_modes); int is_dfs_global_op_class(u8 op_class); +bool is_80plus_op_class(u8 op_class); enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht); int supp_rates_11b_only(struct ieee802_11_elems *elems); @@ -287,7 +276,7 @@ struct oper_class_map { u8 max_chan; u8 inc; enum { BW20, BW40PLUS, BW40MINUS, BW40, BW80, BW2160, BW160, BW80P80, - BW4320, BW6480, BW8640} bw; + BW320, BW4320, BW6480, BW8640} bw; enum { P2P_SUPP, NO_P2P_SUPP } p2p; }; @@ -306,7 +295,10 @@ const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type); size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len); -size_t add_multi_ap_ie(u8 *buf, size_t len, u8 value); +u16 check_multi_ap_ie(const u8 *multi_ap_ie, size_t multi_ap_len, + struct multi_ap_params *multi_ap); +size_t add_multi_ap_ie(u8 *buf, size_t len, + const struct multi_ap_params *multi_ap); struct country_op_class { u8 country_op_class; @@ -323,6 +315,10 @@ bool is_6ghz_op_class(u8 op_class); bool is_6ghz_psc_frequency(int freq); int get_6ghz_sec_channel(int channel); +bool is_same_band(int freq1, int freq2); +#define IS_2P4GHZ(n) (n >= 2412 && n <= 2484) +#define IS_5GHZ(n) (n > 4000 && n < 5895) + int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep, size_t nei_rep_len); @@ -331,7 +327,8 @@ bool ieee802_11_rsnx_capab_len(const u8 *rsnxe, size_t rsnxe_len, unsigned int capab); bool ieee802_11_rsnx_capab(const u8 *rsnxe, unsigned int capab); int op_class_to_bandwidth(u8 op_class); -int op_class_to_ch_width(u8 op_class); +enum oper_chan_width op_class_to_ch_width(u8 op_class); +int chwidth_freq2_to_ch_width(int chwidth, int freq2); /* element iteration helpers */ #define for_each_element(_elem, _data, _datalen) \ @@ -388,20 +385,10 @@ void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel, int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed, struct ieee80211_edmg_config requested); -#ifdef CONFIG_MLD_PATCH -struct wpabuf * ieee802_11_defrag_data(const u8 *data, size_t len, bool ext_elem); -#else -struct wpabuf * ieee802_11_defrag_data(const struct ieee802_11_elems *elems, - u8 eid, u8 eid_ext, - const u8 *data, u8 len); -#endif -struct wpabuf * ieee802_11_defrag(const struct ieee802_11_elems *elems, - u8 eid, u8 eid_ext); -#ifdef CONFIG_MLD_PATCH -struct wpabuf * ieee802_11_defrag_mle(struct ieee802_11_elems *elems, u8 type); + +struct wpabuf * ieee802_11_defrag(const u8 *data, size_t len, bool ext_elem); const u8 * get_ml_ie(const u8 *ies, size_t len, u8 type); const u8 * get_basic_mle_mld_addr(const u8 *buf, size_t len); -#endif int get_oh_max_noss_capa(struct ieee802_11_elems *elements, int parse_rx); diff --git a/wpa_supplicant-2.9_standard/src/common/ieee802_11_defs.h b/wpa_supplicant-2.9_standard/src/common/ieee802_11_defs.h index ea5f3b92d97252a4cb2648c6effc5834d812d63f..61056add1c16a14c29f9196b9daabb08318bffd8 100644 --- a/wpa_supplicant-2.9_standard/src/common/ieee802_11_defs.h +++ b/wpa_supplicant-2.9_standard/src/common/ieee802_11_defs.h @@ -24,6 +24,13 @@ #define WLAN_FC_ISWEP 0x4000 #define WLAN_FC_HTC 0x8000 +#define WLAN_FC_S1G_BEACON_NEXT_TBTT 0x0100 +#define WLAN_FC_S1G_BEACON_COMP_SSID 0x0200 +#define WLAN_FC_S1G_BEACON_ANO 0x0400 +#define WLAN_FC_S1G_BEACON_BSS_BW 0x3800 +#define WLAN_FC_S1G_BEACON_SECURITY 0x4000 +#define WLAN_FC_S1G_BEACON_AP_PM 0x8000 + #define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2) #define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4) @@ -36,6 +43,7 @@ #define WLAN_FC_TYPE_MGMT 0 #define WLAN_FC_TYPE_CTRL 1 #define WLAN_FC_TYPE_DATA 2 +#define WLAN_FC_TYPE_EXT 3 /* management */ #define WLAN_FC_STYPE_ASSOC_REQ 0 @@ -77,6 +85,10 @@ #define WLAN_FC_STYPE_QOS_CFPOLL 14 #define WLAN_FC_STYPE_QOS_CFACKPOLL 15 +/* extension */ +#define WLAN_FC_STYPE_DMG_BEACON 0 +#define WLAN_FC_STYPE_S1G_BEACON 1 + /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 @@ -107,7 +119,7 @@ #define WLAN_CAPABILITY_DELAYED_BLOCK_ACK BIT(14) #define WLAN_CAPABILITY_IMM_BLOCK_ACK BIT(15) -/* Status codes (IEEE Std 802.11-2016, 9.4.1.9, Table 9-46) */ +/* Status codes (IEEE Std 802.11-2020, 9.4.1.9, Table 9-50) */ #define WLAN_STATUS_SUCCESS 0 #define WLAN_STATUS_UNSPECIFIED_FAILURE 1 #define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2 @@ -209,9 +221,20 @@ #define WLAN_STATUS_DENIED_HE_NOT_SUPPORTED 124 #define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126 #define WLAN_STATUS_SAE_PK 127 +#define WLAN_STATUS_DENIED_STA_AFF_WITH_MLD_WITH_EXISTING_ASSOC 130 +#define WLAN_STATUS_EPCS_DENIED_UNAUTHORIZED 131 +#define WLAN_STATUS_EPCS_DENIED 132 +#define WLAN_STATUS_DENIED_TID_TO_LINK_MAPPING 133 +#define WLAN_STATUS_PREFERRED_TID_TO_LINK_MAPPING_SUGGESTED 134 +#define WLAN_STATUS_DENIED_EHT_NOT_SUPPORTED 135 +#define WLAN_STATUS_INVALID_PUBLIC_KEY 136 +#define WLAN_STATUS_PASN_BASE_AKMP_FAILED 137 +#define WLAN_STATUS_OCI_MISMATCH 138 #define WLAN_STATUS_DENIED_TX_LINK_NOT_ACCEPTED 139 +#define WLAN_STATUS_EPCS_DENIED_VERIFICATION_FAILURE 140 +#define WLAN_STATUS_DENIED_OPERATION_PARAMETER_UPDATE 141 -/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */ +/* Reason codes (IEEE Std 802.11-2020, 9.4.1.7, Table 9-90) */ #define WLAN_REASON_UNKNOWN 0 #define WLAN_REASON_UNSPECIFIED 1 #define WLAN_REASON_PREV_AUTH_NOT_VALID 2 @@ -276,7 +299,7 @@ #define WLAN_REASON_MESH_CHANNEL_SWITCH_UNSPECIFIED 66 -/* Information Element IDs (IEEE Std 802.11-2016, 9.4.2.1, Table 9-77) */ +/* Element IDs (IEEE Std 802.11-2020, 9.4.2.1, Table 9-92) */ #define WLAN_EID_SSID 0 #define WLAN_EID_SUPP_RATES 1 #define WLAN_EID_DS_PARAMS 3 @@ -437,13 +460,13 @@ #define WLAN_EID_ANTENNA_SECTOR_ID_PATTERN 190 #define WLAN_EID_VHT_CAP 191 #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_EXTENDED_BSS_LOAD 193 +#define WLAN_EID_WIDE_BW_CHSWITCH 194 #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 -#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199 +#define WLAN_EID_CHANNEL_SWITCH_WRAPPER 196 +#define WLAN_EID_AID 197 +#define WLAN_EID_QUIET_CHANNEL 198 +#define WLAN_EID_OPERATING_MODE_NOTIFICATION 199 #define WLAN_EID_UPSIM 200 #define WLAN_EID_REDUCED_NEIGHBOR_REPORT 201 #define WLAN_EID_TVHT_OPERATION 202 @@ -484,12 +507,11 @@ #define WLAN_EID_EXT_HE_OPERATION 36 #define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38 #define WLAN_EID_EXT_SPATIAL_REUSE 39 +#define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42 #define WLAN_EID_EXT_OCV_OCI 54 -#ifdef CONFIG_MLD_PATCH #define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55 #define WLAN_EID_EXT_NON_INHERITANCE 56 #define WLAN_EID_EXT_KNOWN_BSSID 57 -#endif #define WLAN_EID_EXT_SHORT_SSID_LIST 58 #define WLAN_EID_EXT_HE_6GHZ_BAND_CAP 59 #define WLAN_EID_EXT_EDMG_CAPABILITIES 61 @@ -499,15 +521,12 @@ #define WLAN_EID_EXT_REJECTED_GROUPS 92 #define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93 #define WLAN_EID_EXT_PASN_PARAMS 100 - -#ifdef CONFIG_MLD_PATCH #define WLAN_EID_EXT_EHT_OPERATION 106 #define WLAN_EID_EXT_MULTI_LINK 107 #define WLAN_EID_EXT_EHT_CAPABILITIES 108 #define WLAN_EID_EXT_TID_TO_LINK_MAPPING 109 #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110 #define WLAN_EID_EXT_QOS_CHARACTERISTICS 113 -#endif #define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114 /* Extended Capabilities field */ @@ -599,9 +618,14 @@ #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 +#define WLAN_RSNX_CAPAB_URNM_MFPR_X20 10 +#define WLAN_RSNX_CAPAB_URNM_MFPR 15 +#define WLAN_RSNX_CAPAB_SSID_PROTECTION 21 -/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */ +/* Multiple BSSID element subelements */ +#define WLAN_MBSSID_SUBELEMENT_NONTRANSMITTED_BSSID_PROFILE 0 + +/* Action frame categories (IEEE Std 802.11-2020, 9.4.1.11, Table 9-51) */ #define WLAN_ACTION_SPECTRUM_MGMT 0 #define WLAN_ACTION_QOS 1 #define WLAN_ACTION_DLS 2 @@ -624,17 +648,25 @@ #define WLAN_ACTION_ROBUST_AV_STREAMING 19 #define WLAN_ACTION_UNPROTECTED_DMG 20 #define WLAN_ACTION_VHT 21 -#define WLAN_ACTION_S1G 22 -#define WLAN_ACTION_S1G_RELAY 23 +#define WLAN_ACTION_UNPROTECTED_S1G 22 +#define WLAN_ACTION_S1G 23 #define WLAN_ACTION_FLOW_CONTROL 24 #define WLAN_ACTION_CTRL_RESP_MCS_NEG 25 #define WLAN_ACTION_FILS 26 +#define WLAN_ACTION_CDMG 27 +#define WLAN_ACTION_CMMG 28 +#define WLAN_ACTION_GLK 29 +#define WLAN_ACTION_HE 30 +#define WLAN_ACTION_PROTECTED_HE 31 +#define WLAN_ACTION_WUR 32 #define WLAN_ACTION_PROTECTED_FTM 34 +#define WLAN_ACTION_EHT 36 +#define WLAN_ACTION_PROTECTED_EHT 37 #define WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED 126 #define WLAN_ACTION_VENDOR_SPECIFIC 127 /* Note: 128-255 used to report errors by setting category | 0x80 */ -/* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */ +/* Public action codes (IEEE Std 802.11-2020, 9.6.7.1, Table 9-364) */ #define WLAN_PA_20_40_BSS_COEX 0 #define WLAN_PA_DSE_ENABLEMENT 1 #define WLAN_PA_DSE_DEENABLEMENT 2 @@ -672,8 +704,21 @@ #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) */ +/* HT Action field values (IEEE P802.11-REVme/D4.0, 9.6.11.1, Table 9-491) */ +#define WLAN_HT_ACTION_NOTIFY_CHANWIDTH 0 +#define WLAN_HT_ACTION_SMPS 1 +#define WLAN_HT_ACTION_CSI 4 +#define WLAN_HT_ACTION_NONCOMPRESSED_BF 5 +#define WLAN_HT_ACTION_COMPRESSED_BF 6 +#define WLAN_HT_ACTION_ASEL_IDX_FEEDBACK 7 + +/* VHT Action field values (IEEE P802.11-REVme/D4.0, 9.6.22.1, Table 9-579) */ +#define WLAN_VHT_ACTION_COMPRESSED_BF 0 +#define WLAN_VHT_ACTION_GROUP_ID_MGMT 1 +#define WLAN_VHT_ACTION_OPMODE_NOTIF 2 + +/* Protected Dual of Public Action frames (IEEE Std 802.11-2020, 9.6.10, + * Table 9-404) */ #define WLAN_PROT_DSE_ENABLEMENT 1 #define WLAN_PROT_DSE_DEENABLEMENT 2 #define WLAN_PROT_EXT_CSA 4 @@ -701,7 +746,7 @@ #define WLAN_PROT_NETWORK_CHANNEL_CONTROL 30 #define WLAN_PROT_WHITE_SPACE_MAP_ANNOUNCEMENT 31 -/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ +/* SA Query Action frame (IEEE Std 802.11-2020, 9.6.9) */ #define WLAN_SA_QUERY_REQUEST 0 #define WLAN_SA_QUERY_RESPONSE 1 @@ -734,7 +779,7 @@ #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 */ + * IEEE Std 802.11-2020, 9.4.2.44, Table 9-179 */ /* byte 1 (out of 5) */ #define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0) #define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1) @@ -747,8 +792,8 @@ #define WLAN_RRM_CAPS_FTM_RANGE_REPORT BIT(2) /* - * IEEE P802.11-REVmc/D5.0, 9.4.2.21.19 (Fine Timing Measurement Range - * request) - Minimum AP count + * IEEE Std 802.11-2020, 9.4.2.20.19 (Fine Timing Measurement Range + * request) - Minimum AP Count */ #define WLAN_RRM_RANGE_REQ_MAX_MIN_AP 15 @@ -757,7 +802,8 @@ #define WLAN_TIMEOUT_KEY_LIFETIME 2 #define WLAN_TIMEOUT_ASSOC_COMEBACK 3 -/* Interworking element (IEEE 802.11u) - Access Network Options */ +/* Interworking element (IEEE Std 802.11-2020, 9.4.2.91) - + * Access Network Options */ #define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f #define INTERWORKING_ANO_INTERNET 0x10 #define INTERWORKING_ANO_ASRA 0x20 @@ -773,7 +819,7 @@ #define INTERWORKING_ANT_TEST 6 #define INTERWORKING_ANT_WILDCARD 15 -/* Advertisement Protocol ID definitions (IEEE Std 802.11-2016, Table 9-215) */ +/* Advertisement Protocol ID definitions (IEEE Std 802.11-2020, Table 9-237) */ enum adv_proto_id { ACCESS_NETWORK_QUERY_PROTOCOL = 0, MIH_INFO_SERVICE = 1, @@ -783,8 +829,7 @@ enum adv_proto_id { ADV_PROTO_VENDOR_SPECIFIC = 221 }; -/* Access Network Query Protocol info ID definitions (IEEE Std 802.11-2016, - * Table 9-271; P802.11ai) */ +/* ANQP-element definitions (IEEE Std 802.11-2020, Table 9-331) */ enum anqp_info_id { ANQP_QUERY_LIST = 256, ANQP_CAPABILITY_LIST = 257, @@ -859,7 +904,7 @@ enum nai_realm_eap_cred_type { #define S1G_ACT_TWT_INFORMATION 11 /* - * IEEE P802.11-REVmc/D5.0 Table 9-81 - Measurement type definitions for + * IEEE Std 802.11-2020, Table 9-98 - Measurement type definitions for * measurement requests */ enum measure_type { @@ -883,7 +928,7 @@ enum measure_type { MEASURE_TYPE_MEASURE_PAUSE = 255, }; -/* IEEE Std 802.11-2012 Table 8-71 - Location subject definition */ +/* IEEE Std 802.11-2020, Table 9-110 - Location Subject field definition */ enum location_subject { LOCATION_SUBJECT_LOCAL = 0, LOCATION_SUBJECT_REMOTE = 1, @@ -891,7 +936,7 @@ enum location_subject { }; /* - * IEEE P802.11-REVmc/D5.0 Table 9-94 - Optional subelement IDs for LCI request + * IEEE Std 802.11-2020, Table 9-111 - Optional subelement IDs for LCI request */ enum lci_req_subelem { LCI_REQ_SUBELEM_AZIMUTH_REQ = 1, @@ -926,6 +971,23 @@ struct ieee80211_hdr { #define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr)) +struct ieee80211_hdr_s1g_beacon { + le16 frame_control; + le16 duration_id; + u8 sa[6]; + u8 timestamp[4]; + u8 change_seq[1]; + /* followed by: + * 'u8 next_tbtt[3];' if the Next TBTT Present field in the + * Frame Control field is 1 + * 'u8 compressed_ssid[4];' if the Compressed SSID Present field in + * the Frame Control is 1 + * 'u8 ano[1];' if the ANO field in the Frame Control field is 1 + */ +} STRUCT_PACKED; + +#define IEEE80211_HDRLEN_S1G_BEACON (sizeof(struct ieee80211_hdr_s1g_beacon)) + #define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) struct ieee80211_mgmt { @@ -1185,9 +1247,6 @@ struct ieee80211_ampe_ie { */ } STRUCT_PACKED; -#ifdef _MSC_VER -#pragma pack(pop) -#endif /* _MSC_VER */ #define ERP_INFO_NON_ERP_PRESENT BIT(0) #define ERP_INFO_USE_PROTECTION BIT(1) @@ -1294,9 +1353,12 @@ struct ieee80211_ampe_ie { #define HT_OPER_PARAM_PCO_PHASE ((u16) BIT(11)) /* B36..B39 - Reserved */ +#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122 +#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY 123 +#define BSS_MEMBERSHIP_SELECTOR_EPD 124 +#define BSS_MEMBERSHIP_SELECTOR_GLK 125 #define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 -#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY 123 /* VHT Defines */ #define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0)) @@ -1354,16 +1416,15 @@ struct ieee80211_ampe_ie { #define VHT_RX_NSS_MAX_STREAMS 8 -/* VHT/EDMG channel widths */ +#define VHT_OPMODE_CHANNEL_40MHZ ((u8) BIT(0)) +#define VHT_OPMODE_CHANNEL_80MHZ ((u8) BIT(1)) +#define VHT_OPMODE_CHANNEL_160MHZ ((u8) BIT(1) | BIT(2)) + +/* VHT operation information - channel widths */ #define CHANWIDTH_USE_HT 0 #define CHANWIDTH_80MHZ 1 #define CHANWIDTH_160MHZ 2 #define CHANWIDTH_80P80MHZ 3 -#define CHANWIDTH_2160MHZ 4 -#define CHANWIDTH_4320MHZ 5 -#define CHANWIDTH_6480MHZ 6 -#define CHANWIDTH_8640MHZ 7 -#define CHANWIDTH_40MHZ_6GHZ 8 #define HE_NSS_MAX_STREAMS 8 @@ -1378,7 +1439,11 @@ struct ieee80211_ampe_ie { #define WFD_OUI_TYPE 10 #define HS20_IE_VENDOR_TYPE 0x506f9a10 #define OSEN_IE_VENDOR_TYPE 0x506f9a12 +#define NAN_IE_VENDOR_TYPE 0x506f9a13 +#define NAN_SDF_VENDOR_TYPE 0x506f9a13 +#define NAN_OUI_TYPE 0x13 #define MBO_IE_VENDOR_TYPE 0x506f9a16 +#define NAN_NAF_VENDOR_TYPE 0x506f9a18 #define MBO_OUI_TYPE 22 #define OWE_IE_VENDOR_TYPE 0x506f9a1c #define OWE_OUI_TYPE 28 @@ -1393,11 +1458,20 @@ struct ieee80211_ampe_ie { #define WFA_CAPA_OUI_TYPE 0x23 #define MULTI_AP_SUB_ELEM_TYPE 0x06 +#define MULTI_AP_PROFILE_SUB_ELEM_TYPE 0x07 +#define MULTI_AP_VLAN_SUB_ELEM_TYPE 0x08 + +#define MULTI_AP_PROFILE2_BACKHAUL_STA_DISALLOWED BIT(2) +#define MULTI_AP_PROFILE1_BACKHAUL_STA_DISALLOWED BIT(3) #define MULTI_AP_TEAR_DOWN BIT(4) #define MULTI_AP_FRONTHAUL_BSS BIT(5) #define MULTI_AP_BACKHAUL_BSS BIT(6) #define MULTI_AP_BACKHAUL_STA BIT(7) +#define MULTI_AP_PROFILE_1 1 +#define MULTI_AP_PROFILE_2 2 +#define MULTI_AP_PROFILE_MAX 6 + #define WMM_OUI_TYPE 2 #define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0 #define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1 @@ -1864,8 +1938,9 @@ enum wnm_action { #define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2) #define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3) #define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4) +#define WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT BIT(5) -/* IEEE Std 802.11-2012 - Table 8-253 */ +/* IEEE Std 802.11-2020, Table 9-428 (BTM status code definitions) */ enum bss_trans_mgmt_status_code { WNM_BSS_TM_ACCEPT = 0, WNM_BSS_TM_REJECT_UNSPECIFIED = 1, @@ -1878,9 +1953,36 @@ enum bss_trans_mgmt_status_code { WNM_BSS_TM_REJECT_LEAVING_ESS = 8 }; +/* BSS transition management reasons + * IEEE Std 802.11-2020, Table 9-198 (Transition and Transition Query reasons) + */ +enum bss_trans_mgmt_reason { + WNM_TRANSITION_REASON_UNSPECIFIED = 0, + WNM_TRANSITION_REASON_EXCESSIVE_FRAME_LOSS = 1, + WNM_TRANSITION_REASON_EXCESSIVE_DELAY = 2, + WNM_TRANSITION_REASON_INSUFFICIENT_QOS = 3, + WNM_TRANSITION_REASON_FIRST_ESS_ASSOC = 4, + WNM_TRANSITION_REASON_LOAD_BALANCING = 5, + WNM_TRANSITION_REASON_BETTER_AP_FOUND = 6, + WNM_TRANSITION_REASON_DEAUTH_FROM_PREV_AP = 7, + WNM_TRANSITION_REASON_AP_FAILED_EAP = 8, + WNM_TRANSITION_REASON_AP_FAILED_4WAY_HS = 9, + WNM_TRANSITION_REASON_RX_TOO_MANY_REPLAYS = 10, + WNM_TRANSITION_REASON_RX_TOO_MANY_MIC_FAILURES = 11, + WNM_TRANSITION_REASON_EXCEEDED_MAX_RETRANS = 12, + WNM_TRANSITION_REASON_RX_TOO_MANY_BC_DISASSOC = 13, + WNM_TRANSITION_REASON_RX_TOO_MANY_BC_DEAUTH = 14, + WNM_TRANSITION_REASON_PREV_TRANSITION_FAILED = 15, + WNM_TRANSITION_REASON_LOW_RSSI = 16, + WNM_TRANSITION_REASON_ROAM_FROM_NON_802_11 = 17, + WNM_TRANSITION_REASON_TRANSITION_DUE_TO_BTM_REQ = 18, + WNM_TRANSITION_REASON_PREF_TRANSITION_CANDIDATE_LIST = 19, + WNM_TRANSITION_REASON_LEAVING_ESS = 20, +}; + /* - * IEEE P802.11-REVmc/D5.0 Table 9-150 - Optional subelement IDs for - * neighbor report + * IEEE Std 802.11-2020, Table 9-173 - Optional subelement IDs for + * Neighbor Report */ #define WNM_NEIGHBOR_TSF 1 #define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING 2 @@ -1907,7 +2009,7 @@ enum qos_action { QOS_QOS_MAP_CONFIG = 4, }; -/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */ +/* IEEE Std 802.11-2020, 9.4.2.59 (20/40 BSS Coexistence element) */ #define WLAN_20_40_BSS_COEX_INFO_REQ BIT(0) #define WLAN_20_40_BSS_COEX_40MHZ_INTOL BIT(1) #define WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ BIT(2) @@ -1955,13 +2057,49 @@ enum wnm_sleep_mode_subelement_id { WNM_SLEEP_SUBELEM_BIGTK = 2, }; -/* WNM notification type (IEEE P802.11-REVmd/D3.0, Table 9-430) */ +/* WNM notification type (IEEE Std 802.11-2020, Table 9-431) */ enum wnm_notification_Type { WNM_NOTIF_TYPE_FIRMWARE_UPDATE = 0, WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE = 2, WNM_NOTIF_TYPE_VENDOR_SPECIFIC = 221, }; +struct wnm_event_report_element { + u8 eid; /* WLAN_EID_EVENT_REPORT */ + u8 len; + u8 token; + u8 type; + u8 status; + /* Followed by conditional fields */ + union { + struct { + u8 tsf[8]; /* Event TSF */ + u8 color_bitmap[8]; /* Event Report field */ + } STRUCT_PACKED bss_color_collision; + struct { + u8 tsf[8]; /* Event TSF */ + u8 color; /* Event Report field */ + } STRUCT_PACKED bss_color_in_use; + } u; +} STRUCT_PACKED; + +enum wnm_event_report_status { + WNM_STATUS_SUCCESSFUL = 0, + WNM_STATUS_REQ_FAILED = 1, + WNM_STATUS_REQ_REFUSED = 2, + WNM_STATUS_REQ_INCAPABLE = 3, + WNM_STATUS_FREQUENT_TRANSITION = 4, +}; + +enum wnm_event_report_type { + WNM_EVENT_TYPE_TRANSITION = 0, + WNM_EVENT_TYPE_RSNA = 1, + WNM_EVENT_TYPE_P2P_LINK = 2, + WNM_EVENT_TYPE_WNM_LOG = 3, + WNM_EVENT_TYPE_BSS_COLOR_COLLISION = 4, + WNM_EVENT_TYPE_BSS_COLOR_IN_USE = 5, +}; + /* Channel Switch modes (802.11h) */ #define CHAN_SWITCH_MODE_ALLOW_TX 0 #define CHAN_SWITCH_MODE_BLOCK_TX 1 @@ -1973,9 +2111,29 @@ struct tpc_report { u8 link_margin; } STRUCT_PACKED; +/* + * IEEE Std 802.11ax-2021, Table 9-275a - Maximum Transmit Power + * Interpretation subfield encoding + */ +enum max_tx_pwr_interpretation { + LOCAL_EIRP = 0, + LOCAL_EIRP_PSD = 1, + REGULATORY_CLIENT_EIRP = 2, + REGULATORY_CLIENT_EIRP_PSD = 3, +}; + +/* + * IEEE Std 802.11ax-2021, Table E-13 - Maximum Transmit Power + * Category subfield encoding in the United States + */ +enum reg_6g_client_type { + REG_DEFAULT_CLIENT = 0, + REG_SUBORDINATE_CLIENT = 1, +}; + #define RRM_CAPABILITIES_IE_LEN 5 -/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */ +/* IEEE Std 802.11-2020, 9.6.6.4 - Link Measurement Request frame format */ struct rrm_link_measurement_request { u8 dialog_token; s8 tx_power; @@ -1983,7 +2141,7 @@ struct rrm_link_measurement_request { u8 variable[0]; } STRUCT_PACKED; -/* IEEE Std 802.11-2012, 8.5.7.5 - Link Measurement Report frame format */ +/* IEEE Std 802.11-2020, 9.6.6.5 - Link Measurement Report frame format */ struct rrm_link_measurement_report { u8 dialog_token; struct tpc_report tpc; @@ -1994,7 +2152,7 @@ struct rrm_link_measurement_report { u8 variable[0]; } STRUCT_PACKED; -/* IEEE Std 802.11-2016, 9.4.2.21 - Measurement Request element */ +/* IEEE Std 802.11-2020, 9.4.2.20 - Measurement Request element */ struct rrm_measurement_request_element { u8 eid; /* Element ID */ u8 len; /* Length */ @@ -2004,14 +2162,14 @@ struct rrm_measurement_request_element { u8 variable[0]; /* Measurement Request */ } STRUCT_PACKED; -/* IEEE Std 802.11-2016, Figure 9-148 - Measurement Request Mode field */ +/* IEEE Std 802.11-2020, Figure 9-180 - Measurement Request Mode field format */ #define MEASUREMENT_REQUEST_MODE_PARALLEL BIT(0) #define MEASUREMENT_REQUEST_MODE_ENABLE BIT(1) #define MEASUREMENT_REQUEST_MODE_REQUEST BIT(2) #define MEASUREMENT_REQUEST_MODE_REPORT BIT(3) #define MEASUREMENT_REQUEST_MODE_DURATION_MANDATORY BIT(4) -/* IEEE Std 802.11-2016, 9.4.2.21.7 - Beacon request */ +/* IEEE Std 802.11-2020, 9.4.2.20.7 - Beacon request */ struct rrm_measurement_beacon_request { u8 oper_class; /* Operating Class */ u8 channel; /* Channel Number */ @@ -2023,7 +2181,7 @@ struct rrm_measurement_beacon_request { } STRUCT_PACKED; /* - * IEEE Std 802.11-2016, Table 9-87 - Measurement Mode definitions for Beacon + * IEEE Std 802.11-2020, Table 9-103 - Measurement Mode definitions for Beacon * request */ enum beacon_report_mode { @@ -2032,20 +2190,19 @@ enum beacon_report_mode { BEACON_REPORT_MODE_TABLE = 2, }; -/* IEEE Std 802.11-2016, Table 9-88 - Beacon Request subelement IDs */ -/* IEEE P802.11-REVmd/D2.0, Table 9-106 - Optional subelement IDs for +/* IEEE Std 802.11-2020, Table 9-104 - Optional subelement IDs for * Beacon request */ #define WLAN_BEACON_REQUEST_SUBELEM_SSID 0 #define WLAN_BEACON_REQUEST_SUBELEM_INFO 1 /* Beacon Reporting */ #define WLAN_BEACON_REQUEST_SUBELEM_DETAIL 2 /* Reporting Detail */ #define WLAN_BEACON_REQUEST_SUBELEM_REQUEST 10 +#define WLAN_BEACON_REQUEST_SUBELEM_EXT_REQUEST 11 #define WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL 51 /* AP Channel Report */ +#define WLAN_BEACON_REQUEST_SUBELEM_WIDE_BW_CS 163 #define WLAN_BEACON_REQUEST_SUBELEM_LAST_INDICATION 164 #define WLAN_BEACON_REQUEST_SUBELEM_VENDOR 221 -/* - * IEEE Std 802.11-2016, Table 9-90 - Reporting Detail values - */ +/* IEEE Std 802.11-2020, Table 9-106 - Reporting Detail values */ enum beacon_report_detail { /* No fixed-length fields or elements */ BEACON_REPORT_DETAIL_NONE = 0, @@ -2057,7 +2214,7 @@ enum beacon_report_detail { BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS = 2, }; -/* IEEE Std 802.11-2016, 9.4.2.22 - Measurement Report element */ +/* IEEE Std 802.11-2020, 9.4.2.21 - Measurement Report element */ struct rrm_measurement_report_element { u8 eid; /* Element ID */ u8 len; /* Length */ @@ -2067,13 +2224,13 @@ struct rrm_measurement_report_element { u8 variable[0]; /* Measurement Report */ } STRUCT_PACKED; -/* IEEE Std 802.11-2016, Figure 9-192 - Measurement Report Mode field */ +/* IEEE Std 802.11-2020, Figure 9-223 - Measurement Report Mode field */ #define MEASUREMENT_REPORT_MODE_ACCEPT 0 #define MEASUREMENT_REPORT_MODE_REJECT_LATE BIT(0) #define MEASUREMENT_REPORT_MODE_REJECT_INCAPABLE BIT(1) #define MEASUREMENT_REPORT_MODE_REJECT_REFUSED BIT(2) -/* IEEE Std 802.11-2016, 9.4.2.22.7 - Beacon report */ +/* IEEE Std 802.11-2020, 9.4.2.21.7 - Beacon report */ struct rrm_measurement_beacon_report { u8 op_class; /* Operating Class */ u8 channel; /* Channel Number */ @@ -2089,27 +2246,27 @@ struct rrm_measurement_beacon_report { u8 variable[0]; /* Optional Subelements */ } STRUCT_PACKED; -/* IEEE Std 802.11-2016, Table 9-112 - Beacon report Subelement IDs */ -/* IEEE P802.11-REVmd/D2.0, Table 9-130 - Optional subelement IDs for +/* IEEE Std 802.11-2020, Table 9-130 - Optional subelement IDs for * Beacon report */ #define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY 1 #define WLAN_BEACON_REPORT_SUBELEM_FRAME_BODY_FRAGMENT_ID 2 +#define WLAN_BEACON_REPORT_SUBELEM_WID_BW_CS 163 #define WLAN_BEACON_REPORT_SUBELEM_LAST_INDICATION 164 #define WLAN_BEACON_REPORT_SUBELEM_VENDOR 221 -/* IEEE P802.11-REVmd/D2.0, Table 9-232 - Data field format of the - * Reported Frame Body Fragment ID subelement */ +/* IEEE Std 802.11-2020, Table 9-232 - Data field format (of the + * Reported Frame Body Fragment ID subelement) */ #define REPORTED_FRAME_BODY_SUBELEM_LEN 4 #define REPORTED_FRAME_BODY_MORE_FRAGMENTS BIT(7) -/* IEEE P802.11-REVmd/D2.0, 9.4.2.21.7 - Beacon report */ +/* IEEE Std 802.11-2020, 9.4.2.21.7 - Beacon report */ #define BEACON_REPORT_LAST_INDICATION_SUBELEM_LEN 3 #ifdef CONFIG_VENDOR_EXT #define MAX_AP_VENDOR_INFO_LEN 150 #endif /* CONFIG_VENDOR_EXT */ -/* IEEE Std 802.11ad-2012 - Multi-band element */ +/* IEEE Std 802.11-2020, 9.4.2.138 - Multi-band element */ struct multi_band_ie { u8 eid; /* WLAN_EID_MULTI_BAND */ u8 len; @@ -2155,7 +2312,7 @@ enum mb_band_id { #define MB_CONNECTION_CAPABILITY_TDLS ((u8) (BIT(3))) #define MB_CONNECTION_CAPABILITY_IBSS ((u8) (BIT(4))) -/* IEEE Std 802.11ad-2014 - FST Action field */ +/* IEEE Std 802.11-2020, Table 9-479 - FST Action field values */ enum fst_action { FST_ACTION_SETUP_REQUEST = 0, FST_ACTION_SETUP_RESPONSE = 1, @@ -2165,21 +2322,23 @@ enum fst_action { FST_ACTION_ON_CHANNEL_TUNNEL = 5, }; -/* IEEE Std 802.11ac-2013, Annex C - dot11PHYType */ +/* IEEE Std 802.11-2020, Annex C - dot11PHYType */ enum phy_type { PHY_TYPE_UNSPECIFIED = 0, - PHY_TYPE_FHSS = 1, PHY_TYPE_DSSS = 2, - PHY_TYPE_IRBASEBAND = 3, PHY_TYPE_OFDM = 4, PHY_TYPE_HRDSSS = 5, PHY_TYPE_ERP = 6, PHY_TYPE_HT = 7, PHY_TYPE_DMG = 8, PHY_TYPE_VHT = 9, + PHY_TYPE_TVHT = 10, + PHY_TYPE_S1G = 11, + PHY_TYPE_CDMG = 12, + PHY_TYPE_CMMG = 13, }; -/* IEEE P802.11-REVmd/D3.0, 9.4.2.36 - Neighbor Report element */ +/* IEEE Std 802.11-2020, 9.4.2.36 - Neighbor Report element */ /* BSSID Information Field */ #define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0) #define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1) @@ -2197,9 +2356,10 @@ enum phy_type { #define NEI_REP_BSSID_INFO_VHT BIT(12) #define NEI_REP_BSSID_INFO_FTM BIT(13) #define NEI_REP_BSSID_INFO_HE BIT(14) +#define NEI_REP_BSSID_INFO_EHT BIT(21) /* - * IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information + * IEEE Std 802.11-2020, Table 9-175 - HT/VHT Operation Information * subfields. * Note: These definitions are not the same as other CHANWIDTH_*. */ @@ -2218,7 +2378,7 @@ struct ieee80211_he_capabilities { le16 rx_map; le16 tx_map; } he_basic_supported_mcs_set; - /* Followed by 0, 4, or 8 octets of optional supported HE-MCS And NSS Set field + /* Followed by 4, 8, or 12 octets of Supported HE-MCS And NSS Set field * and optional variable length PPE Thresholds field. */ u8 optional[33]; } STRUCT_PACKED; @@ -2233,7 +2393,7 @@ struct ieee80211_he_operation { * Operation Information subfield (5 octets). */ } STRUCT_PACKED; -/* IEEE P802.11ax/D6.0, Figure 9-787k - 6 GHz Operation Information field */ +/* IEEE Std 802.11ax-2021, Figure 9-788k - 6 GHz Operation Information field */ struct ieee80211_he_6ghz_oper_info { u8 primary_chan; u8 control; @@ -2242,15 +2402,22 @@ struct ieee80211_he_6ghz_oper_info { u8 min_rate; } STRUCT_PACKED; +/* IEEE Std 802.11ax-2021, Figure 9-788l - Control field format */ #define HE_6GHZ_OPER_INFO_CTRL_CHAN_WIDTH_MASK (BIT(0) | BIT(1)) #define HE_6GHZ_OPER_INFO_CTRL_DUP_BEACON BIT(2) +#define HE_6GHZ_OPER_INFO_CTRL_REG_INFO_MASK (BIT(3) | BIT(4) | BIT(5)) +#define HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT 3 -/* IEEE P802.11ax/D6.0, 9.4.2.261 HE 6 GHz Band Capabilities element */ +/* IEEE Std 802.11ax-2021, 9.4.2.263 HE 6 GHz Band Capabilities element */ struct ieee80211_he_6ghz_band_cap { /* Minimum MPDU Start Spacing B0..B2 * Maximum A-MPDU Length Exponent B3..B5 - * Maximum MPDU Length B6..B7 */ - le16 capab; + * Maximum MPDU Length B6..B7 + * SM Power Save B9..B10 + * RD Responder B11 + * Rx Antenna Pattern Consistency B12 + * Tx Antenna Consistency B13 */ + le16 capab; /* Capabilities Information field */ } STRUCT_PACKED; #define HE_6GHZ_BAND_CAP_MIN_MPDU_START (BIT(0) | BIT(1) | BIT(2)) @@ -2276,7 +2443,7 @@ struct ieee80211_he_6ghz_band_cap { #define HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS BIT(13) /* - * IEEE P802.11ax/D4.0, 9.4.2.246 Spatial Reuse Parameter Set element + * IEEE Std 802.11ax-2021, 9.4.2.252 Spatial Reuse Parameter Set element */ struct ieee80211_spatial_reuse { u8 sr_ctrl; /* SR Control */ @@ -2346,12 +2513,40 @@ struct ieee80211_6ghz_oper_information { #define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30)) #define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31)) #define HE_OPERATION_BSS_COLOR_OFFSET 24 +#define HE_OPERATION_BSS_COLOR_MAX 64 /* HE operation fields length*/ #define HE_OPERATION_IE_MIN_LEN 6 #define HE_OPERATION_VHT_OPER_INFO_LEN 3 #define HE_OPERATION_COHOSTED_BSSID_INDICATOR_LEN 1 #define HE_OPERATION_6GHZ_OPER_INFO_LEN 5 + +/** + * enum he_reg_info_6ghz_ap_type - Allowed Access Point types for 6 GHz Band + * + * IEEE P802.11-REVme/D4.0, Table E-12 (Regulatory Info subfield encoding) + */ +enum he_reg_info_6ghz_ap_type { + HE_REG_INFO_6GHZ_AP_TYPE_INDOOR = 0, + HE_REG_INFO_6GHZ_AP_TYPE_SP = 1, + HE_REG_INFO_6GHZ_AP_TYPE_VLP = 2, + HE_REG_INFO_6GHZ_AP_TYPE_INDOOR_ENABLED = 3, + HE_REG_INFO_6GHZ_AP_TYPE_INDOOR_SP = 4, + HE_REG_INFO_6GHZ_AP_TYPE_MAX = HE_REG_INFO_6GHZ_AP_TYPE_INDOOR_SP, +}; + +static inline bool he_reg_is_indoor(enum he_reg_info_6ghz_ap_type type) +{ + return type == HE_REG_INFO_6GHZ_AP_TYPE_INDOOR || + type == HE_REG_INFO_6GHZ_AP_TYPE_INDOOR_SP; +} + +static inline bool he_reg_is_sp(enum he_reg_info_6ghz_ap_type type) +{ + return type == HE_REG_INFO_6GHZ_AP_TYPE_SP || + type == HE_REG_INFO_6GHZ_AP_TYPE_INDOOR_SP; +} + /* Spatial Reuse defines */ #define SPATIAL_REUSE_SRP_DISALLOWED BIT(0) #define SPATIAL_REUSE_NON_SRG_OBSS_PD_SR_DISALLOWED BIT(1) @@ -2401,12 +2596,14 @@ struct ieee80211_he_mu_edca_parameter_set { */ #define RNR_HEADER_LEN 2 #define RNR_TBTT_HEADER_LEN 4 +#define RNR_TBTT_INFO_HDR_TYPE_MSK 0x03 +#define RNR_TBTT_INFO_HDR_FILTERED_AP 0x04 +#define RNR_TBTT_INFO_HDR_CNT_MSK 0xf0 #define RNR_TBTT_INFO_COUNT(x) (((x) & 0xf) << 4) #define RNR_TBTT_INFO_COUNT_MAX 16 +#define RNR_TBTT_INFO_COUNT_VAL(x) (((x) & 0xf0) >> 4) #define RNR_TBTT_INFO_LEN 13 -#ifdef CONFIG_MLD_PATCH #define RNR_TBTT_INFO_MLD_LEN 16 -#endif #define RNR_NEIGHBOR_AP_OFFSET_UNKNOWN 255 /* Figure 9-632a - BSS Parameters subfield format */ #define RNR_BSS_PARAM_OCT_RECOMMENDED BIT(0) @@ -2416,8 +2613,19 @@ struct ieee80211_he_mu_edca_parameter_set { #define RNR_BSS_PARAM_MEMBER_CO_LOCATED_ESS BIT(4) #define RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE BIT(5) #define RNR_BSS_PARAM_CO_LOCATED BIT(6) -#define RNR_20_MHZ_PSD_MAX_TXPOWER 255 /* dBm */ -#ifdef CONFIG_MLD_PATCH +/* Maximum transmit power in Y/2 dBm (-127..126); 127 indicates no maximum + * transmit power is specified for the corresponding 20 MHz channel. */ +#define RNR_20_MHZ_PSD_MAX_TXPOWER 127 + +/* IEEE P802.11be/D5.0, Figure 9-704c - MLD Parameters subfield format */ +/* B0..B7: AP MLD ID */ +/* B8..B11: Link ID */ +/* B12..B19: BSS Parameters Change Count */ +/* B20: All Updates Included */ +#define RNR_TBTT_INFO_MLD_PARAM2_ALL_UPDATE_INC 0x10 +/* B21: Disabled Link Indication */ +#define RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED 0x20 + /* IEEE P802.11be/D2.3, 9.4.2.311 - EHT Operation element */ #define EHT_OPERATION_IE_MIN_LEN 1 @@ -2691,7 +2899,6 @@ enum ieee80211_eht_ml_sub_elem { EHT_ML_SUB_ELEM_VENDOR = 221, EHT_ML_SUB_ELEM_FRAGMENT = 254, }; -#endif /* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */ #define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6 @@ -2745,7 +2952,6 @@ enum scs_request_type { SCS_REQ_CHANGE = 2, }; -#ifdef CONFIG_MLD_PATCH /* * IEEE P802.11be/D4.0, 9.4.2.316 QoS Characteristics element, * Table 9-404s (Direction subfield encoding) @@ -2778,7 +2984,6 @@ enum scs_direction { #define SCS_QOS_BIT_MSDU_LIFETIME ((u16) BIT(5)) #define SCS_QOS_BIT_MSDU_DELIVERY_INFO ((u16) BIT(6)) #define SCS_QOS_BIT_MEDIUM_TIME ((u16) BIT(7)) -#endif /* Optional subelement IDs for MSCS Descriptor element */ enum mscs_description_subelem { @@ -2786,8 +2991,8 @@ enum mscs_description_subelem { }; /* - * IEEE Std 802.11ai-2016, 9.6.8.36 FILS Discovery frame format, - * Figure 9-687b - FILS Discovery Frame Control subfield format + * IEEE Std 802.11-2020, 9.6.7.36 FILS Discovery frame format, + * Figure 9-900 - 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)) @@ -2800,8 +3005,8 @@ enum mscs_description_subelem { #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 + * IEEE Std 802.11-2020, 9.6.7.36 FILS Discovery frame format, + * Figure 9-901 - FD Capability subfield format */ #define FD_CAP_ESS BIT(0) #define FD_CAP_PRIVACY BIT(1) @@ -2811,6 +3016,7 @@ enum mscs_description_subelem { #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_320 4 #define FD_CAP_BSS_CHWIDTH_SHIFT 2 #define FD_CAP_NSS_1 0 @@ -2825,13 +3031,20 @@ enum mscs_description_subelem { #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_EHT 5 /* P802.11be */ #define FD_CAP_PHY_INDEX_SHIFT 10 /* - * IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning + * IEEE Std 802.11ax-2021, 26.17.2.3.2, AP behavior for fast passive scanning */ #define FD_MAX_INTERVAL_6GHZ 20 /* TUs */ +/* IEEE Std 802.11ax-2021, 26.17.3.5.1: AP needs to wait and see the collision + * persists for at least the minimum default timeout + * dot11BSSColorCollisionAPPeriod (50 seconds) + */ +#define DOT11BSS_COLOR_COLLISION_AP_PERIOD 50 + /* Protected Vendor-specific QoS Management Action frame identifiers - WFA */ #define QM_ACTION_VENDOR_TYPE 0x506f9a1a #define QM_ACTION_OUI_TYPE 0x1a @@ -2862,8 +3075,8 @@ enum dscp_policy_request_type { /* Wi-Fi Alliance Capabilities element - Capabilities field */ #define WFA_CAPA_QM_DSCP_POLICY BIT(0) #define WFA_CAPA_QM_UNSOLIC_DSCP BIT(1) +#define WFA_CAPA_QM_NON_EHT_SCS_TRAFFIC_DESC BIT(2) -#ifdef CONFIG_MLD_PATCH struct ieee80211_neighbor_ap_info { u8 tbtt_info_hdr; u8 tbtt_info_len; @@ -2873,5 +3086,18 @@ struct ieee80211_neighbor_ap_info { /* Followed by the rest of the TBTT Information field contents */ u8 data[0]; } STRUCT_PACKED; -#endif + +/* S1G Beacon Compatibility element */ +struct ieee80211_s1g_beacon_compat { + u8 element_id; + u8 length; + le16 compat_info; + le16 beacon_interval; + le32 tsf_completion; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + #endif /* IEEE802_11_DEFS_H */ diff --git a/wpa_supplicant-2.9_standard/src/common/nan.h b/wpa_supplicant-2.9_standard/src/common/nan.h new file mode 100644 index 0000000000000000000000000000000000000000..19ab7468711e301aab39654459f8747082cfad08 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/common/nan.h @@ -0,0 +1,98 @@ +/* + * NAN (Wi-Fi Aware) definitions + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef NAN_H +#define NAN_H + +enum nan_attr_id { + NAN_ATTR_MASTER_INDICATION = 0x00, + NAN_ATTR_CLUSTER = 0x01, + NAN_ATTR_NAN_ATTR_SERVICE_ID_LIST = 0x02, + NAN_ATTR_SDA = 0x03, /* Service Descriptor attribute */ + NAN_ATTR_CONN_CAPA = 0x04, + NAN_ATTR_WLAN_INFRA = 0x05, + NAN_ATTR_P2P_OPER = 0x06, + NAN_ATTR_IBSS = 0x07, + NAN_ATTR_MESH = 0x08, + NAN_ATTR_FURTHER_NAN_SD = 0x09, + NAN_ATTR_FURTHER_AVAIL_MAP = 0x0A, + NAN_ATTR_COUNTRY_CODE = 0x0B, + NAN_ATTR_RANGIN = 0x0C, + NAN_ATTR_CLUSTER_DISCOVERY = 0x0D, + NAN_ATTR_SDEA = 0x0E, /* Service Descriptor Extension attribute */ + NAN_ATTR_DEVICE_CAPABILITY = 0x0F, + NAN_ATTR_NDP = 0x10, + NAN_ATTR_NAN_AVAILABILITY = 0x12, + NAN_ATTR_NDC = 0x13, + NAN_ATTR_NDL = 0x14, + NAN_ATTR_NDL_QOS = 0x15, + NAN_ATTR_UNALIGNED_SCHEDULE = 0x17, + NAN_ATTR_RANGING_INFO = 0x1A, + NAN_ATTR_RANGING_SETUP = 0x1B, + NAN_ATTR_FTM_RANGING_REPORT = 0x1C, + NAN_ATTR_ELEM_CONTAINER = 0x1D, + NAN_ATTR_EXT_WLAN_INFRA = 0x1E, + NAN_ATTR_EXT_P2P_OPER = 0x1FE, + NAN_ATTR_EXT_IBSS = 0x20, + NAN_ATTR_EXT_MESH = 0x21, + NAN_ATTR_CSIA = 0x22, /* Cipher Suite Info attribute */ + NAN_ATTR_SCIA = 0x23, /* Security Context Info attribute */ + NAN_ATTR_SHARED_KEY_DESCR = 0x24, + NAN_ATTR_PUBLIC_AVAILABILITY = 0x27, + NAN_ATTR_SUBSC_SERVICE_ID_LIST = 0x28, + NAN_ATTR_NDP_EXT = 0x29, + NAN_ATTR_DCEA = 0x2A, /* Device Capability Extension attribute */ + NAN_ATTR_NIRA = 0x2B, /* NAN Identity Resolution attribute */ + NAN_ATTR_BPBA = 0x2C, /* NAN Pairing Bootstrapping attribute */ + NAN_ATTR_S3 = 0x2D, + NAN_ATTR_TPEA = 0x2E, /* Transmit Power Envelope attribute */ + NAN_ATTR_VENDOR_SPECIFIC = 0xDD, +}; + +/* Service Descriptor attribute (SDA) */ + +/* Service Control field */ +#define NAN_SRV_CTRL_TYPE_MASK (BIT(0) | BIT(1)) +#define NAN_SRV_CTRL_MATCHING_FILTER BIT(2) +#define NAN_SRV_CTRL_RESP_FILTER BIT(3) +#define NAN_SRV_CTRL_SRV_INFO BIT(4) +#define NAN_SRV_CTRL_DISCOVERY_RANGE_LIMITED BIT(5) +#define NAN_SRV_CTRL_BINDING_BITMAP BIT(6) + +enum nan_service_control_type { + NAN_SRV_CTRL_PUBLISH = 0, + NAN_SRV_CTRL_SUBSCRIBE = 1, + NAN_SRV_CTRL_FOLLOW_UP = 2, +}; + +/* Service Descriptor Extension attribute (SDEA) */ + +/* SDEA Control field */ +#define NAN_SDEA_CTRL_FSD_REQ BIT(0) +#define NAN_SDEA_CTRL_FSD_GAS BIT(1) +#define NAN_SDEA_CTRL_DATA_PATH_REQ BIT(2) +#define NAN_SDEA_CTRL_DATA_PATH_TYPE BIT(3) +#define NAN_SDEA_CTRL_QOS_REQ BIT(5) +#define NAN_SDEA_CTRL_SECURITY_REQ BIT(6) +#define NAN_SDEA_CTRL_RANGING_REQ BIT(7) +#define NAN_SDEA_CTRL_RANGE_LIMIT BIT(8) +#define NAN_SDEA_CTRL_SRV_UPD_INDIC BIT(9) +#define NAN_SDEA_CTRL_GTK_REQ BIT(10) + +enum nan_service_protocol_type { + NAN_SRV_PROTO_BONJOUR = 1, + NAN_SRV_PROTO_GENERIC = 2, + NAN_SRV_PROTO_CSA_MATTER = 3, +}; + +#define NAN_ATTR_HDR_LEN 3 +#define NAN_SERVICE_ID_LEN 6 + +#define NAN_USD_DEFAULT_FREQ 2437 + +#endif /* NAN_H */ diff --git a/wpa_supplicant-2.9_standard/src/common/nan_de.c b/wpa_supplicant-2.9_standard/src/common/nan_de.c new file mode 100644 index 0000000000000000000000000000000000000000..12fad3112bdc96e930dff0ed78c64211a183856b --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/common/nan_de.c @@ -0,0 +1,1395 @@ +/* + * NAN Discovery Engine + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "utils/eloop.h" +#include "crypto/crypto.h" +#include "crypto/sha256.h" +#include "ieee802_11_defs.h" +#include "nan.h" +#include "nan_de.h" + +static const u8 nan_network_id[ETH_ALEN] = +{ 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 }; +static const u8 wildcard_bssid[ETH_ALEN] = +{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +enum nan_de_service_type { + NAN_DE_PUBLISH, + NAN_DE_SUBSCRIBE, +}; + +struct nan_de_service { + int id; + enum nan_de_service_type type; + char *service_name; + u8 service_id[NAN_SERVICE_ID_LEN]; + struct nan_publish_params publish; + struct nan_subscribe_params subscribe; + enum nan_service_protocol_type srv_proto_type; + struct wpabuf *ssi; + struct wpabuf *elems; + struct os_reltime time_started; + struct os_reltime end_time; + struct os_reltime last_multicast; + struct os_reltime first_discovered; + struct os_reltime last_followup; + bool needs_fsd; + unsigned int freq; + unsigned int default_freq; + int *freq_list; + + /* pauseState information for Publish function */ + struct os_reltime pause_state_end; + u8 sel_peer_id; + u8 sel_peer_addr[ETH_ALEN]; + + /* Publish state - channel iteration */ + bool in_multi_chan; + bool first_multi_chan; + int multi_chan_idx; /* index to freq_list[] */ + struct os_reltime next_publish_state; + struct os_reltime next_publish_chan; + unsigned int next_publish_duration; +}; + +struct nan_de { + u8 nmi[ETH_ALEN]; + bool ap; + struct nan_callbacks cb; + + struct nan_de_service *service[NAN_DE_MAX_SERVICE]; + unsigned int num_service; + + int next_handle; + + unsigned int ext_listen_freq; + unsigned int listen_freq; + unsigned int tx_wait_status_freq; + unsigned int tx_wait_end_freq; +}; + + +struct nan_de * nan_de_init(const u8 *nmi, bool ap, + const struct nan_callbacks *cb) +{ + struct nan_de *de; + + de = os_zalloc(sizeof(*de)); + if (!de) + return NULL; + + os_memcpy(de->nmi, nmi, ETH_ALEN); + de->ap = ap; + os_memcpy(&de->cb, cb, sizeof(*cb)); + + return de; +} + + +static void nan_de_service_free(struct nan_de_service *srv) +{ + os_free(srv->service_name); + wpabuf_free(srv->ssi); + wpabuf_free(srv->elems); + os_free(srv->freq_list); + os_free(srv); +} + + +static void nan_de_service_deinit(struct nan_de *de, struct nan_de_service *srv, + enum nan_de_reason reason) +{ + if (!srv) + return; + if (srv->type == NAN_DE_PUBLISH && de->cb.publish_terminated) + de->cb.publish_terminated(de->cb.ctx, srv->id, reason); + if (srv->type == NAN_DE_SUBSCRIBE && de->cb.subscribe_terminated) + de->cb.subscribe_terminated(de->cb.ctx, srv->id, reason); + nan_de_service_free(srv); +} + + +static void nan_de_clear_pending(struct nan_de *de) +{ + de->listen_freq = 0; + de->tx_wait_status_freq = 0; + de->tx_wait_end_freq = 0; +} + + +void nan_de_flush(struct nan_de *de) +{ + unsigned int i; + + if (!de) + return; + + for (i = 0; i < NAN_DE_MAX_SERVICE; i++) { + nan_de_service_deinit(de, de->service[i], + NAN_DE_REASON_USER_REQUEST); + de->service[i] = NULL; + } + + de->num_service = 0; + nan_de_clear_pending(de); +} + + +static void nan_de_pause_state(struct nan_de_service *srv, const u8 *peer_addr, + u8 peer_id) +{ + wpa_printf(MSG_DEBUG, "NAN: Start pauseState"); + os_get_reltime(&srv->pause_state_end); + srv->pause_state_end.sec += 60; + os_memcpy(srv->sel_peer_addr, peer_addr, ETH_ALEN); + srv->sel_peer_id = peer_id; +} + + +static void nan_de_unpause_state(struct nan_de_service *srv) +{ + wpa_printf(MSG_DEBUG, "NAN: Stop pauseState"); + srv->pause_state_end.sec = 0; + srv->pause_state_end.usec = 0; + os_memset(srv->sel_peer_addr, 0, ETH_ALEN); + srv->sel_peer_id = 0; +} + + +static struct wpabuf * nan_de_alloc_sdf(size_t len) +{ + struct wpabuf *buf; + + buf = wpabuf_alloc(2 + 4 + len); + if (buf) { + wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC); + wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC); + wpabuf_put_be32(buf, NAN_SDF_VENDOR_TYPE); + } + + return buf; +} + + +static int nan_de_tx(struct nan_de *de, unsigned int freq, + unsigned int wait_time, + const u8 *dst, const u8 *src, const u8 *bssid, + const struct wpabuf *buf) +{ + int res; + + if (!de->cb.tx) + return -1; + + res = de->cb.tx(de->cb.ctx, freq, wait_time, dst, src, bssid, buf); + if (res < 0) + return res; + + de->tx_wait_status_freq = freq; + de->tx_wait_end_freq = wait_time ? freq : 0; + + return res; +} + + +static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv, + unsigned int wait_time, + enum nan_service_control_type type, + const u8 *dst, u8 req_instance_id, + const struct wpabuf *ssi) +{ + struct wpabuf *buf; + size_t len = 0, sda_len, sdea_len; + u8 ctrl = type; + u16 sdea_ctrl = 0; + + /* Service Descriptor attribute */ + sda_len = NAN_SERVICE_ID_LEN + 1 + 1 + 1; + len += NAN_ATTR_HDR_LEN + sda_len; + + /* Service Descriptor Extension attribute */ + sdea_len = 1 + 2; + if (ssi) + sdea_len += 2 + 4 + wpabuf_len(ssi); + len += NAN_ATTR_HDR_LEN + sdea_len; + + /* Element Container attribute */ + if (srv->elems) + len += NAN_ATTR_HDR_LEN + 1 + wpabuf_len(srv->elems); + + buf = nan_de_alloc_sdf(len); + if (!buf) + return; + + /* Service Descriptor attribute */ + wpabuf_put_u8(buf, NAN_ATTR_SDA); + wpabuf_put_le16(buf, sda_len); + wpabuf_put_data(buf, srv->service_id, NAN_SERVICE_ID_LEN); + wpabuf_put_u8(buf, srv->id); /* Instance ID */ + wpabuf_put_u8(buf, req_instance_id); /* Requestor Instance ID */ + wpabuf_put_u8(buf, ctrl); + + /* Service Descriptor Extension attribute */ + if (srv->type == NAN_DE_PUBLISH || ssi) { + wpabuf_put_u8(buf, NAN_ATTR_SDEA); + wpabuf_put_le16(buf, sdea_len); + wpabuf_put_u8(buf, srv->id); /* Instance ID */ + if (srv->type == NAN_DE_PUBLISH) { + if (srv->publish.fsd) + sdea_ctrl |= NAN_SDEA_CTRL_FSD_REQ; + if (srv->publish.fsd_gas) + sdea_ctrl |= NAN_SDEA_CTRL_FSD_GAS; + } + wpabuf_put_le16(buf, sdea_ctrl); + if (ssi) { + wpabuf_put_le16(buf, 4 + wpabuf_len(ssi)); + wpabuf_put_be24(buf, OUI_WFA); + wpabuf_put_u8(buf, srv->srv_proto_type); + wpabuf_put_buf(buf, ssi); + } + } + + /* Element Container attribute */ + if (srv->elems) { + wpabuf_put_u8(buf, NAN_ATTR_ELEM_CONTAINER); + wpabuf_put_le16(buf, 1 + wpabuf_len(srv->elems)); + wpabuf_put_u8(buf, 0); /* Map ID */ + wpabuf_put_buf(buf, srv->elems); + } + + /* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD, + * but there is no synchronization in USD as as such, no NAN Cluster + * either. Use Wildcard BSSID instead. */ + nan_de_tx(de, srv->freq, wait_time, dst, de->nmi, wildcard_bssid, buf); + wpabuf_free(buf); +} + + +static int nan_de_time_to_next_chan_change(struct nan_de_service *srv) +{ + struct os_reltime tmp, diff, now; + + if (os_reltime_before(&srv->next_publish_state, + &srv->next_publish_chan)) + tmp = srv->next_publish_state; + else if (srv->in_multi_chan) + tmp = srv->next_publish_chan; + else + tmp = srv->next_publish_state; + + os_get_reltime(&now); + os_reltime_sub(&tmp, &now, &diff); + return os_reltime_in_ms(&diff); +} + + +static void nan_de_set_publish_times(struct nan_de_service *srv) +{ + os_get_reltime(&srv->next_publish_state); + srv->next_publish_chan = srv->next_publish_state; + /* Swap single/multi channel state in N * 100 TU */ + os_reltime_add_ms(&srv->next_publish_state, + srv->next_publish_duration * 1024 / 1000); + + /* Swap channel in multi channel state after 150 ms */ + os_reltime_add_ms(&srv->next_publish_chan, 150); +} + + +static void nan_de_check_chan_change(struct nan_de_service *srv) +{ + if (srv->next_publish_duration) { + /* Update end times for the first operation of the publish + * iteration */ + nan_de_set_publish_times(srv); + srv->next_publish_duration = 0; + } else if (srv->in_multi_chan) { + if (!os_reltime_initialized(&srv->pause_state_end)) { + srv->multi_chan_idx++; + if (srv->freq_list[srv->multi_chan_idx] == 0) + srv->multi_chan_idx = 0; + srv->freq = srv->freq_list[srv->multi_chan_idx]; + wpa_printf(MSG_DEBUG, + "NAN: Publish multi-channel change to %u MHz", + srv->freq); + } + os_get_reltime(&srv->next_publish_chan); + os_reltime_add_ms(&srv->next_publish_chan, 150); + } +} + + +static void nan_de_tx_multicast(struct nan_de *de, struct nan_de_service *srv, + u8 req_instance_id) +{ + enum nan_service_control_type type; + unsigned int wait_time = 100; + + if (srv->type == NAN_DE_PUBLISH) { + int ms; + + type = NAN_SRV_CTRL_PUBLISH; + + nan_de_check_chan_change(srv); + ms = nan_de_time_to_next_chan_change(srv); + if (ms < 100) + ms = 100; + wait_time = ms; + } else if (srv->type == NAN_DE_SUBSCRIBE) { + type = NAN_SRV_CTRL_SUBSCRIBE; + } else { + return; + } + + nan_de_tx_sdf(de, srv, wait_time, type, nan_network_id, + req_instance_id, srv->ssi); + os_get_reltime(&srv->last_multicast); +} + + +static void nan_de_add_srv(struct nan_de *de, struct nan_de_service *srv) +{ + int ttl; + + os_get_reltime(&srv->time_started); + ttl = srv->type == NAN_DE_PUBLISH ? srv->publish.ttl : + srv->subscribe.ttl; + if (ttl) { + srv->end_time = srv->time_started; + srv->end_time.sec += ttl; + } + + de->service[srv->id - 1] = srv; + de->num_service++; +} + + +static void nan_de_del_srv(struct nan_de *de, struct nan_de_service *srv, + enum nan_de_reason reason) +{ + de->service[srv->id - 1] = NULL; + nan_de_service_deinit(de, srv, reason); + de->num_service--; + if (de->num_service == 0) + nan_de_clear_pending(de); +} + + +static bool nan_de_srv_expired(struct nan_de_service *srv, + struct os_reltime *now) +{ + if (os_reltime_initialized(&srv->end_time)) + return os_reltime_before(&srv->end_time, now); + + if (srv->type == NAN_DE_PUBLISH) { + /* Time out after one transmission (and wait for FSD) */ + if (!os_reltime_initialized(&srv->last_multicast)) + return false; + if (!srv->publish.fsd) + return true; + if (os_reltime_initialized(&srv->last_followup) && + !os_reltime_expired(now, &srv->last_followup, 1)) + return false; + if (os_reltime_expired(now, &srv->last_multicast, 1)) + return true; + } + + if (srv->type == NAN_DE_SUBSCRIBE) { + /* Time out after first DiscoveryResult event (and wait for + * FSD) */ + if (!os_reltime_initialized(&srv->first_discovered)) + return false; + if (!srv->needs_fsd) + return true; + if (os_reltime_initialized(&srv->last_followup) && + !os_reltime_expired(now, &srv->last_followup, 1)) + return false; + if (os_reltime_expired(now, &srv->first_discovered, 1)) + return true; + } + + return false; +} + + +static int nan_de_next_multicast(struct nan_de *de, struct nan_de_service *srv, + struct os_reltime *now) +{ + unsigned int period; + struct os_reltime next, diff; + + if (srv->type == NAN_DE_PUBLISH && !srv->publish.unsolicited) + return -1; + if (srv->type == NAN_DE_SUBSCRIBE && !srv->subscribe.active) + return -1; + + if (!os_reltime_initialized(&srv->last_multicast)) + return 0; + + if (srv->type == NAN_DE_PUBLISH && srv->publish.ttl == 0) + return -1; + + if (srv->type == NAN_DE_PUBLISH && + os_reltime_initialized(&srv->pause_state_end)) + return -1; + + period = srv->type == NAN_DE_PUBLISH ? + srv->publish.announcement_period : + srv->subscribe.query_period; + if (period == 0) + period = 100; + next = srv->last_multicast; + os_reltime_add_ms(&next, period); + + if (srv->type == NAN_DE_PUBLISH) { + if (!de->tx_wait_end_freq && srv->publish.unsolicited && + os_reltime_before(&next, now)) + return 0; + next = srv->next_publish_state; + } + + if (os_reltime_before(&next, now)) + return 0; + + os_reltime_sub(&next, now, &diff); + return os_reltime_in_ms(&diff); +} + + +static int nan_de_srv_time_to_next(struct nan_de *de, + struct nan_de_service *srv, + struct os_reltime *now) +{ + struct os_reltime diff; + int next = -1, tmp; + + if (os_reltime_initialized(&srv->end_time)) { + os_reltime_sub(&srv->end_time, now, &diff); + tmp = os_reltime_in_ms(&diff); + if (next == -1 || tmp < next) + next = tmp; + } + + tmp = nan_de_next_multicast(de, srv, now); + if (tmp >= 0 && (next == -1 || tmp < next)) + next = tmp; + + if (srv->type == NAN_DE_PUBLISH && + os_reltime_initialized(&srv->last_multicast)) { + /* Time out after one transmission (and wait for FSD) */ + tmp = srv->publish.fsd ? 1000 : 100; + if (next == -1 || tmp < next) + next = tmp; + } + + if (srv->type == NAN_DE_SUBSCRIBE && + os_reltime_initialized(&srv->first_discovered)) { + /* Time out after first DiscoveryResult event (and wait for + * FSD) */ + tmp = srv->needs_fsd ? 1000 : 100; + if (next == -1 || tmp < next) + next = tmp; + } + + if (os_reltime_initialized(&srv->next_publish_state)) { + os_reltime_sub(&srv->next_publish_state, now, &diff); + if (diff.sec < 0 || (diff.sec == 0 && diff.usec < 0)) + tmp = 0; + else + tmp = os_reltime_in_ms(&diff); + if (next == -1 || tmp < next) + next = tmp; + } + + return next; +} + + +static void nan_de_start_new_publish_state(struct nan_de_service *srv, + bool force_single) +{ + unsigned int n; + + if (force_single || !srv->freq_list || srv->freq_list[0] == 0) + srv->in_multi_chan = false; + else + srv->in_multi_chan = !srv->in_multi_chan; + + /* Use hardcoded Nmin=5 and Nmax=10 and pick a random N from that range. + * Use same values for M. */ + n = 5 + os_random() % 5; + srv->next_publish_duration = n * 100; + + nan_de_set_publish_times(srv); + + if (os_reltime_initialized(&srv->pause_state_end)) + return; + + if (srv->in_multi_chan && srv->freq_list && srv->freq_list[0]) { + if (!srv->first_multi_chan) + srv->multi_chan_idx++; + if (srv->freq_list[srv->multi_chan_idx] == 0) + srv->multi_chan_idx = 0; + srv->first_multi_chan = false; + srv->freq = srv->freq_list[srv->multi_chan_idx]; + } else { + srv->freq = srv->default_freq; + } + + wpa_printf(MSG_DEBUG, + "NAN: Publish in %s channel state for %u TU; starting with %u MHz", + srv->in_multi_chan ? "multi" : "single", n * 100, srv->freq); +} + + +static void nan_de_timer(void *eloop_ctx, void *timeout_ctx) +{ + struct nan_de *de = eloop_ctx; + unsigned int i; + int next = -1; + bool started = false; + struct os_reltime now; + + os_get_reltime(&now); + + for (i = 0; i < NAN_DE_MAX_SERVICE; i++) { + struct nan_de_service *srv = de->service[i]; + int srv_next; + + if (!srv) + continue; + + if (nan_de_srv_expired(srv, &now)) { + wpa_printf(MSG_DEBUG, "NAN: Service id %d expired", + srv->id); + nan_de_del_srv(de, srv, NAN_DE_REASON_TIMEOUT); + continue; + } + + if (os_reltime_initialized(&srv->next_publish_state) && + os_reltime_before(&srv->next_publish_state, &now)) + nan_de_start_new_publish_state(srv, false); + + if (srv->type == NAN_DE_PUBLISH && + os_reltime_initialized(&srv->pause_state_end) && + (os_reltime_before(&srv->pause_state_end, &now) || + (srv->publish.fsd && + os_reltime_initialized(&srv->last_followup) && + os_reltime_expired(&now, &srv->last_followup, 1)))) + nan_de_unpause_state(srv); + + srv_next = nan_de_srv_time_to_next(de, srv, &now); + if (srv_next >= 0 && (next == -1 || srv_next < next)) + next = srv_next; + + if (srv_next == 0 && !started && + de->listen_freq == 0 && de->ext_listen_freq == 0 && + de->tx_wait_end_freq == 0 && + nan_de_next_multicast(de, srv, &now) == 0) { + started = true; + nan_de_tx_multicast(de, srv, 0); + } + + if (!started && de->cb.listen && + de->listen_freq == 0 && de->ext_listen_freq == 0 && + de->tx_wait_end_freq == 0 && + ((srv->type == NAN_DE_PUBLISH && + !srv->publish.unsolicited && srv->publish.solicited) || + (srv->type == NAN_DE_SUBSCRIBE && + !srv->subscribe.active))) { + int duration = 1000; + + if (srv->type == NAN_DE_PUBLISH) { + nan_de_check_chan_change(srv); + duration = nan_de_time_to_next_chan_change(srv); + if (duration < 150) + duration = 150; + } + + started = true; + if (de->cb.listen(de->cb.ctx, srv->freq, duration) == 0) + de->listen_freq = srv->freq; + } + + } + + if (next < 0) + return; + + if (next == 0) + next = 1; + wpa_printf(MSG_DEBUG, "NAN: Next timer in %u ms", next); + eloop_register_timeout(next / 1000, (next % 1000) * 1000, nan_de_timer, + de, NULL); +} + + +static void nan_de_run_timer(struct nan_de *de) +{ + eloop_cancel_timeout(nan_de_timer, de, NULL); + eloop_register_timeout(0, 0, nan_de_timer, de, NULL); +} + + +void nan_de_deinit(struct nan_de *de) +{ + eloop_cancel_timeout(nan_de_timer, de, NULL); + nan_de_flush(de); + os_free(de); +} + + +void nan_de_listen_started(struct nan_de *de, unsigned int freq, + unsigned int duration) +{ + if (freq != de->listen_freq) + de->ext_listen_freq = freq; +} + + +void nan_de_listen_ended(struct nan_de *de, unsigned int freq) +{ + if (freq == de->ext_listen_freq) + de->ext_listen_freq = 0; + + if (freq == de->listen_freq) { + de->listen_freq = 0; + nan_de_run_timer(de); + } +} + + +void nan_de_tx_status(struct nan_de *de, unsigned int freq, const u8 *dst) +{ + if (freq == de->tx_wait_status_freq) + de->tx_wait_status_freq = 0; +} + + +void nan_de_tx_wait_ended(struct nan_de *de) +{ + de->tx_wait_end_freq = 0; + nan_de_run_timer(de); +} + + +static const u8 * +nan_de_get_attr(const u8 *buf, size_t len, enum nan_attr_id id, + unsigned int skip) +{ + const u8 *pos = buf, *end = buf + len; + + while (end - pos >= NAN_ATTR_HDR_LEN) { + const u8 *attr = pos; + u8 attr_id; + u16 attr_len; + + attr_id = *pos++; + attr_len = WPA_GET_LE16(pos); + pos += 2; + if (attr_len > end - pos) { + wpa_printf(MSG_DEBUG, + "NAN: Truncated attribute %u (len %u; left %zu)", + attr_id, attr_len, end - pos); + break; + } + + if (attr_id == id) { + if (skip == 0) + return attr; + skip--; + } + + pos += attr_len; + } + + return NULL; +} + + +static void nan_de_get_sdea(const u8 *buf, size_t len, u8 instance_id, + u16 *sdea_control, + enum nan_service_protocol_type *srv_proto_type, + const u8 **ssi, size_t *ssi_len) +{ + unsigned int skip; + const u8 *sdea, *end; + u16 sdea_len; + + for (skip = 0; ; skip++) { + sdea = nan_de_get_attr(buf, len, NAN_ATTR_SDEA, skip); + if (!sdea) + break; + + sdea++; + sdea_len = WPA_GET_LE16(sdea); + sdea += 2; + if (sdea_len < 1 + 2) + continue; + end = sdea + sdea_len; + + if (instance_id != *sdea++) + continue; /* Mismatching Instance ID */ + + *sdea_control = WPA_GET_LE16(sdea); + sdea += 2; + + if (*sdea_control & NAN_SDEA_CTRL_RANGE_LIMIT) { + if (end - sdea < 4) + continue; + sdea += 4; + } + + if (*sdea_control & NAN_SDEA_CTRL_SRV_UPD_INDIC) { + if (end - sdea < 1) + continue; + sdea++; + } + + if (end - sdea >= 2) { + u16 srv_info_len; + + srv_info_len = WPA_GET_LE16(sdea); + sdea += 2; + + if (srv_info_len > end - sdea) + continue; + + if (srv_info_len >= 4 && + WPA_GET_BE24(sdea) == OUI_WFA) { + *srv_proto_type = sdea[3]; + *ssi = sdea + 4; + *ssi_len = srv_info_len - 4; + } + } + } +} + + +static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv, + const u8 *peer_addr, u8 instance_id, + u8 req_instance_id, u16 sdea_control, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len) +{ + /* Subscribe function processing of a receive Publish message */ + if (!os_reltime_initialized(&srv->first_discovered)) { + os_get_reltime(&srv->first_discovered); + srv->needs_fsd = sdea_control & NAN_SDEA_CTRL_FSD_REQ; + nan_de_run_timer(de); + } + + if (srv->subscribe.active && req_instance_id == 0) { + /* Active subscriber replies with a Subscribe message if it + * received a matching unsolicited Publish message. */ + nan_de_tx_multicast(de, srv, instance_id); + } + + if (!srv->subscribe.active && req_instance_id == 0) { + /* Passive subscriber replies with a Follow-up message without + * Service Specific Info field if it received a matching + * unsolicited Publish message. */ + nan_de_transmit(de, srv->id, NULL, NULL, peer_addr, + instance_id); + } + + if (de->cb.discovery_result) + de->cb.discovery_result( + de->cb.ctx, srv->id, srv_proto_type, + ssi, ssi_len, instance_id, + peer_addr, + sdea_control & NAN_SDEA_CTRL_FSD_REQ, + sdea_control & NAN_SDEA_CTRL_FSD_GAS); +} + + +static bool nan_de_filter_match(struct nan_de_service *srv, + const u8 *matching_filter, + size_t matching_filter_len) +{ + const u8 *pos, *end; + + /* Since we do not currently support matching_filter_rx values for the + * local Publish function, any matching filter with at least one + * pair with length larger than zero implies a mismatch. + */ + + if (!matching_filter) + return true; + + pos = matching_filter; + end = matching_filter + matching_filter_len; + + while (pos < end) { + u8 len; + + len = *pos++; + if (len > end - pos) + break; + if (len) { + /* A non-empty Matching Filter entry: no match since + * there is no local matching_filter_rx. */ + return false; + } + } + + return true; +} + + +static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv, + const u8 *peer_addr, u8 instance_id, + const u8 *matching_filter, + size_t matching_filter_len, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len) +{ + struct wpabuf *buf; + size_t len = 0, sda_len, sdea_len; + u8 ctrl = 0; + u16 sdea_ctrl = 0; + + /* Publish function processing of a receive Subscribe message */ + + if (!nan_de_filter_match(srv, matching_filter, matching_filter_len)) + return; + + if (!srv->publish.solicited) + return; + + if (os_reltime_initialized(&srv->pause_state_end) && + (!ether_addr_equal(peer_addr, srv->sel_peer_addr) || + instance_id != srv->sel_peer_id)) { + wpa_printf(MSG_DEBUG, + "NAN: In pauseState - ignore Subscribe message from another subscriber"); + return; + } + + /* Reply with a solicited Publish message */ + /* Service Descriptor attribute */ + sda_len = NAN_SERVICE_ID_LEN + 1 + 1 + 1; + len += NAN_ATTR_HDR_LEN + sda_len; + + /* Service Descriptor Extension attribute */ + sdea_len = 1 + 2; + if (srv->ssi) + sdea_len += 2 + 4 + wpabuf_len(srv->ssi); + len += NAN_ATTR_HDR_LEN + sdea_len; + + /* Element Container attribute */ + if (srv->elems) + len += NAN_ATTR_HDR_LEN + 1 + wpabuf_len(srv->elems); + + buf = nan_de_alloc_sdf(len); + if (!buf) + return; + + /* Service Descriptor attribute */ + wpabuf_put_u8(buf, NAN_ATTR_SDA); + wpabuf_put_le16(buf, sda_len); + wpabuf_put_data(buf, srv->service_id, NAN_SERVICE_ID_LEN); + wpabuf_put_u8(buf, srv->id); /* Instance ID */ + wpabuf_put_u8(buf, instance_id); /* Requestor Instance ID */ + ctrl |= NAN_SRV_CTRL_PUBLISH; + wpabuf_put_u8(buf, ctrl); + + /* Service Descriptor Extension attribute */ + if (srv->type == NAN_DE_PUBLISH || srv->ssi) { + wpabuf_put_u8(buf, NAN_ATTR_SDEA); + wpabuf_put_le16(buf, sdea_len); + wpabuf_put_u8(buf, srv->id); /* Instance ID */ + if (srv->type == NAN_DE_PUBLISH) { + if (srv->publish.fsd) + sdea_ctrl |= NAN_SDEA_CTRL_FSD_REQ; + if (srv->publish.fsd_gas) + sdea_ctrl |= NAN_SDEA_CTRL_FSD_GAS; + } + wpabuf_put_le16(buf, sdea_ctrl); + if (srv->ssi) { + wpabuf_put_le16(buf, 4 + wpabuf_len(srv->ssi)); + wpabuf_put_be24(buf, OUI_WFA); + wpabuf_put_u8(buf, srv->srv_proto_type); + wpabuf_put_buf(buf, srv->ssi); + } + } + + /* Element Container attribute */ + if (srv->elems) { + wpabuf_put_u8(buf, NAN_ATTR_ELEM_CONTAINER); + wpabuf_put_le16(buf, 1 + wpabuf_len(srv->elems)); + wpabuf_put_u8(buf, 0); /* Map ID */ + wpabuf_put_buf(buf, srv->elems); + } + + /* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD, + * but there is no synchronization in USD as as such, no NAN Cluster + * either. Use Wildcard BSSID instead. */ + nan_de_tx(de, srv->freq, 100, + srv->publish.solicited_multicast ? nan_network_id : peer_addr, + de->nmi, wildcard_bssid, buf); + wpabuf_free(buf); + + nan_de_pause_state(srv, peer_addr, instance_id); + + if (!srv->publish.disable_events && de->cb.replied) + de->cb.replied(de->cb.ctx, srv->id, peer_addr, instance_id, + srv_proto_type, ssi, ssi_len); +} + + +static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv, + const u8 *peer_addr, u8 instance_id, + const u8 *ssi, size_t ssi_len) +{ + /* Follow-up function processing of a receive Follow-up message for a + * Subscribe or Publish instance */ + + if (srv->type == NAN_DE_PUBLISH && + os_reltime_initialized(&srv->pause_state_end) && + (!ether_addr_equal(peer_addr, srv->sel_peer_addr) || + instance_id != srv->sel_peer_id || + !ssi)) { + wpa_printf(MSG_DEBUG, + "NAN: In pauseState - ignore Follow-up message from another subscriber or without ssi"); + return; + } + + os_get_reltime(&srv->last_followup); + + if (srv->type == NAN_DE_PUBLISH && !ssi) + nan_de_pause_state(srv, peer_addr, instance_id); + + if (de->cb.receive) + de->cb.receive(de->cb.ctx, srv->id, instance_id, ssi, ssi_len, + peer_addr); +} + + +static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, + unsigned int freq, const u8 *buf, size_t len, + const u8 *sda, size_t sda_len) +{ + const u8 *service_id; + u8 instance_id, req_instance_id, ctrl; + u16 sdea_control = 0; + unsigned int i; + enum nan_service_control_type type = 0; + enum nan_service_protocol_type srv_proto_type = 0; + const u8 *ssi = NULL; + size_t ssi_len = 0; + bool first = true; + const u8 *end; + const u8 *matching_filter = NULL; + size_t matching_filter_len = 0; + + if (sda_len < NAN_SERVICE_ID_LEN + 1 + 1 + 1) + return; + end = sda + sda_len; + + service_id = sda; + sda += NAN_SERVICE_ID_LEN; + instance_id = *sda++; + req_instance_id = *sda++; + ctrl = *sda; + type = ctrl & NAN_SRV_CTRL_TYPE_MASK; + wpa_printf(MSG_DEBUG, + "NAN: SDA - Service ID %02x%02x%02x%02x%02x%02x Instance ID %u Requestor Instance ID %u Service Control 0x%x (Service Control Type %u)", + MAC2STR(service_id), instance_id, req_instance_id, + ctrl, type); + if (type != NAN_SRV_CTRL_PUBLISH && + type != NAN_SRV_CTRL_SUBSCRIBE && + type != NAN_SRV_CTRL_FOLLOW_UP) { + wpa_printf(MSG_DEBUG, + "NAN: Discard SDF with unknown Service Control Type %u", + type); + return; + } + + if (ctrl & NAN_SRV_CTRL_BINDING_BITMAP) { + if (end - sda < 2) + return; + sda += 2; + } + + if (ctrl & NAN_SRV_CTRL_MATCHING_FILTER) { + u8 flen; + + if (end - sda < 1) + return; + flen = *sda++; + if (end - sda < flen) + return; + matching_filter = sda; + matching_filter_len = flen; + sda += flen; + } + + if (ctrl & NAN_SRV_CTRL_RESP_FILTER) { + u8 flen; + + if (end - sda < 1) + return; + flen = *sda++; + if (end - sda < flen) + return; + sda += flen; + } + + if (ctrl & NAN_SRV_CTRL_SRV_INFO) { + u8 flen; + + if (end - sda < 1) + return; + flen = *sda++; + if (end - sda < flen) + return; + if (flen >= 4 && WPA_GET_BE24(sda) == OUI_WFA) { + srv_proto_type = sda[3]; + ssi = sda + 4; + ssi_len = flen - 4; + wpa_printf(MSG_DEBUG, "NAN: Service Protocol Type %d", + srv_proto_type); + wpa_hexdump(MSG_MSGDUMP, "NAN: ssi", ssi, ssi_len); + } + sda += flen; + } + + for (i = 0; i < NAN_DE_MAX_SERVICE; i++) { + struct nan_de_service *srv = de->service[i]; + + if (!srv) + continue; + if (os_memcmp(srv->service_id, service_id, + NAN_SERVICE_ID_LEN) != 0) + continue; + if (type == NAN_SRV_CTRL_PUBLISH) { + if (srv->type == NAN_DE_PUBLISH) + continue; + if (req_instance_id && srv->id != req_instance_id) + continue; + } + if (type == NAN_SRV_CTRL_SUBSCRIBE && + srv->type == NAN_DE_SUBSCRIBE) + continue; + wpa_printf(MSG_DEBUG, "NAN: Received SDF matches service ID %u", + i + 1); + + if (first) { + first = false; + nan_de_get_sdea(buf, len, instance_id, &sdea_control, + &srv_proto_type, &ssi, &ssi_len); + + if (ssi) { + wpa_printf(MSG_DEBUG, + "NAN: Service Protocol Type %d", + srv_proto_type); + wpa_hexdump(MSG_MSGDUMP, "NAN: ssi", + ssi, ssi_len); + } + } + + switch (type) { + case NAN_SRV_CTRL_PUBLISH: + nan_de_rx_publish(de, srv, peer_addr, instance_id, + req_instance_id, + sdea_control, srv_proto_type, + ssi, ssi_len); + break; + case NAN_SRV_CTRL_SUBSCRIBE: + nan_de_rx_subscribe(de, srv, peer_addr, instance_id, + matching_filter, + matching_filter_len, + srv_proto_type, + ssi, ssi_len); + break; + case NAN_SRV_CTRL_FOLLOW_UP: + nan_de_rx_follow_up(de, srv, peer_addr, instance_id, + ssi, ssi_len); + break; + } + } +} + + +void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq, + const u8 *buf, size_t len) +{ + const u8 *sda; + u16 sda_len; + unsigned int skip; + + if (!de->num_service) + return; + + wpa_printf(MSG_DEBUG, "NAN: RX SDF from " MACSTR " freq=%u len=%zu", + MAC2STR(peer_addr), freq, len); + + wpa_hexdump(MSG_MSGDUMP, "NAN: SDF payload", buf, len); + + for (skip = 0; ; skip++) { + sda = nan_de_get_attr(buf, len, NAN_ATTR_SDA, skip); + if (!sda) + break; + + sda++; + sda_len = WPA_GET_LE16(sda); + sda += 2; + nan_de_rx_sda(de, peer_addr, freq, buf, len, sda, sda_len); + } +} + + +static int nan_de_get_handle(struct nan_de *de) +{ + int i = de->next_handle; + + if (de->num_service >= NAN_DE_MAX_SERVICE) + goto fail; + + do { + if (!de->service[i]) { + de->next_handle = (i + 1) % NAN_DE_MAX_SERVICE; + return i + 1; + } + i = (i + 1) % NAN_DE_MAX_SERVICE; + } while (i != de->next_handle); + +fail: + wpa_printf(MSG_DEBUG, "NAN: No more room for a new service"); + return -1; +} + + +static int nan_de_derive_service_id(struct nan_de_service *srv) +{ + u8 hash[SHA256_MAC_LEN]; + char *name, *pos; + int ret; + const u8 *addr[1]; + size_t len[1]; + + name = os_strdup(srv->service_name); + if (!name) + return -1; + pos = name; + while (*pos) { + *pos = tolower(*pos); + pos++; + } + + addr[0] = (u8 *) name; + len[0] = os_strlen(name); + ret = sha256_vector(1, addr, len, hash); + os_free(name); + if (ret == 0) + os_memcpy(srv->service_id, hash, NAN_SERVICE_ID_LEN); + + return ret; +} + + +int nan_de_publish(struct nan_de *de, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_publish_params *params) +{ + int publish_id; + struct nan_de_service *srv; + + if (!service_name) { + wpa_printf(MSG_DEBUG, "NAN: Publish() - no service_name"); + return -1; + } + + if (!params->unsolicited && !params->solicited) { + wpa_printf(MSG_INFO, + "NAN: Publish() - both unsolicited and solicited disabled is invalid"); + return -1; + } + + publish_id = nan_de_get_handle(de); + if (publish_id < 1) + return -1; + + srv = os_zalloc(sizeof(*srv)); + if (!srv) + return -1; + srv->type = NAN_DE_PUBLISH; + srv->freq = srv->default_freq = params->freq; + srv->service_name = os_strdup(service_name); + if (!srv->service_name) + goto fail; + if (nan_de_derive_service_id(srv) < 0) + goto fail; + os_memcpy(&srv->publish, params, sizeof(*params)); + + if (params->freq_list) { + size_t len; + + len = (int_array_len(params->freq_list) + 1) * sizeof(int); + srv->freq_list = os_memdup(params->freq_list, len); + if (!srv->freq_list) + goto fail; + } + srv->publish.freq_list = NULL; + + srv->srv_proto_type = srv_proto_type; + if (ssi) { + srv->ssi = wpabuf_dup(ssi); + if (!srv->ssi) + goto fail; + } + if (elems) { + srv->elems = wpabuf_dup(elems); + if (!srv->elems) + goto fail; + } + + /* Prepare for single and multi-channel states; starting with + * single channel */ + srv->first_multi_chan = true; + nan_de_start_new_publish_state(srv, true); + + wpa_printf(MSG_DEBUG, "NAN: Assigned new publish handle %d for %s", + publish_id, service_name); + srv->id = publish_id; + nan_de_add_srv(de, srv); + nan_de_run_timer(de); + return publish_id; +fail: + nan_de_service_free(srv); + return -1; +} + + +void nan_de_cancel_publish(struct nan_de *de, int publish_id) +{ + struct nan_de_service *srv; + + wpa_printf(MSG_DEBUG, "NAN: CancelPublish(publish_id=%d)", publish_id); + + if (publish_id < 1 || publish_id > NAN_DE_MAX_SERVICE) + return; + srv = de->service[publish_id - 1]; + if (!srv || srv->type != NAN_DE_PUBLISH) + return; + nan_de_del_srv(de, srv, NAN_DE_REASON_USER_REQUEST); +} + + +int nan_de_update_publish(struct nan_de *de, int publish_id, + const struct wpabuf *ssi) +{ + struct nan_de_service *srv; + + wpa_printf(MSG_DEBUG, "NAN: UpdatePublish(publish_id=%d)", publish_id); + + if (publish_id < 1 || publish_id > NAN_DE_MAX_SERVICE) + return -1; + srv = de->service[publish_id - 1]; + if (!srv || srv->type != NAN_DE_PUBLISH) + return -1; + + wpabuf_free(srv->ssi); + srv->ssi = NULL; + if (!ssi) + return 0; + srv->ssi = wpabuf_dup(ssi); + if (!srv->ssi) + return -1; + return 0; +} + + +int nan_de_subscribe(struct nan_de *de, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_subscribe_params *params) +{ + int subscribe_id; + struct nan_de_service *srv; + + if (!service_name) { + wpa_printf(MSG_DEBUG, "NAN: Subscribe() - no service_name"); + return -1; + } + + subscribe_id = nan_de_get_handle(de); + if (subscribe_id < 1) + return -1; + + srv = os_zalloc(sizeof(*srv)); + if (!srv) + return -1; + srv->type = NAN_DE_SUBSCRIBE; + srv->freq = params->freq; + srv->service_name = os_strdup(service_name); + if (!srv->service_name) + goto fail; + if (nan_de_derive_service_id(srv) < 0) + goto fail; + os_memcpy(&srv->subscribe, params, sizeof(*params)); + srv->srv_proto_type = srv_proto_type; + if (ssi) { + srv->ssi = wpabuf_dup(ssi); + if (!srv->ssi) + goto fail; + } + if (elems) { + srv->elems = wpabuf_dup(elems); + if (!srv->elems) + goto fail; + } + + wpa_printf(MSG_DEBUG, "NAN: Assigned new subscribe handle %d for %s", + subscribe_id, service_name); + srv->id = subscribe_id; + nan_de_add_srv(de, srv); + nan_de_run_timer(de); + return subscribe_id; +fail: + nan_de_service_free(srv); + return -1; +} + + +void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id) +{ + struct nan_de_service *srv; + + if (subscribe_id < 1 || subscribe_id > NAN_DE_MAX_SERVICE) + return; + srv = de->service[subscribe_id - 1]; + if (!srv || srv->type != NAN_DE_SUBSCRIBE) + return; + nan_de_del_srv(de, srv, NAN_DE_REASON_USER_REQUEST); +} + + +int nan_de_transmit(struct nan_de *de, int handle, + const struct wpabuf *ssi, const struct wpabuf *elems, + const u8 *peer_addr, u8 req_instance_id) +{ + struct nan_de_service *srv; + + if (handle < 1 || handle > NAN_DE_MAX_SERVICE) + return -1; + + srv = de->service[handle - 1]; + if (!srv) + return -1; + + nan_de_tx_sdf(de, srv, 100, NAN_SRV_CTRL_FOLLOW_UP, + peer_addr, req_instance_id, ssi); + + os_get_reltime(&srv->last_followup); + return 0; +} diff --git a/wpa_supplicant-2.9_standard/src/common/nan_de.h b/wpa_supplicant-2.9_standard/src/common/nan_de.h new file mode 100644 index 0000000000000000000000000000000000000000..62235064b0757f7418e279379ab05129c5de58f1 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/common/nan_de.h @@ -0,0 +1,145 @@ +/* + * NAN Discovery Engine + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef NAN_DE_H +#define NAN_DE_H + +#include "nan.h" + +/* Maximum number of active local publish and subscribe instances */ +#ifndef NAN_DE_MAX_SERVICE +#define NAN_DE_MAX_SERVICE 20 +#endif /* NAN_DE_MAX_SERVICE */ + +struct nan_de; + +enum nan_de_reason { + NAN_DE_REASON_TIMEOUT, + NAN_DE_REASON_USER_REQUEST, + NAN_DE_REASON_FAILURE, +}; + +struct nan_callbacks { + void *ctx; + + int (*tx)(void *ctx, unsigned int freq, unsigned int wait_time, + const u8 *dst, const u8 *src, const u8 *bssid, + const struct wpabuf *buf); + int (*listen)(void *ctx, unsigned int freq, unsigned int duration); + + /* NAN DE Events */ + void (*discovery_result)(void *ctx, int subscribe_id, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len, + int peer_publish_id, + const u8 *peer_addr, bool fsd, bool fsd_gas); + + void (*replied)(void *ctx, int publish_id, const u8 *peer_addr, + int peer_subscribe_id, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len); + + void (*publish_terminated)(void *ctx, int publish_id, + enum nan_de_reason reason); + + void (*subscribe_terminated)(void *ctx, int subscribe_id, + enum nan_de_reason reason); + + void (*receive)(void *ctx, int id, int peer_instance_id, + const u8 *ssi, size_t ssi_len, + const u8 *peer_addr); +}; + +struct nan_de * nan_de_init(const u8 *nmi, bool ap, + const struct nan_callbacks *cb); +void nan_de_flush(struct nan_de *de); +void nan_de_deinit(struct nan_de *de); + +void nan_de_listen_started(struct nan_de *de, unsigned int freq, + unsigned int duration); +void nan_de_listen_ended(struct nan_de *de, unsigned int freq); +void nan_de_tx_status(struct nan_de *de, unsigned int freq, const u8 *dst); +void nan_de_tx_wait_ended(struct nan_de *de); + +void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq, + const u8 *buf, size_t len); + +struct nan_publish_params { + /* configuration_parameters */ + + /* Publish type */ + bool unsolicited; + bool solicited; + + /* Solicited transmission type */ + bool solicited_multicast; + + /* Time to live (in seconds); 0 = one TX only */ + unsigned int ttl; + + /* Event conditions */ + bool disable_events; + + /* Further Service Discovery flag */ + bool fsd; + + /* Further Service Discovery function */ + bool fsd_gas; + + /* Default frequency (defaultPublishChannel) */ + unsigned int freq; + + /* Multi-channel frequencies (publishChannelList) */ + const int *freq_list; + + /* Announcement period in ms; 0 = use default */ + unsigned int announcement_period; +}; + +/* Returns -1 on failure or >0 publish_id */ +int nan_de_publish(struct nan_de *de, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_publish_params *params); + +void nan_de_cancel_publish(struct nan_de *de, int publish_id); + +int nan_de_update_publish(struct nan_de *de, int publish_id, + const struct wpabuf *ssi); + +struct nan_subscribe_params { + /* configuration_parameters */ + + /* Subscribe type */ + bool active; + + /* Time to live (in seconds); 0 = until first result */ + unsigned int ttl; + + /* Selected frequency */ + unsigned int freq; + + /* Query period in ms; 0 = use default */ + unsigned int query_period; +}; + +/* Returns -1 on failure or >0 subscribe_id */ +int nan_de_subscribe(struct nan_de *de, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, const struct wpabuf *elems, + struct nan_subscribe_params *params); + +void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id); + +/* handle = publish_id or subscribe_id + * req_instance_id = peer publish_id or subscribe_id */ +int nan_de_transmit(struct nan_de *de, int handle, + const struct wpabuf *ssi, const struct wpabuf *elems, + const u8 *peer_addr, u8 req_instance_id); + +#endif /* NAN_DE_H */ diff --git a/wpa_supplicant-2.9_standard/src/common/ocv.c b/wpa_supplicant-2.9_standard/src/common/ocv.c index c9dc14fa6c09352b799a3a03825530e69da5e0a1..d77bc4bb820eda736e74b38f235f1cb070aac795 100644 --- a/wpa_supplicant-2.9_standard/src/common/ocv.c +++ b/wpa_supplicant-2.9_standard/src/common/ocv.c @@ -159,11 +159,10 @@ ocv_verify_tx_params(const u8 *oci_ie, size_t oci_ie_len, } /* - * When using a 160 or 80+80 MHz channel to transmit, verify that we use + * When using an 80+80 MHz channel to transmit, verify that we use * the same segments as the receiver by comparing frequency segment 1. */ - if ((ci->chanwidth == CHAN_WIDTH_160 || - ci->chanwidth == CHAN_WIDTH_80P80) && + if (ci->chanwidth == CHAN_WIDTH_80P80 && tx_seg1_idx != oci.seg1_idx) { os_snprintf(ocv_errorstr, sizeof(ocv_errorstr), "frequency segment 1 mismatch in received OCI (we use %d but receiver is using %d)", diff --git a/wpa_supplicant-2.9_standard/src/common/ptksa_cache.c b/wpa_supplicant-2.9_standard/src/common/ptksa_cache.c index 7ac28b9bf42d01b136e304a097787189d8b59f92..cc7120055793a3c5c2a471b8cdc5ada116224ee9 100644 --- a/wpa_supplicant-2.9_standard/src/common/ptksa_cache.c +++ b/wpa_supplicant-2.9_standard/src/common/ptksa_cache.c @@ -19,6 +19,8 @@ struct ptksa_cache { unsigned int n_ptksa; }; +#ifdef CONFIG_PTKSA_CACHE + static void ptksa_cache_set_expiration(struct ptksa_cache *ptksa); @@ -51,7 +53,10 @@ static void ptksa_cache_expire(void *eloop_ctx, void *timeout_ctx) wpa_printf(MSG_DEBUG, "Expired PTKSA cache entry for " MACSTR_SEC, MAC2STR_SEC(e->addr)); - ptksa_cache_free_entry(ptksa, e); + if (e->cb && e->ctx) + e->cb(e); + else + ptksa_cache_free_entry(ptksa, e); } ptksa_cache_set_expiration(ptksa); @@ -138,7 +143,7 @@ struct ptksa_cache_entry * ptksa_cache_get(struct ptksa_cache *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) && + if ((!addr || ether_addr_equal(e->addr, addr)) && (cipher == WPA_CIPHER_NONE || cipher == e->cipher)) return e; } @@ -235,7 +240,7 @@ void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher) dl_list_for_each_safe(e, next, &ptksa->ptksa, struct ptksa_cache_entry, list) { - if ((!addr || os_memcmp(e->addr, addr, ETH_ALEN) == 0) && + if ((!addr || ether_addr_equal(e->addr, addr)) && (cipher == WPA_CIPHER_NONE || cipher == e->cipher)) { wpa_printf(MSG_DEBUG, "Flush PTKSA cache entry for " MACSTR_SEC, @@ -254,10 +259,14 @@ void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher) /* * ptksa_cache_add - Add a PTKSA cache entry * @ptksa: Pointer to PTKSA cache data from ptksa_cache_init() + * @own_addr: Own MAC address * @addr: Peer address * @cipher: The cipher used * @life_time: The PTK life time in seconds * @ptk: The PTK + * @life_time_expiry_cb: Callback for alternative expiration handling + * @ctx: Context pointer to save into e->ctx for the callback + * @akmp: The key management mechanism that was used to derive 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. @@ -265,12 +274,17 @@ void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher) * this entry will be replaced with the new entry. */ struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa, + const u8 *own_addr, const u8 *addr, u32 cipher, u32 life_time, - const struct wpa_ptk *ptk) + const struct wpa_ptk *ptk, + void (*life_time_expiry_cb) + (struct ptksa_cache_entry *e), + void *ctx, u32 akmp) { struct ptksa_cache_entry *entry, *tmp, *tmp2 = NULL; struct os_reltime now; + bool set_expiry = false; if (!ptksa || !ptk || !addr || !life_time || cipher == WPA_CIPHER_NONE) return NULL; @@ -289,6 +303,12 @@ struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa, dl_list_init(&entry->list); os_memcpy(entry->addr, addr, ETH_ALEN); entry->cipher = cipher; + entry->cb = life_time_expiry_cb; + entry->ctx = ctx; + entry->akmp = akmp; + + if (own_addr) + os_memcpy(entry->own_addr, own_addr, ETH_ALEN); os_memcpy(&entry->ptk, ptk, sizeof(entry->ptk)); @@ -302,6 +322,8 @@ struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa, } } + if (dl_list_empty(&entry->list)) + set_expiry = true; /* * If the expiration is later then all other or the list is empty * entries, add it to the end of the list; @@ -317,5 +339,49 @@ struct ptksa_cache_entry * ptksa_cache_add(struct ptksa_cache *ptksa, "Added PTKSA cache entry addr=" MACSTR_SEC " cipher=%u", MAC2STR_SEC(addr), cipher); + if (set_expiry) + ptksa_cache_set_expiration(ptksa); + return entry; } + +#else /* CONFIG_PTKSA_CACHE */ + +struct ptksa_cache * ptksa_cache_init(void) +{ + return (struct ptksa_cache *) 1; +} + + +void ptksa_cache_deinit(struct ptksa_cache *ptksa) +{ +} + + +struct ptksa_cache_entry * +ptksa_cache_get(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher) +{ + return NULL; +} + + +int ptksa_cache_list(struct ptksa_cache *ptksa, char *buf, size_t len) +{ + return -1; +} + + +struct ptksa_cache_entry * +ptksa_cache_add(struct ptksa_cache *ptksa, const u8 *own_addr, const u8 *addr, + u32 cipher, u32 life_time, const struct wpa_ptk *ptk, + void (*cb)(struct ptksa_cache_entry *e), void *ctx, u32 akmp) +{ + return NULL; +} + + +void ptksa_cache_flush(struct ptksa_cache *ptksa, const u8 *addr, u32 cipher) +{ +} + +#endif /* CONFIG_PTKSA_CACHE */ diff --git a/wpa_supplicant-2.9_standard/src/common/ptksa_cache.h b/wpa_supplicant-2.9_standard/src/common/ptksa_cache.h index 28ef291446472b62b188cd71cd003f438f766227..dd5e7db8f98c04de49b5a21538d3af6cb9c626e2 100644 --- a/wpa_supplicant-2.9_standard/src/common/ptksa_cache.h +++ b/wpa_supplicant-2.9_standard/src/common/ptksa_cache.h @@ -23,9 +23,12 @@ struct ptksa_cache_entry { os_time_t expiration; u32 cipher; u8 addr[ETH_ALEN]; + u8 own_addr[ETH_ALEN]; + void (*cb)(struct ptksa_cache_entry *e); + void *ctx; + u32 akmp; }; -#ifdef CONFIG_PTKSA_CACHE struct ptksa_cache; @@ -35,45 +38,13 @@ 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 *own_addr, const u8 *addr, u32 cipher, u32 life_time, - const struct wpa_ptk *ptk); + const struct wpa_ptk *ptk, + void (*cb) + (struct ptksa_cache_entry *e), + void *ctx, u32 akmp); 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/wpa_supplicant-2.9_standard/src/common/qca-vendor.h b/wpa_supplicant-2.9_standard/src/common/qca-vendor.h index b77e29939195ff5cf8b4cff2bf63582a5c0352a9..5b58ffb3943cc6791683eb4447d02910a6f16b52 100644 --- a/wpa_supplicant-2.9_standard/src/common/qca-vendor.h +++ b/wpa_supplicant-2.9_standard/src/common/qca-vendor.h @@ -2,6 +2,7 @@ * Qualcomm Atheros OUI and vendor specific assignments * Copyright (c) 2014-2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -30,6 +31,119 @@ enum qca_radiotap_vendor_ids { QCA_RADIOTAP_VID_WLANTEST = 0, }; +/** + * DOC: TX/RX NSS and chain configurations + * This document describes all of the attributes used in the vendor command + * QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION to configure the number of + * spatial streams (NSS) and the number of chains used for transmitting (TX) and + * receiving (RX) the data. + * + * Global NSS configuration - Applies to all bands (2.4 GHz and 5/6 GHz) + * The following attributes are used to dynamically configure the number of + * spatial streams to be used for transmitting or receiving the data in the + * 2.4 GHz and 5/6 GHz bands. When configured in disconnected state, the + * updated configuration will be considered for the immediately following + * connection attempt. If the NSS is updated during a connection, the updated + * NSS value is notified to the peer using 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. The + * driver rejects any such higher value configuration with a failure. + * + * @QCA_WLAN_VENDOR_ATTR_CONFIG_NSS: Only symmetric NSS configuration + * (such as 2X2 or 1X1) can be done using this attribute. + * @QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS: Configure NSS for transmitting the data + * @QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS: Configure NSS for receiving the data + * + * The QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS and QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS + * attributes must be defined together or the driver will reject the command + * with a failure. They can be used to configure either symmetric NSS + * configuration (such as 2X2 or 1X1) or asymmetric configuration (such as 1X2). + * + * Per band NSS configuration - Applies to the 2.4 GHz or 5/6 GHz band + * The following attributes are used to dynamically configure the number of + * spatial streams to be used for transmitting or receiving the data in the + * 2.4 GHz band or 5/6 GHz band. All these attributes must be defined together + * to configure symmetric NSS configuration (such as 1X1 or 2X2) or asymmetric + * NSS configuration (such as 1X2). If any of the attributes is missing, the + * driver will reject the command with a failure. This configuration is allowed + * only when in connected state and will be effective until disconnected. The + * 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. + * + * @QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS_2GHZ: Configure TX_NSS in 2.4 GHz band + * @QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS_2GHZ: Configure RX_NSS in 2.4 GHz band + * @QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS_5GHZ: Configure TX_NSS in 5 or 6 GHz band + * @QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS_5GHZ: Configure RX_NSS in 5 or 6 GHz band + * + * Global chain configuration - Applies to all bands (2.4 GHz and 5/6 GHz) + * The following attributes are used to dynamically configure the number of + * chains to be used for transmitting or receiving the data in the 2.4 GHz and + * 5/6 GHz bands. 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: The number of chains to be used + * for transmitting the data in both the 2.4 GHz and 5/6 GHz bands. + * @QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS: The number of chains to be used + * for receiving the data in both the 2.4 GHz and 5/6 GHz bands. + * + * The attributes QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS and + * QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS must be defined together or the + * driver will reject the command with a failure. + * + * Per band chain configuration - Applies to the 2.4 GHz or 5/6 GHz band + * The following band specific attributes are used to dynamically configure the + * number of chains to be used for tranmissting or receiving the data in the + * 2.4 GHz or 5/6 GHz band. These attributes must be defined together or the + * driver will reject the command. 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_2GHZ: The number of chains to be + * used for transmitting the data in the 2.4 GHz band. + * @QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS_2GHZ: The number of chains to be + * used for receiving the data in the 2.4 GHz band. + * @QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS_5GHZ: The number of chains to be + * used for transmitting the data in the 5/6 GHz band. + * @QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS_5GHZ: The number of chains to be + * used for receiving the data in the 5/6 GHz band. + * + * The following scenarios capture how the driver process the configuration when + * different TX/RX NSS and chain config attributes are used in the command. + * + * Case 1: CONFIG_NSS + CONFIG_TX_NSS/RX_NSS - Only CONFIG_NSS is applied + * since only one of the TX_NSS or RX_NSS attribute is present. + * + * Case 2: CONFIG_NSS + CONFIG_TX_NSS + CONFIG_RX_NSS - Same NSS values are + * used to configure TX,RX in both the 2.4 GHz and 5/6 GHz bands. + * + * Case 3: Case 2 + NUM_TX_CHAINS + NUM_RX_CHAINS - The NSS and the number of + * chains values are used to configure TX,RX in both the 2.4 GHz and 5/6 GHz + * bands. + * + * Case 4: TX_NSS_2GHZ/TX_NSS_5GHZ + RX_NSS_2GHZ/RX_NSS_5GHZ - Since per band + * TX/RX NSS attribute is missing, the driver rejects the command. + * + * Case 5: TX_NSS_2GHZ + TX_NSS_5GHZ + RX_NSS_2GHZ + RX_NSS_5GHZ - The 2.4 GHz + * band is configured with the TX_NSS_2GHZ, RX_NSS_2GHZ values. The 5/6 GHz band + * is configured with the TX_NSS_5GHZ, RX_NSS_5GHZ values. + * + * Case 6: TX_CHAINS_2GHZ/TX_CHAINS_5GHZ + RX_CHAINS_5GHZ/RX_CHAINS_5GHZ - Since + * per band TX/RX chains attribute is missing, the driver rejects the command. + * + * Case 7: TX_CHAINS_2GHZ + TX_CHAINS_5GHZ + RX_CHAINS_5GHZ + RX_CHAINS_5GHZ - + * The 2.4 GHz band is configured with the TX_CHAINS_2GHZ, RX_CHAINS_2GHZ + * values. The 5/6 GHz band is configured with the TX_CHAINS_5GHZ, + * RX_CHAINS_5GHZ values. + * + * Case 8: Case 5 + Case 7 - Per band TX,RX NSS and chains are configured. + * + * Case 9: Case 2 + Case 8 - Per band TX,RX NSS and chains are configured. + */ + /** * enum qca_nl80211_vendor_subcmds - QCA nl80211 vendor command identifiers * @@ -63,6 +177,42 @@ enum qca_radiotap_vendor_ids { * encapsulated inside any attribute. Attribute QCA_WLAN_VENDOR_ATTR_NAN * is used when receiving vendor events in userspace from the driver. * + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE: This command is used to enable TDLS + * capability or to form a session with the specified peer. + * If %NL80211_ATTR_VENDOR_DATA is sent as an empty nested attribute this + * indicates to enable TDLS capability on the interface. + * If %QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR is nested in + * %NL80211_ATTR_VENDOR_DATA this indicates the userspace requests to + * form a TDLS session with the specified peer MAC address. + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_tdls_enable. + * + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE: This command is used to disable TDLS + * capability or to terminate the session with the specified peer. + * If %NL80211_ATTR_VENDOR_DATA is sent as an empty nested attribute this + * indicates to disable TDLS capability on the interface. + * If %QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR is nested in + * %NL80211_ATTR_VENDOR_DATA this indicates the userspace requests to + * terminate TDLS session with the specified peer MAC address. + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_tdls_disable. + * + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS: This command is to get the TDLS + * status at the interface level or with the specific peer. + * If %NL80211_ATTR_VENDOR_DATA is sent as an empty nested attribute this + * indicates the TDLS status query is at interface level. + * If %QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR is nested in + * %NL80211_ATTR_VENDOR_DATA this indicates the userspace requests to + * get TDLS session status with the specified peer MAC address. + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_tdls_get_status. + * + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE: This event is to indicate the result + * of the TDLS session request with the peer sent by userspace in + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE. + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_tdls_state. + * * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: Set key operation that can be * used to configure PMK to the driver even when not connected. This can * be used to request offloading of key management operations. Only used @@ -105,6 +255,32 @@ enum qca_radiotap_vendor_ids { * @QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO: Get information from the driver. * Attributes defined in enum qca_wlan_vendor_attr_get_wifi_info. * + * @QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION: This command is used to + * configure various wiphy or interface level configurations. Attributes + * are defined in enum qca_wlan_vendor_attr_config. Userspace can send one + * or more configuration attributes with a single command. The driver + * accepts the command only if all the configurations are known, otherwise + * it rejects the command. The driver returns success only if processing of + * all the configurations succeeds. The driver continues to process all the + * configurations even if processing of some configurations failed and + * returns the last error occurred while processing the failed + * configurations. + * + * @QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION: This command is used to + * get the current values of the various wiphy or interface level + * configurations. Attributes are defined in enum + * qca_wlan_vendor_attr_config. Userspace needs to specify the + * configuration attributes for which it wants to get the values in the + * command, there is no significance for the value sent in the attribute + * unless explicitly specified in the corresponding configuration + * attribute documentation. The driver accepts the command only if all the + * configurations are known, otherwise it rejects the command. The driver + * returns success only if fetching of all configuration values succeeds + * and indicates the configuration values in corresponding attributes in + * the response. The driver continues to process all the configurations + * even if processing of some configurations failed and returns the last + * error occurred while processing the failed configurations. + * * @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: Get the feature bitmap * based on enum wifi_logger_supported_features. Attributes defined in * enum qca_wlan_vendor_attr_get_logger_features. @@ -711,10 +887,10 @@ enum qca_radiotap_vendor_ids { * This event contains Tx VDEV group information, other VDEVs * interface index, and status information. * - * @QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY: Vendor command to - * configure the concurrent session policies when multiple STA interfaces + * @QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY: Vendor command to + * configure the concurrent session policies when multiple interfaces * are (getting) active. The attributes used by this command are defined - * in enum qca_wlan_vendor_attr_concurrent_sta_policy. + * in enum qca_wlan_vendor_attr_concurrent_policy. * * @QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS: Userspace can use this command * to query usable channels for different interface types such as STA, @@ -762,6 +938,295 @@ enum qca_radiotap_vendor_ids { * various roam events to userspace. * Applicable only for the STA mode. The attributes used with this command * are defined in enum qca_wlan_vendor_attr_roam_events. + * + * @QCA_NL80211_VENDOR_SUBCMD_RATEMASK_CONFIG: Subcommand to set or reset the + * rate mask config for a list of PHY types. Userspace shall provide an + * array of the vendor attributes defined in + * enum qca_wlan_vendor_attr_ratemask_params. + * + * @QCA_NL80211_VENDOR_SUBCMD_MCC_QUOTA: Multi-channel Concurrency (MCC) occurs + * when two interfaces are active on the same band, using two different + * home channels, and only supported by a single radio. In this scenario + * the device must split the use of the radio between the two interfaces. + * The percentage of time allocated to a given interface is the quota. + * Depending on the configuration, the quota can either be fixed or + * dynamic. + * + * When used as an event, the device will report the quota type, and for + * all interfaces operating in MCC it will report the current quota. + * When used as a command, the device can be configured for a specific + * quota type, and in the case of a fixed quota, the quota to apply to one + * of the interfaces. + * + * Applications can use the event to do TX bitrate control based on the + * information, and can use the command to explicitly set the quota to + * enhance performance in specific scenarios. + * + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_mcc_quota. + * + * @QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX: Vendor command to + * get the WLAN radio combinations matrix supported by the device which + * provides the device simultaneous radio configurations such as + * standalone, dual band simultaneous, and single band simultaneous. + * + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_radio_combination_matrix. + * + * @QCA_NL80211_VENDOR_SUBCMD_DRIVER_READY: Event indicating to the user space + * that the driver is ready for operations again after recovering from + * internal failures. This occurs following a failure that was indicated by + * @QCA_NL80211_VENDOR_SUBCMD_HANG. + * + * @QCA_NL80211_VENDOR_SUBCMD_PASN: Subcommand used to offload preassociation + * security negotiation and key generation to user space. + * + * When used as an event, the driver requests userspace to trigger the PASN + * authentication or dropping of a PTKSA for the indicated peer devices. + * When used as a command response, userspace indicates a consolidated + * status report for all the peers that were requested for. + * + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_pasn. + * + * @QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT: Subcommand used to set + * secure ranging context such as TK and LTF keyseed for each peer + * requested by the driver with a @QCA_NL80211_VENDOR_SUBCMD_PASN event. + * + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_secure_ranging_ctx. + * + * @QCA_NL80211_VENDOR_SUBCMD_COAP_OFFLOAD: This vendor subcommand is used to + * enable/disable offload processing in firmware during system/runtime + * suspend for CoAP messages (see RFC7252: The Constrained Application + * Protocol) and fetch information of the CoAP messages cached during + * offload processing. + * + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_coap_offload. + * + * @QCA_NL80211_VENDOR_SUBCMD_SCS_RULE_CONFIG: Subcommand to configure + * (add, remove, or change) a Stream Classification Service (SCS) rule. + * + * The attributes used with this event are defined in + * enum qca_wlan_vendor_attr_scs_rule_config. + * + * @QCA_NL80211_VENDOR_SUBCMD_GET_SAR_CAPABILITY: Fetch SAR capabilities + * supported by the WLAN firmware. + * + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_sar_capability. + * + * @QCA_NL80211_VENDOR_SUBCMD_SR: Subcommand used to implement Spatial Reuse + * (SR) feature. This command is used by userspace to configure SR + * parameters to the driver and to get the SR related parameters and + * statistics with synchronous responses from the driver. + * The driver also uses this command to send asynchronous events to + * userspace to indicate suspend/resume of SR feature and changes + * in SR parameters. + * + * The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_sr. + * + * @QCA_NL80211_VENDOR_SUBCMD_MLO_PEER_PRIM_NETDEV_EVENT: Subcommand used to + * notify application layer about the primary netdev of an MLO connection. + * In some implementations, MLO has multiple netdevs out of which one + * netdev is designated as primary to provide a unified interface to the + * bridge. In those implementations this event is sent on every MLO peer + * connection. User applications on an AP MLD will use this event to get + * info for all the links from non-AP MLD that were negotiated to be used + * for the ML association. + * + * The attributes used with this event are defined in + * enum qca_wlan_vendor_attr_mlo_peer_prim_netdev_event. + * + * @QCA_NL80211_VENDOR_SUBCMD_AFC_EVENT: This vendor command is used by the + * driver to notify different AFC events to userspace. The attributes used + * with this command are defined in enum qca_wlan_vendor_attr_afc_event. + * + * @QCA_NL80211_VENDOR_SUBCMD_AFC_RESPONSE: This vendor command is used by + * userspace to deliver AFC response data to driver. The attributes used + * with this command are defined in enum qca_wlan_vendor_attr_afc_response. + * + * @QCA_NL80211_VENDOR_SUBCMD_DOZED_AP: Subcommand to configure AP interface to + * operate in doze mode. + * + * Userspace uses this command to configure the AP interface to enter or + * exit from doze mode. The driver sends this event after it enters or + * exits the doze mode with the updated AP doze mode settings. + * + * The attributes used with this subcommand are defined in + * enum qca_wlan_vendor_attr_dozed_ap. + * + * @QCA_NL80211_VENDOR_SUBCMD_GET_MONITOR_MODE: This vendor subcommand is used + * to get the status of local packet capture of monitor mode. The monitor + * mode can be started using QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE + * subcommand. + * + * The attributes used with this command are defined in enum + * qca_wlan_vendor_attr_get_monitor_mode. + * + * @QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS: This vendor command is used to + * get roam information from the driver to user space. It provides the + * latest several instances of roam information cached in the driver. + * The command is only used for STA mode. The attributes used with this + * command are defined in enum qca_wlan_vendor_attr_roam_cached_stats. + * + * @QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE: This vendor subcommand is used to + * configure and fetch the state information of the MLO links affiliated + * with the STA interface. The attributes used with this command are + * defined in enum qca_wlan_vendor_attr_mlo_link_state. + * + * @QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS: Userspace can use this + * vendor subcommand to trigger channel utilization measurement on entire + * channel width of the connected channel(s). For MLO connection, connected + * channel utilization measurement shall be done on all the MLO links. + * The driver may use regular scan or wideband energy detection feature + * based on the hardware capability for connected channel(s) utilization + * measurement. The driver indicates the connected channel(s) utilization + * measurement completion as an asynchronous event with this command ID to + * userspace. Upon receiving this event, userspace can use + * %NL80211_CMD_GET_INTERFACE to determine the channel width of the current + * connected channel(s) and can derive the channel utilization percentage + * (CU) of each 20 MHz sub-channel of the entire connected channel using + * %NL80211_CMD_GET_SURVEY response. + * CU = %NL80211_SURVEY_INFO_TIME_BUSY * 100 / %NL80211_SURVEY_INFO_TIME. + * This command is only used for STA mode. + * + * @QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP: This vendor subcommand is + * used as an event to notify the userspace of TID-to-link map changes + * negotiated by the driver or updated by associated AP MLD with Beacon, + * Probe Response, or Action frames. The attributes used with this command + * are defined in enum qca_wlan_vendor_attr_tid_to_link_map. + * + * Note that the attribute + * %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR may not correspond to + * the current connected AP MLD address. + * + * @QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG: Notify userspace about the removal + * of STA MLD setup links due to the AP MLD removing the corresponding + * affiliated APs with Multi-Link reconfiguration. If all the STA MLD setup + * links are removed during Multi-Link reconfiguration, the driver shall + * use %NL80211_CMD_DISCONNECT instead of this command since it is a + * connection drop. The attributes used with this command are defined in + * enum qca_wlan_vendor_attr_link_reconfig. + * Note that the attribute + * %QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR may not correspond to + * the current connected AP MLD address. + * + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT: Vendor command to configure + * the driver with MLO link id information on which to transmit the TDLS + * discovery response frame on the configured MLO BSS link when the + * local station is connected in MLO mode. This command is sent to the + * driver prior to the TDLS discovery response management transmit + * operation and is followed immediately by the TDLS discovery response + * management frame transmit command. + * + * The driver saves the configured MLO link id information and uses it for + * the following TDLS discovery response frame transmission on the + * configured MLO BSS link and the link id information is cleared in the + * driver after the TDLS discovery response frame is successfully + * transmitted. This behavior is indepent of the TDLS peer STA connection + * mode (MLO or non-MLO). + * + * Uses the attributes defined in + * enum qca_wlan_vendor_attr_tdls_disc_rsp_ext. + * + * @QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY: This vendor subcommand is used to + * configure, retrieve, and report per-link transmit latency statistics. + * + * The attributes used with this subcommand are defined in + * enum qca_wlan_vendor_attr_tx_latency. + * + * @QCA_NL80211_VENDOR_SUBCMD_REGULATORY_TPC_INFO: Vendor command is used to + * query transmit power information on STA interface from the driver for a + * connected AP. The attributes included in response are defined in + * enum qca_wlan_vendor_attr_tpc_links. In case of MLO STA, multiple links + * TPC info may be returned. The information includes regulatory maximum + * transmit power limit, AP local power constraint advertised from AP's + * Beacon and Probe Response frames. For PSD power mode, the information + * includes PSD power levels for each subchannel of operating bandwidth. + * The information is driver calculated power limits based on the current + * regulatory domain, AP local power constraint, and other IEs. The + * information will be set to target. Target will decide the final TX power + * based on this and chip specific power conformance test limits (CTL), and + * SAR limits. + * + * @QCA_NL80211_VENDOR_SUBCMD_FW_PAGE_FAULT_REPORT: Event indication from the + * driver to user space which is carrying firmware page fault related + * summary report. The attributes for this command are defined in + * enum qca_wlan_vendor_attr_fw_page_fault_report. + * + * @QCA_NL80211_VENDOR_SUBCMD_DISASSOC_PEER: Event indication from the driver + * to user space to disassociate with a peer based on the peer MAC address + * provided. Specify the peer MAC address in + * QCA_WLAN_VENDOR_ATTR_MAC_ADDR. For MLO, MLD MAC address is provided. + * + * @QCA_NL80211_VENDOR_SUBCMD_ADJUST_TX_POWER: This vendor command is used to + * adjust transmit power. The attributes used with this subcommand are + * defined in enum qca_wlan_vendor_attr_adjust_tx_power. + * + * @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_COMPLETE: Event indication from the + * driver to notify user application about the spectral scan completion. + * The attributes used with this subcommand are defined in + * enum qca_wlan_vendor_attr_spectral_scan_complete. + * + * @QCA_NL80211_VENDOR_SUBCMD_ASYNC_GET_STATION: Register for receiving + * %NL80211_CMD_GET_STATION responses as unicast events when there are + * %NL80211_CMD_GET_STATION requests from any userspace module on the same + * interface index with which this command is sent. This command is also + * used as the unicast event to indicate the %NL80211_CMD_GET_STATION + * response. The attributes for this command are defined in + * enum qca_wlan_vendor_async_get_station_attr. + * + * The driver will send the unicast events with same netlink port ID which + * is used by userspace application for sending the registration command. + * If multiple registration commands are received with different netlink + * port IDs, the driver will send unicast events with each netlink port ID + * separately. + * + * Userspace applications can deregister the unicast event reporting with + * disable configuration. The registrations will be removed automatically + * by the driver when the corresponding netlink socket is closed. + * + * @QCA_NL80211_VENDOR_SUBCMD_AP_SUSPEND: Vendor command to put an AP interface + * in suspend state. On enabling suspend, AP deauthenticates all associated + * stations and stops TX/RX operations on the interface. The driver + * retains the AP configuration and on resume, starts all TX/RX operations + * with the same AP configuration. + * + * This subcommand is also used as an event to notify userspace about AP + * suspended/resumed state changes. + * + * The attributes used with this command/event are defined in enum + * qca_wlan_vendor_attr_ap_suspend. + * + * @QCA_NL80211_VENDOR_SUBCMD_FLOW_STATS: Event indication from the driver to + * the userspace which contains all the statistics collected for a flow to + * be classified. This event is sent if the userspace enables the + * flow stats reporting via the command + * @QCA_NL80211_VENDOR_SUBCMD_ASYNC_STATS_POLICY and when the driver has + * collected the required flow statistics, as specified by the attributes + * of this event. The attributes for this event are defined in + * enum qca_wlan_vendor_attr_flow_stats. + * @QCA_NL80211_VENDOR_SUBCMD_FLOW_CLASSIFY_RESULT: This vendor command is used + * to indicate the flow classification result based on the flow samples + * received as a part of @QCA_NL80211_VENDOR_SUBCMD_FLOW_STATS. The + * attributes for this command are defined in the + * enum qca_wlan_vendor_attr_flow_classify_result. + * @QCA_NL80211_VENDOR_SUBCMD_ASYNC_STATS_POLICY: This vendor command is used to + * indicate the ASYNC statistics policy from the userspace to the driver + * and it contains the STATS type for which the command is intended. The + * attributes for this command are defined in the + * enum qca_wlan_vendor_attr_async_stats_policy. + * @QCA_NL80211_VENDOR_SUBCMD_CLASSIFIED_FLOW_REPORT: Event indication from the + * driver to the userspace containing all the samples of a classified + * flow along with its classification result. This event is sent by the + * driver to userspace when it receives classification result via the + * command @QCA_NL80211_VENDOR_SUBCMD_FLOW_CLASSIFY_RESULT and the + * collection of these statistics has been enabled by the command + * @QCA_NL80211_VENDOR_SUBCMD_ASYNC_STATS_POLICY. The attributes for this + * event are defined in enum qca_wlan_vendor_attr_flow_stats. */ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, @@ -948,15 +1413,60 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_UPDATE_SSID = 194, QCA_NL80211_VENDOR_SUBCMD_WIFI_FW_STATS = 195, QCA_NL80211_VENDOR_SUBCMD_MBSSID_TX_VDEV_STATUS = 196, - QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY = 197, + QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY = 197, QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS = 198, QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY = 199, QCA_NL80211_VENDOR_SUBCMD_MDNS_OFFLOAD = 200, /* 201 - reserved for QCA */ QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE = 202, QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS = 203, + QCA_NL80211_VENDOR_SUBCMD_RATEMASK_CONFIG = 204, + QCA_NL80211_VENDOR_SUBCMD_MCC_QUOTA = 205, + /* 206..212 - reserved for QCA */ + QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX = 213, + QCA_NL80211_VENDOR_SUBCMD_DRIVER_READY = 214, + QCA_NL80211_VENDOR_SUBCMD_PASN = 215, + QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT = 216, + QCA_NL80211_VENDOR_SUBCMD_COAP_OFFLOAD = 217, + QCA_NL80211_VENDOR_SUBCMD_SCS_RULE_CONFIG = 218, + QCA_NL80211_VENDOR_SUBCMD_GET_SAR_CAPABILITY = 219, + QCA_NL80211_VENDOR_SUBCMD_SR = 220, + QCA_NL80211_VENDOR_SUBCMD_MLO_PEER_PRIM_NETDEV_EVENT = 221, + QCA_NL80211_VENDOR_SUBCMD_AFC_EVENT = 222, + QCA_NL80211_VENDOR_SUBCMD_AFC_RESPONSE = 223, + QCA_NL80211_VENDOR_SUBCMD_DOZED_AP = 224, + QCA_NL80211_VENDOR_SUBCMD_GET_MONITOR_MODE = 225, + QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS = 226, + QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE = 227, + QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS = 228, + QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP = 229, + QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG = 230, + QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT = 231, + /* 232 - reserved for QCA */ + QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY = 233, + /* 234 - reserved for QCA */ + QCA_NL80211_VENDOR_SUBCMD_SDWF_PHY_OPS = 235, + QCA_NL80211_VENDOR_SUBCMD_SDWF_DEV_OPS = 236, + QCA_NL80211_VENDOR_SUBCMD_REGULATORY_TPC_INFO = 237, + QCA_NL80211_VENDOR_SUBCMD_FW_PAGE_FAULT_REPORT = 238, + QCA_NL80211_VENDOR_SUBCMD_FLOW_POLICY = 239, + QCA_NL80211_VENDOR_SUBCMD_DISASSOC_PEER = 240, + QCA_NL80211_VENDOR_SUBCMD_ADJUST_TX_POWER = 241, + QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_COMPLETE = 242, + QCA_NL80211_VENDOR_SUBCMD_ASYNC_GET_STATION = 243, + QCA_NL80211_VENDOR_SUBCMD_AP_SUSPEND = 244, + QCA_NL80211_VENDOR_SUBCMD_FLOW_STATS = 245, + QCA_NL80211_VENDOR_SUBCMD_FLOW_CLASSIFY_RESULT = 246, + QCA_NL80211_VENDOR_SUBCMD_ASYNC_STATS_POLICY = 247, + QCA_NL80211_VENDOR_SUBCMD_CLASSIFIED_FLOW_REPORT = 248, }; +/* Compatibility defines for previously used subcmd names. + * These values should not be used in any new implementation. + */ +#define QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY \ + QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY + enum qca_wlan_vendor_attr { QCA_WLAN_VENDOR_ATTR_INVALID = 0, /* used by QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */ @@ -991,7 +1501,7 @@ enum qca_wlan_vendor_attr { * use QCA_WLAN_VENDOR_ATTR_SETBAND_MASK instead. */ QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12, - /* Dummy (NOP) attribute for 64 bit padding */ + /* Attribute used for padding for 64-bit alignment */ QCA_WLAN_VENDOR_ATTR_PAD = 13, /* Unique FTM session cookie (Unsigned 64 bit). Specified in * QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION. Reported in @@ -1161,14 +1671,45 @@ enum qca_wlan_vendor_attr { */ QCA_WLAN_VENDOR_ATTR_SETBAND_MASK = 43, + /* Unsigned 8-bit used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES. + * This field describes the maximum number of links supported by the + * chip for MLO association. + * This is an optional attribute. + */ + QCA_WLAN_VENDOR_ATTR_MLO_CAPABILITY_MAX_ASSOCIATION_COUNT = 44, + + /* Unsigned 8-bit used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES. + * This field describes the maximum number of Simultaneous Transmit + * and Receive (STR) links used in Multi-Link Operation. + * The maximum number of STR links used can be different + * from the maximum number of radios supported by the chip. + * This is a static configuration of the chip. + * This is an optional attribute. + */ + QCA_WLAN_VENDOR_ATTR_MLO_CAPABILITY_MAX_STR_LINK_COUNT = 45, + /* keep last */ QCA_WLAN_VENDOR_ATTR_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1, }; +/** + * enum qca_roaming_policy - Represents the policies for roaming. Used by + * QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY. + * + * QCA_ROAMING_NOT_ALLOWED: Roaming is not allowed/disabled. + * + * QCA_ROAMING_ALLOWED_WITHIN_ESS: Roaming is allowed with in an ESS with + * default RSSI thresholds. + * + * QCA_ROAMING_MODE_AGGRESSIVE: This mode is an extension of + * QCA_ROAMING_ALLOWED_WITHIN_ESS. The driver/firmware roams on higher RSSI + * thresholds when compared to QCA_ROAMING_ALLOWED_WITHIN_ESS. + */ enum qca_roaming_policy { QCA_ROAMING_NOT_ALLOWED, QCA_ROAMING_ALLOWED_WITHIN_ESS, + QCA_ROAMING_MODE_AGGRESSIVE, }; /** @@ -1221,6 +1762,9 @@ enum qca_roaming_policy { * * @QCA_ROAM_REASON_BT_ACTIVITY: Roam triggered due to Bluetooth connection is * established when the station is connected in the 2.4 GHz band. + * + * @QCA_ROAM_REASON_STA_KICKOUT: Roam triggered due to continuous TX Data frame + * failures to the connected AP. */ enum qca_roam_reason { QCA_ROAM_REASON_UNKNOWN, @@ -1238,10 +1782,14 @@ enum qca_roam_reason { QCA_ROAM_REASON_PERIODIC_TIMER, QCA_ROAM_REASON_BACKGROUND_SCAN, QCA_ROAM_REASON_BT_ACTIVITY, + QCA_ROAM_REASON_STA_KICKOUT, }; enum qca_wlan_vendor_attr_roam_auth { QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0, + /* Indicates BSSID of the roamed AP for non-MLO roaming and MLD address + * of the roamed AP for MLO roaming. + */ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE, @@ -1286,6 +1834,11 @@ enum qca_wlan_vendor_attr_roam_auth { * Defined by enum qca_roam_reason. */ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REASON = 14, + /* A nested attribute containing per-link information of all the links + * of MLO connection done while roaming. The attributes used inside this + * nested attribute are defined in enum qca_wlan_vendor_attr_mlo_links. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MLO_LINKS = 15, /* keep last */ QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST, @@ -1467,6 +2020,17 @@ enum qca_wlan_vendor_attr_p2p_listen_offload { * Used with command to configure ACS operation for EHT mode. * Disable (flag attribute not present) - EHT disabled and * Enable (flag attribute present) - EHT enabled. + * + * @QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME: Optional (u32). + * Used with command to configure how older scan can be considered for ACS + * scoring. In case scan was performed on a partial set of channels configured + * with this command within last QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME + * (in ms), scan only the remaining channels. + * + * @QCA_WLAN_VENDOR_ATTR_ACS_LINK_ID: Mandatory on AP MLD (u8). + * Used with command to configure ACS operation for a specific link affiliated + * to an AP MLD. + * */ enum qca_wlan_vendor_attr_acs_offload { QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0, @@ -1489,6 +2053,8 @@ enum qca_wlan_vendor_attr_acs_offload { QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL = 17, QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP = 18, QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED = 19, + QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME = 20, + QCA_WLAN_VENDOR_ATTR_ACS_LINK_ID = 21, /* keep last */ QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST, @@ -1571,6 +2137,49 @@ enum qca_wlan_vendor_acs_hw_mode { * 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. + * @QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI: Flag indicates + * that the driver requires add/del virtual interface path using the + * generic nl80211 commands for NDP interface create/delete and to + * register/unregister the netdev instead of creating/deleting the NDP + * interface using the vendor commands + * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE and + * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE. With the latest kernel + * (5.12 version onward), interface creation/deletion is not allowed using + * vendor commands as it leads to a deadlock while acquiring the RTNL_LOCK + * during the register/unregister of netdev. Create and delete NDP + * interface using NL80211_CMD_NEW_INTERFACE and NL80211_CMD_DEL_INTERFACE + * commands respectively if the driver advertises this capability set. + * @QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_STA: Flag indicates that the device in + * station mode supports secure LTF. If NL80211_EXT_FEATURE_SECURE_LTF is + * set, then QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_STA will be ignored. + * @QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_AP: Flag indicates that the device in AP + * mode supports secure LTF. If NL80211_EXT_FEATURE_SECURE_LTF is set, then + * QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_AP will be ignored. + * @QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_STA: Flag indicates that the device in + * station mode supports secure RTT measurement exchange. If + * NL80211_EXT_FEATURE_SECURE_RTT is set, + * QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_STA will be ignored. + * @QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_AP: Flag indicates that the device in AP + * mode supports secure RTT measurement exchange. If + * NL80211_EXT_FEATURE_SECURE_RTT is set, + * QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_AP will be ignored. + * @QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_STA: Flag indicates that + * the device in station mode supports protection of range negotiation and + * measurement management frames. If + * NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE is set, then + * QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_STA will be ignored. + * @QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP: Flag indicates that + * the device in AP mode supports protection of range negotiation and + * measurement management frames. If + * NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE is set, then + * QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP will be ignored. + * @QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST: Flag indicates that the device + * in AP mode supports configuring allowed frequency list for AP operation + * with %QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST. + * @QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN: Flag indicates + * that the device supports enhanced audio experience over WLAN feature. + * @QCA_WLAN_VENDOR_FEATURE_HT_VHT_TWT_RESPONDER: Flag indicates that the device + * in AP mode supports TWT responder mode in HT and VHT modes. * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits */ enum qca_wlan_vendor_features { @@ -1582,13 +2191,23 @@ enum qca_wlan_vendor_features { QCA_WLAN_VENDOR_FEATURE_OCE_AP = 5, QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON = 6, QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY = 7, - QCA_WLAN_VENDOR_FEATURE_TWT = 8, + QCA_WLAN_VENDOR_FEATURE_TWT = 8, 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, + QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI = 15, + QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_STA = 16, + QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_AP = 17, + QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_STA = 18, + QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_AP = 19, + QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_STA = 20, + QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP = 21, + QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST = 22, + QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN = 23, + QCA_WLAN_VENDOR_FEATURE_HT_VHT_TWT_RESPONDER = 24, NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */ }; @@ -1800,7 +2419,8 @@ enum qca_access_policy { * &enum qca_tsf_cmd. * @QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE: Optional (u64) * This attribute contains TSF timer value. This attribute is only available - * in %QCA_TSF_GET or %QCA_TSF_SYNC_GET response. + * in %QCA_TSF_GET, %QCA_TSF_SYNC_GET or %QCA_TSF_SYNC_GET_CSA_TIMESTAMP + * response. * @QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE: Optional (u64) * This attribute contains SOC timer value at TSF capture. This attribute is * only available in %QCA_TSF_GET or %QCA_TSF_SYNC_GET response. @@ -1808,6 +2428,8 @@ enum qca_access_policy { * This attribute is used to provide TSF sync interval and only applicable when * TSF command is %QCA_TSF_SYNC_START. If this attribute is not provided, the * driver will use the default value. Time unit is in milliseconds. + * @QCA_WLAN_VENDOR_ATTR_TSF_PAD: Attribute used for padding for 64-bit + * alignment. */ enum qca_vendor_attr_tsf_cmd { QCA_WLAN_VENDOR_ATTR_TSF_INVALID = 0, @@ -1815,6 +2437,7 @@ enum qca_vendor_attr_tsf_cmd { QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE, QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE, QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL, + QCA_WLAN_VENDOR_ATTR_TSF_PAD, QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_TSF_MAX = QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST - 1 @@ -1827,13 +2450,15 @@ enum qca_vendor_attr_tsf_cmd { * @QCA_TSF_SYNC_GET: Initiate TSF capture and return with captured value * @QCA_TSF_AUTO_REPORT_ENABLE: Used in STA mode only. Once set, the target * will automatically send TSF report to the host. To query - * %QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY, this operation needs to be - * initiated first. + * %QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY or + * %QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY_JITTER, this operation needs + * to be initiated first. * @QCA_TSF_AUTO_REPORT_DISABLE: Used in STA mode only. Once set, the target * will not automatically send TSF report to the host. If * %QCA_TSF_AUTO_REPORT_ENABLE is initiated and - * %QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY is not queried anymore, this - * operation needs to be initiated. + * %QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY or + * %QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY_JITTER is not queried + * anymore, this operation needs to be initiated. * @QCA_TSF_SYNC_START: Start periodic TSF sync feature. The driver periodically * fetches TSF and host time mapping from the firmware with interval configured * through the %QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL attribute. If the @@ -1841,6 +2466,12 @@ enum qca_vendor_attr_tsf_cmd { * userspace can query the TSF and host time mapping via the %QCA_TSF_GET * command. * @QCA_TSF_SYNC_STOP: Stop periodic TSF sync feature. + * @QCA_TSF_SYNC_GET_CSA_TIMESTAMP: Get TSF timestamp when AP will move and + * starts beaconing on a new channel. The driver synchronously responds with the + * TSF value using attribute %QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE. Userspace + * gets the valid CSA TSF after receiving %NL80211_CMD_CH_SWITCH_STARTED_NOTIFY + * on the AP interface. This TSF can be sent via OOB mechanism to connected + * clients. */ enum qca_tsf_cmd { QCA_TSF_CAPTURE, @@ -1850,6 +2481,7 @@ enum qca_tsf_cmd { QCA_TSF_AUTO_REPORT_DISABLE, QCA_TSF_SYNC_START, QCA_TSF_SYNC_STOP, + QCA_TSF_SYNC_GET_CSA_TIMESTAMP, }; /** @@ -1989,6 +2621,12 @@ enum qca_wlan_vendor_scan_priority { * qca_wlan_vendor_scan_priority. This is an optional attribute. * If this attribute is not configured, the driver shall use * QCA_WLAN_VENDOR_SCAN_PRIORITY_HIGH as the priority of vendor scan. + * @QCA_WLAN_VENDOR_ATTR_SCAN_PAD: Attribute used for padding for 64-bit + * alignment. + * @QCA_WLAN_VENDOR_ATTR_SCAN_LINK_ID: This u8 attribute is used for OBSS scan + * when AP is operating as MLD to specify which link is requesting the + * scan or which link the scan result is for. No need of this attribute + * in other cases. */ enum qca_wlan_vendor_attr_scan { QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0, @@ -2005,6 +2643,8 @@ enum qca_wlan_vendor_attr_scan { QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11, QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME = 12, QCA_WLAN_VENDOR_ATTR_SCAN_PRIORITY = 13, + QCA_WLAN_VENDOR_ATTR_SCAN_PAD = 14, + QCA_WLAN_VENDOR_ATTR_SCAN_LINK_ID = 15, QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_SCAN_MAX = QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1 @@ -2087,9 +2727,11 @@ enum qca_wlan_vendor_attr_config { * used to calculate statistics like average the TSF offset or average * number of frame leaked. * For instance, upon Beacon frame reception: - * current_avg = ((beacon_TSF - TBTT) * factor + previous_avg * (0x10000 - factor) ) / 0x10000 + * current_avg = ((beacon_TSF - TBTT) * factor + + * previous_avg * (0x10000 - factor)) / 0x10000 * For instance, when evaluating leaky APs: - * current_avg = ((num frame received within guard time) * factor + previous_avg * (0x10000 - factor)) / 0x10000 + * current_avg = ((num frame received within guard time) * factor + + * previous_avg * (0x10000 - factor)) / 0x10000 */ QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR = 2, /* Unsigned 32-bit value to configure guard time, i.e., when @@ -2218,7 +2860,10 @@ enum qca_wlan_vendor_attr_config { /* 32-bit unsigned value to set reorder timeout for AC_BK */ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_BACKGROUND = 34, /* 6-byte MAC address to point out the specific peer */ - QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_PEER_MAC = 35, + QCA_WLAN_VENDOR_ATTR_CONFIG_PEER_MAC = 35, + /* Backward compatibility with the original name */ + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_PEER_MAC = + QCA_WLAN_VENDOR_ATTR_CONFIG_PEER_MAC, /* 32-bit unsigned value to set window size for specific peer */ QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_WINLIMIT = 36, /* 8-bit unsigned value to set the beacon miss threshold in 2.4 GHz */ @@ -2362,7 +3007,10 @@ enum qca_wlan_vendor_attr_config { QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES = 58, /* 8-bit unsigned value for ELNA bypass. - * 1-Enable, 0-Disable + * 0 - Disable eLNA bypass. + * 1 - Enable eLNA bypass. + * 2 - Reset eLNA bypass configuration, the driver should + * revert to the default configuration of eLNA bypass. */ QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59, @@ -2393,12 +3041,11 @@ enum qca_wlan_vendor_attr_config { * 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 + * This configuration can be sent inside + * %QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS to specify the maximum + * supported channel width per-MLO link. + * + * This uses values defined in enum nl80211_chan_width. */ QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH = 63, @@ -2458,23 +3105,16 @@ enum qca_wlan_vendor_attr_config { */ 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). - */ + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ QCA_WLAN_VENDOR_ATTR_CONFIG_NSS = 70, - /* 8-bit unsigned value to trigger Optimized Power Management: - * 1-Enable, 0-Disable + + /* 8-bit unsigned value to configure Optimized Power Management mode: + * Modes are defined by enum qca_wlan_vendor_opm_mode. + * + * This attribute shall be configured along with + * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO and + * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL attributes + * when its value is set to %QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED. */ QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT = 71, @@ -2488,24 +3128,21 @@ enum qca_wlan_vendor_attr_config { * 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. + * + * If only UDP frames of BE or BK access category needs to be upgraded + * without changing the access category of VO or VI UDP frames, refer to + * attribute QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE_FOR_BE_BK. + * + * This attribute is not recommended to be used as it blindly forces all + * UDP packets to a higher access category which could impact the + * traffic pattern of all apps using UDP and can cause unknown behavior. */ 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. - */ + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ 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. - */ + + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS = 74, /* 8-bit unsigned value to configure ANI setting type. @@ -2599,6 +3236,416 @@ enum qca_wlan_vendor_attr_config { */ QCA_WLAN_VENDOR_ATTR_CONFIG_ARP_NS_OFFLOAD = 81, + /* + * 8-bit unsigned value. This attribute can be used to configure the + * data path mode to be followed for audio traffic. Possible values + * are defined in enum qca_wlan_audio_data_path. + * + * This attribute is used only when the driver advertises support for + * QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_AUDIO_DATA_PATH = 82, + + /* + * 8-bit unsigned value. This attribute can be used to configure the + * Dedicated Bluetooth Antenna Mode (DBAM) feature. Possible values for + * this attribute are defined in the enum qca_wlan_dbam_config. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_DBAM = 83, + + /* 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 of BE or BK access category to this access + * category. This attribute will not modify UDP frames of VO or VI + * 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. + * + * This attribute behavior is similar to + * QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE with the difference that + * only UDP frames of BE or BK access category are upgraded and not + * UDP frames of VI or VO access category. + * + * This attribute is not recommended to be used as it blindly forces all + * UDP packets of BE or BK access category to a higher access category + * which could impact the traffic pattern of all apps using UDP and can + * cause unknown behavior. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE_FOR_BE_BK = 84, + + /* 8-bit unsigned value to configure the driver to enable/disable the + * periodic sounding for Tx beamformer functionality. The default + * behavior uses algorithm to do sounding based on packet stats. + * + * 0 - Default behavior. + * 1 - Enable the periodic sounding for Tx beamformer. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_BEAMFORMER_PERIODIC_SOUNDING = 85, + + /* 8-bit unsigned value, whenever wifi calling (wfc) begins or ends, + * userspace sends this information to the driver/firmware to configure + * wfc state. The driver/firmware uses this information to + * optimize power savings, rate adaption, roaming, etc. + * + * 1 - wfc is on. + * 0 - wfc is off. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_WFC_STATE = 86, + + /* 8-bit unsigned value to configure the driver to enable/disable the + * EHT EML capability in management frame EHT capabilities. + * 1 - Enable, 0 - Disable. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_EML_CAPABILITY = 87, + + /* 8-bit unsigned value to configure the driver with EHT MLO max + * simultaneous links to be used for MLO connection. + * The range of the value is 0 to 14. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MAX_SIMULTANEOUS_LINKS = 88, + + /* 8-bit unsigned value to configure the driver with EHT MLO maximum + * number of links to be used for MLO connection. Value 0 restores the + * default value of the maximum MLO links capability of the device. + * The range of the value is 0 to 15. + * + * 0 - Restore default device limit. + * 1 to 15 - Set the maximum number of links to be used for an MLO + * connection. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MAX_NUM_LINKS = 89, + + /* 8-bit unsigned value to configure the driver with EHT MLO mode. + * Uses enum qca_wlan_eht_mlo_mode values. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MODE = 90, + + /* Nested attribute with frequencies in u32 attributes to configure a + * list of allowed 20 MHz channel center frequencies in MHz for AP + * operation. Whenever performing a channel selection operation, the + * driver shall generate a new list based on this provided list by + * filtering out channels that cannot be used at that time due to + * regulatory or other constraints. The resulting list is used as the + * list of all allowed channels, i.e., operation on any channel that is + * not included is not allowed, whenever performing operations like ACS + * and DFS. + * + * Userspace shall configure this before starting the AP and the + * configuration is valid only from the next BSS start and until the + * BSS is stopped. The driver shall clear this configuration when the + * AP is stopped and fall back to the default behavior for subsequent + * AP operation. + * + * The default behavior when this configuration is not applicable is the + * driver can choose any of the channels supported by the hardware + * except the channels that cannot be used due to regulatory or other + * constraints. + * + * The driver shall reject this configuration if done after the AP is + * started. This attribute can be used to specify user's choice of + * frequencies and static puncture channel list, etc. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST = 91, + + /* Nested attribute to indicate EHT MLO links to be forced active. + * It contains link MAC address attributes. These nested attributes are + * of the type NL80211_ATTR_MAC and are used to force enabling of the + * MLO links corresponding to the indicated link MAC addresses. + * Subsequently, the links corresponding to the link MAC addresses that + * are not indicated are forced inactive. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_ACTIVE_LINKS = 92, + + /* 8-bit unsigned value to configure EMLSR mode entry or exit. + * Uses enum qca_wlan_emlsr_mode values. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_EMLSR_MODE_SWITCH = 93, + + /* 8-bit unsigned value to configure the channel bandwidth + * for CTS frame transmission during the dymamic bandwidth + * signaling CTS procedure referred in IEEE Std 802.11-2020, + * 10.3.2.9 CTS and DMG CTS procedure. + * This configuration is used for testing purposes. + * + * This uses values defined in enum nl80211_chan_width. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_CTS_CHANNEL_WIDTH = 94, + + /* 8-bit unsigned value. This attribute is used to dynamically + * enable/suspend trigger based UL MU transmission. + * This is supported in STA mode and the device sends Operating + * Mode Indication to inform the change as described in + * IEEE Std 802.11ax-2021, 26.9. + * + * This attribute can be configured when the STA is associated + * to an AP and the configuration is maintained until the current + * association terminates. + * + * By default all UL MU transmissions are enabled. + * + * Uses enum qca_ul_mu_config values. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_UL_MU_CONFIG = 95, + + /* 8-bit unsigned value. Optionally specified along with + * %QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH when STA is in connected + * state. This configuration is applicable only for the current + * connection. This configuration not allowed in disconnected state. + * This configuration can be sent inside + * %QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS to specify the maximum + * supported channel width update type per-MLO link. + * + * Uses enum qca_chan_width_update_type values. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_CHAN_WIDTH_UPDATE_TYPE = 96, + + /* 8-bit unsigned value to set EPCS (Emergency Preparedness + * Communications Service) feature capability + * 1 - Enable, 0 - Disable. + * + * This configuration is used for testing purposes. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_EPCS_CAPABILITY = 97, + + /* 8-bit unsigned value to enable/disable EPCS priority access + * 1 - Enable, 0 - Disable. + * The EPCS priority access shall be enabled only when EPCS feature + * capability is also enabled (see + * QCA_WLAN_VENDOR_ATTR_CONFIG_EPCS_CAPABILITY). + * + * This configuration is used for testing purposes. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_EPCS_FUNCTION = 98, + + /* 8-bit unsigned value. Used to specify the MLO link ID of a link + * that is being configured. This attribute must be included in each + * record nested inside %QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS, and + * may be included without nesting to indicate the link that is the + * target of other configuration attributes. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID = 99, + + /* Array of nested links each identified by + * %QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID. This uses values defined in + * enum qca_wlan_vendor_attr_config, explicit documentation shall be + * added for the attributes in enum qca_wlan_vendor_attr_config to + * support per-MLO link configuration through + * %QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS. + * + * Userspace can configure a single link or multiple links with this + * attribute by nesting the corresponding configuration attributes and + * %QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID for each link. + * + * Userspace can fetch the configuration attribute values for a single + * link or multiple links with this attribute by nesting the + * corresponding configuration attributes and + * %QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID for each link. + * + * For STA interface, this attribute is applicable only in connected + * state when the current connection is MLO capable. The valid values of + * %QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID are the link IDs of the + * connected AP MLD links. + * + * For AP interface, this configuration applicable only after adding + * MLO links to the AP interface with %NL80211_CMD_ADD_LINK and the + * valid values of %QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID are the link + * IDs specified in %NL80211_CMD_ADD_LINK while adding the MLO links to + * the AP interface. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS = 100, + + /* 16-bit unsigned value to configure power save inactivity timeout in + * milliseconds. + * + * STA enters into power save mode (PM=1) after TX/RX inactivity of time + * duration specified by %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO. + * + * This attribute shall be configured along with + * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL when + * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT + * is set to %QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED mode. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO = 101, + + /* 16-bit unsigned value to configure speculative wake interval in + * milliseconds. + * + * STA speculatively wakes up to look for buffered data by AP at + * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL interval after + * entering into power save. If configured zero, STA wakes up at + * upcoming DTIM beacon. + * + * This attribute shall be configured along with + * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO and + * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT + * to %QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED mode. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL = 102, + + /* + * 16-bit unsigned value to configure TX max A-MPDU count. + * + * For STA interface, this attribute is applicable only in connected + * state, peer MAC address is not required to be provided. + * + * For AP interface, this attribute is applicable only in started + * state and one of the associated peer STAs must be specified with + * QCA_WLAN_VENDOR_ATTR_CONFIG_PEER_MAC. If this is for an ML + * association, the peer MAC address provided is the link address of + * the non-AP MLD. + * + * This attribute runtime configures the TX maximum aggregation size. + * The value must be in range of 1 to BA window size for the specific + * peer. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_PEER_AMPDU_CNT = 103, + + /* + * 8-bit unsigned value to configure TID-to-link mapping negotiation + * type. + * Uses enum qca_wlan_ttlm_negotiation_support values. + * + * This value applies to the complete AP/non-AP MLD interface, and the + * MLD advertises it within the Basic Multi-Link element in the + * association frames. If a new value is configured during an active + * connection, it will take effect in the subsequent associations and + * is not reset during disconnection. + * + * This attribute is used for testing purposes. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_TTLM_NEGOTIATION_SUPPORT = 104, + + /* 8-bit unsigned value. + * + * This attribute configures a traffic shaping mode + * applied during coex scenarios. + * By default all coex traffic shaping modes are enabled, + * i.e., shape WLAN traffic based on coex traffic pattern and priority. + * To shape traffic, STA may enter in power save mode + * and AP may send CTS-to-self frame. + * + * Uses enum qca_coex_traffic_shaping_mode values. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_COEX_TRAFFIC_SHAPING_MODE = 105, + + /* 8-bit unsigned value. + * + * This attribute is used to specify whether an associated peer is a QCA + * device. The associated peer is specified with + * QCA_WLAN_VENDOR_ATTR_CONFIG_PEER_MAC. For MLO cases, the MLD MAC + * address of the peer is used. + * 1 - QCA device, 0 - non-QCA device. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_QCA_PEER = 106, + + /* 8-bit unsigned value to configure BTM support. + * + * The attribute is applicable only for STA interface. Uses enum + * qca_wlan_btm_support values. This configuration is not allowed in + * connected state. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_BTM_SUPPORT = 107, + + /* 16-bit unsigned value to configure client's keep-alive interval in + * seconds. The driver will reduce the keep-alive interval to this + * configured value if the AP advertises BSS maximum idle period and if + * that BSS max idle period is larger than this configured value. If the + * AP does not advertise a maximum value, the configured value will be + * used as a keep-alive period for unprotected frames. + * + * This configuration is applicable only during the STA's current + * association. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_KEEP_ALIVE_INTERVAL = 108, + + /* 8-bit unsigned value to configure reduced power scan mode. + * + * This attribute is used to configure the driver to optimize power + * during scan. For example, the driver can switch to 1x1 from 2x2 mode + * for additional power save. + * + * 1 - Enable reduced power scan mode. + * 0 - Disable reduced power scan mode. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_REDUCED_POWER_SCAN_MODE = 109, + + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ + QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS_2GHZ = 110, + + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS_2GHZ = 111, + + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ + QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS_5GHZ = 112, + + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS_5GHZ = 113, + + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ + QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS_2GHZ = 114, + + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ + QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS_2GHZ = 115, + + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ + QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS_5GHZ = 116, + + /* 8-bit unsigned value. Refer to TX/RX NSS and chain configurations */ + QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS_5GHZ = 117, + + /* 16-bit unsigned value. This attribute is used to dynamically + * configure the time duration of data stall detection. Unit is + * milliseconds. Valid value range is 0 or 10 ms to 10000 ms. If the + * value is 0, the previously configured value is cleared. The driver + * rejects this configuration if the value is out of range. This + * configuration is effective for all connections on the chip. If the + * duration is greater than this configuration and consecutive TX no ack + * count is greater than + * QCA_WLAN_VENDOR_ATTR_CONFIG_CONSECUTIVE_TX_NO_ACK_THRESHOLD, + * data stall event is sent to userspace. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_CONSECUTIVE_TX_NO_ACK_DURATION = 118, + + /* 16-bit unsigned value. This attribute is used to dynamically + * configure the threshold of data stall detection. Valid value is 0 or + * greater than 10. if the value is 0, the previously configured value + * is cleared. The driver rejects this configuration if the value is out + * of range. This configuration is effective for all connections on the + * chip. If consecutive TX no ack count is greater than this + * configuration and duration is greater than + * QCA_WLAN_VENDOR_ATTR_CONFIG_CONSECUTIVE_TX_NO_ACK_DURATION, + * data stall event is sent to userspace. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_CONSECUTIVE_TX_NO_ACK_THRESHOLD = 119, + + /* 8-bit unsigned value to configure the interface offload type + * + * This attribute is used to configure the interface offload capability. + * User can configure software based acceleration, hardware based + * acceleration, or a combination of both using this option. More + * details on each option is described under the enum definition below. + * Uses enum qca_wlan_intf_offload_type for values. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_INTF_OFFLOAD_TYPE = 120, + + /* 8-bit unsigned integer to configure the driver to follow AP's + * preference values to select a roam candidate from BTM request. + * + * This attribute is used to configure the driver to select the roam + * candidate based on AP advertised preference values. If not set, + * the driver uses its internal scoring algorithm to do the same. + * + * 1 - STA follows AP's preference values to select a roam candidate + * 0 - STA uses internal scoring algorithm to select a roam candidate + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_FOLLOW_AP_PREFERENCE_FOR_CNDS_SELECT = 121, + /* keep last */ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX = @@ -2613,6 +3660,29 @@ enum qca_wlan_vendor_attr_config { #define QCA_WLAN_VENDOR_ATTR_BEACON_REPORT_FAIL \ QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL +/** + * enum qca_ul_mu_config - UL MU configuration + * @QCA_UL_MU_SUSPEND - All trigger based UL MU transmission is suspended + * @QCA_UL_MU_ENABLE - All trigger based UL MU transmission is enabled + */ +enum qca_ul_mu_config { + QCA_UL_MU_SUSPEND = 0, + QCA_UL_MU_ENABLE = 1, +}; + +/** + * enum qca_dbam_config - Specifies DBAM config mode + * @QCA_DBAM_DISABLE: Firmware disables DBAM + * @QCA_DBAM_ENABLE: Firmware enables DBAM opportunistically when + * internal criteria are met. + * @QCA_DBAM_FORCE_ENABLE: Firmware enables DBAM forcefully. + */ +enum qca_dbam_config { + QCA_DBAM_DISABLE = 0, + QCA_DBAM_ENABLE = 1, + QCA_DBAM_FORCE_ENABLE = 2, +}; + /** * enum qca_wlan_ani_setting - ANI setting type * @QCA_WLAN_ANI_SETTING_AUTO: Automatically determine ANI level @@ -3113,6 +4183,8 @@ enum qca_wlan_vendor_attr_get_hw_capability { * timestamp and calculate transfer delay for the message. * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MEASUREMENT_TIME: u32 * Real period for this measurement, unit in us. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PAD: Attribute used for padding for + * 64-bit alignment. */ enum qca_wlan_vendor_attr_ll_stats_ext { QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_INVALID = 0, @@ -3208,6 +4280,7 @@ enum qca_wlan_vendor_attr_ll_stats_ext { QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_REPORT_TIME, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MEASUREMENT_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PAD, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_LAST, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX = @@ -3493,7 +4566,8 @@ enum qca_vendor_attr_loc_session_status { * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INITIATOR_TOA_ERR: TOA error measured by * initiator. Not always provided. * See IEEE P802.11-REVmc/D7.0, 9.6.8.33 for more information. - * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD: Dummy attribute for padding. + * @QCA_WLAN_VENDOR_ATTR_FTM_MEAS_PAD: Attribute used for padding for 64-bit + * alignment. */ enum qca_wlan_vendor_attr_ftm_meas { QCA_WLAN_VENDOR_ATTR_FTM_MEAS_INVALID, @@ -3664,18 +4738,55 @@ enum qca_wlan_vendor_attr_ll_stats_set { QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST - 1, }; +/** + * qca_wlan_ll_stats_clr_req_bitmap - Represents the bitmap to clear LL STATS + * values for %QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO: Clear all radio statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CCA: Clear cca_busy_time within + * radio statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CHANNEL: Clear all channel + * statistics within radio statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_SCAN: Clear all scan statistics within + * radio statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE: Clear all interface statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_TXRATE: Clear all TX rate statistics + * within interface statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_AC: Clear all AC statistics within + * interface statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_CONTENTION: Clear all contention + * (min, max, avg) statistics within AC statistics. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_ALL_PEER: Clear all peer statistics + * on this interface. + * + * @QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_PER_PEER: Clear particular peer + * statistics depending on the peer_mac. + */ +enum qca_wlan_ll_stats_clr_req_bitmap { + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO = BIT(0), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CCA = BIT(1), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_CHANNELS = BIT(2), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_RADIO_SCAN = BIT(3), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE = BIT(4), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_TXRATE = BIT(5), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_AC = BIT(6), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_CONTENTION = BIT(7), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_ALL_PEER = BIT(8), + QCA_WLAN_LL_STATS_CLR_REQ_BITMAP_IFACE_PER_PEER = BIT(9), +}; + enum qca_wlan_vendor_attr_ll_stats_clr { QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_INVALID = 0, - /* Unsigned 32bit bitmap for clearing statistics - * All radio statistics 0x00000001 - * cca_busy_time (within radio statistics) 0x00000002 - * All channel stats (within radio statistics) 0x00000004 - * All scan statistics (within radio statistics) 0x00000008 - * All interface statistics 0x00000010 - * All tx rate statistics (within interface statistics) 0x00000020 - * All ac statistics (with in interface statistics) 0x00000040 - * All contention (min, max, avg) statistics (within ac statisctics) - * 0x00000080. + /* Unsigned 32bit bitmap for clearing statistics, specified + * in the enum qca_wlan_ll_stats_clr_req_bitmap. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK = 1, /* Unsigned 8 bit value: Request to stop statistics collection */ @@ -3695,6 +4806,25 @@ enum qca_wlan_vendor_attr_ll_stats_clr { QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST - 1, }; +/** + * qca_wlan_ll_stats_get_req_bitmap - Represents the bitmap to request LL STATS + * values for %QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK. + * + * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_RADIO: Request all radio statistics. + * + * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_IFACE: Request interface statistics. + * + * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_ALL_PEER: Request all peer statistics. + * + * @QCA_WLAN_LL_STATS_GET_REQ_BITMAP_PER_PEER: Request per peer statistics. + */ +enum qca_wlan_ll_stats_get_req_bitmap { + QCA_WLAN_LL_STATS_GET_REQ_BITMAP_RADIO = BIT(0), + QCA_WLAN_LL_STATS_GET_REQ_BITMAP_IFACE = BIT(1), + QCA_WLAN_LL_STATS_GET_REQ_BITMAP_ALL_PEER = BIT(2), + QCA_WLAN_LL_STATS_GET_REQ_BITMAP_PER_PEER = BIT(3), +}; + enum qca_wlan_vendor_attr_ll_stats_get { QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_INVALID = 0, /* Unsigned 32 bit value provided by the caller issuing the GET stats @@ -3703,11 +4833,8 @@ enum qca_wlan_vendor_attr_ll_stats_get { */ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID = 1, /* Unsigned 32 bit value - bit mask to identify what statistics are - * requested for retrieval. - * Radio Statistics 0x00000001 - * Interface Statistics 0x00000020 - * All Peer Statistics 0x00000040 - * Peer Statistics 0x00000080 + * requested for retrieval specified in the enum + * qca_wlan_ll_stats_get_req_bitmap */ QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK = 2, /* keep last */ @@ -3718,24 +4845,65 @@ enum qca_wlan_vendor_attr_ll_stats_get { enum qca_wlan_vendor_attr_ll_stats_results { QCA_WLAN_VENDOR_ATTR_LL_STATS_INVALID = 0, + + /* + * For Multi Link Operation (MLO) connection, per-link statistics will + * be sent inside of %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and + * cumulative statistics will be sent outside of + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to maintain backward + * compatibility with legacy user space. Attributes which don't have + * explicit documentation for MLO will be sent only outside of + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK, such attributes values + * don't depend on whether the connection is MLO capable or not, e.g., + * radio and channel specific attributes. + */ + /* Unsigned 32bit value. Used by the driver; must match the request id * provided with the QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET command. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_REQ_ID = 1, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX = 2, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX = 3, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX = 4, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX = 5, - /* Signed 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT = 6, - /* Signed 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA = 7, - /* Signed 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK = 8, /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_* are @@ -3759,7 +4927,8 @@ enum qca_wlan_vendor_attr_ll_stats_results { QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES = 13, /* NULL terminated SSID. An array of 33 Unsigned 8bit values */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID = 14, - /* BSSID. An array of 6 unsigned 8 bit values */ + /* For non-MLO connection, BSSID of the AP. For MLO connection, MLD + * address of the AP. An array of 6 unsigned 8 bit values */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID = 15, /* Country string advertised by AP. An array of 3 unsigned 8 bit * values. @@ -3772,6 +4941,15 @@ enum qca_wlan_vendor_attr_ll_stats_results { /* Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_* could * be nested within the interface stats. + * For an MLO connection, all %QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_* + * attributes except %QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_* + * indicate the aggregate of all links outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_* attributes + * indicate value of the MLO link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + * These attributes indicate the link specific value inside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. */ /* Type = enum wifi_traffic_ac, e.g., V0, VI, BE and BK */ @@ -3874,6 +5052,12 @@ enum qca_wlan_vendor_attr_ll_stats_results { */ QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG = 48, + /* Unsigned 32 bit value. This is used to indicate radio ID of the radio + * statistics when %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE is + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO. This is also used + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to indicate radio ID + * of the MLO link. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID = 49, /* Unsigned 32 bit value. Total number of msecs the radio is awake * accruing over time. @@ -3920,7 +5104,13 @@ enum qca_wlan_vendor_attr_ll_stats_results { /* Type = enum wifi_channel_width. Channel width, e.g., 20, 40, 80 */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH = 60, - /* Unsigned 32 bit value. Primary 20 MHz channel. */ + /* Unsigned 32 bit value. Primary 20 MHz channel. This is used to + * indicate the primary frequency of the channel when + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE is + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO. This is also used inside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to indicate the frequency + * on which the MLO link is operating. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ = 61, /* Unsigned 32 bit value. Center frequency (MHz) first segment. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0 = 62, @@ -3950,7 +5140,9 @@ enum qca_wlan_vendor_attr_ll_stats_results { QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO = 67, /* Signifies the nested list of peer info attributes - * QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_* + * QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_*. For MLO connection, + * this also contains %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID to + * indicate on which link the peer is connected. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO = 68, @@ -3971,16 +5163,32 @@ enum qca_wlan_vendor_attr_ll_stats_results { */ QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA = 71, - /* Unsigned 64 bit value */ + /* Unsigned 64 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET = 72, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED = 73, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED = 74, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME = 75, /* Unsigned 32 bit value */ @@ -3993,13 +5201,29 @@ enum qca_wlan_vendor_attr_ll_stats_results { */ QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL = 78, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT = 79, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT = 80, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT = 81, - /* Unsigned 32 bit value */ + /* Unsigned 32 bit value. For an MLO connection, indicates the value of + * the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT = 82, /* Unsigned int 32 value. @@ -4023,9 +5247,68 @@ enum qca_wlan_vendor_attr_ll_stats_results { */ QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_LOAD_PERCENTAGE = 86, /* u8 value representing the time slicing duty cycle percentage. - * Possible values are 0-100. + * Possible values are 0-100. For an MLO connection, indicates the value + * of the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. */ QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_TS_DUTY_CYCLE = 87, + /* Unsigned 32 bit value. The number of Beacon frames which are received + * from the associated AP and indicate buffered unicast frame(s) for us + * in the TIM element. For an MLO connection, indicates the value of the + * link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON = 88, + /* Unsigned 32 bit value. The total number of Beacon frames received + * from the associated AP that have wrongly indicated buffered unicast + * traffic in the TIM element for us. + * Below scenarios will be considered as wrong TIM element beacon: + * 1) The related TIM element is set in the beacon for STA but STA + * doesn’t receive any unicast data after this beacon. + * 2) The related TIM element is still set in the beacon for STA + * after STA has indicated power save exit by QoS Null Data frame. + * For an MLO connection, indicates the value of the link with the best + * RSSI outside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link + * specific value inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON_ERR = 89, + + /* Signed 32 bit value. It represents the noise floor calibration value. + * Possible values are -120~-50 dBm. For an MLO connection, indicates + * the value of the link with the best RSSI outside + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK and the link specific value + * inside %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK. + */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NF_CAL_VAL = 90, + + /* Attribute used for padding for 64-bit alignment */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_PAD = 91, + + /* Unsigned u8 value, link ID of an MLO link. Used inside nested + * attribute %QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK to represent the + * link ID of the MLO link for which the statistics are embedded in the + * nested attribute. Used inside nested attribute + * %QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO to represent the connected + * link ID of the peer. + */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID = 92, + + /* A nested array of attributes for each MLO link, each containing + * per-link statistics of a multi link connection. The attributes used + * inside this nested attribute are defined in enum + * qca_wlan_vendor_attr_ll_stats_results. + * + * For non-MLO connection, this attribute is not present and the + * statistics will be sent outside this attribute (without nesting). + * + * For MLO connection, this attribute is present and also cumulative + * statistics of all the links will be sent outside of this attribute + * to be compatible with legacy user space. + */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK = 93, + /* keep last */ QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX = @@ -4408,7 +5691,10 @@ enum qca_roam_scan_scheme { * due to poor RSSI of the connected AP. * @QCA_ROAM_TRIGGER_REASON_BETTER_RSSI: Set if the roam has to be triggered * upon finding a BSSID with a better RSSI than the connected BSSID. - * Here the RSSI of the current BSSID need not be poor. + * Also, set if the roam has to be triggered due to the high RSSI of the + * current connected AP (better than + * QCA_ATTR_ROAM_CONTROL_CONNECTED_HIGH_RSSI_OFFSET). Here the RSSI of + * the current BSSID need not be poor. * @QCA_ROAM_TRIGGER_REASON_PERIODIC: Set if the roam has to be triggered * by triggering a periodic scan to find a better AP to roam. * @QCA_ROAM_TRIGGER_REASON_DENSE: Set if the roam has to be triggered @@ -4507,6 +5793,8 @@ enum qca_vendor_roam_triggers { * @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. + * @QCA_ROAM_FAIL_REASON_CURR_AP_STILL_OK: Roam scan did not happen since the + * current network conditions are fine. */ enum qca_vendor_roam_fail_reasons { QCA_ROAM_FAIL_REASON_NONE = 0, @@ -4539,6 +5827,7 @@ enum qca_vendor_roam_fail_reasons { QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID = 27, QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT = 28, QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL = 29, + QCA_ROAM_FAIL_REASON_CURR_AP_STILL_OK = 30, }; /* @@ -4639,7 +5928,7 @@ enum qca_vendor_attr_roam_candidate_selection_criteria { /** * enum qca_vendor_attr_roam_control - Attributes to carry roam configuration - * The following attributes are used to set/get/clear the respective + * The following attributes are used to set/get/clear the respective * configurations to/from the driver. * For the get, the attribute for the configuration to be queried shall * carry any of its acceptable values to the driver. In return, the driver @@ -4748,7 +6037,11 @@ enum qca_vendor_attr_roam_candidate_selection_criteria { * @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. + * is less than this threshold. The RSSI threshold through this attribute + * is only used by the STA when the connected AP asks it to roam through + * a BTM request. Based on this threshold, the STA can either honor or + * reject the AP's request to roam, and notify the status to the AP in a + * BTM response. * * @QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD: Signed 32-bit value in dBm, * signifying the RSSI threshold of the candidate AP, indicating @@ -4841,12 +6134,92 @@ enum qca_vendor_attr_roam_candidate_selection_criteria { * Optional parameter. Scan dwell time for 6G Non Preferred Scanning * Channels. If this attribute is not configured, the driver shall proceed * with default behavior. + * + * @QCA_ATTR_ROAM_CONTROL_RX_LINKSPEED_THRESHOLD: u16 value in Mbps. + * Optional parameter. RX link speed threshold to disable roaming. + * If the current RX link speed is above the threshold, roaming is not + * needed. If this attribute is not configured, or if it is set to 0, the + * driver will not consider the RX link speed in the roaming decision. + * + * @QCA_ATTR_ROAM_CONTROL_HO_DELAY_FOR_RX: u16 value in milliseconds. + * Optional parameter. This configuration delays hand-off by the + * specified duration to receive pending RX frames from the current BSS. + * + * @QCA_ATTR_ROAM_CONTROL_FULL_SCAN_NO_REUSE_PARTIAL_SCAN_FREQ: Unsigned 8-bit + * value. + * During the roam scan, if there are no desired APs found in the partial + * frequency list, an immediate full scan on all the supported frequencies + * is initiated as a fallback. This flag controls the frequency list + * creation for the full scan on the following lines. + * 1 - Full scan to exclude the frequencies that were already scanned by + * the previous partial scan. + * 0 - Full scan to include all the supported frequencies irrespective of + * the ones part of the earlier partial scan. + * If this flag is not specified, a full scan shall include all the + * supported frequencies irrespective of the ones part of an earlier + * partial scan. + * + * @QCA_ATTR_ROAM_CONTROL_FULL_SCAN_6GHZ_ONLY_ON_PRIOR_DISCOVERY: Unsigned 8-bit + * value. + * During the roam scan, if there are no desired APs found in the partial + * frequency list, an immediate full scan on all the supported frequencies + * is initiated as a fallback. This full scan would add the 2.4/5/6 GHz + * frequencies, including all PSC frequencies by default. This attribute + * controls the inclusion of the 6 GHz PSC frequencies for the full scan + * as following. + * 1 - Full scan to include the supported 6 GHz PSC frequencies only on the + * prior discovery of any 6 GHz frequency support in the environment. + * This discovery can happen through a prior RNR, 11k neighbor + * request, 11v BTM request, host scan, etc. + * 0 - Default behavior. Full scan to include all the supported 6 GHz + * PSC frequencies regardless of whether 6 GHz BSSs have been + * discovered. + * The default behavior if this flag is not specified is to include all + * the supported 6 GHz PSC frequencies in the roam full scan. + * + * @QCA_ATTR_ROAM_CONTROL_CONNECTED_LOW_RSSI_THRESHOLD: Signed 32-bit value + * in dBm. + * This attribute configures the low RSSI threshold of the connected AP, + * based on which the STA can start looking for the neighbor APs and + * trigger the roam eventually. STA keeps monitoring for the connected + * AP's RSSI and will start scanning for neighboring APs once the RSSI + * falls below this threshold. This attribute differs from + * QCA_ATTR_ROAM_CONTROL_CONNECTED_RSSI_THRESHOLD where the configured + * threshold is used only when the connected AP asks the STA to roam + * through a BTM request. + * + * @QCA_ATTR_ROAM_CONTROL_CANDIDATE_ROAM_RSSI_DIFF: Unsigned 8-bit value. + * This attribute signifies the RSSI difference threshold between the + * connected AP and the new candidate AP. This parameter influences the + * STA to roam to the new candidate only when its RSSI is better than + * the current connected one by this threshold. + * This parameter configures the roam behavior among the 2.4/5/6 GHz bands. + * + * @QCA_ATTR_ROAM_CONTROL_6GHZ_CANDIDATE_ROAM_RSSI_DIFF: Unsigned 8-bit value. + * This attribute signifies the RSSI difference threshold between the + * connected AP in the 2.4/5 GHz bands and the new candidate AP in the + * 6 GHz band. This parameter influences the STA to roam to the new 6 GHz + * candidate only when its RSSI is better than the current connected one + * by this threshold. This threshold overrides + * QCA_ATTR_ROAM_CONTROL_CANDIDATE_ROAM_RSSI_DIFF for the roam from 2.4/5 + * GHz to 6 GHz alone with the intention to have a different value to roam + * to the preferred 6 GHz band. + * + * @QCA_ATTR_ROAM_CONTROL_CONNECTED_HIGH_RSSI_OFFSET: Unsigned 8-bit value. + * This attribute signifies the RSSI offset that is added to low RSSI + * threshold (QCA_ATTR_ROAM_CONTROL_CONNECTED_LOW_RSSI_THRESHOLD) to imply + * high RSSI threshold. STA is expected to trigger roam if the current + * connected AP's RSSI gets above this high RSSI threshold. STA's roam + * attempt on high RSSI threshold aims to find candidates from other + * better Wi-Fi bands. E.g., STA would initially connect to a 2.4 GHz BSSID + * and would migrate to 5/6 GHz when it comes closer to the AP (high RSSI + * for 2.4 GHz BSS). */ enum qca_vendor_attr_roam_control { QCA_ATTR_ROAM_CONTROL_ENABLE = 1, QCA_ATTR_ROAM_CONTROL_STATUS = 2, QCA_ATTR_ROAM_CONTROL_CLEAR_ALL = 3, - QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME= 4, + QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME = 4, QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD = 5, QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD = 6, QCA_ATTR_ROAM_CONTROL_TRIGGERS = 7, @@ -4866,6 +6239,14 @@ enum qca_vendor_attr_roam_control { QCA_ATTR_ROAM_CONTROL_MAXIMUM_AWAY_TIME = 21, QCA_ATTR_ROAM_CONTROL_SCAN_6G_PSC_DWELL_TIME = 22, QCA_ATTR_ROAM_CONTROL_SCAN_6G_NON_PSC_DWELL_TIME = 23, + QCA_ATTR_ROAM_CONTROL_LINKSPEED_THRESHOLD = 24, + QCA_ATTR_ROAM_CONTROL_HO_DELAY_FOR_RX = 25, + QCA_ATTR_ROAM_CONTROL_FULL_SCAN_NO_REUSE_PARTIAL_SCAN_FREQ = 26, + QCA_ATTR_ROAM_CONTROL_FULL_SCAN_6GHZ_ONLY_ON_PRIOR_DISCOVERY = 27, + QCA_ATTR_ROAM_CONTROL_CONNECTED_LOW_RSSI_THRESHOLD = 28, + QCA_ATTR_ROAM_CONTROL_CANDIDATE_ROAM_RSSI_DIFF = 29, + QCA_ATTR_ROAM_CONTROL_6GHZ_CANDIDATE_ROAM_RSSI_DIFF = 30, + QCA_ATTR_ROAM_CONTROL_CONNECTED_HIGH_RSSI_OFFSET = 31, /* keep last */ QCA_ATTR_ROAM_CONTROL_AFTER_LAST, @@ -4888,14 +6269,14 @@ enum qca_vendor_attr_roam_control { * ignored BSSIDs and accordingly clear the respective ones with the * matching ID. * - * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS: Unsigned - * 32-bit value.Represents the number of whitelist SSIDs configured. + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID_NUM_NETWORKS: Unsigned + * 32-bit value. Represents the number of allowlist SSIDs configured. * - * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST: Nested attribute - * to carry the list of Whitelist SSIDs. + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID_LIST: Nested attribute + * to carry the list of allowlist SSIDs. * - * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID: SSID (binary attribute, - * 0..32 octets). Represents the white list SSID. Whitelist SSIDs + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID: SSID (binary attribute, + * 0..32 octets). Represents the allow list SSID. Allowlist SSIDs * represent the list of SSIDs to which the firmware/driver can consider * to roam to. * @@ -4933,7 +6314,7 @@ enum qca_vendor_attr_roam_control { * * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE: Unsigned 32-bit * value. 1-Enable, 0-Disable. Represents "Lazy" mode, where - * firmware is hunting for a better BSSID or white listed SSID even though + * firmware is hunting for a better BSSID or allow listed SSID even though * the RSSI of the link is good. The parameters enabling the roaming are * configured through the PARAM_A_BAND_XX attrbutes. * @@ -4975,10 +6356,10 @@ enum qca_wlan_vendor_attr_roaming_config_params { QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD = 1, QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID = 2, - /* Attributes for wifi_set_ssid_white_list */ - QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS = 3, - QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST = 4, - QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID = 5, + /* Attributes for wifi_set_ssid_allow_list */ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID_NUM_NETWORKS = 3, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID_LIST = 4, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID = 5, /* Attributes for set_roam_params */ QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD = 6, @@ -5013,16 +6394,24 @@ enum qca_wlan_vendor_attr_roaming_config_params { QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST - 1, }; +/* old names for API compatibility */ +#define QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID_NUM_NETWORKS +#define QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID_LIST +#define QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID + /* * enum qca_wlan_vendor_roaming_subcmd: Referred by * QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD. * - * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST: Sub command to - * configure the white list SSIDs. These are configured through + * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_ALLOW_LIST: Sub command to + * configure the allow list SSIDs. These are configured through * the following attributes. - * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS, - * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST, - * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID + * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID_NUM_NETWORKS, + * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID_LIST, + * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALLOW_LIST_SSID * * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS: Sub command to * configure the Roam params. These parameters are evaluated on the GScan @@ -5038,7 +6427,7 @@ 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 list of BSSIDs + * @QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_DENYLIST_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. * @@ -5062,17 +6451,23 @@ enum qca_wlan_vendor_attr_roaming_config_params { */ enum qca_wlan_vendor_roaming_subcmd { QCA_WLAN_VENDOR_ROAMING_SUBCMD_INVALID = 0, - QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST = 1, + QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_ALLOW_LIST = 1, QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_GSCAN_ROAM_PARAMS = 2, QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM = 3, QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS = 4, QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PARAMS = 5, - QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID = 6, + QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_DENYLIST_BSSID = 6, QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET = 7, QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET = 8, QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR = 9, }; +/* old names for API compatibility */ +#define QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST \ + QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_ALLOW_LIST +#define QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID \ + QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_DENYLIST_BSSID + enum qca_wlan_vendor_attr_gscan_config_params { QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_INVALID = 0, @@ -5431,7 +6826,7 @@ enum qca_wlan_vendor_attr_gscan_results { QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID = 43, /* Unsigned 32-bit value; a GSCAN Capabilities attribute. */ - QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID + QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_ALLOWLISTED_SSID = 44, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_BUCKETS_SCANNED = 45, @@ -5439,10 +6834,13 @@ enum qca_wlan_vendor_attr_gscan_results { /* Unsigned 32-bit value; a GSCAN Capabilities attribute. * This is used to limit the maximum number of BSSIDs while sending * the vendor command QCA_NL80211_VENDOR_SUBCMD_ROAM with subcmd - * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID and attribute + * QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_DENYLIST_BSSID and attribute * QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID. */ - QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_BLACKLISTED_BSSID = 46, + QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_DENYLISTED_BSSID = 46, + + /* Attribute used for padding for 64-bit alignment */ + QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_PAD = 47, /* keep last */ QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST, @@ -5450,6 +6848,12 @@ enum qca_wlan_vendor_attr_gscan_results { QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_AFTER_LAST - 1, }; +/* old names for API compatibility */ +#define QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID \ + QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_ALLOWLISTED_SSID +#define QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_BLACKLISTED_BSSID \ + QCA_WLAN_VENDOR_ATTR_GSCAN_MAX_NUM_DENYLISTED_BSSID + enum qca_wlan_vendor_attr_pno_config_params { QCA_WLAN_VENDOR_ATTR_PNO_INVALID = 0, /* Attributes for data used by @@ -5579,6 +6983,8 @@ enum qca_wlan_vendor_acs_select_reason { * current channel. */ QCA_WLAN_VENDOR_ACS_SELECT_REASON_JAMMER_INTERFERENCE, + /* Represents the reason that ACS triggered by AFC */ + QCA_WLAN_VENDOR_ACS_SELECT_REASON_AFC_TRIGGER, }; /** @@ -5661,7 +7067,7 @@ enum qca_wlan_vendor_channel_prop_flags { /* HE 40 with extension channel below */ QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40MINUS = 1 << 30, /* HE 40 intolerant */ - QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40INTOL = 1 << 31, + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40INTOL = 1U << 31, }; /** @@ -5747,6 +7153,22 @@ enum qca_wlan_vendor_external_acs_event_chan_info_attr { QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS_2 = 11, /* + * Segment 0 in MHz (u32). + * + * For 20/40/80 MHz bandwidth, this indicates the channel center + * frequency index for the 20/40/80 MHz operating channel. + * For 160 MHz bandwidth, this indicates the channel center + * frequency of the primary 80 MHz channel. + * For 320 MHz bandwidth, indicates the channel center frequency + * of the primary 160 MHz channel. + * + * To maintain backward compatibility, + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 + * is also maintained. + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_SEG_0 = 12, + /* Legacy alias for the Segment 0 attribute. + * * VHT segment 0 in MHz (u32) and the attribute is mandatory. * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 @@ -5764,9 +7186,25 @@ enum qca_wlan_vendor_external_acs_event_chan_info_attr { * is still used if either of the driver or user space application * doesn't support the 6 GHz band. */ - QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 = 12, + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 = + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_SEG_0, /* + * Segment 1 in MHz (u32). + * + * For 20/40/80 MHz bandwidth, this is set to 0. + * For 160 MHz bandwidth, indicates the channel center frequency of the + * 160 MHz channel. + * For 320 MHz bandwidth, indicates the channel center frequency of the + * 320 MHz channel. + * + * To maintain backward compatibility, + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 + * is also maintained. + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_SEG_1 = 13, + /* Legacy alias for the Segment 1 attribute. + * * VHT segment 1 in MHz (u32) and the attribute is mandatory. * Note: Event QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS includes * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 @@ -5784,7 +7222,50 @@ enum qca_wlan_vendor_external_acs_event_chan_info_attr { * is still used if either of the driver or user space application * doesn't support the 6 GHz band. */ - QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 = 13, + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 = + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_SEG_1, + + /* + * 16-bit attribute of bits indicating the AP power modes supported by + * the channel (u16). + * Note: Currently, only 3 bits are used in the attribute and each bit + * corresponds to the power mode mentioned in enum + * qca_wlan_vendor_external_acs_chan_power_mode and a given bit is + * set if the associated mode is supported. + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_SUPP_POWER_MODES + = 14, + /* Array of nested attributes for each power mode. It takes attr as + * defined in enum + * qca_wlan_vendor_external_acs_event_chan_power_info_attr. + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR = 15, + /* + * This indicates the overlapping 320 MHz center frequency in MHz + * (u32), if the given primary channel supports more than one + * 320 MHz channel bonding. + * + * Example: + * For 6 GHz, channel frequency 6115 MHz (channel number 33) segment 0 + * center frequency (primary 160 MHz) is 6185 MHz and there can be two + * possible segment 2 frequencies for this (320 MHz center + * frequencies): + * + * 1) Center frequency 6105 MHz (channel 31): 320 MHz channel bonding + * from frequency 5945 MHz - 6265 MHz + * 2) Center frequency 6265 MHz (channel 63): 320 MHz channel bonding + * from frequency 6105 MHz - 6425 MHz + * + * In this case, + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_SEG_0 will + * return 6185 MHz. + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_SEG_1 will + * return 6105 MHz. + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_OVERLAP_SEG_1 + * will return 6265 MHz. + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_OVERLAP_SEG_1 + = 16, /* keep last */ QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_LAST, @@ -5793,9 +7274,59 @@ enum qca_wlan_vendor_external_acs_event_chan_info_attr { }; /** - * qca_wlan_vendor_attr_pcl: Represents attributes for - * preferred channel list (PCL). These attributes are sent as part of - * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL and + * qca_wlan_vendor_external_acs_chan_power_mode - Specifies the valid + * values that the vendor external ACS channel power attribute + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE can + * take. + * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_LOW_POWER: Low power/Indoor mode + * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_STANDARD_POWER: Standard power mode + * @QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_VERY_LOW_POWER: Very low power mode + */ +enum qca_wlan_vendor_external_acs_chan_power_level { + QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_LOW_POWER = 0, + QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_STANDARD_POWER = 1, + QCA_WLAN_VENDOR_EXTERNAL_ACS_CHAN_VERY_LOW_POWER = 2, +}; + +/** + * qca_wlan_vendor_external_acs_event_chan_power_info_attr: Represents nested + * attributes for power mode type and power values corresponding to that. + * These attributes are sent as part of + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR. + */ +enum qca_wlan_vendor_external_acs_event_chan_power_info_attr { + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_INVALID = 0, + /* + * Power mode (u8) takes the values defined in enum + * qca_wlan_vendor_external_acs_chan_power_mode + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE + = 1, + /* + * Indicates if power value is a PSD/EIRP value (flag). If flag is + * present, it indicates a PSD value. + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_PSD_FLAG = 2, + /* + * Power value (u32) PSD/EIRP as indicated by + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_PSD_FLAG, + * for power mode corresponding to the + * QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_MODE. + * Units for PSD - dBm/MHz + * Units for EIRP - dBm + */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_POWER_VALUE + = 3, + /* keep last */ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_LAST, + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_MAX = + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_POWER_INFO_ATTR_LAST - 1, +}; + +/** + * qca_wlan_vendor_attr_pcl: Represents attributes for + * preferred channel list (PCL). These attributes are sent as part of + * QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL and * QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST. */ enum qca_wlan_vendor_attr_pcl { @@ -5816,6 +7347,10 @@ enum qca_wlan_vendor_attr_pcl { * bit 3 set: channel should be excluded in GO negotiation */ QCA_WLAN_VENDOR_ATTR_PCL_FLAG = 4, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_PCL_LAST, + QCA_WLAN_VENDOR_ATTR_PCL_MAX = QCA_WLAN_VENDOR_ATTR_PCL_LAST - 1 }; /** @@ -5878,6 +7413,10 @@ enum qca_wlan_vendor_attr_external_acs_event { * qca_wlan_vendor_attr_rropavail_info. */ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_RROPAVAIL_INFO = 14, + /* Flag attribute to indicate if driver supports 6 GHz AFC trigger + * for External ACS + */ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_AFC_CAPABILITY = 15, /* keep last */ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST, @@ -5980,6 +7519,14 @@ enum qca_wlan_vendor_attr_external_acs_event { * VHT seg1 channel frequency in MHz * Note: If user-space application has no support of the 6 GHz band, this * attribute is optional. + * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_PUNCTURE_BITMAP: Required (u16) + * Puncture Bitmap for selected primary channel. Optional if no support + * for EHT (IEEE 802.11be). Encoding for this attribute follows the + * convention used in the Disabled Subchannel Bitmap field of the EHT Operation + * element. + * @QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_LINK_ID: Mandatory on AP MLD (u8). + * Used with command to configure external ACS operation for a specific link + * affiliated to an AP MLD. */ enum qca_wlan_vendor_attr_external_acs_channels { QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_INVALID = 0, @@ -6015,6 +7562,8 @@ enum qca_wlan_vendor_attr_external_acs_channels { QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY = 11, QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 = 12, QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 = 13, + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_PUNCTURE_BITMAP = 14, + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_LINK_ID = 15, /* keep last */ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LAST, @@ -6481,6 +8030,28 @@ enum qca_wlan_vendor_attr_spectral_scan { * for the current operating bandwidth. */ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BANDWIDTH = 30, + /* Spectral FFT recapture flag attribute, to enable FFT recapture. + * Recapture can only be enabled for scan period greater than 52 us. + * If this attribute is enabled, re-triggers will be enabled when AGC + * gain changes. + */ + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_RECAPTURE = 31, + /* Attribute used for padding for 64-bit alignment */ + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PAD = 32, + /* Spectral data transport mode. u32 attribute. It uses values + * defined in enum qca_wlan_vendor_spectral_data_transport_mode. + * This is an optional attribute. If this attribute is not populated, + * the driver should configure the default transport mode to netlink. + */ + QCA_WLAN_VENDOR_ATTR_SPECTRAL_DATA_TRANSPORT_MODE = 33, + /* Spectral scan completion timeout. u32 attribute. This + * attribute is used to configure a timeout value (in us). The + * timeout value would be from the beginning of a spectral + * scan. This is an optional attribute. If this attribute is + * not populated, the driver would internally derive the + * timeout value. + */ + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETION_TIMEOUT = 34, QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX = @@ -6513,6 +8084,8 @@ enum qca_wlan_vendor_attr_spectral_diag_stats { * mismatches in search fft report. u64 attribute. */ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG2ID_MISMATCH = 5, + /* Attribute used for padding for 64-bit alignment */ + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_PAD = 6, QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_MAX = @@ -6791,6 +8364,28 @@ enum qca_wlan_vendor_hang_reason { QCA_WLAN_HANG_BUS_FAILURE = 26, /* tasklet/credit latency found */ QCA_WLAN_HANG_TASKLET_CREDIT_LATENCY_DETECT = 27, + /* MSDU buffers received in REO error ring, exceeding certain + * threshold + */ + QCA_WLAN_HANG_RX_MSDU_BUF_RCVD_IN_ERR_RING = 28, + /* Vdev SM is out of sync and connect req received + * when already connected + */ + QCA_WLAN_HANG_VDEV_SM_OUT_OF_SYNC = 29, + /* Stats request timeout */ + QCA_WLAN_HANG_STATS_REQ_TIMEOUT = 30, + /* Leak in TX descriptor for a packet */ + QCA_WLAN_HANG_TX_DESC_LEAK = 31, + /* Scheduler watchdog timeout */ + QCA_WLAN_HANG_SCHED_TIMEOUT = 32, + /* Failed to send self peer deletion cmd to firmware */ + QCA_WLAN_HANG_SELF_PEER_DEL_FAIL = 33, + /* Received del self sta without del bss */ + QCA_WLAN_HANG_DEL_SELF_STA_FAIL = 34, + /* Recovery needed when sending flush completion to userspace */ + QCA_WLAN_HANG_FLUSH_LOGS = 35, + /* Host wakeup because of page fault */ + QCA_WLAN_HANG_HOST_WAKEUP_REASON_PAGE_FAULT = 36, }; /** @@ -6815,6 +8410,28 @@ enum qca_wlan_vendor_attr_hang { QCA_WLAN_VENDOR_ATTR_HANG_AFTER_LAST - 1, }; +/** + * enum qca_wlan_vendor_flush_pending_policy: Represents values for + * the policy to flush pending frames, configured via + * %QCA_NL80211_VENDOR_SUBCMD_PEER_FLUSH_PENDING. This enumeration defines the + * valid values for %QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_POLICY. + * + * @QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_NONE: This value clears all + * the flush policy configured before. This command basically disables the + * flush config set by the user. + * @QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_IMMEDIATE: This value configures + * the flush policy to be immediate. All pending packets for the peer/TID are + * flushed when this command/policy is received. + * @QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_TWT_SP_END: This value configures + * the flush policy to the end of TWT SP. All pending packets for the peer/TID + * are flushed when the end of TWT SP is reached. + */ +enum qca_wlan_vendor_flush_pending_policy { + QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_NONE = 0, + QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_IMMEDIATE = 1, + QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_TWT_SP_END = 2, +}; + /** * enum qca_wlan_vendor_attr_flush_pending - Attributes for * flushing pending traffic in firmware. @@ -6823,12 +8440,25 @@ enum qca_wlan_vendor_attr_hang { * @QCA_WLAN_VENDOR_ATTR_AC: Configure access category of the pending * packets. It is u8 value with bit 0~3 represent AC_BE, AC_BK, * AC_VI, AC_VO respectively. Set the corresponding bit to 1 to - * flush packets with access category. + * flush packets with access category. This is optional. See below. + * @QCA_WLAN_VENDOR_ATTR_TID_MASK: Configure TID mask of the pending packets. + * It is a u32 value with bit 0-7 representing TID 0-7. Set corresponding + * bit to 1 to act upon the TID. This is optional. Either this attribute or + * %QCA_WLAN_VENDOR_ATTR_AC must be provided. If both are provided, + * %QCA_WLAN_VENDOR_ATTR_TID_MASK takes precedence. If neither are provided + * it is an error. + * @QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_POLICY: Policy of flushing the pending + * packets corresponding to the peer/TID provided. It is a u32 value, + * represented by %enum qca_wlan_vendor_flush_pending_policy. This + * value is honored only when TID mask is provided. This is not honored when AC + * mask is provided. */ enum qca_wlan_vendor_attr_flush_pending { QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_INVALID = 0, QCA_WLAN_VENDOR_ATTR_PEER_ADDR = 1, QCA_WLAN_VENDOR_ATTR_AC = 2, + QCA_WLAN_VENDOR_ATTR_TID_MASK = 3, + QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_POLICY = 4, /* keep last */ QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_AFTER_LAST, @@ -6945,10 +8575,11 @@ enum qca_wlan_vendor_attr_rtplinst { * * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL: * Default WLAN operation level which throughput orientated. - * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MODERATE: - * Use moderate level to improve latency by limit scan duration. + * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_XR: + * Use XR level to benefit XR (extended reality) application to achieve + * latency and power by via constraint scan/roaming/adaptive PS. * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW: - * Use low latency level to benifit application like concurrent + * Use low latency level to benefit application like concurrent * downloading or video streaming via constraint scan/adaptive PS. * @QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW: * Use ultra low latency level to benefit for gaming/voice @@ -6957,7 +8588,10 @@ enum qca_wlan_vendor_attr_rtplinst { enum qca_wlan_vendor_attr_config_latency_level { QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_INVALID = 0, QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL = 1, - QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MODERATE = 2, + QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_XR = 2, + /* legacy name */ + QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MODERATE = + QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_XR, QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW = 3, QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW = 4, @@ -7064,7 +8698,12 @@ enum wifi_logger_supported_features { enum qca_wlan_tdls_caps_features_supported { WIFI_TDLS_SUPPORT = (1 << (0)), WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT = (1 << (1)), - WIFI_TDLS_OFFCHANNEL_SUPPORT = (1 << (2)) + WIFI_TDLS_OFFCHANNEL_SUPPORT = (1 << (2)), + + /* Indicates if the TDLS session can be formed with the peer using + * higher bandwidth than the bandwidth of the AP path. + */ + WIFI_TDLS_WIDER_BW_SUPPORT = (1 << (3)), }; /** @@ -7269,6 +8908,38 @@ enum qca_wlan_vendor_attr_ndp_params { * 1:support 0:not support */ QCA_WLAN_VENDOR_ATTR_PEER_NDPE_SUPPORT = 30, + /* As per Wi-Fi Aware Specification v3.2 Service Id is the first + * 48 bits of the SHA-256 hash of the Service Name. + * A lower-case representation of the Service Name shall be used to + * calculate the Service ID. + * Array of u8: length is 6 bytes + * This attribute is used and optional for ndp indication. + */ + QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_ID = 31, + /* Unsigned 8-bit value for Cipher Suite capabilities. + * u8 attribute. + * This attribute is used and optional in ndp request, ndp response, + * ndp indication, and ndp confirm. + * This attribute is used to indicate the Capabilities field of Cipher + * Suite Information attribute (CSIA) of NDP frames as defined in + * Wi-Fi Aware Specification v4.0, 9.5.21.2, Table 122. + * Firmware can accept or ignore any of the capability bits. + */ + QCA_WLAN_VENDOR_ATTR_NDP_CSIA_CAPABILITIES = 32, + /* Indicate that GTK protection is required for NDP. + * NLA_FLAG attribute. + * This attribute can be used in ndp request, ndp response, ndp + * indication, and ndp confirm. + * GTK protection required is indicated in the NDPE attribute of NAN + * action frame (NAF) during NDP negotiation as defined in + * Wi-Fi Aware Specification v4.0, 9.5.16.2. + * If the device and peer supports GTKSA and if GTK protection required + * bit is set in NDPE IE, devices will share GTK to each other in SKDA + * of Data Path Security Confirm and Data Path Security Install frames + * of NDP negotiation to send and receive protected group addressed data + * frames from each other. + */ + QCA_WLAN_VENDOR_ATTR_NDP_GTK_REQUIRED = 33, /* keep last */ QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST, @@ -7278,9 +8949,24 @@ enum qca_wlan_vendor_attr_ndp_params { enum qca_wlan_ndp_sub_cmd { QCA_WLAN_VENDOR_ATTR_NDP_INVALID = 0, - /* Command to create a NAN data path interface */ + /* Command to create a NAN data path interface. + * This command was initially designed to both create and start a NAN + * data path interface. However, changes to Linux 5.12 no longer allow + * interface creation via vendor commands. When the driver advertises + * QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI + * userspace must explicitly first create the interface using + * NL80211_CMD_NEW_INTERFACE before subsequently invoking this command + * to start the interface. + */ QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE = 1, - /* Command to delete a NAN data path interface */ + /* Command to delete a NAN data path interface. + * This command was initially designed to both stop and delete a NAN + * data path interface. However, changes to Linux 5.12 no longer allow + * interface deletion via vendor commands. When the driver advertises + * QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI + * userspace must explicitly delete the interface using + * NL80211_CMD_DEL_INTERFACE after calling this command. + */ QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE = 2, /* Command to initiate a NAN data path session */ QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST = 3, @@ -7859,9 +9545,81 @@ enum qca_wlan_keep_alive_data_type { }; /** - * enum qca_wlan_vendor_attr_he_omi_tx: Represents attributes for - * HE operating mode control transmit request. These attributes are - * sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX and + * enum eht_mcs_config - EHT MCS support configuration + * + * Configures the EHT Tx/Rx MCS map in EHT Capability element. + * These values are used in the driver to configure the EHT MCS map to advertise + * Tx/Rx MCS map in EHT capability and these values are applied for all the + * streams supported by the device. + * @EHT_MCS0_7: EHT MCS 0 to 7 support + * @EHT_MCS0_9: EHT MCS 0 to 9 support + * @EHT_MCS0_11: EHT MCS 0 to 11 support + * @EHT_MCS0_13: EHT MCS 0 to 13 support + */ +enum eht_mcs_config { + EHT_MCS0_7 = 0, + EHT_MCS0_9 = 1, + EHT_MCS0_11 = 2, + EHT_MCS0_13 = 3, +}; + +/** + * enum qca_wlan_eht_mlo_mode: EHT MLO mode configuration. + * @QCA_WLAN_EHT_MODE_INVALID: Invalid. + * @QCA_WLAN_EHT_MLSR: Multi-link single radio mode + * @QCA_WLAN_EHT_EMLSR: Enhanced multi-link single radio mode. + * @QCA_WLAN_EHT_NON_STR_MLMR: Non simultaneous transmit and receive + * multi-link multi radio mode. + * @QCA_WLAN_EHT_STR_MLMR: Simultaneous transmit and receive + * multi-link multi radio mode. + */ +enum qca_wlan_eht_mlo_mode { + QCA_WLAN_EHT_MODE_INVALID = 0, + QCA_WLAN_EHT_MLSR = 1, + QCA_WLAN_EHT_EMLSR = 2, + QCA_WLAN_EHT_NON_STR_MLMR = 3, + QCA_WLAN_EHT_STR_MLMR = 4, +}; + +/** + * enum qca_wlan_emlsr_mode: Enhanced Multi-link Single Radio mode configuration + * @QCA_WLAN_EMLSR_MODE_ENTER: Enter EMLSR mode + * @QCA_WLAN_EMLSR_MODE_EXIT: Exit EMLSR mode + */ +enum qca_wlan_emlsr_mode { + QCA_WLAN_EMLSR_MODE_ENTER = 0, + QCA_WLAN_EMLSR_MODE_EXIT = 1, +}; + +/** + * enum qca_wlan_ttlm_negotiation_support: TID-To-Link Mapping Negotiation + * support + * @QCA_WLAN_TTLM_DISABLE: TTLM disabled + * @QCA_WLAN_TTLM_SAME_LINK_SET: Mapping of all TIDs to the same link set, + * both DL and UL + * @QCA_WLAN_TTLM_SAME_DIFF_LINK_SET: Mapping of each TID to the same or + * different link set + */ +enum qca_wlan_ttlm_negotiation_support { + QCA_WLAN_TTLM_DISABLE = 0, + QCA_WLAN_TTLM_SAME_LINK_SET = 1, + QCA_WLAN_TTLM_SAME_DIFF_LINK_SET = 2, +}; + +/** + * enum qca_coex_traffic_shaping_mode: Coex traffic shaping mode + * @QCA_COEX_TRAFFIC_SHAPING_MODE_DISABLE: Coex policies disabled + * @QCA_COEX_TRAFFIC_SHAPING_MODE_ENABLE: All coex policies enabled + */ +enum qca_coex_traffic_shaping_mode { + QCA_COEX_TRAFFIC_SHAPING_MODE_DISABLE = 0, + QCA_COEX_TRAFFIC_SHAPING_MODE_ENABLE = 1, +}; + +/** + * enum qca_wlan_vendor_attr_omi_tx: Represents attributes for HE and + * EHT operating mode control transmit request. These attributes are + * sent as part of QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OMI_TX and * QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION. * * @QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS: Mandatory 8-bit unsigned value @@ -7891,21 +9649,48 @@ enum qca_wlan_keep_alive_data_type { * 1 - Determine which HE TB PPDU types are allowed by the STA if UL MU disable * bit is not set, else UL MU Tx is suspended. * + * @QCA_WLAN_VENDOR_ATTR_EHT_OMI_RX_NSS_EXTN: 8-bit unsigned value in the EHT OM + * Control subfield combined with the Rx NSS subfield in the OM Control subfield + * indicates NSS - 1, where NSS is the maximum number of spatial streams that + * STA supports in reception for PPDU bandwidths less than or equal to 80 MHz. + * + * @QCA_WLAN_VENDOR_ATTR_EHT_OMI_CH_BW_EXTN: 8-bit unsigned value indicates + * 320 MHz operating channel width supported by the EHT STA for both reception + * and transmission. + * + * @QCA_WLAN_VENDOR_ATTR_EHT_OMI_TX_NSS_EXTN: 8-bit unsigned value in the EHT OM + * Control subfield combined with the Tx NSTS subfield in OM Control subfield + * indicates NSTS - 1, where NSTS is the maximum number of space-time streams + * that the STA supports in transmission for PPDU bandwidths less than or equal + * to 80 MHz. */ -enum qca_wlan_vendor_attr_he_omi_tx { +enum qca_wlan_vendor_attr_omi_tx { QCA_WLAN_VENDOR_ATTR_HE_OMI_INVALID = 0, QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS = 1, QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW = 2, QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE = 3, QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS = 4, QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE = 5, + QCA_WLAN_VENDOR_ATTR_EHT_OMI_RX_NSS_EXTN = 6, + QCA_WLAN_VENDOR_ATTR_EHT_OMI_CH_BW_EXTN = 7, + QCA_WLAN_VENDOR_ATTR_EHT_OMI_TX_NSS_EXTN = 8, /* keep last */ - QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST, - QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX = - QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST - 1, + QCA_WLAN_VENDOR_ATTR_OMI_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OMI_MAX = + QCA_WLAN_VENDOR_ATTR_OMI_AFTER_LAST - 1, }; +/* deprecated legacy names */ +#define QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX \ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OMI_TX +#define qca_wlan_vendor_attr_he_omi_tx \ + qca_wlan_vendor_attr_omi_tx +#define QCA_WLAN_VENDOR_ATTR_HE_OMI_AFTER_LAST \ + QCA_WLAN_VENDOR_ATTR_OMI_AFTER_LAST +#define QCA_WLAN_VENDOR_ATTR_HE_OMI_MAX \ + QCA_WLAN_VENDOR_ATTR_OMI_MAX + /** * enum qca_wlan_vendor_phy_mode - Different PHY modes * These values are used with %QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE. @@ -8223,10 +10008,10 @@ enum qca_wlan_vendor_attr_wifi_test_config { * channel bandwidth, Tx Nsts and UL MU disable attributes. * These nested attributes are used to send HE operating mode control * with configured values. - * Uses the enum qca_wlan_vendor_attr_he_omi_tx attributes. + * Uses the enum qca_wlan_vendor_attr_omi_tx attributes. * This attribute is used to configure the testbed device. */ - QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX = 33, + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OMI_TX = 33, /* 8-bit unsigned value to configure +HTC_HE support to indicate the * support for the reception of a frame that carries an HE variant @@ -8428,6 +10213,151 @@ enum qca_wlan_vendor_attr_wifi_test_config { */ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BCAST_TWT_SUPPORT = 57, + /* 8-bit unsigned value to configure the driver/firmware to allow eMLSR + * mode for IEEE 802.11be MLO capable devices. If the attribute is set + * to 1, and if the firmware supports this capability too, the STA + * advertises this capability to the AP over Association Request frame. + * This attribute will not have any effect on legacy devices with no + * IEEE 802.11be support. + * 0 - Default behavior + * 1 - Enable eMLSR (Enhanced Multi-link Single-Radio) mode + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_11BE_EMLSR_MODE = 58, + + /* 8-bit unsigned value to configure the driver to enable/disable the + * periodic sounding for Tx beamformer functionality. The default + * behavior uses algorithm to do sounding based on packet stats. + * + * 0 - Default behavior. + * 1 - Enable the periodic sounding for Tx beamformer. + * This attribute is used for testing purposes. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BEAMFORMER_PERIODIC_SOUNDING = 59, + + /* 8-bit unsigned value to configure beamformee SS EHT capability + * to indicate the maximum number of spatial streams that the STA + * can receive in an EHT sounding NDP for <= 80 MHz bandwidth. + * The range of the value is 3 to 7. + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_BEAMFORMEE_SS_80MHZ = 60, + + /* 8-bit unsigned value to configure beamformee SS EHT capability + * to indicate the maximum number of spatial streams that the STA + * can receive in an EHT sounding NDP for 160 MHz bandwidth. + * The range of the value is 3 to 7. + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_BEAMFORMEE_SS_160MHZ = 61, + + /* 8-bit unsigned value to configure beamformee SS EHT capability + * to indicate the maximum number of spatial streams that the STA + * can receive in an EHT sounding NDP for 320 MHz bandwidth. + * The range of the value is 3 to 7. + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_BEAMFORMEE_SS_320MHZ = 62, + + /* 8-bit unsigned value to configure the driver to exclude station + * profile in Probe Request frame Multi-Link element. + * 0 - Default behavior, sends the Probe Request frame with station + * profile data included in the Multi-Link element. + * 1 - Exclude station profile in Probe Request frame Multi-Link + * element. + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EXCLUDE_STA_PROF_IN_PROBE_REQ = 63, + + /* 8-bit unsigned value to configure EHT testbed defaults. + * This attribute is used to configure the testbed device. + * 1 - Set the device EHT capabilities to testbed defaults. + * 0 - Reset the device EHT capabilities to supported config. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SET_EHT_TESTBED_DEFAULTS = 64, + + /* 8-bit unsigned value to indicate the EHT MCS support. + * Uses enum eht_mcs_config values. + * This attribute is used to configure the testbed device to + * allow the advertised hardware capabilities to be downgraded + * for testing purposes. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MCS = 65, + + /* 8-bit unsigned value to configure EHT TB Sounding Feedback + * Rate Limit capability. + * This attribute is used to configure the testbed device. + * 0 - Indicates no maximum supported data rate limitation. + * 1 - Indicates the maximum supported data rate is the lower of + * the 1500 Mb/s and the maximum supported data rate. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_TB_SOUNDING_FB_RL = 66, + + /* 8-bit unsigned value to configure the support for receiving an MPDU + * that contains an EHT operating mode control subfield. + * This attribute is used to configure the testbed device. + * 1-enable, 0-disable. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_OM_CTRL_SUPPORT = 67, + + /* 8-bit unsigned value to configure the driver with EMLSR padding delay + * subfield value. + * + * 0 - 0 us + * 1 - 32 us + * 2 - 64 us + * 3 - 128 us + * 4 - 256 us + * 5-255 - Reserved + * + * This attribute is used for testing purposes. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EMLSR_PADDING_DELAY = 68, + + /* + * 8-bit unsigned value to indicate the firmware to force the active MLO + * links to power save mode for the configured number of beacon periods. + * This allows the firmware to suspend STA links for X beacon periods + * and remain asleep even if the AP advertises TIM as opposed to regular + * power save mode where STA links wake up if the AP indicates that it + * has buffered data to send. + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FORCE_MLO_POWER_SAVE_BCN_PERIOD = 69, + + /* + * 8-bit unsigned value to indicate the firmware to be in STR MLMR mode + * to enable simultaneous transmission of PPDUs on all active links. + * 0 - Default behavior + * 1 - Enter STR mode for simultaneous data transmission on all links + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MLO_STR_TX = 70, + + /* Nested attribute to indicate EHT MLO links on which powersave to be + * enabled. It contains link ID attributes. These nested attributes are + * of the type u8 and are used to enable the powersave on associated + * MLO links corresponding to the link IDs provided in the command. + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MLO_LINK_POWER_SAVE = 71, + + /* 8-bit unsigned value to configure the MLD ID of the BSS whose link + * info is requested in the ML Probe Request frame. In the MLO-MBSSID + * testcase, STA can request information of non-Tx BSS through Tx BSS + * by configuring non-Tx BSS MLD ID within the ML probe request that + * is transmitted via host initiated scan request. + * + * This attribute is used for testing purposes. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MLD_ID_ML_PROBE_REQ = 72, + + /* 8-bit unsigned value to configure the SCS traffic description + * support in the EHT capabilities of an Association Request frame. + * 1-enable, 0-disable + * This attribute is used to configure the testbed device. + */ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_SCS_TRAFFIC_SUPPORT = 73, + /* keep last */ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX = @@ -8498,12 +10428,17 @@ enum qca_wlan_vendor_attr_wifi_test_config { * 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 + * @QCA_WLAN_TWT_SETUP_READY_NOTIFY: Notify userspace that the firmware is * ready for a new TWT session setup after it issued a TWT teardown. * * @QCA_WLAN_TWT_SET_PARAM: Configure TWT related parameters. Required * parameters are obtained through QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS. Refer * the enum qca_wlan_vendor_attr_twt_set_param. + * + * @QCA_WLAN_TWT_NOTIFY: Used to notify userspace about changes in TWT + * related information for example TWT required bit in AP capabilities etc. + * The reason for the notification is sent using + * QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS. */ enum qca_wlan_twt_operation { QCA_WLAN_TWT_SET = 0, @@ -8517,6 +10452,7 @@ enum qca_wlan_twt_operation { QCA_WLAN_TWT_GET_CAPABILITIES = 8, QCA_WLAN_TWT_SETUP_READY_NOTIFY = 9, QCA_WLAN_TWT_SET_PARAM = 10, + QCA_WLAN_TWT_NOTIFY = 11, }; /** @@ -8533,11 +10469,17 @@ enum qca_wlan_twt_operation { * enum qca_wlan_vendor_attr_twt_setup, enum qca_wlan_vendor_attr_twt_resume, * enum qca_wlan_vendor_attr_twt_set_param, or * enum qca_wlan_vendor_attr_twt_stats based on the operation. + * + * @QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS: Size is u8, mandatory when + * QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION is set to QCA_WLAN_TWT_NOTIFY. + * The values used by this attribute are defined in + * enum qca_wlan_vendor_twt_status. */ 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, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS = 3, /* keep last */ QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_AFTER_LAST, @@ -8631,12 +10573,15 @@ enum qca_wlan_vendor_bss_filter_action { * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI_TS: Time stamp of the host * driver for the last received RSSI. Unsigned 64 bit number containing * nanoseconds from the boottime. + * @QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_PAD: Attribute used for padding for + * 64-bit alignment. */ enum qca_wlan_vendor_bss_filter_sta_stats { QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_INVALID = 0, QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_MAC = 1, QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI = 2, QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_RSSI_TS = 3, + QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_PAD = 4, /* keep last */ QCA_WLAN_VENDOR_BSS_FILTER_STA_STATS_AFTER_LAST, @@ -8913,10 +10858,13 @@ enum qca_wlan_twt_setup_state { * * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE: Optional (u8) * This attribute contains the value of the Responder PM Mode subfield (0 or 1) - * from TWT response frame. + * from TWT response frame. During TWT setup request, this attribute is used to + * configure the Responder PM Mode bit in the control field of the TWT element + * for broadcast TWT schedule. * This parameter is used for * 1. TWT SET Response * 2. TWT GET Response + * 3. TWT SET Request * * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT: Optional (u32) * This attribute is used to configure the announce timeout value (in us) in @@ -8927,6 +10875,9 @@ enum qca_wlan_twt_setup_state { * start. The default value in the firmware is 0. * This parameter is used for * 1. TWT SET Request + * + * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PAD: Attribute used for padding for 64-bit + * alignment. */ enum qca_wlan_vendor_attr_twt_setup { QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0, @@ -8963,6 +10914,8 @@ enum qca_wlan_vendor_attr_twt_setup { QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE = 25, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT = 26, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PAD = 27, + /* keep last */ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX = @@ -9013,6 +10966,10 @@ enum qca_wlan_vendor_attr_twt_setup { * QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE: The driver requested to * terminate an existing TWT session on power save exit request from userspace. * Used on the TWT_TERMINATE notification from the driver/firmware. + * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED: The peer has set the TWT + * required bit in its capabilities. + * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED: The peer has cleared + * the TWT required bit(1->0) in its capabilities. */ enum qca_wlan_vendor_twt_status { QCA_WLAN_VENDOR_TWT_STATUS_OK = 0, @@ -9038,6 +10995,8 @@ enum qca_wlan_vendor_twt_status { QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS = 20, QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS = 21, QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE = 22, + QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED = 23, + QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED = 24, }; /** @@ -9122,6 +11081,16 @@ enum qca_wlan_vendor_attr_twt_resume { * @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. + * + * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_SP_START_OFFSET: Optional (s32) + * This field will be used when device supports Flexible TWT. + * This field contains an offset value by which to shift the starting time + * of the next service period. The value of offset can be negative or positive. + * If provided, this attribute will override + * QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME. The units are in microseconds. + * + * @QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_PAD: Attribute used for padding for 64-bit + * alignment. */ enum qca_wlan_vendor_attr_twt_nudge { QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_INVALID = 0, @@ -9130,6 +11099,8 @@ enum qca_wlan_vendor_attr_twt_nudge { 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, + QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_SP_START_OFFSET = 6, + QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_PAD = 7, /* keep last */ QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_AFTER_LAST, @@ -9303,10 +11274,18 @@ enum qca_wlan_vendor_attr_twt_capability { * This attribute configures AC parameters to be used for all TWT * sessions in AP mode. * Uses the enum qca_wlan_ac_type values. + * + * @QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_UNAVAILABILITY_MODE: Flag attribute, + * used by TWT responder to indicate unavailability outside of the SPs. + * Enable (flag attribute present) - Indicates that the TWT responder may be + * unavailable outside of the SPs of its broadcast TWT schedule. + * Disable (flag attribute not present) - Indicates that the responder will be + * available for all TWT sessions (including individual TWT). */ enum qca_wlan_vendor_attr_twt_set_param { QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_INVALID = 0, QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE = 1, + QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_UNAVAILABILITY_MODE = 2, /* keep last */ QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AFTER_LAST, @@ -9631,6 +11610,9 @@ enum qca_wlan_vendor_cfr_capture_type { * to userspace along with QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG as an * asynchronous event when the driver is configured to send CFR data using * netlink events with %QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_PAD: Attribute used for padding for 64-bit + * alignment. */ enum qca_wlan_vendor_peer_cfr_capture_attr { QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_INVALID = 0, @@ -9662,6 +11644,7 @@ enum qca_wlan_vendor_peer_cfr_capture_attr { QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE = 26, QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID = 27, QCA_WLAN_VENDOR_ATTR_PEER_CFR_RESP_DATA = 28, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_PAD = 29, /* Keep last */ QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST, @@ -9883,7 +11866,6 @@ enum qca_vendor_attr_coex_config { * has priority over BT_A2DP and ZB_HIGH. * 3: BT_A2DP has priority over ZB_HIGH. */ - enum qca_vendor_attr_coex_config_three_way { QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_INVALID = 0, QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE = 1, @@ -9955,6 +11937,8 @@ enum qca_vendor_attr_peer_stats_cache_type { * containing buffer of statistics to send to application layer entity. * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_COOKIE: Unsigned 64-bit attribute * representing a cookie for peer unique session. + * @QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PAD: Attribute used for padding for + * 64-bit alignment. */ enum qca_wlan_vendor_attr_peer_stats_cache_params { QCA_WLAN_VENDOR_ATTR_PEER_STATS_INVALID = 0, @@ -9963,6 +11947,7 @@ enum qca_wlan_vendor_attr_peer_stats_cache_params { QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_MAC = 2, QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_DATA = 3, QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PEER_COOKIE = 4, + QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_PAD = 5, /* Keep last */ QCA_WLAN_VENDOR_ATTR_PEER_STATS_CACHE_LAST, @@ -10241,6 +12226,8 @@ enum qca_wlan_vendor_attr_beacon_reporting_params { * reported. */ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME = 13, + /* Attribute used for padding for 64-bit alignment */ + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAD = 14, /* Keep last */ QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_LAST, @@ -10382,6 +12369,14 @@ enum qca_wlan_vendor_attr_oem_data_params { * %QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM or based on * regulatory/SAE limits if %QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM * is not provided. + * + * @QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_IFINDEX: u32 attribute, optional. + * This specifies the interface index (netdev) for which the corresponding + * configurations are applied. If the interface index is not specified, the + * configurations are applied based on + * %QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_IFACES_BITMASK. + * %QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_IFACES_BITMASK along with this + * attribute shall have the matching nl80211_iftype. */ enum qca_wlan_vendor_attr_avoid_frequency_ext { QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_INVALID = 0, @@ -10390,6 +12385,7 @@ enum qca_wlan_vendor_attr_avoid_frequency_ext { QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END = 3, QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM = 4, QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_IFACES_BITMASK = 5, + QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_IFINDEX = 6, QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX = @@ -10409,6 +12405,12 @@ enum qca_wlan_vendor_attr_add_sta_node_params { */ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO = 2, + /* + * This flag attribute is set if the node being added is an + * MLD STA node. + */ + QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_IS_ML = 3, + /* keep last */ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_MAX = @@ -10421,14 +12423,21 @@ enum qca_wlan_vendor_attr_add_sta_node_params { * These values are used by attribute %QCA_VENDOR_ATTR_BTC_CHAIN_MODE of * %QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE. * - * @QCA_BTC_CHAIN_SHARED: chains of BT and WLAN 2.4G are shared. - * @QCA_BTC_CHAIN_SEPARATED: chains of BT and WLAN 2.4G are separated. + * @QCA_BTC_CHAIN_SHARED: chains of BT and WLAN 2.4 GHz are shared. + * @QCA_BTC_CHAIN_SEPARATED_HYBRID: chains of BT and WLAN 2.4 GHz are + * separated, hybrid mode. + * @QCA_BTC_CHAIN_SEPARATED_FDD: chains of BT and WLAN 2.4 GHz are + * separated, fixed FDD mode. */ enum qca_btc_chain_mode { QCA_BTC_CHAIN_SHARED = 0, - QCA_BTC_CHAIN_SEPARATED = 1, + QCA_BTC_CHAIN_SEPARATED_HYBRID = 1, + QCA_BTC_CHAIN_SEPARATED_FDD = 2, }; +/* deprecated legacy name */ +#define QCA_BTC_CHAIN_SEPARATED QCA_BTC_CHAIN_SEPARATED_HYBRID + /** * enum qca_vendor_attr_btc_chain_mode - Specifies attributes for BT coex * chain mode. @@ -10652,7 +12661,7 @@ enum qca_vendor_wlan_sta_guard_interval { * the disconnected state. * * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0: u32, used in the - * STA mode. This represents the Target power in dBm for for transmissions done + * STA mode. This represents the Target power in dBm for transmissions done * to the AP in 5 GHz at MCS0 rate. This data is maintained per connect session. * Represents the count of last connected session, when queried in the * disconnected state. @@ -10765,6 +12774,31 @@ enum qca_vendor_wlan_sta_guard_interval { * This represents the average congestion duration of uplink frames in MAC * queue in unit of ms. This can be queried either in connected state or * disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_TX_PACKETS: Array of u32 nested + * values, used in AP mode. This represents the MPDU packet count per MCS + * rate value of TX packets. Every index of this nested attribute corresponds + * to MCS index, e.g., Index 0 represents MCS0 TX rate. This can be + * queried in connected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_RX_PACKETS: Array of u32 nested + * values, used in AP mode. This represents the MPDU packet count per MCS + * rate value of RX packets. Every index of this nested attribute corresponds + * to MCS index, e.g., Index 0 represents MCS0 RX rate. This can be + * queried in connected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PAD: Attribute used for padding for + * 64-bit alignment. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY_JITTER: u32, used in STA mode + * only. This represents the average of the delta between successive uplink + * frames congestion duration in MAC queue in unit of ms. This can be queried + * either in connected state or disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_NSS_PKT_COUNT: Array of nested attributes, + * used in STA mode. This represents the number of MSDU packets + * (unicast/multicast/broadcast) transmitted/received with each NSS value. See + * enum qca_wlan_vendor_attr_nss_pkt. */ enum qca_wlan_vendor_attr_get_sta_info { QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0, @@ -10818,6 +12852,11 @@ enum qca_wlan_vendor_attr_get_sta_info { QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON = 48, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON = 49, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY = 50, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_TX_PACKETS = 51, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_RX_PACKETS = 52, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PAD = 53, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY_JITTER = 54, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_NSS_PKT_COUNT = 55, /* keep last */ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST, @@ -10972,7 +13011,7 @@ enum qca_wlan_tspec_direction { }; /** - * enum qca_wlan_tspec_ack_policy - MAC acknowledgement policy in TSPEC + * enum qca_wlan_tspec_ack_policy - MAC acknowledgment 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. @@ -11337,24 +13376,66 @@ enum qca_wlan_concurrent_sta_policy_config { }; /** - * enum qca_wlan_vendor_attr_concurrent_sta_policy - Defines attributes - * used by QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_MULTI_STA_POLICY vendor command. + * enum qca_wlan_concurrent_ap_policy_config - Concurrent AP policies + * + * @QCA_WLAN_CONCURRENT_AP_POLICY_UNSPECIFIED: No specific policy for this AP + * interface. + * + * @QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO: Select interface concurrencies + * to meet gaming audio latency requirements. + * This policy is used only when the driver advertises support for + * QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN. + * + * @QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING: Select interface + * concurrencies to meet lossless audio streaming requirements. + * This policy is used only when the driver advertises support for + * QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN. + * + * @QCA_WLAN_CONCURRENT_AP_POLICY_XR: Select interface concurrencies to meet + * XR (eXtended Reality) requirements. + */ +enum qca_wlan_concurrent_ap_policy_config { + QCA_WLAN_CONCURRENT_AP_POLICY_UNSPECIFIED = 0, + QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO = 1, + QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING = 2, + QCA_WLAN_CONCURRENT_AP_POLICY_XR = 3, +}; + +/** + * enum qca_wlan_vendor_attr_concurrent_policy - Defines attributes + * used by QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY vendor command. * - * @QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG: + * @QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG: * u8 attribute. Configures the concurrent STA policy configuration. * Possible values are defined in enum qca_wlan_concurrent_sta_policy_config. + + * @QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AP_CONFIG: + * u8 attribute. Configures the concurrent AP policy configuration. + * Possible values are defined in enum qca_wlan_concurrent_ap_policy_config. */ -enum qca_wlan_vendor_attr_concurrent_sta_policy { - QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_INVALID = 0, - QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG = 1, +enum qca_wlan_vendor_attr_concurrent_policy { + QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG = 1, + QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AP_CONFIG = 2, /* keep last */ - QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_AFTER_LAST, - QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_MAX = - QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_AFTER_LAST - 1, + QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_MAX = + QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AFTER_LAST - 1, }; +/* Compatibility defines for previously used enum + * qca_wlan_vendor_attr_concurrent_policy names. These values should not be used + * in any new implementation. + */ +#define QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_CONFIG \ + QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG +#define QCA_WLAN_VENDOR_ATTR_CONCURRENT_STA_POLICY_MAX \ + QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_MAX +#define qca_wlan_vendor_attr_concurrent_sta_policy \ + qca_wlan_vendor_attr_concurrent_policy + /** * enum qca_sta_connect_fail_reason_codes - Defines values carried * by QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE vendor @@ -11503,6 +13584,8 @@ enum qca_wlan_vendor_attr_usable_channels { * or radar detection. * @QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_DETECTED: NLA_FLAG attribute. * This flag indicates radar signal has been detected. + * @QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_PAD: Attribute used for padding for + * 64-bit alignment. */ enum qca_wlan_vendor_attr_radar_history { QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_INVALID = 0, @@ -11511,6 +13594,7 @@ enum qca_wlan_vendor_attr_radar_history { QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_FREQ = 2, QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_TIMESTAMP = 3, QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_DETECTED = 4, + QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_PAD = 5, /* keep last */ QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_LAST, @@ -11518,6 +13602,645 @@ enum qca_wlan_vendor_attr_radar_history { QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_LAST - 1, }; +/** + * enum qca_wlan_vendor_mcc_quota_type: MCC channel time quota type + * + * @QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_CLEAR: In the event, it indicates that the + * target exited MCC state and cleared the quota information. In the + * command it clears MCC quota setting and restores adaptive scheduling. + * @QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_FIXED: Channel time quota is fixed and + * will not be changed. + * This quota type is present in command/event. + * @QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_DYNAMIC: Channel time quota is dynamic + * and the target may change the quota based on the data activity. + * This quota type is only present in event. + * @QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_LOW_LATENCY: Channel time quota is optimized + * by the target for low latency. + * This quota type is only present in command. + */ +enum qca_wlan_vendor_mcc_quota_type { + QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_CLEAR = 0, + QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_FIXED = 1, + QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_DYNAMIC = 2, + QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_LOW_LATENCY = 3, +}; + +/** + * enum qca_wlan_vendor_attr_mcc_quota: Used by the vendor event + * QCA_NL80211_VENDOR_SUBCMD_MCC_QUOTA to indicate MCC channel + * quota information or as a command to set the required MCC quota for an + * interface. + * + * @QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_TYPE: u32 attribute. + * The type is defined in enum qca_wlan_vendor_mcc_quota_type. + * In a command this specifies the MCC quota type to be set for the interface. + * In an event this provides the current quota type in force. + * This is required in a command and an event. + * + * @QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_ENTRIES: Nested attribute to carry + * the list of channel quota entries. + * In an event each entry contains the frequency and respective time quota for + * all the MCC interfaces. + * In a command it specifies the interface index and respective time quota. + * In a command only one entry (ifindex, quota pair) may be specified. + * + * @QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_FREQ: u32 attribute. + * Channel frequency in MHz. This is present only in an event. + * + * @QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_TIME_PERCENTAGE: u32 attribute. + * Channel time quota expressed as percentage. + * This is present in an event and a command. + * In an command, the user shall specify the quota to be allocated for the + * interface represented by %QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_IFINDEX. + * In an event this provides the existing quota for the channel. + * + * @QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_IFINDEX: u32 attribute. + * Specifies the interface index (netdev) for which the corresponding + * configurations are applied. This is required in a command only. Only one + * interface index may be specified. If not specified, the configuration is + * rejected. + * + * @QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_LOW_LATENCY_MODE_ENABLE + * 8-bit unsigned value to enable/disable Multi-Channel Concurrency + * low latency mode. The firmware will do optimization for low + * latency in Multi-Channel concurrency state if enabled. And all existing + * user quota setting will be overwritten by the target. + * 0 - disable(default), 1 - enable. + * It is only present in a command with quota type of + * QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_LOW_LATENCY. + */ +enum qca_wlan_vendor_attr_mcc_quota { + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_TYPE = 1, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_ENTRIES = 2, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_FREQ = 3, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_TIME_PERCENTAGE = 4, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_IFINDEX = 5, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_LOW_LATENCY_MODE_ENABLE = 6, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_LAST, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX = + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_LAST - 1, +}; + +/** + * enum qca_wlan_roam_stats_invoke_reason - Roam invoke reason. These values + * are used by the attribute + * %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_USER_TRIGGER_INVOKE_REASON. + * + * @QCA_WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED: Default value when target + * invoke roam. + * @QCA_WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE: Neighbor unreachable + * detection failed when the roam trigger. + * @QCA_WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE: Invoke from user space. + */ + +enum qca_wlan_roam_stats_invoke_reason { + QCA_WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED = 0, + QCA_WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE = 1, + QCA_WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE = 2, +}; + +/** + * enum qca_wlan_roam_stats_tx_failures_reason - Roam TX failures reason. These + * values are used by the attribute + * %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_REASON. + * + * @QCA_WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED: Default value when + * roam by kickout. + * @QCA_WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY: Excessive retry when roam + * trigger by kickout. + * @QCA_WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY: Station inactivity when + * roam trigger by kickout. + * @QCA_WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT: IBSS disconnect when + * roam trigger by kickout. + * @QCA_WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT: TDLS peer has + * disappeared, and all TX is failing when roam trigger by kickout. + * @QCA_WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT: SA query process + * timeout when roam trigger by kickout. + * @QCA_WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT: Directly connected + * peer has roamed to a repeater. + */ +enum qca_wlan_roam_stats_tx_failures_reason { + QCA_WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED = 0, + QCA_WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY = 1, + QCA_WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY = 2, + QCA_WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT = 3, + QCA_WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT = 4, + QCA_WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT = 5, + QCA_WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT = 6, +}; + +/** + * enum qca_wlan_roam_stats_abort_reason - Roam abort reason. These values + * are used by the attribute %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ABORT_REASON. + * + * @QCA_WLAN_ROAM_STATS_ABORT_UNSPECIFIED: Target did not specify the + * detailed reason for roam scan being aborted. + * @QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH: Roam scan is not + * started due to high data RSSI during LOW-RSSI roaming. + * @QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD: Roam scan is not + * started due to good link speed during LOW-RSSI roaming. + * @QCA_WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH: Roam scan is not started + * due to high data RSSI during background roaming. + * @QCA_WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD: Roam scan is not + * started due to high beacon RSSI during background roaming + */ +enum qca_wlan_roam_stats_abort_reason { + QCA_WLAN_ROAM_STATS_ABORT_UNSPECIFIED = 0, + QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH = 1, + QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD = 2, + QCA_WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH = 3, + QCA_WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD = 4, +}; + +/** + * enum qca_wlan_roam_stats_scan_type - Roam scan type define. + * These values are used by the attribute + * %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_TYPE. + * + * @QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL: Partial channel scan + * @QCA_WLAN_ROAM_STATS_SCAN_TYPE_FULL: Full channel scan + * @QCA_WLAN_ROAM_STATS_SCAN_TYPE_NO_SCAN: No roam scan was triggered. + * This is generally used in BTM events to indicate BTM frame exchange logs. + * @QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ: Higher band roam scan + * from 2.4 GHz to 5 GHz or 6 GHz + * @QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ: Higher band roam scan from + * 5 GHz to 6 GHz + */ +enum qca_wlan_roam_stats_scan_type { + QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL = 0, + QCA_WLAN_ROAM_STATS_SCAN_TYPE_FULL = 1, + QCA_WLAN_ROAM_STATS_SCAN_TYPE_NO_SCAN = 2, + QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ = 3, + QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ = 4, +}; + +/** + * enum qca_wlan_roam_stats_scan_dwell_type - Roam scan dwell type. + * These values are used by the attribute + * %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_DWELL_TYPE. + * + * @QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED: Target did not specify the + * detailed roam scan type. + * @QCA_WLAN_ROAM_STATS_DWELL_ACTIVE_TYPE: Active scan during roam. + * @QCA_WLAN_ROAM_STATS_DWELL_PASSIVE_TYPE: Passive scan during roam. + */ +enum qca_wlan_roam_stats_scan_dwell_type { + QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED = 0, + QCA_WLAN_ROAM_STATS_DWELL_TYPE_ACTIVE = 1, + QCA_WLAN_ROAM_STATS_DWELL_TYPE_PASSIVE = 2, +}; + +/** + * enum qca_wlan_vendor_attr_roam_stats_scan_chan_info - Attributes used inside + * the %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHAN_INFO nested attribute. + */ +enum qca_wlan_vendor_attr_roam_stats_scan_chan_info { + /* 32-bit unsigned value to indicate center frequency of the primary + * channel in MHz for each roam scan channel. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHANNEL_FREQ = 1, + /* 8-bit unsigned value to indicate channel scan type for each + * roam scan channel, values in qca_wlan_roam_stats_scan_dwell_type. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_DWELL_TYPE = 2, + /* 32-bit unsigned value to indicate maximum scan time in milliseconds + * for each roam scan channel. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_MAX_DWELL_TIME = 3, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_INFO_FRAME_MAX = + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_INFO_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_roam_stats_frame_subtype - Roam frame subtypes. These values + * are used by the attribute %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_SUBTYPE. + * + * @QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP: Authentication Response frame + * @QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP: Reassociation Response frame + * @QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1: EAPOL-Key M1 frame + * @QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2: EAPOL-Key M2 frame + * @QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3: EAPOL-Key M3 frame + * @QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4: EAPOL-Key M4 frame + * @QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1: EAPOL-Key GTK M1 frame + * @QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2: EAPOL-Key GTK M2 frame + * @QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ: Authentication Request frame + * @QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ: Reassociation Request frame + */ +enum qca_wlan_roam_stats_frame_subtype { + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP = 1, + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP = 2, + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1 = 3, + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2 = 4, + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3 = 5, + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4 = 6, + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1 = 7, + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2 = 8, + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ = 9, + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ = 10, +}; + +/* Compatibility defines for previously used names. + * These values should not be used in any new implementation. + */ +#define QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_PREAUTH \ + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP +#define QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC \ + QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP + +/** + * enum roam_frame_status - Specifies the valid values the vendor roam frame + * attribute QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_STATUS can take. + * + * @QCA_WLAN_ROAM_FRAME_STATUS_SUCCESS: It indicates the roam frame was + * sent or received successfully. + * @QCA_WLAN_ROAM_FRAME_STATUS_FAIL: It indicates the roam frame sending or + * receiving failed. + */ +enum qca_wlan_roam_stats_frame_status { + QCA_WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS = 0, + QCA_WLAN_ROAM_STATS_FRAME_STATUS_FAIL = 1, +}; + +/** + * enum qca_wlan_vendor_attr_roam_stats_frame_info - Attributes used within the + * %QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO nested attribute. + */ +enum qca_wlan_vendor_attr_roam_stats_frame_info { + /* 8-bit unsigned value to indicate the frame subtype during + * roaming, one of the values in qca_wlan_roam_stats_frame_subtype. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_SUBTYPE = 1, + /* 8-bit unsigned value to indicate the frame is successful or failed + * during roaming, one of the values in + * qca_wlan_roam_stats_frame_status. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_STATUS = 2, + /* 64-bit unsigned value to indicate the timestamp for frame of + * preauthentication/reassociation/EAPOL-M1/EAPOL-M2/EAPOL-M3/EAPOL-M4 + * when sent or received during roaming, timestamp in milliseconds + * from system boot. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_TIMESTAMP = 3, + /* Attribute used for padding for 64-bit alignment */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_PAD = 4, + /* This attribute indicates a 6-byte MAC address representing + * the BSSID of the AP. + * For non-MLO scenario, it indicates the AP BSSID. + * For MLO scenario, it indicates the AP BSSID which may be the primary + * link BSSID or a nonprimary link BSSID. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_BSSID = 5, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO_MAX = + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_roam_stats_info - Used by the attribute + * QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO. + */ +enum qca_wlan_vendor_attr_roam_stats_info { + /* 64-bit unsigned value to indicate the timestamp when roam was + * triggered by the firmware, timestamp in milliseconds from system + * boot. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_TRIGGER_TIMESTAMP = 1, + /* 32-bit unsigned value to indicate the roam trigger reason for the + * last roaming attempted by the firmware. This can be queried either + * in a connected state or disconnected state. The values of this + * attribute represent the roam trigger reason codes, which + * are defined in enum qca_roam_reason. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TRIGGER_REASON = 2, + /* 8-bit unsigned value to indicate percentage of packets for which + * the RX rate is lower than the RX rate threshold in total RX packets, + * used for roaming trigger by per. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT = 3, + /* 8-bit unsigned value to indicate percentage of packets for which + * the TX rate is lower than TX rate threshold in total TX packets, + * used for roaming trigger by per. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT = 4, + /* 32-bit unsigned value to indicate final beacon miss count for + * trigger reason of beacon miss. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FINAL_BMISS_CNT = 5, + /* 32-bit unsigned value to indicate consecutive beacon miss count + * for trigger reason of beacon miss. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONSECUTIVE_BMISS_CNT = 6, + /* 8-bit unsigned value to indicate QOS-NULL TX status for trigger + * reason of beacon miss, 0 - success, 1 - fail. + * If QOS-NULL TX status is successful, beacon miss final count and + * consecutive beacon miss count will be reset to zero, and roam will + * not be triggered. If QOS-NULL TX status is failed, beacon miss final + * count and consecutive beacon miss count continue to calculate until + * roaming trigger by beacon miss. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BMISS_QOS_NULL_SUCCESS = 7, + /* 8-bit signed value to indicate connected AP RSSI in dBm + * for trigger reason of poor RSSI. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_CURRENT_RSSI = 8, + /* 8-bit signed value to indicate RSSI threshold value in dBm + * for trigger reason of poor RSSI. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD = 9, + /* 8-bit unsigned value to indicate RX link speed status + * for trigger reason of poor RSSI, 0 - good link speed, + * 1 - bad link speed. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS = 10, + /* 8-bit signed value to indicate connected AP RSSI in dBm + * for trigger reason of better RSSI. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_CURRENT_RSSI = 11, + /* 8-bit signed value to indicate RSSI threshold value in dBm + * for trigger reason of better RSSI. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD = 12, + /* 32-bit unsigned value to indicate RX throughput in bytes per second + * for trigger reason of congestion. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_RX_TPUT = 13, + /* 32-bit unsigned value to indicate TX throughput in bytes per second + * for trigger reason of congestion. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_TX_TPUT = 14, + /* 8-bit unsigned value to indicate roamable AP count + * for trigger reason of congestion. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_ROAMABLE_CNT = 15, + /* 8-bit unsigned value to indicate invoke reason, one of the values + * defined in qca_wlan_roam_stats_invoke_reason. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_USER_TRIGGER_INVOKE_REASON = 16, + /* 8-bit unsigned value to indicate request mode for trigger reason + * of BTM, values are defined in IEEE Std 802.11-2020, 9.6.13.9. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_REQUEST_MODE = 17, + /* 32-bit unsigned value to indicate disassociate time in milliseconds + * for trigger reason of BTM. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME = 18, + /* 32-bit unsigned value to indicate preferred candidate list valid + * interval in milliseconds for trigger reason of BTM. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_VALID_INTERNAL = 19, + /* 8-bit unsigned value to indicate the number of preferred + * candidates for trigger reason of BTM. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_CANDIDATE_LIST_CNT = 20, + /* 8-bit unsigned value to indicate response status for trigger + * reason of BTM, values are defined in IEEE Std 802.11-2020, + * Table 9-428 (BTM status code definitions). + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_RESPONSE_STATUS_CODE = 21, + /* 32-bit unsigned value to indicate BSS termination timeout value + * in milliseconds for trigger reason of BTM. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT = 22, + /* 32-bit unsigned value to indicate MBO associate retry timeout + * value in milliseconds for trigger reason of BTM. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT = 23, + /* 8-bit unsigned value to indicate dialog token number + * for trigger reason of BTM. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_REQ_DIALOG_TOKEN = 24, + /* 8-bit unsigned value to indicate percentage of connected AP + * channel congestion utilization for trigger reason of BSS load. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BSS_CU_LOAD = 25, + /* 8-bit unsigned value to indicate disconnection type + * for trigger reason of disconnection. 1 - Deauthentication, + * 2 - Disassociation. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DISCONNECTION_TYPE = 26, + /* 16-bit unsigned value to indicate deauthentication or disassociation + * reason for trigger reason of disconnection, values are defined + * in IEEE Std 802.11-2020, Table 9-49 (Reason codes). + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DISCONNECTION_REASON = 27, + /* 32-bit unsigned value to indicate milliseconds of roam scan + * periodicity when needing to roam to find a better AP for trigger + * reason of periodic timer. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PERIODIC_TIMER_MS = 28, + /* 8-bit signed value to indicate connected AP RSSI in dBm for + * trigger reason of background scan. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI = 29, + /* 8-bit signed value to indicate data RSSI in dBm for trigger reason + * of background scan. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI = 30, + /* 8-bit signed value to indicate data RSSI threshold in dBm + * for trigger reason of background scan. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_THRESH = 31, + /* 32-bit unsigned value to indicate consecutive TX failure threshold + * for trigger reason of TX failures. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_THRESHOLD = 32, + /* 8-bit unsigned value to indicate TX failure reason for trigger + * reason of TX failures, one of the values defined in + * qca_wlan_roam_stats_tx_failures_reason. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_REASON = 33, + /* 8-bit unsigned value to indicate detail abort reason. One of the + * values in enum qca_wlan_roam_stats_abort_reason. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ABORT_REASON = 34, + /* 8-bit signed value to indicate data RSSI in dBm when aborting the + * roam scan. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI = 35, + /* 8-bit signed value to indicate data RSSI threshold in dBm when + * aborting the roam scan. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI_THRESHOLD = 36, + /* 8-bit unsigned value to indicate data RSSI threshold in RX link + * speed status when aborting the roam scan. + * 0 - good link speed, 1 - bad link speed + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RX_LINKSPEED_STATUS = 37, + /* 8-bit unsigned value to indicate roaming scan type. + * One of the values in enum qca_wlan_roam_stats_scan_type. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_TYPE = 38, + /* 8-bit unsigned value to indicate roaming result, used in STA mode + * only. + * 0-Roaming is successful, 1-Roaming is failed + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_STATUS = 39, + /* 8-bit unsigned value to indicate 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_ROAM_STATS_FAIL_REASON = 40, + /* Nested attribute. Indicate roam scan info for each channel, the + * attributes defined in enum + * qca_wlan_vendor_attr_roam_stats_scan_chan_info are used inside + * this attribute. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHAN_INFO = 41, + /* 32-bit unsigned value to indicate total scan time during roam scan + * all channels, time in milliseconds. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TOTAL_SCAN_TIME = 42, + /* Nested attribute. This attribute shall be used by the driver to + * send roam information of each subtype. The attributes defined in + * enum qca_wlan_vendor_attr_roam_stats_frame_info are used inside + * this attribute. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO = 43, + /* Attribute used for padding for 64-bit alignment */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PAD = 44, + /* 6-byte MAC address used by the driver to send roam stats information + * of the original AP BSSID. The original AP is the connected AP before + * roam happens, regardless of the roam resulting in success or failure. + * This attribute is only present when + * QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_STATUS has a value of + * 0 (success) or 1 (failure). + * For non-MLO scenario, it indicates the original connected AP BSSID. + * For MLO scenario, it indicates the original BSSID of the link + * for which the reassociation occurred during the roam. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ORIGINAL_BSSID = 45, + /* 6-byte MAC address used by the driver to send roam stats information + * of the roam candidate AP BSSID when roam failed. This is only present + * when QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_STATUS has a value of + * 1 (failure). If the firmware updates more than one candidate AP BSSID + * to the driver, the driver only fills the last candidate AP BSSID and + * reports it to user space. + * For non-MLO scenario, it indicates the last candidate AP BSSID. + * For MLO scenario, it indicates the AP BSSID which may be the primary + * link BSSID or a nonprimary link BSSID. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CANDIDATE_BSSID = 46, + /* 6-byte MAC address used by the driver to send roam stats information + * of the roamed AP BSSID when roam succeeds. This is only present when + * QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_STATUS has a value of + * 0 (success). + * For non-MLO scenario, it indicates the new AP BSSID to which has + * been successfully roamed. + * For MLO scenario, it indicates the new AP BSSID of the link on + * which the reassociation occurred during the roam. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAMED_BSSID = 47, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_roam_cached_stats - Vendor subcmd attributes to + * report cached roam info from the driver to user space, enum values are used + * for netlink attributes sent with the + * %QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS sub command. + */ +enum qca_wlan_vendor_attr_roam_cached_stats { + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INVALID = 0, + /* Nested attribute, this attribute contains nested array roam info + * statistics defined in enum qca_wlan_vendor_attr_roam_stats_info. + */ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ROAM_CACHED_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAM_CACHED_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_ROAM_CACHED_STATS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_supported_radio_cfg - Attributes for + * radio configurations present in each radio combination. + * + * @QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND: u32 attribute indicates + * the band info in the radio configuration. Uses the enum qca_set_band values. + * + * @QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA: u8 attribute indicates + * the number of antennas info in the radio configuration. + */ +enum qca_wlan_vendor_attr_supported_radio_cfg { + QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND = 1, + QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_LAST, + QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_MAX = + QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_radio_combination - Attributes for + * radio combinations supported by the device. + * + * @QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_CFGS: Nested attribute + * provides the radio configurations present in the radio combination. + * Uses the enum qca_wlan_vendor_attr_supported_radio_cfg attributes. + * This attribute provides the values for radio combination matrix. + * For standalone config, the number of config values is one and the config + * carries the band and antenna information for standalone configuration. For + * Dual Band Simultaneous (DBS)/Single Band Simultaneous (SBS) mode + * configuration the number of config values is two and the config carries the + * band and antenna information for each simultaneous radio. + */ +enum qca_wlan_vendor_attr_radio_combination { + QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_CFGS = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_LAST, + QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_MAX = + QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_radio_combination_matrix - Attributes used by + * %QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX + * + * @QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_SUPPORTED_CFGS: Nested attribute + * provides the radio combinations supported by the device. + * Uses the enum qca_wlan_vendor_attr_radio_combination attributes. + * For example, in the radio combination matrix for a device which has two + * radios, where one radio is capable of 2.4 GHz 2X2 only and another radio is + * capable of either 5 GHz or 6 GHz 2X2, the possible number of radio + * combinations is 5 and the radio combinations are + * {{{2.4 GHz 2X2}}, //Standalone 2.4 GHz + * {{5 GHz 2X2}}, //Standalone 5 GHz + * {{6 GHz 2X2}}, //Standalone 6 GHz + * {{2.4 GHz 2X2}, {5 GHz 2X2}}, //2.4 GHz + 5 GHz DBS + * {{2.4 GHz 2X2}, {6 GHz 2X2}}} //2.4 GHz + 6 GHz DBS + * The band and antenna info together as nested data provides one radio config. + * Standalone configuration has one config with band and antenna nested data. + * Dual Band Simultaneous (DBS)/Single Band Simultaneous (SBS) configuration + * have two nested band and antenna info data. + */ +enum qca_wlan_vendor_attr_radio_combination_matrix { + QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_SUPPORTED_CFGS = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_LAST, + QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_MAX = + QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_LAST - 1, +}; + /** * enum qca_wlan_vendor_attr_mdns_offload - Attributes used by * %QCA_NL80211_VENDOR_SUBCMD_MDNS_OFFLOAD vendor command. @@ -11612,7 +14335,6 @@ enum qca_wlan_vendor_monitor_data_frame_type { * the Beacon frames obtained during the scan (off channel and connected * channel), when in connected state. */ - enum qca_wlan_vendor_monitor_mgmt_frame_type { QCA_WLAN_VENDOR_MONITOR_MGMT_FRAME_TYPE_ALL = BIT(0), /* valid only if QCA_WLAN_VENDOR_MONITOR_MGMT_FRAME_TYPE_ALL is not set @@ -11672,8 +14394,7 @@ enum qca_wlan_vendor_monitor_ctrl_frame_type { * expecting the connected BSS's Beacon frames to be sent on the monitor * interface at this specific interval. */ -enum qca_wlan_vendor_attr_set_monitor_mode -{ +enum qca_wlan_vendor_attr_set_monitor_mode { QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_INVALID = 0, QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_DATA_TX_FRAME_TYPE = 1, QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_DATA_RX_FRAME_TYPE = 2, @@ -11825,9 +14546,7 @@ enum qca_wlan_vendor_attr_roam_events_candidate_info { * u32 values. List of frequencies in MHz considered for a roam scan. * This is sent as an event through QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS. */ - -enum qca_wlan_vendor_attr_roam_events -{ +enum qca_wlan_vendor_attr_roam_events { QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVALID = 0, QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CONFIGURE = 1, QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_SUSPEND_STATE = 2, @@ -11841,7 +14560,3293 @@ enum qca_wlan_vendor_attr_roam_events /* keep last */ QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_MAX = - QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_AFTER_LAST -1, + QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_ratemask_params_type - Rate mask config type + * + * @QCA_WLAN_RATEMASK_PARAMS_TYPE_CCK_OFDM: CCK/OFDM rate mask config + * @QCA_WLAN_RATEMASK_PARAMS_TYPE_HT: HT rate mask config + * @QCA_WLAN_RATEMASK_PARAMS_TYPE_VHT: VHT rate mask config + * @QCA_WLAN_RATEMASK_PARAMS_TYPE_HE: HE rate mask config + * @QCA_WLAN_RATEMASK_PARAMS_TYPE_EHT: EHT rate mask config + */ +enum qca_wlan_ratemask_params_type { + QCA_WLAN_RATEMASK_PARAMS_TYPE_CCK_OFDM = 0, + QCA_WLAN_RATEMASK_PARAMS_TYPE_HT = 1, + QCA_WLAN_RATEMASK_PARAMS_TYPE_VHT = 2, + QCA_WLAN_RATEMASK_PARAMS_TYPE_HE = 3, + QCA_WLAN_RATEMASK_PARAMS_TYPE_EHT = 4, +}; + +/** + * enum qca_wlan_vendor_attr_ratemask_params - Used by the + * vendor command QCA_NL80211_VENDOR_SUBCMD_RATEMASK_CONFIG. + * This is used to set the rate mask value to be used in rate selection. + * + * @QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_LIST: + * Array of nested containing attributes + * QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_TYPE and + * QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP. + * + * @QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_TYPE: u8, represents + * the different PHY types to which the rate mask config is to be applied. + * The values for this attribute are referred from enum + * qca_wlan_vendor_ratemask_params_type. + * + * @QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP: binary, rate mask bitmap. + * A bit value of 1 represents rate is enabled and a value of 0 + * represents rate is disabled. + * For EHT targets, + * b0-1 => NSS1, MCS 14-15 + * b2-15 => NSS1, MCS 0-13 + * b16-29 => NSS2, MCS 0-13 + * For HE targets, 14 bits correspond to one NSS setting. + * b0-13 => NSS1, MCS 0-13 + * b14-27 => NSS2, MCS 0-13 and so on for other NSS. + * For VHT targets, 10 bits correspond to one NSS setting. + * b0-9 => NSS1, MCS 0-9 + * b10-19 => NSS2, MCS 0-9 and so on for other NSS. + * For HT targets, 8 bits correspond to one NSS setting. + * b0-7 => NSS1, MCS 0-7 + * b8-15 => NSS2, MCS 0-7 and so on for other NSS. + * For OFDM/CCK targets, 8 bits correspond to one NSS setting. + * + * @QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_LINK_ID: u8, used to specify the + * MLO link ID of a link to be configured. Optional attribute. + * No need of this attribute in non-MLO cases. If the attribute is + * not provided, ratemask will be applied for setup link. + */ +enum qca_wlan_vendor_attr_ratemask_params { + QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_LIST = 1, + QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_TYPE = 2, + QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP = 3, + QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_LINK_ID = 4, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_MAX = + QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_audio_data_path - Defines the data path to be used for audio + * traffic. + * + * @QCA_WLAN_AUDIO_DATA_PATH_VIA_HOST_PROCESSOR: + * Send audio traffic through the host processor. + * @QCA_WLAN_AUDIO_DATA_PATH_VIA_LOW_POWER_DSP: + * Send audio traffic using the low power DSP to/from the encoder. + */ +enum qca_wlan_audio_data_path { + QCA_WLAN_AUDIO_DATA_PATH_VIA_HOST_PROCESSOR = 0, + QCA_WLAN_AUDIO_DATA_PATH_VIA_LOW_POWER_DSP = 1, +}; + +/** + * enum qca_wlan_vendor_pasn_action - Action to authenticate (and generate keys + * for) or drop existing PASN security association for the listed the + * peers. Used by QCA_WLAN_VENDOR_ATTR_PASN_ACTION and sent from the driver + * to userspace. + * + * @QCA_WLAN_VENDOR_PASN_ACTION_AUTH: Initiate PASN handshake with the peer + * devices indicated with %QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR. + * @QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT: Indication from + * the driver to userspace to inform that the existing PASN keys of the + * peer devices specified with %QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR are + * not valid anymore. + */ +enum qca_wlan_vendor_pasn_action { + QCA_WLAN_VENDOR_PASN_ACTION_AUTH, + QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT, +}; + +/** + * enum qca_wlan_vendor_attr_pasn_peer: Defines the nested attributes used in + * QCA_WLAN_VENDOR_ATTR_PASN_PEERS. + * + * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR: This attribute is optional in the + * event from the driver to userspace and represents the local MAC address + * to be used for PASN handshake. When this attribute is present, userspace + * shall use the source address specified in this attribute by the driver + * for PASN handshake with peer device. + * This attribute is required in a command response from userspace to the + * driver and represents the MAC address that was used in PASN handshake + * with the peer device. + * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR: Indicates the MAC address of the + * peer device to which PASN handshake is requested in an event from the + * driver to userspace when QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to + * QCA_WLAN_VENDOR_PASN_ACTION_AUTH. + * Indicates the MAC address of the peer device for which the keys are to + * be invalidated in an event from the driver to userspace when + * QCA_WLAN_VENDOR_ATTR_PASN_ACTION is set to + * QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT. + * Indicates the MAC address of the peer device for which the status is + * being sent in a status report from userspace to the driver. + * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED: NLA_FLAG attribute used + * in the event from the driver to userspace. When set, userspace is + * required to derive LTF key seed from KDK and set it to the driver. + * @QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS: NLA_FLAG attribute. This + * attribute is used in the command response from userspace to the driver. + * If present, it indicates the successful PASN handshake with the peer. If + * this flag is not present, it indicates that the PASN handshake with the + * peer device failed. + */ +enum qca_wlan_vendor_attr_pasn_peer { + QCA_WLAN_VENDOR_ATTR_PASN_PEER_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR = 2, + QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED = 3, + QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS = 4, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_PASN_PEER_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX = + QCA_WLAN_VENDOR_ATTR_PASN_PEER_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_pasn: Defines the attributes used in the + * QCA_NL80211_VENDOR_SUBCMD_PASN command. + * + * @QCA_WLAN_VENDOR_ATTR_PASN_ACTION: u32 attribute, possible values are + * defined in enum qca_wlan_vendor_pasn_action and used only in an event + * from the driver to userspace. + * @QCA_WLAN_VENDOR_ATTR_PASN_PEERS: Nested attribute, used to pass PASN peer + * details for each peer and used in both an event and a command response. + * The nested attributes used inside QCA_WLAN_VENDOR_ATTR_PASN_PEERS are + * defined in enum qca_wlan_vendor_attr_pasn_peer. + * @QCA_WLAN_VENDOR_ATTR_PASN_LINK_ID: u8 attribute used to identify a + * specific link affiliated to an MLD. + */ +enum qca_wlan_vendor_attr_pasn { + QCA_WLAN_VENDOR_ATTR_PASN_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_PASN_ACTION = 1, + QCA_WLAN_VENDOR_ATTR_PASN_PEERS = 2, + QCA_WLAN_VENDOR_ATTR_PASN_LINK_ID = 3, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_PASN_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_PASN_MAX = + QCA_WLAN_VENDOR_ATTR_PASN_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_secure_ranging_ctx_action - Used to add or delete + * the ranging security context derived from PASN for each peer. Used in + * QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION. + * + * @QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_ADD: Add the secure ranging + * context for the peer. + * @QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_DELETE: Delete the secure ranging + * context for the peer. + */ +enum qca_wlan_vendor_secure_ranging_ctx_action { + QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_ADD, + QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_DELETE, +}; + +/** + * enum qca_wlan_vendor_sha_type - SHA types. Used to configure the SHA type + * used for deriving PASN keys to the driver. Used in + * QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE + * @QCA_WLAN_VENDOR_SHA_256: SHA-256 + * @QCA_WLAN_VENDOR_SHA_384: SHA-384 + */ +enum qca_wlan_vendor_sha_type { + QCA_WLAN_VENDOR_SHA_256, + QCA_WLAN_VENDOR_SHA_384, +}; + +/** + * enum qca_wlan_vendor_attr_secure_ranging_ctx: Defines the attributes used + * to set security context for the PASN peer from userspace to the driver. + * Used with QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT. + * + * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION: u32 attribute, possible + * values are defined in enum qca_wlan_vendor_secure_ranging_ctx_action + * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR: The local MAC address that + * was used during the PASN handshake. + * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR: The MAC address of + * the peer device for which secure ranging context is being configured. + * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE: u32 attribute, defines the + * hash algorithm to be used, possible values are defined in enum + * qca_wlan_vendor_sha_type. + * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK: Variable length attribute, holds + * the temporal key generated from the PASN handshake. The length of this + * attribute is dependent on the value of + * %QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER. + * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER: cipher suite to use with the + * TK, u32, as defined in IEEE Std 802.11-2020, 9.4.2.24.2 (Cipher suites) + * (e.g., 0x000FAC04). + * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED: Variable length + * attribute, holds the LTF keyseed derived from KDK of PASN handshake. + * The length of this attribute is dependent on the value of + * %QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE. + * @QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LINK_ID: This u8 attribute is used + * for secure ranging to identify a specific link affiliated to an AP MLD. + */ +enum qca_wlan_vendor_attr_secure_ranging_ctx { + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION = 1, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR = 2, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR = 3, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE = 4, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK = 5, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER = 6, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED = 7, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LINK_ID = 8, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_MAX = + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_coap_offload_filter - Attributes used + * inside %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_FILTER + * nested attribute. The packets that match a filter will be replied with + * attributes configured in %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4: + * u32 attribute. Destination IPv4 address in network byte order, the + * IPv4 packets with different address will be filtered out. + * This attribute is optional. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4_IS_BC: + * Flag attribute. If it's present, indicates that + * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4 is a broadcast + * address; while if not, indicates that the address is a unicast/multicast + * address. + * This attribute is optional. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV6: + * NLA_BINARY attribute, length is 16 bytes. + * Destination IPv6 address in network byte order, the IPv6 packets + * with different destination address will be filtered out. + * This attribute is optional. + * + * At least one of %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4 and + * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV6 must be configured. + * Packets on both IPv4 and IPv6 will be processed if both are configured. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_PORT: + * u16 attribute. Destination UDP port, the packets with different destination + * UDP port will be filtered out. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MATCH_OFFSET: + * u32 attribute. Represents the offset (in UDP payload) of the data + * to be matched. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MATCH_DATA: + * NLA_BINARY attribute, the maximum allowed size is 16 bytes. + * Binary data that is compared bit-by-bit against the data (specified + * by %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MATCH_OFFSET) in UDP + * payload, the packets don't match will be filtered out. + * This attribute is mandatory. + */ +enum qca_wlan_vendor_attr_coap_offload_filter { + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4 = 1, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV4_IS_BC = 2, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_IPV6 = 3, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_DEST_PORT = 4, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MATCH_OFFSET = 5, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MATCH_DATA = 6, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_MAX = + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_FILTER_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_coap_offload_reply - Attributes used + * inside %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY nested attribute. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV4: + * u32 attribute. Source address (in network byte order) for replying + * the matching broadcast/multicast IPv4 packets. + * This attribute is optional. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV6: + * NLA_BINARY attribute, length is 16 bytes. + * Source address (in network byte order) for replying the matching + * multicast IPv6 packets. + * This attribute is optional. + * + * For broadcast/multicast offload reply, one of + * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV4 and + * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV6 or both must be + * configured according to version of the IP address(es) configured in + * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_FILTER; + * while for unicast case, firmware will take the destination IP address + * in the received matching packet as the source address for replying. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_FILTER: + * Nested attribute. Filter for the received UDP packets, only the matching + * packets will be replied and cached. + * See enum qca_wlan_vendor_attr_coap_offload_filter for list of supported + * attributes. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_MSG: + * NLA_BINARY attribute, the maximum allowed size is 1152 bytes. + * CoAP message (UDP payload) to be sent upon receiving matching packets. + * Firmware is responsible for adding any necessary protocol headers. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_CACHE_EXPTIME: + * u32 attribute. Expiration time in milliseconds of the cached CoAP messages. + * A cached message will be dropped by firmware if it's expired. + * This attribute is optional. A default value of 40000 will be used in the + * absence of it. + */ +enum qca_wlan_vendor_attr_coap_offload_reply { + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV4 = 1, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_SRC_IPV6 = 2, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_FILTER = 3, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_MSG = 4, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_CACHE_EXPTIME = 5, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_MAX = + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_coap_offload_tx_ipv4 - Represents parameters for + * CoAP message (UDP) transmitting on IPv4. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_SRC_ADDR: + * u32 attribute. Source address (in network byte order) for transmitting + * packets on IPv4. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_SRC_PORT: + * u16 attribute. Source UDP port. + * This attribute is optional, a random port is taken if it's not present. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_ADDR: + * u32 attribute. Destination IPv4 address (in network byte order). + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_IS_BC: + * Flag attribute. If it's present, indicates that + * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_ADDR is a broadcast + * address; while if not, indicates that the address is unicast/multicast + * address. + * This attribute is optional. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_PORT: + * u16 attribute. Destination UDP port. + * This attribute is mandatory. + */ +enum qca_wlan_vendor_attr_coap_offload_tx_ipv4 { + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_SRC_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_SRC_PORT = 2, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_ADDR = 3, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_IS_BC = 4, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_DEST_PORT = 5, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_MAX = + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV4_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_coap_offload_tx_ipv6 - Represents parameters for + * CoAP message (UDP) transmitting on IPv6. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_SRC_ADDR: + * NLA_BINARY attribute, length is 16 bytes. + * Source address (in network byte order) for transmitting packets on IPv6. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_SRC_PORT: + * u16 attribute. Source UDP port. + * This attribute is optional, a random port is taken if it's not present. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_DEST_ADDR: + * NLA_BINARY attribute, length is 16 bytes. + * Destination IPv6 address (in network byte order). + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_DEST_PORT: + * u16 attribute. Destination UDP port. + * This attribute is mandatory. + */ +enum qca_wlan_vendor_attr_coap_offload_tx_ipv6 { + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_SRC_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_SRC_PORT = 2, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_DEST_ADDR = 3, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_DEST_PORT = 4, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_MAX = + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_TX_IPV6_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_coap_offload_periodic_tx - Attributes used + * inside %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX nested attribute. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV4: + * Nested attribute. The IPv4 source/destination address/port for offload + * transmitting. See enum qca_wlan_vendor_attr_coap_offload_tx_ipv4 for the list + * of supported attributes. + * This attribute is optional. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV6: + * Nested attribute. The IPv6 source/destination address/port for offload + * transmitting. See enum qca_wlan_vendor_attr_coap_offload_tx_ipv6 for the list + * of supported attributes. + * This attribute is optional. + * + * At least one of %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV4 and + * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV6 must be configured. + * Firmware will transmit the packets on both IPv4 and IPv6 if both are + * configured. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_PERIOD: + * u32 attribute. Period in milliseconds for the periodic transmitting. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_MSG: + * NLA_BINARY attribute, the maximum allowed size is 1152 bytes. + * CoAP message (UDP payload) to be periodically transmitted. Firmware + * is responsible for adding any necessary protocol headers. + * This attribute is mandatory. + */ +enum qca_wlan_vendor_attr_coap_offload_periodic_tx { + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV4 = 1, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_IPV6 = 2, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_PERIOD = 3, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_MSG = 4, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_MAX = + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_coap_offload_cache_info - Attributes used + * inside %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHES nested attribute. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_TS: + * u64 attribute. Received time (since system booted in microseconds) of + * the cached CoAP message. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV4: + * u32 attribute. Source IPv4 address (in network byte order) of the cached + * CoAP message. + * This attribute is optional. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV6: + * NLA_BINARY attribute, length is 16 bytes. + * Source IPv6 address (in network byte order) of the cached CoAP message. + * This attribute is optional. + * + * At most and at least one of + * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV4 and + * %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV6 is given for + * an entry. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_MSG: + * NLA_BINARY attribute, the maximum allowed size is 1152 bytes. + * The cached CoAP message (UDP payload). If the actual message size is + * greater than the maximum size, it will be truncated and leaving only + * the first 1152 bytes. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_PAD: Attribute used for + * padding for 64-bit alignment + */ +enum qca_wlan_vendor_attr_coap_offload_cache_info { + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_TS = 1, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV4 = 2, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV6 = 3, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_MSG = 4, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_PAD = 5, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_MAX = + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_coap_offload_action - Actions for + * vendor command QCA_NL80211_VENDOR_SUBCMD_COAP_OFFLOAD. + * + * @QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_ENABLE: + * Enable CoAP offload reply. + * If it's enabled, firmware will start offload processing on each suspend + * and stop on each resume. + * + * Offload reply on match works as follows: + * Reply the packets that match the filter with the given CoAP + * message (with necessary protocol headers), increase the CoAP message + * ID in the given CoAP message by one for the next use after each successful + * transmission, and try to store the information of the received packet, + * including the received time, source IP address, and CoAP message (UDP + * payload). + * + * Firmware has a limit to the maximum stored entries, it takes the source IP + * address as the key of an entry, and keeps at most one entry for each key. + * A packet won't be stored if no entry for the same key is present and the + * total number of the existing unexpired entries reaches the maximum value. + * + * If any configured item is changed, user space should disable offload reply + * first and then issue a new enable request. + * + * @QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_DISABLE: + * Disable CoAP offload reply and return information of any cached CoAP + * messages. + * + * @QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_ENABLE: + * Enable CoAP offload periodic transmitting. + * If it's enabled, firmware will start offload periodic transmitting on + * each suspend and stop on each resume. + * + * Offload periodic transmitting works as follows: + * Send the given CoAP message (with necessary protocol headers) with the given + * source/destination IP address/UDP port periodically based on the given + * period and increase the CoAP message ID in the given CoAP message by one + * for the next use after each successful transmission. + * + * If any configured item is changed, user space should disable offload + * periodic transmitting first and then issue a new enable request. + * + * @QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_DISABLE: + * Disable CoAP offload periodic transmitting. + * + * @QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_CACHE_GET: + * Get information of the CoAP messages cached during offload reply + * processing. The cache is cleared after retrieval. + */ +enum qca_wlan_vendor_coap_offload_action { + QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_ENABLE = 0, + QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_DISABLE = 1, + QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_ENABLE = 2, + QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_DISABLE = 3, + QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_CACHE_GET = 4, +}; + +/** + * enum qca_wlan_vendor_attr_coap_offload - Used by the + * vendor command QCA_NL80211_VENDOR_SUBCMD_COAP_OFFLOAD. + * This is used to set parameters for CoAP offload processing, or get + * cached CoAP messages from firmware. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ACTION: + * u32 attribute. Action to take in this vendor command. + * See enum qca_wlan_vendor_coap_offload_action for supported actions. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REQ_ID: + * u32 attribute. Represents the Request ID for the CoAP offload + * configuration, which can help to identify the user entity starting + * the CoAP offload processing and accordingly stop the respective + * ones/get the cached CoAP messages with the matching ID. + * This attribute is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY: + * Nested attribute. Parameters for offload reply. + * See enum qca_wlan_vendor_attr_coap_offload_reply for the list of + * supported attributes. + * This attribute is mandatory if %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ACTION + * is QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_ENABLE, and is ignored + * otherwise. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX: + * Nested attribute. Parameters for offload periodic transmitting. + * See enum qca_wlan_vendor_attr_coap_offload_periodic_tx for the list of + * supported attributes. + * This attribute is mandatory if %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ACTION is + * QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_ENABLE, and is ignored + * otherwise. + * + * @QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHES: + * Array of nested attributes. Information of the cached CoAP messages, + * where each entry is taken from + * enum qca_wlan_vendor_attr_coap_offload_cache_info. + * This attribute is used for reporting the cached CoAP messages + * in reply for command in which %QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ACTION + * is QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_CACHE_GET or + * QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_DISABLE. It means there is no + * cached item if this attribute is not present. + */ +enum qca_wlan_vendor_attr_coap_offload { + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ACTION = 1, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REQ_ID = 2, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_REPLY = 3, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_PERIODIC_TX = 4, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHES = 5, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_MAX = + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_scs_rule_config - Used by the vendor command + * QCA_NL80211_VENDOR_SUBCMD_SCS_RULE_CONFIG to configure Stream Classification + * Service (SCS) rule. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_RULE_ID: Mandatory u32 attribute. + * Represents the unique id of SCS rule to be configured. + + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_REQUEST_TYPE: Mandatory u8 attribute. + * Represents the request type: add, remove, or change. + * Values as defined in IEEE Std 802.11-2020, Table 9-246 (SCS Request + * Type definitions). + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_OUTPUT_TID: Mandatory u8 attribute + * in case of add/change request type. + * Represents the output traffic identifier (TID) to be assigned to the flow + * matching the rule. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_CLASSIFIER_TYPE: Mandatory u8 + * attribute in case of add/change request type. + * Represents type of classifier parameters present in SCS rule. + * Refer IEEE Std 802.11-2020 Table 9-164 (Frame classifier type). + * Only classifier types 4 and 10 are supported for SCS. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_VERSION: Mandatory u8 attribute + * in case of add/change request type when classifier type is TCLAS4. + * Represents the IP version (4: IPv4, 6: IPv6) of the rule. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_IPV4_ADDR: Optional + * attribute in case of add/change request type when classifier type is TCLAS4 + * and version attribute is IPv4. + * Represents the source IPv4 address in the rule which is to be compared + * against the source IP address in the IPv4 header. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_IPV4_ADDR: Optional + * attribute in case of add/change request type when classifier type is TCLAS4 + * and version attribute is IPv4. + * Represents the destination IPv4 address in the rule which is to be compared + * against the destination IP address in the IPv4 header. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_IPV6_ADDR: Optional + * attribute in case of add/change request type when classifier type is TCLAS4 + * and version attribute is IPv6. + * Represents the source IPv6 address in the rule which is to be compared + * against the source IP address in the IPv6 header. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_IPV6_ADDR: Optional + * attribute in case of add/change request type when classifier type is TCLAS4 + * and version attribute is IPv6. + * Represents the destination IPv6 address in the rule which is to be compared + * against the destination IP address in the IPv6 header. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_PORT: Optional u16 attribute + * in case of add/change request type when classifier type is TCLAS4. + * Represents the source port number in the rule which is to be compared against + * the source port number in the protocol header. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_PORT: Optional u16 attribute + * in case of add/change request type when classifier type is TCLAS4. + * Represents the destination port number in the rule which is to be compared + * against the destination port number in the protocol header. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DSCP: Optional u8 attribute + * in case of add/change request type when classifier type is TCLAS4. + * Represents the DSCP value in the rule which is to be compared against the + * DSCP field present in the IP header. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_NEXT_HEADER: Optional u8 + * attribute in case of add/change request type when classifier type is TCLAS4. + * Represents the protocol/next header in the rule which is to be compared + * against the protocol/next header field present in the IPv4/IPv6 header. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_FLOW_LABEL: Optional + * attribute of size 3 bytes present in case of add/change request type + * when classifier type is TCLAS4 and version is IPv6. + * Represents the flow label value in the rule which is to be compared against + * the flow label field present in the IPv6 header. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_PROTOCOL_INSTANCE: Optional u8 + * attribute in case of add/change request type when classifier type is TCLAS10. + * Represents the protocol instance number in the rule. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_NEXT_HEADER: Optional u8 + * attribute in case of add/change request type when classifier type is TCLAS10. + * Represents the protocol/next header in the rule which is to be compared + * against the protocol/next header field present in the IPv4/IPv6 header. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_FILTER_MASK: Optional + * attribute of variable length present when request type is add/change and + * classifier type is TCLAS10. + * Represents the mask to be used for masking the header contents of the header + * specified by QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_NEXT_HEADER + * attribute. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_FILTER_VALUE: Optional + * attribute of variable length present when request type is add/change and + * classifier type is TCLAS10. + * Represents the value to be compared against after masking the header contents + * of the header specified by the + * QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_NEXT_HEADER attribute with the + * filter mask specified by the + * QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_FILTER_MASK attribute. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_SERVICE_CLASS_ID: Optional u16 + * attribute. + * Represents the service class id of the configured SCS rule. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_DST_MAC_ADDR: Optional 6 bytes + * MAC address. + * Represents the destination MAC address in the rule. + * + * @QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_NETDEV_IF_INDEX: Optional u32 attribute + * Represents the netdevice interface index in the rule. + */ +enum qca_wlan_vendor_attr_scs_rule_config { + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_RULE_ID = 1, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_REQUEST_TYPE = 2, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_OUTPUT_TID = 3, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_CLASSIFIER_TYPE = 4, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_VERSION = 5, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_IPV4_ADDR = 6, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_IPV4_ADDR = 7, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_IPV6_ADDR = 8, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_IPV6_ADDR = 9, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_SRC_PORT = 10, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DST_PORT = 11, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_DSCP = 12, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_NEXT_HEADER = 13, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS4_FLOW_LABEL = 14, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_PROTOCOL_INSTANCE = 15, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_NEXT_HEADER = 16, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_FILTER_MASK = 17, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_TCLAS10_FILTER_VALUE = 18, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_SERVICE_CLASS_ID = 19, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_DST_MAC_ADDR = 20, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_NETDEV_IF_INDEX = 21, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_SCS_RULE_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_mlo_links - Definition of attributes used inside + * nested attribute QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MLO_LINKS. + * + * @QCA_WLAN_VENDOR_ATTR_MLO_LINK_ID: u8 attribute, link ID of this MLO link. + * @QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAC_ADDR: Own MAC address of this MLO link. + * @QCA_WLAN_VENDOR_ATTR_MLO_LINK_BSSID: AP link MAC address of this MLO link. + */ +enum qca_wlan_vendor_attr_mlo_links { + QCA_WLAN_VENDOR_ATTR_MLO_LINK_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_MLO_LINK_ID = 1, + QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAC_ADDR = 2, + QCA_WLAN_VENDOR_ATTR_MLO_LINK_BSSID = 3, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_MLO_LINK_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAX = + QCA_WLAN_VENDOR_ATTR_MLO_LINK_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_sar_version - This describes the current SAR version + * used in the firmware. + * + * @QCA_WLAN_VENDOR_SAR_VERSION_1: The firmware supports legacy SAR. + * In legacy SAR, the firmware supports 5 static and 1 user defined SAR limits. + * + * @QCA_WLAN_VENDOR_SAR_VERSION_2: The firmware supports SAR version 2, + * i.e., SAR Non DBS mode. In SAR version 2, the firmware has 6 SAR tables for + * each CTL group. So user can select up to 6 SAR indexes from the current CTL + * groups. + * + * @QCA_WLAN_VENDOR_SAR_VERSION_3: The firmware supports SAR version 3, + * i.e., SAR DBS mode. In SAR version 3, the firmware has 6 SAR tables for each + * CTL group but user can choose up to 3 SAR set index only, as the top half + * of the SAR index (0 to 2) is used for non DBS purpose and the bottom half of + * the SAR index (3 to 5) is used for DBS mode. + * + * @QCA_WLAN_VENDOR_SAR_VERSION_4: The firmware supports SAR version 4, + * known as SAR Smart Transmit (STX) mode. STX is time averaging algorithmic + * for power limit computation in collaboration with WWAN. + * In STX mode, firmware has 41 indexes and there is no ctl grouping uses. + * + * @QCA_WLAN_VENDOR_SAR_VERSION_5: The firmware supports SAR version 5, + * known as TAS (Time Averaging SAR) mode. In TAS mode, as name implies + * instead of fixed static SAR power limit firmware uses time averaging + * to adjust the SAR limit dynamically. It is wlan soc standalone mechanism. + * In this mode firmware has up to 43 indexes. + */ +enum qca_wlan_vendor_sar_version { + QCA_WLAN_VENDOR_SAR_VERSION_INVALID = 0, + QCA_WLAN_VENDOR_SAR_VERSION_1 = 1, + QCA_WLAN_VENDOR_SAR_VERSION_2 = 2, + QCA_WLAN_VENDOR_SAR_VERSION_3 = 3, + QCA_WLAN_VENDOR_SAR_VERSION_4 = 4, + QCA_WLAN_VENDOR_SAR_VERSION_5 = 5, +}; + +/** + * enum qca_wlan_vendor_sar_ctl_group_state - This describes whether + * CTL grouping is enabled or disabled in the firmware. + * + * @QCA_WLAN_VENDOR_SAR_CTL_GROUP_STATE_ENABLED: CTL grouping + * is enabled in firmware. + * + * @QCA_WLAN_VENDOR_SAR_CTL_GROUP_STATE_DISABLED: CTL grouping + * is disabled in firmware. + * + */ +enum qca_wlan_vendor_sar_ctl_group_state { + QCA_WLAN_VENDOR_SAR_CTL_GROUP_STATE_INVALID = 0, + QCA_WLAN_VENDOR_SAR_CTL_GROUP_STATE_ENABLED = 1, + QCA_WLAN_VENDOR_SAR_CTL_GROUP_STATE_DISABLED = 2, +}; + +/** + * enum qca_wlan_vendor_attr_sar_capability - Used by the vendor command + * QCA_NL80211_VENDOR_SUBCMD_GET_SAR_CAPABILITY to get SAR capabilities + * supported by the firmware. + + * @QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_VERSION: + * u32 attribute. This field describes current SAR version supported by the + * firmware. + * See enum qca_wlan_vendor_sar_version for more information. + * This attribute is mandatory. + + * @QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_CTL_GROUP_STATE: + * u32 attribute. This field describes whether CTL groups are enabled + * or disabled in the firmware. + * See enum qca_wlan_vendor_sar_ctl_group_state for more information. + * This attribute is optional. + */ + +enum qca_wlan_vendor_attr_sar_capability { + QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_VERSION = 1, + QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_CTL_GROUP_STATE = 2, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_MAX = + QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_sr_stats - Attributes for Spatial Reuse statistics. + * These statistics are sent from the driver in a response when userspace + * queries to get the statistics using the operation + * %QCA_WLAN_SR_OPERATION_GET_STATS. These statistics are reset + * by the driver when the SR feature is enabled, when the driver receives + * %QCA_WLAN_SR_OPERATION_CLEAR_STATS operation, or when disconnected. + * + * @QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_OPPORTUNITIES_COUNT: u32 attribute. + * Mandatory only when non-SRG is supported by the AP and optional otherwise. + * This represents the number of non-SRG TX opportunities. + * + * @QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_TRIED_COUNT: u32 attribute. + * Mandatory only when non-SRG is supported by the AP and optional otherwise. + * This represents the number of non-SRG PPDUs tried to transmit. + * + * @QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_SUCCESS_COUNT: u32 attribute. + * Mandatory only when non-SRG is supported by the AP and optional otherwise. + * This represents the number of non-SRG PPDUs successfully transmitted. + * + * @QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_OPPORTUNITIES_COUNT: u32 attribute. + * Mandatory only when SRG is supported by the AP and optional otherwise. + * This represents the number of SRG TX opportunities. + * + * @QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_TRIED_COUNT: u32 attribute. + * Mandatory only when SRG is supported by the AP and optional otherwise. + * This represents the number of SRG PPDUs tried to transmit. + * + * @QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_SUCCESS_COUNT: u32 attribute. + * Mandatory only when SRG is supported by the AP and optional otherwise. + * This represents the number of SRG PPDUs successfully transmitted. + */ +enum qca_wlan_vendor_attr_sr_stats { + QCA_WLAN_VENDOR_ATTR_SR_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_OPPORTUNITIES_COUNT = 1, + QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_TRIED_COUNT = 2, + QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_SUCCESS_COUNT = 3, + QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_OPPORTUNITIES_COUNT = 4, + QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_TRIED_COUNT = 5, + QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_SUCCESS_COUNT = 6, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_SR_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SR_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_SR_STATS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_sr_reason_code - Defines the different reason codes used in + * Spatial Reuse feature. + * + * @QCA_WLAN_SR_REASON_CODE_ROAMING: The SR feature is disabled/enabled due to + * roaming to an AP that doesn't support/supports SR feature, respectively. + * + * @QCA_WLAN_SR_REASON_CODE_CONCURRENCY: The SR feature is disabled/enabled due + * to change in concurrent interfaces that are supported by the driver. + */ +enum qca_wlan_sr_reason_code { + QCA_WLAN_SR_REASON_CODE_ROAMING = 0, + QCA_WLAN_SR_REASON_CODE_CONCURRENCY = 1, +}; + +/** + * enum qca_wlan_sr_operation - Defines the different types of SR operations. + * The values are used inside attribute %QCA_WLAN_VENDOR_ATTR_SR_OPERATION. + * + * @QCA_WLAN_SR_OPERATION_SR_ENABLE: Userspace sends this operation to the + * driver to enable the Spatial Reuse feature. Attributes + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD and + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD are used with this + * operation. + * + * @QCA_WLAN_SR_OPERATION_SR_DISABLE: Userspace sends this operation to the + * driver to disable the Spatial Reuse feature. + * + * @QCA_WLAN_SR_OPERATION_SR_SUSPEND: The driver uses this operation in an + * asynchronous event sent to userspace when the SR feature is disabled. + * The disable reason is encoded in QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE + * and sent along with the asynchronous event. + * + * @QCA_WLAN_SR_OPERATION_SR_RESUME: The driver uses this operation in an + * asynchronous event when the SR feature is enabled again after the SR feature + * was suspended by the driver earlier. The enable reason is + * encoded in QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE. Attributes used are + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD and + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD. + * + * @QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_PROHIBIT: This operation is + * used to prohibit PSR-based spatial reuse and non-SRG OBSS PD-based spatial + * reuse transmissions. Userspace sends this operation to the driver. + * The driver/firmware upon receiving this operation shall prohibit PSR-based + * spatial reuse and non-SRG OBSS PD-based spatial reuse transmissions. + * + * @QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_ALLOW: This operation is + * used to allow PSR-based spatial reuse and non-SRG OBSS PD-based spatial + * reuse transmissions. Userspace sends this operation to the driver. + * The driver/firmware upon receiving this operation shall allow PSR-based + * spatial reuse and non-SRG OBSS PD-based spatial reuse transmissions. + * + * @QCA_WLAN_SR_OPERATION_GET_STATS: Userspace sends this operation to the + * driver to get the SR statistics and the driver sends a synchronous response + * with the attributes defined in enum qca_wlan_vendor_attr_sr_stats using the + * nested attribute %QCA_WLAN_VENDOR_ATTR_SR_STATS. + * + * @QCA_WLAN_SR_OPERATION_CLEAR_STATS: Userspace sends this operation to the + * driver to clear the SR statistics and upon receiving this operation + * the driver/firmware shall clear the SR statistics. + * + * @QCA_WLAN_SR_OPERATION_GET_PARAMS: Userspace sends this operation to the + * driver to get the SR parameters and the driver sends the synchronous response + * with the following required attributes: + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET, + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET, + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET, + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE, + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW. + * + * @QCA_WLAN_SR_OPERATION_UPDATE_PARAMS: The driver uses this operation in an + * asynchronous event to userspace to update any changes in SR parameters. + * The following attributes are used with this operation: + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET, + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET, + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET, + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE, + * %QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW. + */ +enum qca_wlan_sr_operation { + QCA_WLAN_SR_OPERATION_SR_ENABLE = 0, + QCA_WLAN_SR_OPERATION_SR_DISABLE = 1, + QCA_WLAN_SR_OPERATION_SR_SUSPEND = 2, + QCA_WLAN_SR_OPERATION_SR_RESUME = 3, + QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_PROHIBIT = 4, + QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_ALLOW = 5, + QCA_WLAN_SR_OPERATION_GET_STATS = 6, + QCA_WLAN_SR_OPERATION_CLEAR_STATS = 7, + QCA_WLAN_SR_OPERATION_GET_PARAMS = 8, + QCA_WLAN_SR_OPERATION_UPDATE_PARAMS = 9, +}; + +/** + * enum qca_wlan_vendor_attr_sr_params - Defines attributes for SR configuration + * parameters used by attribute %QCA_WLAN_VENDOR_ATTR_SR_PARAMS. + * + * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE: Flag attribute. + * This attribute is optionally set in response to + * %QCA_WLAN_SR_OPERATION_GET_PARAMS and in request when operation is set to + * %QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_PROHIBIT. Refer IEEE Std + * 802.11ax-2021 Figure 9-788r-SR Control field format to understand more + * about HESIGA_Spatial_reuse_value15_allowed. + * + * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW: Flag attribute. + * This attribute is used in response to %QCA_WLAN_SR_OPERATION_GET_PARAMS + * operation. This indicates whether non-SRG OBSS PD SR transmissions are + * allowed or not at non-AP STAs that are associated with the AP. If present + * non-SRG OBSS PD SR transmissions are not allowed else are allowed. + * + * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET: Optional u8 + * attribute. This attribute is used in response to + * %QCA_WLAN_SR_OPERATION_GET_PARAMS operation. This indicates the SRG OBSS PD + * Min Offset field which contains an unsigned integer that is added to -82 dBm + * to generate the value of the SRG OBSS PD Min parameter. + * + * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET: Optional u8 + * attribute. This attribute is used in response to + * %QCA_WLAN_SR_OPERATION_GET_PARAMS operation. This indicates the SRG OBSS PD + * Max Offset field which contains an unsigned integer that is added to -82 dBm + * to generate the value of the SRG OBSS PD Max parameter. + * + * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET: Optional u8 + * attribute. This attribute is used in response to + * %QCA_WLAN_SR_OPERATION_GET_PARAMS operation. This indicates the Non-SRG OBSS + * PD Max Offset field which contains an unsigned integer that is added to -82 + * dBm to generate the value of the Non-SRG OBSS PD Max parameter. + * + * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD: s32 attribute (in dBm). + * Userspace optionally sends this attribute with + * %QCA_WLAN_SR_OPERATION_SR_ENABLE operation to the driver to specify the + * preferred SRG PD threshold. The driver shall send this attribute to + * userspace in SR resume event to indicate the PD threshold being used for SR. + * When there is change in SRG PD threshold (for example, due to roaming, etc.) + * the driver shall indicate the userspace the newly configured SRG PD threshold + * using an asynchronous event. + * + * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD: s32 attribute (in dBm). + * Userspace optionally sends this attribute with + * %QCA_WLAN_SR_OPERATION_SR_ENABLE operation to the driver to specify the + * preferred non-SRG PD threshold. The driver shall send this attribute to + * userspace in SR resume event to indicate the PD threshold being used for SR. + * When there is change in non-SRG PD threshold (for example, due to roaming, + * etc.) the driver shall indicate the userspace the newly configured non-SRG PD + * threshold using an asynchronous event. + * + * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE: u32 attribute. The possible + * values are defined in enum qca_wlan_sr_reason_code. This + * attribute is used with %QCA_WLAN_SR_OPERATION_SR_RESUME and + * %QCA_WLAN_SR_OPERATION_SR_SUSPEND operations. + */ +enum qca_wlan_vendor_attr_sr_params { + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE = 1, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW = 2, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET = 3, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET = 4, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET = 5, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD = 6, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD = 7, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE = 8, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_MAX = + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_sr - Defines the attributes used by the vendor + * command QCA_NL80211_VENDOR_SUBCMD_SR. + * + * @QCA_WLAN_VENDOR_ATTR_SR_OPERATION: Mandatory u8 attribute for all requests + * from userspace to the driver. Possible values are defined in enum + * qca_wlan_sr_operation. + * + * @QCA_WLAN_VENDOR_ATTR_SR_PARAMS: Nested attribute, contains the SR + * configuration parameters. The possible attributes inside this attribute are + * defined in enum qca_wlan_vendor_attr_sr_params. + * This attribute is used when QCA_WLAN_VENDOR_ATTR_SR_OPERATION is set to + * %QCA_WLAN_SR_OPERATION_SR_ENABLE in requests from userspace to the driver and + * also in response from the driver to userspace when the response is sent for + * %QCA_WLAN_SR_OPERATION_GET_PARAMS. + * The driver uses this attribute in asynchronous events in which the operation + * is set to %QCA_WLAN_SR_OPERATION_SR_RESUME, + * %QCA_WLAN_SR_OPERATION_SR_SUSPEND or %QCA_WLAN_SR_OPERATION_UPDATE_PARAMS. + * + * @QCA_WLAN_VENDOR_ATTR_SR_STATS: Nested attribute, contains the SR + * statistics. These attributes used inside this are defined in enum + * qca_wlan_vendor_attr_sr_stats. + * This attribute is used in response from the driver to a command in which + * %QCA_WLAN_VENDOR_ATTR_SR_OPERATION is set to + * %QCA_WLAN_SR_OPERATION_GET_STATS. + */ +enum qca_wlan_vendor_attr_sr { + QCA_WLAN_VENDOR_ATTR_SR_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SR_OPERATION = 1, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS = 2, + QCA_WLAN_VENDOR_ATTR_SR_STATS = 3, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_SR_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SR_MAX = + QCA_WLAN_VENDOR_ATTR_SR_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_mlo_peer_prim_netdev_event - Defines the attributes + * used in the QCA_NL80211_VENDOR_SUBCMD_MLO_PEER_PRIM_NETDEV_EVENT subcommand. + * + * @QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_MACADDR: 6 byte MAC address + * used by the peer on the link that corresponds to the link used for sending + * the event notification. + * @QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_MLD_MAC_ADDR: 6 byte + * MLD MAC address of the peer. + * @QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_PRIM_IFINDEX: u32 attribute, + * used to pass ifindex of the primary netdev. + * @QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_MLD_IFINDEX: u32 attribute, + * used to pass ifindex of the MLD netdev. + * @QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_NUM_LINKS: u8 attribute, + * used to indicate the number of links that the non-AP MLD negotiated to be + * used in the ML connection. + * @QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_LINK_INFO: Nested + * attribute, contains information regarding links of the non-AP MLD. + * User applications need to know all the links of a non-AP MLD that are + * participating in the ML association. The possible attributes inside this + * attribute are defined in enum qca_wlan_vendor_attr_mlo_link_info. + */ +enum qca_wlan_vendor_attr_mlo_peer_prim_netdev_event { + QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_MACADDR = 1, + QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_MLD_MAC_ADDR = 2, + QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_PRIM_IFINDEX = 3, + QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_MLD_IFINDEX = 4, + QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_NUM_LINKS = 5, + QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_LINK_INFO = 6, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_MAX = + QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_mlo_link_info - Defines attributes for + * non-AP MLD link parameters used by the attribute + * %QCA_WLAN_VENDOR_ATTR_MLO_PEER_PRIM_NETDEV_EVENT_LINK_INFO. + * + * @QCA_WLAN_VENDOR_ATTR_MLO_LINK_INFO_IFINDEX: u32 attribute, used + * to pass the netdev ifindex of the non-AP MLD link. + * @QCA_WLAN_VENDOR_ATTR_MLO_LINK_INFO_MACADDR: 6 byte MAC address of + * the non-AP MLD link. + */ +enum qca_wlan_vendor_attr_mlo_link_info { + QCA_WLAN_VENDOR_ATTR_MLO_LINK_INFO_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_MLO_LINK_INFO_IFINDEX = 1, + QCA_WLAN_VENDOR_ATTR_MLO_LINK_INFO_MACADDR = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_MLO_LINK_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_MLO_LINK_INFO_MAX = + QCA_WLAN_VENDOR_ATTR_MLO_LINK_INFO_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_afc_freq_psd_info: This enum is used with + * nested attributes QCA_WLAN_VENDOR_ATTR_AFC_RESP_FREQ_PSD_INFO and + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_FREQ_RANGE_LIST to update the frequency range + * and PSD information. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_RANGE_START: Required and type is + * u32. This attribute is used to indicate the start of the queried frequency + * range in MHz. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_RANGE_END: Required and type is u32. + * This attribute is used to indicate the end of the queried frequency range + * in MHz. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_PSD: Required and type is u32. + * This attribute will contain the PSD information for a single range as + * specified by the QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_RANGE_START and + * QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_RANGE_END attributes. + * + * The PSD power info (dBm/MHz) from user space should be multiplied + * by a factor of 100 when sending to the driver to preserve granularity + * up to 2 decimal places. + * Example: + * PSD power value: 10.21 dBm/MHz + * Value to be updated in QCA_WLAN_VENDOR_ATTR_AFC_PSD_INFO: 1021. + * + * Note: QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_PSD attribute will be used only + * with nested attribute QCA_WLAN_VENDOR_ATTR_AFC_RESP_FREQ_PSD_INFO and with + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_FREQ_RANGE_LIST when + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE. + * + * The following set of attributes will be used to exchange frequency and + * corresponding PSD information for AFC between the user space and the driver. + */ +enum qca_wlan_vendor_attr_afc_freq_psd_info { + QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_RANGE_START = 1, + QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_RANGE_END = 2, + QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_PSD = 3, + + QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_MAX = + QCA_WLAN_VENDOR_ATTR_AFC_FREQ_PSD_INFO_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_afc_chan_eirp_info: This enum is used with + * nested attribute QCA_WLAN_VENDOR_ATTR_AFC_CHAN_LIST_INFO to update the + * channel list and corresponding EIRP information. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_CHAN_NUM: Required and type is u8. + * This attribute is used to indicate queried channel from + * the operating class indicated in QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_EIRP: Optional and type is u32. + * This attribute is used to configure the EIRP power info corresponding + * to the channel number indicated in QCA_WLAN_VENDOR_ATTR_AFC_CHAN_NUM. + * The EIRP power info(dBm) from user space should be multiplied + * by a factor of 100 when sending to Driver to preserve granularity up to + * 2 decimal places. + * Example: + * EIRP power value: 34.23 dBm + * Value to be updated in QCA_WLAN_VENDOR_ATTR_AFC_EIRP_INFO: 3423. + * + * Note: QCA_WLAN_VENDOR_ATTR_AFC_EIRP_INFO attribute will only be used with + * nested attribute QCA_WLAN_VENDOR_ATTR_AFC_RESP_OPCLASS_CHAN_EIRP_INFO and + * with QCA_WLAN_VENDOR_ATTR_AFC_EVENT_OPCLASS_CHAN_LIST when + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE: + * + * The following set of attributes will be used to exchange Channel and + * corresponding EIRP information for AFC between the user space and Driver. + */ +enum qca_wlan_vendor_attr_afc_chan_eirp_info { + QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_CHAN_NUM = 1, + QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_EIRP = 2, + + QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_MAX = + QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_afc_opclass_info: This enum is used with nested + * attributes QCA_WLAN_VENDOR_ATTR_AFC_RESP_OPCLASS_CHAN_EIRP_INFO and + * QCA_WLAN_VENDOR_ATTR_AFC_REQ_OPCLASS_CHAN_INFO to update the operating class, + * channel, and EIRP related information. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_OPCLASS: Required and type is u8. + * This attribute is used to indicate the operating class, as listed under + * IEEE Std 802.11-2020 Annex E Table E-4, for the queried channel list. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_CHAN_LIST: Array of nested attributes + * for updating the channel number and EIRP power information. + * It uses the attributes defined in + * enum qca_wlan_vendor_attr_afc_chan_eirp_info. + * + * Operating class information packing format for + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_OPCLASS_CHAN_INFO when + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE_EXPIRY. + * + * m - Total number of operating classes. + * n, j - Number of queried channels for the corresponding operating class. + * + * QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_OPCLASS[0] + * QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_CHAN_LIST[0] + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_CHAN_NUM[0] + * ..... + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_CHAN_NUM[n - 1] + * .... + * QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_OPCLASS[m] + * QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_CHAN_LIST[m] + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_CHAN_NUM[0] + * .... + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_CHAN_NUM[j - 1] + * + * Operating class information packing format for + * QCA_WLAN_VENDOR_ATTR_AFC_RESP_OPCLASS_CHAN_EIRP_INFO and + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_OPCLASS_CHAN_INFO when + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE. + * + * m - Total number of operating classes. + * n, j - Number of channels for the corresponding operating class. + * + * QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_OPCLASS[0] + * QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_CHAN_LIST[0] + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_CHAN_NUM[0] + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_EIRP[0] + * ..... + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_CHAN_NUM[n - 1] + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_EIRP[n - 1] + * .... + * QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_OPCLASS[m] + * QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_CHAN_LIST[m] + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_CHAN_NUM[0] + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_EIRP[0] + * .... + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_CHAN_NUM[j - 1] + * QCA_WLAN_VENDOR_ATTR_AFC_CHAN_EIRP_INFO_EIRP[j - 1] + * + * The following set of attributes will be used to exchange operating class + * information for AFC between the user space and the driver. + */ +enum qca_wlan_vendor_attr_afc_opclass_info { + QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_OPCLASS = 1, + QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_CHAN_LIST = 2, + + QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_MAX = + QCA_WLAN_VENDOR_ATTR_AFC_OPCLASS_INFO_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_afc_event_type: Defines values for AFC event type. + * Attribute used by QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE attribute. + * + * @QCA_WLAN_VENDOR_AFC_EVENT_TYPE_EXPIRY: AFC expiry event sent from the + * driver to userspace in order to query the new AFC power values. + * + * @QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE: Power update + * complete event will be sent from the driver to userspace to indicate + * processing of the AFC response. + * + * @QCA_WLAN_VENDOR_AFC_EVENT_TYPE_PAYLOAD_RESET: AFC payload reset event + * will be sent from the driver to userspace to indicate last received + * AFC response data has been cleared on the AP due to invalid data + * in the QCA_NL80211_VENDOR_SUBCMD_AFC_RESPONSE. + * + * The following enum defines the different event types that will be + * used by the driver to help trigger corresponding AFC functionality in user + * space. + */ +enum qca_wlan_vendor_afc_event_type { + QCA_WLAN_VENDOR_AFC_EVENT_TYPE_EXPIRY = 0, + QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE = 1, + QCA_WLAN_VENDOR_AFC_EVENT_TYPE_PAYLOAD_RESET = 2, +}; + +/** + * enum qca_wlan_vendor_afc_ap_deployment_type: Defines values for AP + * deployment type. + * Attribute used by QCA_WLAN_VENDOR_ATTR_AFC_EVENT_AP_DEPLOYMENT attribute. + * + * @QCA_WLAN_VENDOR_AFC_AP_DEPLOYMENT_TYPE_UNKNOWN: Unknown AP deployment. + * + * @QCA_WLAN_VENDOR_AFC_AP_DEPLOYMENT_TYPE_INDOOR: Indoor AP deployment. + * + * @QCA_WLAN_VENDOR_AFC_AP_DEPLOYMENT_TYPE_OUTDOOR: Outdoor AP deployment. + * + * The following enum defines different deployment modes that the AP might + * come up in. This information will be essential to retrieve deployment-type + * specific SP power values for AFC operation. + */ +enum qca_wlan_vendor_afc_ap_deployment_type { + QCA_WLAN_VENDOR_AFC_AP_DEPLOYMENT_TYPE_UNKNOWN = 0, + QCA_WLAN_VENDOR_AFC_AP_DEPLOYMENT_TYPE_INDOOR = 1, + QCA_WLAN_VENDOR_AFC_AP_DEPLOYMENT_TYPE_OUTDOOR = 2, +}; + +/** + * enum qca_wlan_vendor_afc_evt_status_code: Defines values AP will use to + * indicate AFC response status. + * Enum used by QCA_WLAN_VENDOR_ATTR_AFC_EVENT_STATUS_CODE attribute. + * + * @QCA_WLAN_VENDOR_AFC_EVT_STATUS_CODE_SUCCESS: Success + * + * @QCA_WLAN_VENDOR_AFC_EVT_STATUS_CODE_TIMEOUT: Indicates AFC indication + * command was not received within the expected time of the AFC expiry event + * being triggered. + * + * @QCA_WLAN_VENDOR_AFC_EVT_STATUS_CODE_PARSING_ERROR: Indicates AFC data + * parsing error by the driver. + * + * @QCA_WLAN_VENDOR_AFC_EVT_STATUS_CODE_LOCAL_ERROR: Indicates any other local + * error. + * + * The following enum defines the status codes that the driver will use to + * indicate whether the AFC data is valid or not. + */ +enum qca_wlan_vendor_afc_evt_status_code { + QCA_WLAN_VENDOR_AFC_EVT_STATUS_CODE_SUCCESS = 0, + QCA_WLAN_VENDOR_AFC_EVT_STATUS_CODE_TIMEOUT = 1, + QCA_WLAN_VENDOR_AFC_EVT_STATUS_CODE_PARSING_ERROR = 2, + QCA_WLAN_VENDOR_AFC_EVT_STATUS_CODE_LOCAL_ERROR = 3, +}; + +/** + * enum qca_wlan_vendor_attr_afc_event: Defines attributes to be used with + * vendor event QCA_NL80211_VENDOR_SUBCMD_AFC_EVENT. These attributes will + * support sending only a single request to the user space at a time. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE: Required u8 attribute. + * Used with event to notify the type of AFC event received. + * Valid values are defined in enum qca_wlan_vendor_afc_event_type. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_AP_DEPLOYMENT: u8 attribute. Required when + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is QCA_WLAN_VENDOR_AFC_EVENT_TYPE_EXPIRY, + * otherwise unused. + * + * This attribute is used to indicate the AP deployment type in the AFC request. + * Valid values are defined in enum qca_wlan_vendor_afc_ap_deployment_type. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_REQ_ID: Required u32 attribute. + * Unique request identifier generated by the AFC client for every + * AFC expiry event trigger. See also QCA_WLAN_VENDOR_ATTR_AFC_RESP_REQ_ID. + * The user space application is responsible for ensuring no duplicate values + * are in-flight with the server, e.g., by delaying a request, should the same + * value be received from different radios in parallel. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_AFC_WFA_VERSION: u32 attribute. Optional. + * It is used when the QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_EXPIRY, otherwise unused. + * + * This attribute indicates the AFC spec version information. This will + * indicate the AFC version AFC client must use to query the AFC data. + * Bits 15:0 - Minor version + * Bits 31:16 - Major version + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_MIN_DES_POWER: u16 attribute. Required when + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is QCA_WLAN_VENDOR_AFC_EVENT_TYPE_EXPIRY, + * otherwise unused. + * This attribute indicates the minimum desired power (in dBm) for + * the queried spectrum. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_STATUS_CODE: u8 attribute. Required when + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE, otherwise unused. + * + * Valid values are defined in enum qca_wlan_vendor_afc_evt_status_code. + * This attribute is used to indicate if there were any errors parsing the + * AFC response. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_SERVER_RESP_CODE: s32 attribute. Required + * when QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE, otherwise unused. + * + * This attribute indicates the AFC response code. The AFC response codes are + * in the following categories: + * -1: General Failure. + * 0: Success. + * 100 - 199: General errors related to protocol. + * 300 - 399: Error events specific to message exchange + * for the Available Spectrum Inquiry. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_EXP_DATE: u32 attribute. Required when + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE, otherwise unused. + * + * This attribute indicates the date until which the current response is + * valid for in UTC format. + * Date format: bits 7:0 - DD (Day 1-31) + * bits 15:8 - MM (Month 1-12) + * bits 31:16 - YYYY (Year) + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_EXP_TIME: u32 attribute. Required when + * QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE, otherwise unused. + * + * This attribute indicates the time until which the current response is + * valid for in UTC format. + * Time format: bits 7:0 - SS (Seconds 0-59) + * bits 15:8 - MM (Minutes 0-59) + * bits 23:16 - HH (Hours 0-23) + * bits 31:24 - Reserved + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_FREQ_RANGE_LIST: Array of nested attributes + * for updating the list of frequency ranges to be queried. + * Required when QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_EXPIRY or + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE, otherwise unused. + * It uses the attributes defined in + * enum qca_wlan_vendor_attr_afc_freq_psd_info. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_EVENT_OPCLASS_CHAN_LIST: Array of nested attributes + * for updating the list of operating classes and corresponding channels to be + * queried. + * Required when QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE is + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_EXPIRY or + * QCA_WLAN_VENDOR_AFC_EVENT_TYPE_POWER_UPDATE_COMPLETE, otherwise unused. + * It uses the attributes defined in enum qca_wlan_vendor_attr_afc_opclass_info. + */ +enum qca_wlan_vendor_attr_afc_event { + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_TYPE = 1, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_AP_DEPLOYMENT = 2, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_REQ_ID = 3, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_AFC_WFA_VERSION = 4, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_MIN_DES_POWER = 5, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_STATUS_CODE = 6, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_SERVER_RESP_CODE = 7, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_EXP_DATE = 8, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_EXP_TIME = 9, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_FREQ_RANGE_LIST = 10, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_OPCLASS_CHAN_LIST = 11, + + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_MAX = + QCA_WLAN_VENDOR_ATTR_AFC_EVENT_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_afc_response: Defines attributes to be used + * with vendor command QCA_NL80211_VENDOR_SUBCMD_AFC_RESPONSE. These attributes + * will support sending only a single AFC response to the driver at a time. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_RESP_DATA: Type is NLA_STRING. Required attribute. + * This attribute will be used to send a single Spectrum Inquiry response object + * from the 'availableSpectrumInquiryResponses' array object from the response + * JSON. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_RESP_TIME_TO_LIVE: Required u32 attribute. + * + * This attribute indicates the period (in seconds) for which the response + * data received is valid for. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_RESP_REQ_ID: Required u32 attribute. + * + * This attribute indicates the request ID for which the corresponding + * response is being sent for. See also QCA_WLAN_VENDOR_ATTR_AFC_EVENT_REQ_ID. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_RESP_EXP_DATE: Required u32 attribute. + * + * This attribute indicates the date until which the current response is + * valid for in UTC format. + * Date format: bits 7:0 - DD (Day 1-31) + * bits 15:8 - MM (Month 1-12) + * bits 31:16 - YYYY (Year) + * + * @QCA_WLAN_VENDOR_ATTR_AFC_RESP_EXP_TIME: Required u32 attribute. + * + * This attribute indicates the time until which the current response is + * valid for in UTC format. + * Time format: bits 7:0 - SS (Seconds 0-59) + * bits 15:8 - MM (Minutes 0-59) + * bits 23:16 - HH (Hours 0-23) + * bits 31:24 - Reserved + * + * @QCA_WLAN_VENDOR_ATTR_AFC_RESP_AFC_SERVER_RESP_CODE: Required s32 attribute. + * + * This attribute indicates the AFC response code. The AFC response codes are + * in the following categories: + * -1: General Failure. + * 0: Success. + * 100 - 199: General errors related to protocol. + * 300 - 399: Error events specific to message exchange + * for the Available Spectrum Inquiry. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_RESP_FREQ_PSD_INFO: Array of nested attributes + * for PSD info of all the queried frequency ranges. It uses the attributes + * defined in enum qca_wlan_vendor_attr_afc_freq_psd_info. Required attribute. + * + * @QCA_WLAN_VENDOR_ATTR_AFC_RESP_OPCLASS_CHAN_EIRP_INFO: Array of nested + * attributes for EIRP info of all queried operating class/channels. It uses + * the attributes defined in enum qca_wlan_vendor_attr_afc_opclass_info and + * enum qca_wlan_vendor_attr_afc_chan_eirp_info. Required attribute. + * + */ +enum qca_wlan_vendor_attr_afc_response { + QCA_WLAN_VENDOR_ATTR_AFC_RESP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_AFC_RESP_DATA = 1, + QCA_WLAN_VENDOR_ATTR_AFC_RESP_TIME_TO_LIVE = 2, + QCA_WLAN_VENDOR_ATTR_AFC_RESP_REQ_ID = 3, + QCA_WLAN_VENDOR_ATTR_AFC_RESP_EXP_DATE = 4, + QCA_WLAN_VENDOR_ATTR_AFC_RESP_EXP_TIME = 5, + QCA_WLAN_VENDOR_ATTR_AFC_RESP_AFC_SERVER_RESP_CODE = 6, + QCA_WLAN_VENDOR_ATTR_AFC_RESP_FREQ_PSD_INFO = 7, + QCA_WLAN_VENDOR_ATTR_AFC_RESP_OPCLASS_CHAN_EIRP_INFO = 8, + + QCA_WLAN_VENDOR_ATTR_AFC_RESP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_AFC_RESP_MAX = + QCA_WLAN_VENDOR_ATTR_AFC_RESP_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_dozed_ap_state - Doze states for AP interface + * + * @QCA_WLAN_DOZED_AP_DISABLE: Disable doze state on the AP interface. + * + * @QCA_WLAN_DOZED_AP_ENABLE: Enable doze state on the AP interface. AP starts + * beaconing at higher beacon interval with Rx disabled. + */ +enum qca_wlan_dozed_ap_state { + QCA_WLAN_DOZED_AP_DISABLE = 0, + QCA_WLAN_DOZED_AP_ENABLE = 1, +}; + +/** + * enum qca_wlan_vendor_attr_dozed_ap - Used by the vendor command + * @QCA_NL80211_VENDOR_SUBCMD_DOZED_AP to configure or receive dozed AP mode + * configuration. + * + * @QCA_WLAN_VENDOR_ATTR_DOZED_AP_STATE: u8 attribute. + * Configures the doze state for an AP interface. Possible values are defined + * in enum qca_wlan_dozed_ap_state. @QCA_NL80211_VENDOR_SUBCMD_DOZED_AP event + * gets triggered asynchronously to provide updated AP interface configuration. + * + * @QCA_WLAN_VENDOR_ATTR_DOZED_AP_COOKIE: Unsigned 64-bit cookie provided by + * the driver in the response to specific @QCA_NL80211_VENDOR_SUBCMD_DOZED_AP + * command, which is used later to maintain synchronization between commands + * and asynchronous events. + * + * @QCA_WLAN_VENDOR_ATTR_DOZED_AP_NEXT_TSF: u64 attribute. + * Used in event to indicate the next TBTT TSF timer value after applying the + * doze mode configuration. Next TBTT TSF is the time at which the AP sends + * the first beacon after entering or exiting dozed mode. + * + * @QCA_WLAN_VENDOR_ATTR_DOZED_AP_BI_MULTIPLIER: u16 attribute. + * Used with event to inform the periodicity of beacon transmission that would + * be skipped at all TBTTs in between. + * + * @QCA_WLAN_VENDOR_ATTR_DOZED_AP_PAD: Attribute used for padding for 64-bit + * alignment. + */ +enum qca_wlan_vendor_attr_dozed_ap { + QCA_WLAN_VENDOR_ATTR_DOZED_AP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DOZED_AP_STATE = 1, + QCA_WLAN_VENDOR_ATTR_DOZED_AP_COOKIE = 2, + QCA_WLAN_VENDOR_ATTR_DOZED_AP_NEXT_TSF = 3, + QCA_WLAN_VENDOR_ATTR_DOZED_AP_BI_MULTIPLIER = 4, + QCA_WLAN_VENDOR_ATTR_DOZED_AP_PAD = 5, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_DOZED_AP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DOZED_AP_MAX = + QCA_WLAN_VENDOR_ATTR_DOZED_AP_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_monitor_mode_status - Represents the status codes + * used with QCA_NL80211_VENDOR_SUBCMD_GET_MONITOR_MODE. + * @QCA_WLAN_VENDOR_MONITOR_MODE_NO_CAPTURE_RUNNING: Used to indicate no + * capture running status. + * @QCA_WLAN_VENDOR_MONITOR_MODE_CAPTURE_RUNNING: Used to indicate + * capture running status. + **/ + +enum qca_wlan_vendor_monitor_mode_status { + QCA_WLAN_VENDOR_MONITOR_MODE_NO_CAPTURE_RUNNING = 0, + QCA_WLAN_VENDOR_MONITOR_MODE_CAPTURE_RUNNING = 1, +}; + +/** + * enum qca_wlan_vendor_attr_get_monitor_mode - Used by the + * vendor command QCA_NL80211_VENDOR_SUBCMD_GET_MONITOR_MODE to report + * information regarding the local packet capture over the monitor mode. + * + * @QCA_WLAN_VENDOR_ATTR_GET_MONITOR_MODE_STATUS: u32 attribute. This attribute + * represents the status of the start capture commands. The values used with + * this attribute are defined in enum qca_wlan_vendor_monitor_mode_status. This + * is returned by the driver in the response to the command. + */ + +enum qca_wlan_vendor_attr_get_monitor_mode { + QCA_WLAN_VENDOR_ATTR_GET_MONITOR_MODE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_GET_MONITOR_MODE_STATUS = 1, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_GET_MONITOR_MODE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_GET_MONITOR_MODE_MAX = + QCA_WLAN_VENDOR_ATTR_GET_MONITOR_MODE_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_link_state_op_types - Defines different types of + * operations for which %QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE can be used. + * Will be used with %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE attribute. + * + * @QCA_WLAN_VENDOR_LINK_STATE_OP_GET - Get the MLO links state information. + * @QCA_WLAN_VENDOR_LINK_STATE_OP_SET - Set the MLO links state information. + */ +enum qca_wlan_vendor_link_state_op_types { + QCA_WLAN_VENDOR_LINK_STATE_OP_GET = 0, + QCA_WLAN_VENDOR_LINK_STATE_OP_SET = 1, +}; + +/** + * enum qca_wlan_vendor_link_state_control_modes - Represents the types of MLO + * links state control modes. This enum is used by + * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE attribute. + * + * @QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT: MLO links state controlled + * by the driver. + * @QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER: MLO links state controlled by + * user space. + * @QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED: User space provides the + * desired number of MLO links to operate in active state at any given time. + * The driver will choose which MLO links should operate in the active state. + * See enum qca_wlan_vendor_link_state for active state definition. + */ +enum qca_wlan_vendor_link_state_control_modes { + QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT = 0, + QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER = 1, + QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED = 2, +}; + +/** + * enum qca_wlan_vendor_link_state_operation_modes - Represents the types of MLO + * links state operation modes. This enum is used by + * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE attribute. + * + * @QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_DEFAULT: In the default operation + * mode, the driver selects the operating mode of the links, without any + * guidance from the user space. + * @QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_LOW_LATENCY: In the low latency + * operation mode the driver should select MLO links that will achieve low + * latency. + * @QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_HIGH_THROUGHPUT: In the high + * throughput operation mode the driver should select MLO links that will + * achieve higher throughput. + * @QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_LOW_POWER: In the low power + * operation mode the driver should select MLO links that will achieve low + * power. + */ +enum qca_wlan_vendor_link_state_operation_modes { + QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_DEFAULT = 0, + QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_LOW_LATENCY = 1, + QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_HIGH_THROUGHPUT = 2, + QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_LOW_POWER = 3, +}; + +/** + * enum qca_wlan_vendor_link_state - Represents the possible link states of an + * MLO link. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_INACTIVE: In this state, the link will not + * be used for data transmission but it can have TIDs mapped to it. It will be + * in doze state always and does not monitor the beacons. + * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_ACTIVE: In this state, the link will be + * used for data TX/RX and monitors the beacons to check TIM bit indication. + * It may enter doze state and comes out based on the transmit data traffic and + * TIM bit indication in the beacon. + */ +enum qca_wlan_vendor_link_state { + QCA_WLAN_VENDOR_LINK_STATE_INACTIVE = 0, + QCA_WLAN_VENDOR_LINK_STATE_ACTIVE = 1, +}; + +/** + * enum qca_wlan_vendor_attr_link_state_config - Definition of attributes used + * inside nested attribute %QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID: u8 attribute, link ID of the + * MLO link. + * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE: u32 attribute. See + * enum qca_wlan_vendor_link_state for possible MLO link states. + */ + +enum qca_wlan_vendor_attr_link_state_config { + QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID = 1, + QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE = 2, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_mlo_link_state - Attributes used by + * %QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE vendor command. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE: u32 attribute. Indicates the type + * of the operation %QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE intended for. + * Required only in a command. Possible values for this attribute are defined in + * enum qca_wlan_vendor_link_state_op_types. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE: u32 attribute. Indicates MLO + * links control mode type. Optional attribute in a command when + * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE is set to + * %QCA_WLAN_VENDOR_LINK_STATE_OP_SET. Required attribute in a response when + * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE is set to + * %QCA_WLAN_VENDOR_LINK_STATE_OP_GET. + * See enum qca_wlan_vendor_link_state_control_modes for possible control modes. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG: Array of nested attributes. + * Indicates the state of the each MLO link affiliated with the interface. + * Required attribute in a command when %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE + * is set to %QCA_WLAN_VENDOR_LINK_STATE_OP_SET and + * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE is set to + * %QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER. Required attribute in a + * response when %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE is set to + * %QCA_WLAN_VENDOR_LINK_STATE_OP_GET. + * See enum qca_wlan_vendor_attr_link_state_config for the nested attributes. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS: u8 attribute. + * Represents the number of active state links. See enum + * qca_wlan_vendor_link_state for active state definition. + * Required attribute in a command when %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE + * is set to %QCA_WLAN_VENDOR_LINK_STATE_OP_SET and + * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE is set to + * %QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE: u32 attribute. Indicates MLO + * links operation mode type. Optional attribute in a command when + * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE is set to + * %QCA_WLAN_VENDOR_LINK_STATE_OP_SET. Required attribute in a response when + * %QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE is set to + * %QCA_WLAN_VENDOR_LINK_STATE_OP_GET. + * See enum qca_wlan_vendor_link_state_operation_modes for possible operation + * modes. + */ +enum qca_wlan_vendor_attr_mlo_link_state { + QCA_WLAN_VENDOR_ATTR_LINK_STATE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE = 1, + QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE = 2, + QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG = 3, + QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS = 4, + QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE = 5, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LINK_STATE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX = + QCA_WLAN_VENDOR_ATTR_LINK_STATE_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tid_link_map_status - Definition of attributes used + * inside nested attribute %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK: Required u16 attribute + * within nested attribute %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS. + * Indicates the link mapping bitmap of a TID for uplink traffic. It is a + * bitmask of the link IDs in which a bit set means that the TID is mapped with + * that link ID in uplink traffic. Otherwise, the TID is not mapped to uplink + * traffic for that link. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK: Required u16 attribute + * within nested attribute %QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS. + * Indicates the link mapping bitmap of a TID for downlink traffic. It is a + * bitmask of the link IDs in which a bit set means that the TID is mapped with + * that link ID in downlink traffic. Otherwise, the TID is not mapped to + * downlink traffic for that link. + */ +enum qca_wlan_vendor_attr_tid_link_map_status { + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK = 1, + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX = + QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_AFTER_LAST - 1, +}; + +/* + * enum qca_wlan_vendor_attr_tid_to_link_map: Definition of attributes used with + * %QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP event. + * + * @QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR: Required attribute. 6-byte + * AP MLD address with which this TID-to-link negotiation mapping is + * established/updated. + * + * @QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS: Optional attribute. Array of + * nested attributes containing TID-to-links mapping information. This will have + * TID-to-link mapping for TID0 to TID7, each containing the uplink and downlink + * map information. If this attribute is not present the default TID-to-link + * mapping is in use, i.e., all TIDs are mapped to all links for both uplink and + * downlink traffic. + * See enum qca_wlan_vendor_attr_tid_link_map_status for the nested attributes. + */ +enum qca_wlan_vendor_attr_tid_to_link_map { + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX = + QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_link_reconfig: Definition of attributes used + * with %QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG event. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR: Required attribute. + * 6-byte AP MLD address of the AP which indicated the link reconfiguration. + * + * @QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS: Required u16 attribute. + * A bitmap of the removed setup links link IDs. + */ +enum qca_wlan_vendor_attr_link_reconfig { + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_tdls_disc_rsp_ext - Attributes used by + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT vendor command. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK: u8 attribute. + * Indicates the MLO link id on which the TDLS discovery response + * frame is to be transmitted. + */ +enum qca_wlan_vendor_attr_tdls_disc_rsp_ext { + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK = 1, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_tdls_state - Represents the possible TDLS states. + * + * @QCA_WLAN_VENDOR_TDLS_STATE_DISABLED: TDLS is not enabled, default status + * for all stations. + * + * @QCA_WLAN_VENDOR_TDLS_STATE_ENABLED: TDLS is enabled, but not yet tried to + * establish the session. + * + * @QCA_WLAN_VENDOR_TDLS_STATE_ESTABLISHED: Direct link TDLS session is + * established. + * + * @QCA_WLAN_VENDOR_TDLS_STATE_ESTABLISHED_OFF_CHANNEL: Direct link TDLS + * session is established using MCC. + * + * @QCA_WLAN_VENDOR_TDLS_STATE_DROPPED: Direct link TDLS session was + * established, but is temporarily dropped currently. + * + * @QCA_WLAN_VENDOR_TDLS_STATE_FAILED: TDLS session is failed to establish. + */ +enum qca_wlan_vendor_tdls_state { + QCA_WLAN_VENDOR_TDLS_STATE_DISABLED = 1, + QCA_WLAN_VENDOR_TDLS_STATE_ENABLED = 2, + QCA_WLAN_VENDOR_TDLS_STATE_ESTABLISHED = 3, + QCA_WLAN_VENDOR_TDLS_STATE_ESTABLISHED_OFF_CHANNEL = 4, + QCA_WLAN_VENDOR_TDLS_STATE_DROPPED = 5, + QCA_WLAN_VENDOR_TDLS_STATE_FAILED = 6, +}; + +/** + * enum qca_wlan_vendor_tdls_reason - Represents the possible TDLS reasons. + * + * @QCA_WLAN_TDLS_REASON_SUCCESS: TDLS session is successfully established. + * + * @QCA_WLAN_TDLS_REASON_UNSPECIFIED: Unspecified reason. + * + * @QCA_WLAN_TDLS_REASON_NOT_SUPPORTED: TDLS is not supported. + * + * @QCA_WLAN_TDLS_REASON_UNSUPPORTED_BAND: The specified band is not supported. + * + * @QCA_WLAN_TDLS_REASON_NOT_BENEFICIAL: Packets going through AP is better + * than through direct link. + * + * @QCA_WLAN_TDLS_REASON_DROPPED_BY_REMOTE: Peer station doesn't want the TDLS + * session anymore. + */ + +enum qca_wlan_vendor_tdls_reason { + QCA_WLAN_TDLS_REASON_SUCCESS = 0, + QCA_WLAN_TDLS_REASON_UNSPECIFIED = -1, + QCA_WLAN_TDLS_REASON_NOT_SUPPORTED = -2, + QCA_WLAN_TDLS_REASON_UNSUPPORTED_BAND = -3, + QCA_WLAN_TDLS_REASON_NOT_BENEFICIAL = -4, + QCA_WLAN_TDLS_REASON_DROPPED_BY_REMOTE = -5, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_enable - Attributes used by + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE vendor command. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR: 6-byte MAC address of the peer + * station to enable the TDLS session. Optional attribute. The driver sends the + * TDLS session result as an asynchronous response using the command + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE when this peer MAC is provided in + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE command. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL: u32 attribute. Indicates the + * channel on which the TDLS session to be established. Required only when + * %QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR is present. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS: u32 attribute. + * Indicates the global operating class of the TDLS session to be established. + * Required only when %QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR is present. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS: u32 attribute. Indicates + * the maximum latency of the WLAN packets to be transmitted/received in + * milliseconds on TDLS session. Required only when + * %QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR is present. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS: u32 attribute. + * Indicates the minimum bandwidth to be used to establish the TDLS session + * in kbps. Required only when %QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR is + * present. + */ +enum qca_wlan_vendor_attr_tdls_enable { + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL = 2, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS = 3, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS = 4, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS = 5, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_disable - Attributes used by + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE vendor command. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR: 6-byte MAC address of the peer + * station to disable the TDLS session. Optional attribute. + */ +enum qca_wlan_vendor_attr_tdls_disable { + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_get_status - Attributes used by + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS vendor command. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR: 6-byte MAC address of the + * peer station. Optional attribute. Used in + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS request and response. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE: u32 attribute. Indicates the + * TDLS session state with the peer specified in + * %QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR. Uses the values from + * enum qca_wlan_vendor_tdls_state. Used in + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS response. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON: s32 attribute. Indicates the + * reason for the TDLS session state indicated in + * %QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE. Uses the values from enum + * qca_wlan_vendor_tdls_reason. Used in + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS response. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL: u32 attribute. Indicates the + * channel of the TDLS session established with + * %QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR. Used in + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS response. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS: u32 attribute. + * Indicates the global operating class of the TDLS session established with + * %QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR. Used in + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS response. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_NUM_SESSIONS: u32 attribute. Indicates + * the current number of active TDLS sessions. This is indicated in the response + * when %QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS is requested with + * %NL80211_ATTR_VENDOR_DATA as an empty nested attribute. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AVAILABLE: Flag attribute. Indicates + * whether the driver can initiate new TDLS session. This is indicated in the + * response when %QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS is requested with + * %NL80211_ATTR_VENDOR_DATA as an empty nested attribute. + */ +enum qca_wlan_vendor_attr_tdls_get_status { + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE = 2, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON = 3, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL = 4, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS = 5, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_NUM_SESSIONS = 6, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AVAILABLE = 7, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_state - Attributes used by + * %QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE vendor command. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR: 6-byte MAC address of the + * peer station. Required attribute. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CURRENT_STATE: u32 attribute. Indicates + * the current TDLS state. Required attribute. Uses the values from + * enum qca_wlan_vendor_tdls_state. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON: s32 attribute. Indicates the + * reason of the current TDLS session state. Required attribute. Uses the values + * from enum qca_wlan_vendor_tdls_reason. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL: u32 attribute. Indicates the + * TDLS session channel. Required attribute. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS: u32 attribute. + * Indicates the TDLS session global operating class. Required attribute. + */ +enum qca_wlan_vendor_attr_tdls_state { + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_NEW_STATE = 2, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON = 3, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL = 4, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS = 5, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_AFTER_LAST - 1, +}; + +/* + * enum qca_wlan_vendor_opm_mode - Modes supported by + * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT vendor attribute. + * + * @QCA_WLAN_VENDOR_OPM_MODE_DISABLE: OPM Disabled + * @QCA_WLAN_VENDOR_OPM_MODE_ENABLE: OPM Enabled + * @QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED: User defined mode which allows user + * to configure power save inactivity timeout and speculative wake up + * interval through %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO and + * %QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL attributes. + */ + +enum qca_wlan_vendor_opm_mode { + QCA_WLAN_VENDOR_OPM_MODE_DISABLE = 0, + QCA_WLAN_VENDOR_OPM_MODE_ENABLE = 1, + QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED = 2, +}; + +/* + * enum qca_wlan_vendor_tx_latency_type - Represents the possible latency + * types. + * + * @QCA_WLAN_VENDOR_TX_LATENCY_TYPE_DRIVER: Per MSDU latency + * from: An MSDU is presented to the driver + * to: the MSDU is queued into TCL SRNG + * + * @QCA_WLAN_VENDOR_TX_LATENCY_TYPE_RING: Per MSDU latency + * from: the MSDU is queued into TCL SRNG + * to: the MSDU is released by the driver + * + * @QCA_WLAN_VENDOR_TX_LATENCY_TYPE_HW: Per MSDU latency + * from: the MSDU is presented to the hardware + * to: the MSDU is released by the hardware + * + * @QCA_WLAN_VENDOR_TX_LATENCY_TYPE_CCA: Per PPDU latency + * The time spent on Clear Channel Assessment, the maximum value is 50000 (us) + * from: A PPDU is presented to the hardware LMAC + * to: over-the-air transmission is started for the PPDU + */ +enum qca_wlan_vendor_tx_latency_type { + QCA_WLAN_VENDOR_TX_LATENCY_TYPE_DRIVER = 0, + QCA_WLAN_VENDOR_TX_LATENCY_TYPE_RING = 1, + QCA_WLAN_VENDOR_TX_LATENCY_TYPE_HW = 2, + QCA_WLAN_VENDOR_TX_LATENCY_TYPE_CCA = 3, +}; + +/** + * enum qca_wlan_vendor_attr_tx_latency_bucket - Definition of attributes + * used inside nested attributes + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKETS and + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_STAT_BUCKETS. + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE: u8 attribute. + * Indicates the latency type. + * See enum qca_wlan_vendor_tx_latency_type for the supported types. + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_GRANULARITY: u32 attribute. + * Indicates the granularity (in microseconds) of the distribution for the + * type (specified by %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE), the value + * must be positive. + * If %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE is + * %QCA_WLAN_VENDOR_TX_LATENCY_TYPE_CCA, the value must be an integer multiple + * of 1000, and the maximum allowed value is 15000 (us). + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_AVERAGE: u32 attribute. + * Indicates the average of the latency (in microseconds) for the type + * (specified by %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE) within a cycle. + * If there is no transmitted MSDUs/MPDUs during a cycle, this average is 0; + * otherwise, it represents the quotient of divided by . + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_DISTRIBUTION: + * Array of u32, 4 elements in total, represents the latency distribution for + * the type (specified by %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE). + * Each element holds the count of MSDUs/PPDUs (according to the latency type) + * within a range: + * element[0]: latency >= 0 && latency < granularity + * element[1]: latency >= granularity && latency < granularity * 2 + * element[2]: latency >= granularity * 2 && latency < granularity * 3 + * element[3]: latency >= granularity * 3 + */ +enum qca_wlan_vendor_attr_tx_latency_bucket { + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE = 1, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_GRANULARITY = 2, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_AVERAGE = 3, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_DISTRIBUTION = 4, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_MAX = + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tx_latency_link - Definition of attributes + * used inside nested attribute %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS. + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAC_REMOTE: 6-byte MAC address. + * Indicates link MAC address of the remote peer. For example, when running + * in station mode, it's the BSSID of the link; while when running in AP + * mode, it's the link MAC address of the remote station. + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_STAT_BUCKETS: + * Array of nested attribute. + * Represents the transmit latency statistics for the link specified by + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAC_REMOTE. + * Each entry represents the statistics for one of the types defined in + * enum qca_wlan_vendor_tx_latency_type. + * Each defined type has and must have one entry. + * See enum qca_wlan_vendor_attr_tx_latency_bucket for nested attributes. + */ +enum qca_wlan_vendor_attr_tx_latency_link { + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAC_REMOTE = 1, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_STAT_BUCKETS = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAX = + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_tx_latency_action - Represents the possible actions + * for %QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY. + * + * @QCA_WLAN_VENDOR_TX_LATENCY_ACTION_DISABLE: + * Disable transmit latency monitoring. + * + * @QCA_WLAN_VENDOR_TX_LATENCY_ACTION_ENABLE: + * Enable transmit latency monitoring. + * + * @QCA_WLAN_VENDOR_TX_LATENCY_ACTION_GET: + * Get transmit latency statistics of the last cycle (period is specified by + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_PERIOD). + */ +enum qca_wlan_vendor_tx_latency_action { + QCA_WLAN_VENDOR_TX_LATENCY_ACTION_DISABLE = 0, + QCA_WLAN_VENDOR_TX_LATENCY_ACTION_ENABLE = 1, + QCA_WLAN_VENDOR_TX_LATENCY_ACTION_GET = 2, +}; + +/** + * enum qca_wlan_vendor_attr_tx_latency - Definition of attributes used by + * %QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY to configure, retrieve, and report + * per-link transmit latency statistics. + * + * There are 6 uses of %QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY: + * 1) used as a command to enable the feature + * Precondition(s): + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ACTION is + * %QCA_WLAN_VENDOR_TX_LATENCY_ACTION_ENABLE + * Mandatory attribute(s): + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ACTION, + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_PERIOD, + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKETS with nested attributes + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE, + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_GRANULARITY. + * Notes: + * The driver will monitor the transmit latency for the active links + * and save the statistics for each cycle (period is set by + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_PERIOD) when the feature is enabled. + * Set flag %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_PERIODIC_REPORT if periodical + * report is required. + * + * 2) used as a command to disable the feature + * Precondition(s): + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ACTION is + * %QCA_WLAN_VENDOR_TX_LATENCY_ACTION_DISABLE + * Mandatory attribute(s): + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ACTION + * + * 3) used as a command to retrieve the statistics for all the active links on + * the requested interface + * Precondition(s): + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ACTION is + * QCA_WLAN_VENDOR_TX_LATENCY_ACTION_GET and + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS is NOT present. + * Mandatory attribute(s): + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ACTION + * Notes: + * The driver returns failure directly if the feature is not enabled or + * there is no active link. + * The driver returns the statistics of the last cycle in the case of + * success. + * + * 4) used as a command to retrieve the statistics for the specified links + * Precondition(s): + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ACTION is + * QCA_WLAN_VENDOR_TX_LATENCY_ACTION_GET and + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS is present. + * Mandatory attribute(s): + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ACTION, + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS, with nested attribute + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAC_REMOTE. + * Notes: + * The driver returns failure directly if the feature is not enabled or + * any of the links (specified by %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS) + * does not exist or is not in active state. + * + * 5) used as a command response for #3 or #4 + * Precondition(s): + * Userspace issues command #3 or #4, and the driver gets corresponding + * statistics successfully. + * Mandatory attribute(s): + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS, with nested attributes + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAC_REMOTE, + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_STAT_BUCKETS with nested + * attributes %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE, + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_GRANULARITY, + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_AVERAGE and + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_DISTRIBUTION. + * + * 6) used as an asynchronous event to report the statistics periodically + * Precondition(s): + * Userspace set flag %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_PERIODIC_REPORT in + * #1. + * One or more links are in active state. + * Mandatory attribute(s): + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS, with nested attributes + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAC_REMOTE, + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_STAT_BUCKETS with nested + * attributes %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE, + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_GRANULARITY, + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_AVERAGE and + * %QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_DISTRIBUTION. + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_INVALID: Invalid attribute + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ACTION: u32 attribute. + * Action to take in this vendor command. + * See enum qca_wlan_vendor_tx_latency_action for supported actions. + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_PERIODIC_REPORT: Flag attribute. + * Enable (flag attribute present) - The driver needs to report transmit latency + * statistics at the end of each statistical period. + * Disable (flag attribute not present) - The driver doesn't need to report + * transmit latency statistics periodically. + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_PERIOD: u32 attribute. + * Indicates statistical period for transmit latency in terms of milliseconds, + * the minimal allowed value is 100 and the maximum allowed value is 60000. + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKETS: Array of nested attribute. + * Each entry represents the latency buckets configuration for one of the types + * defined in enum qca_wlan_vendor_tx_latency_type. + * Each defined type has and must have one entry. + * See enum qca_wlan_vendor_attr_tx_latency_bucket for the list of + * supported attributes. + * + * @QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS: Array of nested attribute. + * Information of the links, each entry represents for one link. + * See enum qca_wlan_vendor_attr_tx_latency_link for the list of + * supported attributes for each entry. + */ +enum qca_wlan_vendor_attr_tx_latency { + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ACTION = 1, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_PERIODIC_REPORT = 2, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_PERIOD = 3, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKETS = 4, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS = 5, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_MAX = + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_AFTER_LAST - 1, +}; + +/** + * enum qca_chan_width_update_type - Represents the possible values for + * %QCA_WLAN_VENDOR_ATTR_CONFIG_CHAN_WIDTH_UPDATE_TYPE. + * + * @QCA_CHAN_WIDTH_UPDATE_TYPE_TX_RX: The maximum allowed bandwidth change is + * applicable for both Tx and Rx paths. The driver shall conduct OMI operation + * as defined in 26.9 (Operating mode indication) or OMN operation as defined in + * 11.40 (Notification of operating mode changes) in IEEE P802.11-REVme/D2.0 + * with AP to indicate the change in the maximum allowed operating bandwidth. + * + * @QCA_CHAN_WIDTH_UPDATE_TYPE_TX_ONLY: Limit the change in maximum allowed + * bandwidth only to Tx path. In this case the driver doesn't need to conduct + * OMI/OMN operation since %QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH is + * expected to be less than the current connection maximum negotiated bandwidth. + * For example: Negotiated maximum bandwidth is 160 MHz and the new maximum + * bandwidth configured is 80 MHz, now the driver limits the maximum bandwidth + * to 80 MHz only in the Tx path. + * + * @QCA_CHAN_WIDTH_UPDATE_TYPE_TX_RX_EXT: This is similar to + * %QCA_CHAN_WIDTH_UPDATE_TYPE_TX_RX but the driver doesn't change current + * phymode bandwidth to avoid interoperability issues with APs which don't + * handle the maximum bandwidth change indication correctly. + * For example: Negotiated maximum bandwidth is 40 MHz and the new maximum + * bandwidth configured is 20 MHz, now the driver indicates the change in + * maximum allowed bandwidth to the AP and limits the bandwidth to 20 MHz in the + * Tx path but keeps the phymode bandwidth as 40 MHz. This will avoid + * interoperability issues with APs which still use 40 MHz for sending the + * frames though it received maximum allowed bandwidth indication as 20 MHz + * from the STA. + */ +enum qca_chan_width_update_type { + QCA_CHAN_WIDTH_UPDATE_TYPE_TX_RX = 0, + QCA_CHAN_WIDTH_UPDATE_TYPE_TX_ONLY = 1, + QCA_CHAN_WIDTH_UPDATE_TYPE_TX_RX_EXT = 2, +}; + +/** + * enum qca_wlan_vendor_attr_tpc_pwr_level - Definition of attributes + * used inside nested attribute %QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL. + * + * @QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_FREQUENCY: u32 channel center + * frequency (MHz): If PSD power, carries one 20 MHz sub-channel center + * frequency. If non PSD power, carries either 20 MHz bandwidth's center + * channel frequency or 40 MHz bandwidth's center channel frequency + * (or 80/160 MHz bandwidth's center channel frequency). + * + * @QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_TX_POWER: s8 transmit power limit (dBm). + * If PSD power, carries PSD power value of the + * QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_FREQUENCY mentioned sub-channel. + * If non PSD power, carries EIRP power value of bandwidth mentioned + * by QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_FREQUENCY center frequency. + */ +enum qca_wlan_vendor_attr_tpc_pwr_level { + QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_FREQUENCY = 1, + QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_TX_POWER = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_MAX = + QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_tpc - Definition of link attributes + * used inside nested attribute %QCA_WLAN_VENDOR_ATTR_TPC_LINKS. + * + * @QCA_WLAN_VENDOR_ATTR_TPC_BSSID: 6-bytes AP BSSID. + * For MLO STA, AP BSSID indicates the AP's link address. + * + * @QCA_WLAN_VENDOR_ATTR_TPC_PSD_POWER: PSD power flag + * Indicates using PSD power mode if this flag is present. + * + * @QCA_WLAN_VENDOR_ATTR_TPC_EIRP_POWER: s8 Regulatory EIRP power + * value in dBm + * + * @QCA_WLAN_VENDOR_ATTR_TPC_POWER_TYPE_6GHZ: u8 power type of 6 GHz + * AP, refer to Table E-12-Regulatory Info subfield encoding in + * IEEE P802.11-REVme/D4.0. Only present if link is connected to 6 GHz AP. + * + * @QCA_WLAN_VENDOR_ATTR_TPC_AP_CONSTRAINT_POWER: u8 Local Power Constraint + * (dBm) advertised by AP in Power Constraint element, refer to + * IEEE Std 802.11-2020, 9.4.2.13 Power Constraint element. + * + * @QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL: A nested attribute containing + * attributes defined by enum qca_wlan_vendor_attr_tpc_pwr_level. + * If PSD power, each power level describes each 20 MHz subchannel PSD + * power value. If non PSD power, each power level describes each supported + * bandwidth's EIRP power value (up to Max bandwidth of AP operating on), + * each level attribute contains corresponding bandwidth's center channel + * frequency and its EIRP power value. + */ +enum qca_wlan_vendor_attr_tpc { + QCA_WLAN_VENDOR_ATTR_TPC_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TPC_BSSID = 1, + QCA_WLAN_VENDOR_ATTR_TPC_PSD_POWER = 2, + QCA_WLAN_VENDOR_ATTR_TPC_EIRP_POWER = 3, + QCA_WLAN_VENDOR_ATTR_TPC_POWER_TYPE_6GHZ = 4, + QCA_WLAN_VENDOR_ATTR_TPC_AP_CONSTRAINT_POWER = 5, + QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL = 6, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TPC_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TPC_MAX = + QCA_WLAN_VENDOR_ATTR_TPC_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tpc_links - Definition of attributes + * for %QCA_NL80211_VENDOR_SUBCMD_REGULATORY_TPC_INFO subcommand + * + * @QCA_WLAN_VENDOR_ATTR_TPC_LINKS: A nested attribute containing + * per-link TPC information of all the active links of MLO STA. + * For non MLO STA, only one link TPC information will be returned + * for connected AP in this nested attribute. + * The attributes used inside this nested attributes are defined + * in enum qca_wlan_vendor_attr_tpc. + */ +enum qca_wlan_vendor_attr_tpc_links { + QCA_WLAN_VENDOR_ATTR_TPC_LINKS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TPC_LINKS = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TPC_LINKS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TPC_LINKS_MAX = + QCA_WLAN_VENDOR_ATTR_TPC_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_fw_page_fault_report - Used by the vendor + * command %QCA_NL80211_VENDOR_SUBCMD_FW_PAGE_FAULT_REPORT. + * + * @QCA_WLAN_VENDOR_ATTR_FW_PAGE_FAULT_REPORT_DATA: The binary blob data + * associated with the firmware page fault that is expected to contain the + * required dump to analyze frequent page faults. + * NLA_BINARY attribute, the maximum size is 1024 bytes. + */ +enum qca_wlan_vendor_attr_fw_page_fault_report { + QCA_WLAN_VENDOR_ATTR_FW_PAGE_FAULT_REPORT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_FW_PAGE_FAULT_REPORT_DATA = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_FW_PAGE_FAULT_REPORT_LAST, + QCA_WLAN_VENDOR_ATTR_FW_PAGE_FAULT_REPORT_MAX = + QCA_WLAN_VENDOR_ATTR_FW_PAGE_FAULT_REPORT_LAST - 1, +}; + +/** + * enum qca_wlan_btm_support: BTM support configuration + * + * @QCA_WLAN_BTM_SUPPORT_DEFAULT: Restore default BTM support policy. The driver + * follows the BSS Transition bit in the Extended Capabilities element from the + * connect request IEs with the default BTM support policy. + * + * @QCA_WLAN_BTM_SUPPORT_DISABLE: Disable BTM support for the subsequent + * (re)association attempts. The driver shall restore the default BTM support + * policy during the first disconnection after successful association. When this + * configuration is enabled, the driver shall overwrite the BSS Transition bit + * as zero in the Extended Capabilities element while sending (Re)Association + * Request frames. Also, the driver shall drop the BTM frames from userspace and + * the connected AP when this configuration is enabled. + */ +enum qca_wlan_btm_support { + QCA_WLAN_BTM_SUPPORT_DEFAULT = 0, + QCA_WLAN_BTM_SUPPORT_DISABLE = 1, +}; + +/** + * enum qca_wlan_vendor_data_rate_type - Represents the possible values for + * attribute %QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_RATE_TYPE. + * + * @QCA_WLAN_VENDOR_DATA_RATE_TYPE_LEGACY: Data rate type is a legacy rate code + * used in OFDM/CCK. + * + * @QCA_WLAN_VENDOR_DATA_RATE_TYPE_MCS: Data rate type is an MCS index. + * + */ +enum qca_wlan_vendor_data_rate_type { + QCA_WLAN_VENDOR_DATA_RATE_TYPE_LEGACY = 0, + QCA_WLAN_VENDOR_DATA_RATE_TYPE_MCS = 1, +}; + +/** + * enum qca_wlan_vendor_attr_adjust_tx_power_rate - Definition + * of data rate related attributes which is used inside nested attribute + * %QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CHAIN_RATE_CONFIG. + * + * @QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_RATE_TYPE: u8 data rate type. + * For this attribute, valid values are enumerated in enum + * %qca_wlan_vendor_data_rate_type. + * + * @QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_RATE_VALUE: u8 value. + * This attribute value is interpreted according to the value of attribute + * %QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_RATE_TYPE. For legacy config + * type, this attribute value is defined in the units of 0.5 Mbps. + * For non legacy config type, this attribute carries the MCS index number. + * + * @QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_RATE_POWER_VALUE: u8 value in dBm. + * Usually the target computes a final transmit power that is the maximum + * power level that doesn't exceed the limits enforced by various sources + * like chip-specific conformance test limits (CTL), Specific Absorption + * Rate (SAR), Transmit Power Control (TPC), wiphy-specific limits, STA-specific + * limits, channel avoidance limits, Automated Frequency Coordination (AFC), + * and others. In some cases it may be desirable to use a power level that is + * lower than the maximum power level allowed by all of these limits, so this + * attribute provides an additional limit that can be used to reduce the + * transmit power level. + * + */ +enum qca_wlan_vendor_attr_adjust_tx_power_rate { + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_RATE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_RATE_TYPE = 1, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_RATE_VALUE = 2, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_RATE_POWER_VALUE = 3, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_adjust_tx_power_chain_config - Definition + * of chain related attributes which is used inside nested attribute + * %QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_CHAIN_CONFIG. + * + * @QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CHAIN_INDEX: u8 value. + * Represents a particular chain for which transmit power adjustment needed. + * + * @QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CHAIN_RATE_CONFIG: A nested + * attribute containing data rate related information to adjust transmit + * power. The attributes used inside this nested attributes are defined in + * enum qca_wlan_vendor_attr_adjust_tx_power_rate. + */ +enum qca_wlan_vendor_attr_adjust_tx_power_chain_config { + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CHAIN_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CHAIN_INDEX = 1, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CHAIN_RATE_CONFIG = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CHAIN_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CHAIN_MAX = + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_CHAIN_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_adjust_tx_power_band_config - Definition + * of band related attributes which is used inside nested attribute + * %QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_CONFIG. + * + * @QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_INDEX: u8 value to + * indicate band for which configuration applies. Valid values are enumerated + * in enum %nl80211_band. + * + * @QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_CHAIN_CONFIG: A nested + * attribute containing per chain related information to adjust transmit + * power. The attributes used inside this nested attribute are defined in + * enum qca_wlan_vendor_attr_adjust_tx_power_chain_config. + * + */ +enum qca_wlan_vendor_attr_adjust_tx_power_band_config { + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_INDEX = 1, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_CHAIN_CONFIG = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_MAX = + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_adjust_tx_power - Definition of attributes + * for %QCA_NL80211_VENDOR_SUBCMD_ADJUST_TX_POWER subcommand. + * + * @QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_CONFIG: A nested attribute + * containing per band related information to adjust transmit power. + * The attributes used inside this nested attributes are defined in + * enum qca_wlan_vendor_attr_adjust_tx_power_band_config. + */ +enum qca_wlan_vendor_attr_adjust_tx_power { + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_BAND_CONFIG = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_MAX = + QCA_WLAN_VENDOR_ATTR_ADJUST_TX_POWER_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_spectral_data_transport_mode - Attribute + * values for QCA_WLAN_VENDOR_ATTR_SPECTRAL_DATA_TRANSPORT_MODE. + * + * @QCA_WLAN_VENDOR_SPECTRAL_DATA_TRANSPORT_NETLINK: Use netlink to + * send spectral data to userspace applications. + * @QCA_WLAN_VENDOR_SPECTRAL_DATA_TRANSPORT_RELAY: Use relay interface + * to send spectral data to userspace applications. + */ +enum qca_wlan_vendor_spectral_data_transport_mode { + QCA_WLAN_VENDOR_SPECTRAL_DATA_TRANSPORT_NETLINK = 0, + QCA_WLAN_VENDOR_SPECTRAL_DATA_TRANSPORT_RELAY = 1, +}; + +/* enum qca_wlan_vendor_spectral_scan_complete_status - Attribute + * values for QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETE_STATUS to + * indicate the completion status for a spectral scan. + * + * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_COMPLETE_STATUS_SUCCESSFUL: + * Indicates a successful completion of the scan. + * + * @QCA_WLAN_VENDOR_SPECTRAL_SCAN_COMPLETE_STATUS_TIMEOUT: Indicates + * a timeout has occured while processing the spectral reports. + */ +enum qca_wlan_vendor_spectral_scan_complete_status { + QCA_WLAN_VENDOR_SPECTRAL_SCAN_COMPLETE_STATUS_SUCCESSFUL = 0, + QCA_WLAN_VENDOR_SPECTRAL_SCAN_COMPLETE_STATUS_TIMEOUT = 1, +}; + +/* enum qca_wlan_vendor_attr_spectral_scan_complete - Definition of + * attributes for @QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_COMPLETE + * to indicate scan status and samples received from hardware. + * + * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETE_INVALID: Invalid attribute + * + * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETE_STATUS: u32 attribute. + * Indicates completion status, either the scan is successful or a timeout + * is issued by the driver. + * See enum qca_wlan_vendor_spectral_scan_complete_status. + * + * @QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETE_RECEIVED_SAMPLES: u32 + * attribute. Number of spectral samples received after the scan has started. + */ +enum qca_wlan_vendor_attr_spectral_scan_complete { + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETE_STATUS = 1, + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETE_RECEIVED_SAMPLES = 2, + + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETE_MAX = + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COMPLETE_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_async_get_station_attr - Attribute values for + * %QCA_NL80211_VENDOR_SUBCMD_ASYNC_GET_STATION command. + * + * @QCA_WLAN_VENDOR_ATTR_ASYNC_GET_STATION_CONFIG: 8-bit unsigned value to + * configure the driver to enable/disable reporting + * %QCA_NL80211_VENDOR_SUBCMD_ASYNC_GET_STATION events. 1-Enable, 0-Disable. + * This is required in a command. + * + * @QCA_WLAN_VENDOR_ATTR_ASYNC_GET_STATION_RESPONSE: Nested attribute. This is + * required in %QCA_NL80211_VENDOR_SUBCMD_ASYNC_GET_STATION event. + * This attribute is nested with the station MAC address in %NL80211_ATTR_MAC + * and the station information in %NL80211_ATTR_STA_INFO nested attribute, see + * enum nl80211_sta_info. + */ +enum qca_wlan_vendor_async_get_station_attr { + QCA_WLAN_VENDOR_ATTR_ASYNC_GET_STATION_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ASYNC_GET_STATION_CONFIG = 1, + QCA_WLAN_VENDOR_ATTR_ASYNC_GET_STATION_RESPONSE = 2, + + QCA_WLAN_VENDOR_ATTR_ASYNC_GET_STATION_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ASYNC_GET_STATION_MAX = + QCA_WLAN_VENDOR_ATTR_ASYNC_GET_STATION_AFTER_LAST - 1, +}; + +/* enum qca_wlan_vendor_ap_suspend_state - Attribute values for + * QCA_WLAN_VENDOR_ATTR_AP_SUSPEND_STATE. + * + * @QCA_WLAN_VENDOR_AP_SUSPEND_STATE_DISABLE: Disable suspend state. When used + * with a command, the driver resumes AP with the same configuration that was + * applied earlier and starts all TX/RX operations. When used in an event, + * indicates the AP interface resumed. + * + * @QCA_WLAN_VENDOR_AP_SUSPEND_STATE_ENABLE: Enable suspend state. In this + * mode, all associated STAs are disconnected and TX/RX is stopped. While an AP + * is in this state, it allows only %QCA_WLAN_VENDOR_AP_SUSPEND_STATE_DISABLE + * or AP stop/teardown operations. When used in an event, indicates the AP + * interface suspended. + */ +enum qca_wlan_vendor_ap_suspend_state { + QCA_WLAN_VENDOR_AP_SUSPEND_STATE_DISABLE = 0, + QCA_WLAN_VENDOR_AP_SUSPEND_STATE_ENABLE = 1, +}; + +/* enum qca_wlan_vendor_attr_ap_suspend - Definition of attributes for + * @QCA_NL80211_VENDOR_SUBCMD_AP_SUSPEND to configure/notify the suspend state. + * + * @QCA_WLAN_VENDOR_ATTR_AP_SUSPEND_STATE: u8 attribute to configure/notify + * suspend state defined in enum qca_wlan_vendor_ap_suspend_state. + */ +enum qca_wlan_vendor_attr_ap_suspend { + QCA_WLAN_VENDOR_ATTR_AP_SUSPEND_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_AP_SUSPEND_STATE = 1, + + QCA_WLAN_VENDOR_ATTR_AP_SUSPEND_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_AP_SUSPEND_MAX = + QCA_WLAN_VENDOR_ATTR_AP_SUSPEND_AFTER_LAST - 1, +}; + +/** + * enum qca_traffic_type - Traffic types into which the flows can be classified. + * @QCA_TRAFFIC_TYPE_STREAMING: Traffic type is streaming + * @QCA_TRAFFIC_TYPE_GAMING: Traffic type is gaming + * @QCA_TRAFFIC_TYPE_VOICE_CALL: Traffic type is a voice call + * @QCA_TRAFFIC_TYPE_VIDEO_CALL: Traffic type is a video call + * @QCA_TRAFFIC_TYPE_SCREEN_SHARE: Traffic type is screen share + * @QCA_TRAFFIC_TYPE_UNKNOWN: Traffic type is unknown + * @QCA_TRAFFIC_TYPE_INVALID: Invalid traffic type + */ +enum qca_traffic_type { + QCA_TRAFFIC_TYPE_STREAMING = 0, + QCA_TRAFFIC_TYPE_GAMING = 1, + QCA_TRAFFIC_TYPE_VOICE_CALL = 2, + QCA_TRAFFIC_TYPE_VIDEO_CALL = 3, + QCA_TRAFFIC_TYPE_SCREEN_SHARE = 4, + QCA_TRAFFIC_TYPE_UNKNOWN = 5, + QCA_TRAFFIC_TYPE_INVALID = 6, +}; + +/** + * enum qca_wlan_vendor_flow_tuple_proto - Definition of the values to specify + * the flow tuple protocol in QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_PROTOCOL. + * + * @QCA_WLAN_VENDOR_FLOW_TUPLE_PROTO_UDP: UDP flow + * + * @QCA_WLAN_VENDOR_FLOW_TUPLE_PROTO_TCP: TCP flow + */ +enum qca_wlan_vendor_flow_tuple_proto { + QCA_WLAN_VENDOR_FLOW_TUPLE_PROTO_UDP = 0, + QCA_WLAN_VENDOR_FLOW_TUPLE_PROTO_TCP = 1, +}; + +/** + * enum qca_wlan_vendor_attr_flow_tuple - Definition of attributes to specify a + * flow tuple. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV4_SRC_ADDR: Optional u32 attribute + * indicates the source IPv4 address (in network byte order). + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV4_DST_ADDR: Optional u32 attribute + * indicates the destination IPv4 address (in network byte order). + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV6_SRC_ADDR: Optional NLA_BINARY + * attribute of 16 bytes length that indicates the source IPv6 address + * (in network byte order) for a flow. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV6_DST_ADDR: Optional NLA_BINARY + * attribute of 16 bytes length that indicates the destination IPv6 address + * (in network byte order) for a flow. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_SRC_PORT: Mandatory u16 attribute indicates + * the TCP/UDP source port. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_DST_PORT: Mandatory u16 attribute indicates + * the TCP/UDP destination port. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_PROTOCOL: Mandatory u8 attribute indicates + * the flow protocol. Uses the enum qca_wlan_vendor_flow_tuple_proto. + * + * IPv4 flows have to specify @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV4_SRC_ADDR + * and @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV4_DST_ADDR. + * IPv6 flows have to specify @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV6_SRC_ADDR + * and @QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV6_DST_ADDR. + */ +enum qca_wlan_vendor_attr_flow_tuple { + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV4_SRC_ADDR = 1, + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV4_DST_ADDR = 2, + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV6_SRC_ADDR = 3, + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_IPV6_DST_ADDR = 4, + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_SRC_PORT = 5, + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_DST_PORT = 6, + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_PROTOCOL = 7, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_LAST, + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_MAX = + QCA_WLAN_VENDOR_ATTR_FLOW_TUPLE_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_txrx_stats - Definition of attributes to specify + * TX/RX sample for one window. + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_STATS_NUM_BYTES: Mandatory u64 attribute indicates + * the total number of uplink/downlink bytes within the sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_STATS_NUM_PKTS: Mandatory u32 attribute indicates + * the total number of packets (uplink/downlink) within the sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_STATS_PKT_SIZE_MIN: Mandatory u32 attribute + * indicates the minimum uplink/downlink packet size (in bytes) during the + * sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_STATS_PKT_SIZE_MAX: Mandatory u32 attribute + * indicates the maximum uplink/downlink packet size (in bytes) during the + * sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_STATS_PKT_IAT_MIN: Mandatory u64 attribute + * indicates the minimum uplink/downlink packet IAT (inter-arrival time) + * in microseconds, during the sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_STATS_PKT_IAT_MAX: Mandatory u64 attribute + * indicates the maximum uplink/downlink packet IAT (inter-arrival time) + * in microseconds, during the sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_STATS_PKT_IAT_SUM: Mandatory u64 attribute + * indicates the sum of all the values of uplink/downlink packet IAT + * (inter-arrival time) in microseconds, during the sampling window. + * This attribute is used to calculate the mean packet (inter-arrival time) + * during the sampling window. + */ +enum qca_wlan_vendor_attr_txrx_stats { + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_NUM_BYTES = 1, + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_NUM_PKTS = 2, + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_PKT_SIZE_MIN = 3, + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_PKT_SIZE_MAX = 4, + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_PKT_IAT_MIN = 5, + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_PKT_IAT_MAX = 6, + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_PKT_IAT_SUM = 7, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_LAST, + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_TXRX_STATS_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_txrx_samples_windows - Definition of attributes + * to specify the TX/RX statistics collected in a sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS_WINDOW_SIZE: Mandatory u32 + * attribute indicates window size for packet TX/RX sampling (in milliseconds). + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS_UL_STATS: Mandatory nested + * attribute containing the uplink TX/RX packet statistics for a flow. Uses the + * enum qca_wlan_vendor_attr_txrx_stats. + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS_DL_STATS: Mandatory nested + * attribute containing the downlink TX/RX packet statistics for a flow. Uses + * the enum qca_wlan_vendor_attr_txrx_stats. + */ +enum qca_wlan_vendor_attr_txrx_samples_windows { + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS_WINDOW_SIZE = 1, + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS_UL_STATS = 2, + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS_DL_STATS = 3, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS_LAST, + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS_MAX = + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_txrx_samples - Definition of attributes to specify + * a TX/RX sample. + * + * @QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS: Mandatory array of nested + * attributes that indicates the TX/RX samples in multiple overlapping windows. + * This uses the attributes defined by + * enum qca_wlan_vendor_attr_txrx_samples_windows. + */ +enum qca_wlan_vendor_attr_txrx_samples { + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_WINDOWS = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_LAST, + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_MAX = + QCA_WLAN_VENDOR_ATTR_TXRX_SAMPLES_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_burst_stats - Definition of attribute to specify + * burst statistics. + * + * @QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_DURATION_MIN: Mandatory u32 attribute + * indicates minimum burst duration (in milliseconds) during the sampling + * window. + * + * @QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_DURATION_MAX: Mandatory u32 attribute + * indicates maximum burst duration (in milliseconds) during the sampling + * window. + * + * @QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_DURATION_SUM: Mandatory u64 attribute + * indicates the sum of all the values of burst duration (in milliseconds) + * during the sampling window. This attribute is used to calculate the mean + * burst duration (in milliseconds) during the sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_SIZE_MIN: Mandatory u64 attribute + * indicates minimum burst size (in bytes) during the sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_SIZE_MAX: Mandatory u64 attribute + * indicates maximum burst size (in bytes) during the sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_SIZE_SUM: Mandatory u64 attribute + * indicates the sum of all the values of burst size (in bytes) during the + * sampling window. This attribute is used to calculate the mean burst size + * (in bytes) during the sampling window. + * + * @QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_COUNT: Mandatory u32 attribute + * indicates the number of bursts during the sampling window. + */ +enum qca_wlan_vendor_attr_burst_stats { + QCA_WLAN_VENDOR_ATTR_BURST_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_DURATION_MIN = 1, + QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_DURATION_MAX = 2, + QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_DURATION_SUM = 3, + QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_SIZE_MIN = 4, + QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_SIZE_MAX = 5, + QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_SIZE_SUM = 6, + QCA_WLAN_VENDOR_ATTR_BURST_STATS_BURST_COUNT = 7, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_BURST_STATS_LAST, + QCA_WLAN_VENDOR_ATTR_BURST_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_BURST_STATS_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_burst_sample - Definition of attributes to specify + * a burst sample. + * + * @QCA_WLAN_VENDOR_ATTR_BURST_SAMPLES_TXRX_STATS: Mandatory nested attribute + * indicates the uplink and downlink packet statistics collected in a + * sampling window, containing attributes defined in + * enum qca_wlan_vendor_attr_txrx_samples_windows. + * + * @QCA_WLAN_VENDOR_ATTR_BURST_SAMPLES_UL_BURST_STATS: Optional nested attribute + * indicates the uplink burst stats, containing attributes defined in + * enum qca_wlan_vendor_attr_burst_stats. + * + * @QCA_WLAN_VENDOR_ATTR_BURST_SAMPLES_DL_BURST_STATS: Optional nested attribute + * indicates the downlink burst stats, containing attributes defined in + * enum qca_wlan_vendor_attr_burst_stats. + */ +enum qca_wlan_vendor_attr_burst_sample { + QCA_WLAN_VENDOR_ATTR_BURST_SAMPLES_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_BURST_SAMPLES_TXRX_STATS = 1, + QCA_WLAN_VENDOR_ATTR_BURST_SAMPLES_UL_BURST_STATS = 2, + QCA_WLAN_VENDOR_ATTR_BURST_SAMPLES_DL_BURST_STATS = 3, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_BURST_SAMPLES_LAST, + QCA_WLAN_VENDOR_ATTR_BURST_SAMPLES_MAX = + QCA_WLAN_VENDOR_ATTR_BURST_SAMPLES_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_flow_stats - Definition of attribute used by + * %QCA_NL80211_VENDOR_SUBCMD_CLASSIFIED_FLOW_REPORT and + * %QCA_NL80211_VENDOR_SUBCMD_FLOW_STATS. + * + * Presence of one of the attributes + * @QCA_WLAN_VENDOR_ATTR_FLOW_STATS_TXRX_SAMPLES and + * @QCA_WLAN_VENDOR_ATTR_FLOW_STATS_BURST_SAMPLES is mandatory. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_STATS_FLOW_TUPLE: Mandatory nested attribute + * containing the flow tuple of the flow for which the statistics are being + * reported. + * Uses the attributes defined by enum qca_wlan_vendor_attr_flow_tuple. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_STATS_TRAFFIC_TYPE: Optional u8 attribute + * indicates the traffic type classified for this flow tuple. Uses the + * enum qca_traffic_type values. + * This attribute is mandatory for the command + * @QCA_NL80211_VENDOR_SUBCMD_CLASSIFIED_FLOW_REPORT. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_STATS_TXRX_SAMPLES: Optional nested attribute + * containing nested array of TX/RX samples defined in + * enum qca_wlan_vendor_attr_txrx_samples. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_STATS_BURST_SAMPLES: Optional nested attribute + * indicates the packet burst statistics for a flow. Uses attributes defined by + * enum qca_wlan_vendor_attr_burst_sample. + */ +enum qca_wlan_vendor_attr_flow_stats { + QCA_WLAN_VENDOR_ATTR_FLOW_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_FLOW_STATS_FLOW_TUPLE = 1, + QCA_WLAN_VENDOR_ATTR_FLOW_STATS_TRAFFIC_TYPE = 2, + QCA_WLAN_VENDOR_ATTR_FLOW_STATS_TXRX_SAMPLES = 3, + QCA_WLAN_VENDOR_ATTR_FLOW_STATS_BURST_SAMPLES = 4, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_FLOW_STATS_LAST, + QCA_WLAN_VENDOR_ATTR_FLOW_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_FLOW_STATS_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_flow_classify_result - Definition of attributes to + * specify the flow classification result. This enum is used by + * @QCA_NL80211_VENDOR_SUBCMD_FLOW_CLASSIFY_RESULT. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_CLASSIFY_RESULT_FLOW_TUPLE: Mandatory nested + * attribute containing attributes defined by + * enum qca_wlan_vendor_attr_flow_tuple. + * + * @QCA_WLAN_VENDOR_ATTR_FLOW_CLASSIFY_RESULT_TRAFFIC_TYPE: Mandatory u8 + * attribute indicates the traffic type learned for this flow tuple. Uses the + * enum qca_traffic_type values. + */ +enum qca_wlan_vendor_attr_flow_classify_result { + QCA_WLAN_VENDOR_ATTR_FLOW_CLASSIFY_RESULT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_FLOW_CLASSIFY_RESULT_FLOW_TUPLE = 1, + QCA_WLAN_VENDOR_ATTR_FLOW_CLASSIFY_RESULT_TRAFFIC_TYPE = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_FLOW_CLASSIFY_RESULT_LAST, + QCA_WLAN_VENDOR_ATTR_FLOW_CLASSIFY_RESULT_MAX = + QCA_WLAN_VENDOR_ATTR_FLOW_CLASSIFY_RESULT_LAST - 1, +}; + +/** + * enum qca_async_stats_sub_module - The statistics type used in async + * statistics policy. + * Used by @QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_STATS_TYPE. + * + * @QCA_ASYNC_STATS_TYPE_POWERSAVE: Wi-Fi powersave statistics + * + * @QCA_ASYNC_STATS_TYPE_FLOW_STATS: Flow statistics + * + * @QCA_ASYNC_STATS_TYPE_CLASSIFIED_FLOW_STATS: Classified flow statistics + */ +enum qca_async_stats_type { + QCA_ASYNC_STATS_TYPE_POWERSAVE = 0, + QCA_ASYNC_STATS_TYPE_FLOW_STATS = 1, + QCA_ASYNC_STATS_TYPE_CLASSIFIED_FLOW_STATS = 2, +}; + +/** + * enum qca_async_stats_action - ASYNC statistics action. Used by + * @QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_ACTION. + * + * @QCA_ASYNC_STATS_ACTION_START: Start indication for async statistics + * collection. + * @QCA_ASYNC_STATS_ACTION_STOP: Stop indication for async statistics + * collection. + */ +enum qca_async_stats_action { + QCA_ASYNC_STATS_ACTION_START = 0, + QCA_ASYNC_STATS_ACTION_STOP = 1, +}; + +/** + * enum qca_wlan_vendor_attr_async_stats_policy - Definition of attributes to + * specify the ASYNC statistics policy. This enum is used by + * @QCA_NL80211_VENDOR_SUBCMD_ASYNC_STATS_POLICY. + * + * @QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_STATS_TYPE: Mandatory u8 + * attribute indicates the statistics type for which the async statistics policy + * needs to be applied by the driver. Uses the enum qca_async_stats_type values. + * + * @QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_ACTION: Mandatory u8 attribute + * indicates the action as part of this policy. + * Uses the enum qca_async_stats_action values. + * + * @QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_STATS_PERIODICITY: Optional u32 + * attribute indicates the periodicity (in milliseconds) for the statistics to + * be reported. This attribute is mandatory for QCA_ASYNC_STATS_TYPE_POWERSAVE. + */ +enum qca_wlan_vendor_attr_async_stats_policy { + QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_STATS_TYPE = 1, + QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_ACTION = 2, + QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_STATS_PERIODICITY = 3, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_LAST, + QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_MAX = + QCA_WLAN_VENDOR_ATTR_ASYNC_STATS_POLICY_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_nss_pkt - Attributes used by + * %QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_NSS_PKT_COUNT. + * + * @QCA_WLAN_VENDOR_ATTR_NSS_PKT_NSS_VALUE: u8 attribute. This + * represents the number of spatial streams. + * + * @QCA_WLAN_VENDOR_ATTR_NSS_PKT_TX_PACKET_COUNT: u64 attribute. This + * represents the number of MSDU packets transmitted with the number of spatial + * streams specified in %QCA_WLAN_VENDOR_ATTR_NSS_PKT_NSS_VALUE. + * + * @QCA_WLAN_VENDOR_ATTR_NSS_PKT_RX_PACKET_COUNT: u64 attribute. This + * represents the number of MSDU packets received with the number of spatial + * streams specified in %QCA_WLAN_VENDOR_ATTR_NSS_PKT_NSS_VALUE. + */ +enum qca_wlan_vendor_attr_nss_pkt { + QCA_WLAN_VENDOR_ATTR_NSS_PKT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_NSS_PKT_NSS_VALUE = 1, + QCA_WLAN_VENDOR_ATTR_NSS_PKT_TX_PACKET_COUNT = 2, + QCA_WLAN_VENDOR_ATTR_NSS_PKT_RX_PACKET_COUNT = 3, + + QCA_WLAN_VENDOR_ATTR_NSS_PKT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_NSS_PKT_MAX = + QCA_WLAN_VENDOR_ATTR_NSS_PKT_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_intf_offload_type - Definition of available values for + * QCA_WLAN_VENDOR_ATTR_CONFIG_INTF_OFFLOAD_TYPE to specify the offload path for + * packets handled through a network device. + * + * There are three offload paths possible for handling packet forwarding between + * Ethernet and Wi-Fi network, and which path to use can be configured on a per + * netdevice level based on use case. Userspace can choose different options + * based on use cases like performance requirements, traffic control features + * and limitations provided in each option. + * + * @QCA_WLAN_VENDOR_ATTR_INTF_OFFLOAD_TYPE_NONE: No acceleration configured. + * Packets are processed through the Linux kernel networking stack. + * + * @QCA_WLAN_VENDOR_ATTR_INTF_OFFLOAD_TYPE_SFE: Packets are processed through + * the shortcut forwarding engine (SFE) to bypass the Linux networking stack + * for improved throughput performance. This option is applicable for AP, STA, + * and Mesh mode and available for all radio designs. From the performance + * aspect, this option consumes more CPU compared to the other two options. + * Linux traffic control can be further applied with this option to have more + * control on the traffic flows. + * + * @QCA_WLAN_VENDOR_ATTR_INTF_OFFLOAD_TYPE_ACTIVE_VP: Packets are processed + * through both hardware and software in this case. Packet classification is + * done by the hardware and then the packets are delivered to software along + * with classification results as meta data. Software can choose to do more + * classification/QoS based on use cases. This is applicable for AP, STA, and + * Mesh modes and this is available for all radio designs. From the performance + * aspect, this option consumes relatively less CPU compared to the SFE option + * above. Linux traffic control rules cannot be applied with this option. + * + * @QCA_WLAN_VENDOR_ATTR_INTF_OFFLOAD_TYPE_PPE_DS: Packets are processed through + * special hardware (Direct Switch) rings which can directly forward the packets + * between Ethernet hardware and Wi-Fi hardware with very little software + * involvement. This is applicable only for AP and STA modes; not applicable + * for Mesh mode. From the performance aspect, this option consumes very much + * less CPU compared to the other options. Linux traffic control rules cannot be + * applied when this option is used. This option is applicable only for + * specific radio designs. When this option is not available, the default option + * (SFE) would be configured. + */ +enum qca_wlan_intf_offload_type { + QCA_WLAN_INTF_OFFLOAD_TYPE_NONE = 0, + QCA_WLAN_INTF_OFFLOAD_TYPE_SFE = 1, + QCA_WLAN_INTF_OFFLOAD_TYPE_ACTIVE_VP = 2, + QCA_WLAN_INTF_OFFLOAD_TYPE_PPE_DS = 3, }; #endif /* QCA_VENDOR_H */ diff --git a/wpa_supplicant-2.9_standard/src/common/sae.c b/wpa_supplicant-2.9_standard/src/common/sae.c index 7687d21ae373a22befad8f374177959cacbab80e..2bc713bec4ebd1368ae656fbd067093e8d37594b 100644 --- a/wpa_supplicant-2.9_standard/src/common/sae.c +++ b/wpa_supplicant-2.9_standard/src/common/sae.c @@ -458,7 +458,7 @@ static int sae_derive_pwe_ffc(struct sae_data *sae, const u8 *addr1, * mask */ u8 mask; struct crypto_bignum *pwe; - size_t prime_len = sae->tmp->prime_len * 8; + size_t prime_len = sae->tmp->prime_len; u8 *pwe_buf; crypto_bignum_deinit(sae->tmp->pwe_ffc, 1); @@ -603,9 +603,9 @@ static int sswu_curve_param(int group, int *z) case 30: *z = 7; return 0; + default: + return -1; } - - return -1; } @@ -1606,7 +1606,9 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k) * (commit-scalar + peer-commit-scalar) mod r part as a bit string by * zero padding it from left to the length of the order (in full * octets). */ - crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len); + if (crypto_bignum_to_bin(tmp, val, sizeof(val), + sae->tmp->order_len) < 0) + goto fail; wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN); #ifdef CONFIG_SAE_PK @@ -1967,8 +1969,10 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 **pos, crypto_ec_point_deinit(sae->tmp->peer_commit_element_ecc, 0); sae->tmp->peer_commit_element_ecc = crypto_ec_point_from_bin(sae->tmp->ec, *pos); - if (sae->tmp->peer_commit_element_ecc == NULL) + if (!sae->tmp->peer_commit_element_ecc) { + wpa_printf(MSG_DEBUG, "SAE: Peer element is not a valid point"); return WLAN_STATUS_UNSPECIFIED_FAILURE; + } if (!crypto_ec_point_is_on_curve(sae->tmp->ec, sae->tmp->peer_commit_element_ecc)) { @@ -2099,8 +2103,11 @@ static int sae_parse_rejected_groups(struct sae_data *sae, wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame", *pos, end - *pos); - if (!sae_is_rejected_groups_elem(*pos, end)) + if (!sae_is_rejected_groups_elem(*pos, end)) { + wpabuf_free(sae->tmp->peer_rejected_groups); + sae->tmp->peer_rejected_groups = NULL; return WLAN_STATUS_SUCCESS; + } epos = *pos; epos++; /* skip IE type */ @@ -2109,6 +2116,12 @@ static int sae_parse_rejected_groups(struct sae_data *sae, return WLAN_STATUS_UNSPECIFIED_FAILURE; epos++; /* skip ext ID */ len--; + if (len & 1) { + wpa_printf(MSG_DEBUG, + "SAE: Invalid length of the Rejected Groups element payload: %u", + len); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } wpabuf_free(sae->tmp->peer_rejected_groups); sae->tmp->peer_rejected_groups = wpabuf_alloc(len); @@ -2153,11 +2166,7 @@ static int sae_parse_akm_suite_selector(struct sae_data *sae, 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 -#ifdef CONFIG_MLD_PATCH - , int *ie_offset -#endif - ) + int h2e, int *ie_offset) { const u8 *pos = data, *end = data + len; u16 res; @@ -2182,10 +2191,9 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, res = sae_parse_commit_element(sae, &pos, end); if (res != WLAN_STATUS_SUCCESS) return res; -#ifdef CONFIG_MLD_PATCH + if (ie_offset) *ie_offset = pos - data; -#endif /* Optional Password Identifier element */ res = sae_parse_password_identifier(sae, &pos, end); @@ -2197,6 +2205,9 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, res = sae_parse_rejected_groups(sae, &pos, end); if (res != WLAN_STATUS_SUCCESS) return res; + } else { + wpabuf_free(sae->tmp->peer_rejected_groups); + sae->tmp->peer_rejected_groups = NULL; } /* Optional Anti-Clogging Token Container element */ @@ -2223,7 +2234,9 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, if (sae->peer_akm_suite_selector == RSN_AUTH_KEY_MGMT_SAE_EXT_KEY) sae->akmp = WPA_KEY_MGMT_SAE_EXT_KEY; - + else if (sae->peer_akm_suite_selector == + RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY) + sae->akmp = WPA_KEY_MGMT_FT_SAE_EXT_KEY; } /* @@ -2378,11 +2391,8 @@ 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 -#ifdef CONFIG_MLD_PATCH - , int *ie_offset -#endif -) +int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len, + int *ie_offset) { u8 verifier[SAE_MAX_HASH_LEN]; size_t hash_len; @@ -2438,11 +2448,10 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len return -1; #endif /* CONFIG_SAE_PK */ -#ifdef CONFIG_MLD_PATCH /* 2 bytes are for send-confirm, then the hash, followed by IEs */ if (ie_offset) *ie_offset = 2 + hash_len; -#endif + return 0; } diff --git a/wpa_supplicant-2.9_standard/src/common/sae.h b/wpa_supplicant-2.9_standard/src/common/sae.h index 1f435f61f7eb449da92ac0fc03256d678df44b5b..a353aa8da357b6214506e64a4938e295020df005 100644 --- a/wpa_supplicant-2.9_standard/src/common/sae.h +++ b/wpa_supplicant-2.9_standard/src/common/sae.h @@ -82,6 +82,8 @@ struct sae_temporary_data { bool omit_pk_elem; #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_SAE_PK */ + + struct os_reltime disabled_until; }; struct sae_pt { @@ -136,17 +138,10 @@ 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 -#ifdef CONFIG_MLD_PATCH - , int *ie_offset -#endif - ); + int h2e, int *ie_offset); 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 -#ifdef CONFIG_MLD_PATCH - , int *ie_offset -#endif - ); +int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len, + int *ie_offset); 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); diff --git a/wpa_supplicant-2.9_standard/src/common/version.h b/wpa_supplicant-2.9_standard/src/common/version.h index 7502f58e0b874ec327635f63d63a738e26e3fb65..5b735984983a3974e7be2670465710a2f9eb8984 100644 --- a/wpa_supplicant-2.9_standard/src/common/version.h +++ b/wpa_supplicant-2.9_standard/src/common/version.h @@ -9,6 +9,6 @@ #define GIT_VERSION_STR_POSTFIX "" #endif /* GIT_VERSION_STR_POSTFIX */ -#define VERSION_STR "2.10" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX +#define VERSION_STR "2.11" VERSION_STR_POSTFIX GIT_VERSION_STR_POSTFIX #endif /* VERSION_H */ diff --git a/wpa_supplicant-2.9_standard/src/common/wpa_common.c b/wpa_supplicant-2.9_standard/src/common/wpa_common.c index 213fdda8d2291aac142f069f51679987f0063bf1..ddd40c36921072b2f40866a89ea4ba6ca5096339 100644 --- a/wpa_supplicant-2.9_standard/src/common/wpa_common.c +++ b/wpa_supplicant-2.9_standard/src/common/wpa_common.c @@ -29,6 +29,7 @@ static unsigned int wpa_kck_len(int akmp, size_t pmk_len) { switch (akmp) { case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: + case WPA_KEY_MGMT_IEEE8021X_SHA384: case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: return 24; case WPA_KEY_MGMT_FILS_SHA256: @@ -41,6 +42,7 @@ static unsigned int wpa_kck_len(int akmp, size_t pmk_len) case WPA_KEY_MGMT_OWE: return pmk_len / 2; case WPA_KEY_MGMT_SAE_EXT_KEY: + case WPA_KEY_MGMT_FT_SAE_EXT_KEY: return pmk_len / 2; default: return 16; @@ -73,12 +75,14 @@ static unsigned int wpa_kek_len(int akmp, size_t pmk_len) case WPA_KEY_MGMT_FILS_SHA256: case WPA_KEY_MGMT_FT_FILS_SHA256: case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: + case WPA_KEY_MGMT_IEEE8021X_SHA384: return 32; case WPA_KEY_MGMT_DPP: return pmk_len <= 32 ? 16 : 32; case WPA_KEY_MGMT_OWE: return pmk_len <= 32 ? 16 : 32; case WPA_KEY_MGMT_SAE_EXT_KEY: + case WPA_KEY_MGMT_FT_SAE_EXT_KEY: return pmk_len <= 32 ? 16 : 32; default: return 16; @@ -106,6 +110,7 @@ unsigned int wpa_mic_len(int akmp, size_t pmk_len) switch (akmp) { case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: + case WPA_KEY_MGMT_IEEE8021X_SHA384: return 24; case WPA_KEY_MGMT_FILS_SHA256: case WPA_KEY_MGMT_FILS_SHA384: @@ -117,6 +122,7 @@ unsigned int wpa_mic_len(int akmp, size_t pmk_len) case WPA_KEY_MGMT_OWE: return pmk_len / 2; case WPA_KEY_MGMT_SAE_EXT_KEY: + case WPA_KEY_MGMT_FT_SAE_EXT_KEY: return pmk_len / 2; default: return 16; @@ -135,6 +141,7 @@ int wpa_use_akm_defined(int akmp) akmp == WPA_KEY_MGMT_OWE || akmp == WPA_KEY_MGMT_DPP || akmp == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 || + akmp == WPA_KEY_MGMT_IEEE8021X_SHA384 || wpa_key_mgmt_sae(akmp) || wpa_key_mgmt_suite_b(akmp) || wpa_key_mgmt_fils(akmp); @@ -173,6 +180,7 @@ int wpa_use_aes_key_wrap(int akmp) return akmp == WPA_KEY_MGMT_OSEN || akmp == WPA_KEY_MGMT_OWE || akmp == WPA_KEY_MGMT_DPP || + akmp == WPA_KEY_MGMT_IEEE8021X_SHA384 || wpa_key_mgmt_ft(akmp) || wpa_key_mgmt_sha256(akmp) || wpa_key_mgmt_sae(akmp) || @@ -235,6 +243,7 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver, "WPA: EAPOL-Key MIC using AES-CMAC (AKM-defined - SAE)"); return omac1_aes_128(key, buf, len, mic); case WPA_KEY_MGMT_SAE_EXT_KEY: + case WPA_KEY_MGMT_FT_SAE_EXT_KEY: wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC using HMAC-SHA%u (AKM-defined - SAE-EXT-KEY)", (unsigned int) key_len * 8 * 2); @@ -330,15 +339,18 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver, os_memcpy(mic, hash, key_len); break; #endif /* CONFIG_DPP */ -#if defined(CONFIG_IEEE80211R) && defined(CONFIG_SHA384) +#ifdef CONFIG_SHA384 + case WPA_KEY_MGMT_IEEE8021X_SHA384: +#ifdef CONFIG_IEEE80211R case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: +#endif /* CONFIG_IEEE80211R */ wpa_printf(MSG_DEBUG, - "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - FT 802.1X SHA384)"); + "WPA: EAPOL-Key MIC using HMAC-SHA384 (AKM-defined - 802.1X SHA384)"); if (hmac_sha384(key, key_len, buf, len, hash)) return -1; os_memcpy(mic, hash, 24); break; -#endif /* CONFIG_IEEE80211R && CONFIG_SHA384 */ +#endif /* CONFIG_SHA384 */ default: wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key MIC algorithm not known (AKM-defined - akmp=0x%x)", @@ -453,14 +465,14 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, 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) +#ifdef CONFIG_SHA384 wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)"); if (sha384_prf(pmk, pmk_len, label, data, data_len, tmp, ptk_len) < 0) return -1; -#else /* CONFIG_SUITEB192 || CONFIG_FILS */ +#else /* CONFIG_SHA384 */ return -1; -#endif /* CONFIG_SUITEB192 || CONFIG_FILS */ +#endif /* CONFIG_SHA384 */ } else if (wpa_key_mgmt_sha256(akmp)) { wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)"); if (sha256_prf(pmk, pmk_len, label, data, data_len, @@ -882,20 +894,22 @@ int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce, #ifdef CONFIG_IEEE80211R -int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr, +int wpa_ft_mic(int key_mgmt, const u8 *kck, size_t kck_len, const u8 *sta_addr, const u8 *ap_addr, u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, const u8 *ftie, size_t ftie_len, const u8 *rsnie, size_t rsnie_len, const u8 *ric, size_t ric_len, const u8 *rsnxe, size_t rsnxe_len, + const struct wpabuf *extra, u8 *mic) { - const u8 *addr[10]; - size_t len[10]; + const u8 *addr[11]; + size_t len[11]; size_t i, num_elem = 0; - u8 zero_mic[24]; + u8 zero_mic[32]; size_t mic_len, fte_fixed_len; + int res; if (kck_len == 16) { mic_len = 16; @@ -903,6 +917,10 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr, } else if (kck_len == 24) { mic_len = 24; #endif /* CONFIG_SHA384 */ +#ifdef CONFIG_SHA512 + } else if (kck_len == 32) { + mic_len = 32; +#endif /* CONFIG_SHA512 */ } else { wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u", (unsigned int) kck_len); @@ -965,8 +983,25 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr, num_elem++; } + if (extra) { + addr[num_elem] = wpabuf_head(extra); + len[num_elem] = wpabuf_len(extra); + num_elem++; + } + for (i = 0; i < num_elem; i++) wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]); + res = -1; +#ifdef CONFIG_SHA512 + if (kck_len == 32) { + u8 hash[SHA512_MAC_LEN]; + + if (hmac_sha512_vector(kck, kck_len, num_elem, addr, len, hash)) + return -1; + os_memcpy(mic, hash, 32); + res = 0; + } +#endif /* CONFIG_SHA384 */ #ifdef CONFIG_SHA384 if (kck_len == 24) { u8 hash[SHA384_MAC_LEN]; @@ -974,26 +1009,32 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr, if (hmac_sha384_vector(kck, kck_len, num_elem, addr, len, hash)) return -1; os_memcpy(mic, hash, 24); + res = 0; } #endif /* CONFIG_SHA384 */ - if (kck_len == 16 && - omac1_aes_128_vector(kck, num_elem, addr, len, mic)) - return -1; + if (kck_len == 16 && key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) { + u8 hash[SHA256_MAC_LEN]; - return 0; + if (hmac_sha256_vector(kck, kck_len, num_elem, addr, len, hash)) + return -1; + os_memcpy(mic, hash, 16); + res = 0; + } + if (kck_len == 16 && key_mgmt != WPA_KEY_MGMT_FT_SAE_EXT_KEY && + omac1_aes_128_vector(kck, num_elem, addr, len, mic) == 0) + res = 0; + + return res; } static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, - struct wpa_ft_ies *parse, int use_sha384) + struct wpa_ft_ies *parse, const u8 *opt) { const u8 *end, *pos; + u8 link_id; - parse->ftie = ie; - parse->ftie_len = ie_len; - - pos = ie + (use_sha384 ? sizeof(struct rsn_ftie_sha384) : - sizeof(struct rsn_ftie)); + pos = opt; end = ie + ie_len; wpa_hexdump(MSG_DEBUG, "FT: Parse FTE subelements", pos, end - pos); @@ -1004,7 +1045,7 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, len = *pos++; if (len > end - pos) { wpa_printf(MSG_DEBUG, "FT: Truncated subelement"); - break; + return -1; } switch (id) { @@ -1016,8 +1057,11 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, return -1; } parse->r1kh_id = pos; + wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", + parse->r1kh_id, FT_R1KH_ID_LEN); break; case FTIE_SUBELEM_GTK: + wpa_printf(MSG_DEBUG, "FT: GTK"); parse->gtk = pos; parse->gtk_len = len; break; @@ -1030,8 +1074,11 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, } parse->r0kh_id = pos; parse->r0kh_id_len = len; + wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", + parse->r0kh_id, parse->r0kh_id_len); break; case FTIE_SUBELEM_IGTK: + wpa_printf(MSG_DEBUG, "FT: IGTK"); parse->igtk = pos; parse->igtk_len = len; break; @@ -1039,12 +1086,60 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, case FTIE_SUBELEM_OCI: parse->oci = pos; parse->oci_len = len; + wpa_hexdump(MSG_DEBUG, "FT: OCI", + parse->oci, parse->oci_len); break; #endif /* CONFIG_OCV */ case FTIE_SUBELEM_BIGTK: + wpa_printf(MSG_DEBUG, "FT: BIGTK"); parse->bigtk = pos; parse->bigtk_len = len; break; + case FTIE_SUBELEM_MLO_GTK: + if (len < 2 + 1 + 1 + 8) { + wpa_printf(MSG_DEBUG, + "FT: Too short MLO GTK in FTE"); + return -1; + } + link_id = pos[2] & 0x0f; + wpa_printf(MSG_DEBUG, "FT: MLO GTK (Link ID %u)", + link_id); + if (link_id >= MAX_NUM_MLD_LINKS) + break; + parse->valid_mlo_gtks |= BIT(link_id); + parse->mlo_gtk[link_id] = pos; + parse->mlo_gtk_len[link_id] = len; + break; + case FTIE_SUBELEM_MLO_IGTK: + if (len < 2 + 6 + 1 + 1) { + wpa_printf(MSG_DEBUG, + "FT: Too short MLO IGTK in FTE"); + return -1; + } + link_id = pos[2 + 6] & 0x0f; + wpa_printf(MSG_DEBUG, "FT: MLO IGTK (Link ID %u)", + link_id); + if (link_id >= MAX_NUM_MLD_LINKS) + break; + parse->valid_mlo_igtks |= BIT(link_id); + parse->mlo_igtk[link_id] = pos; + parse->mlo_igtk_len[link_id] = len; + break; + case FTIE_SUBELEM_MLO_BIGTK: + if (len < 2 + 6 + 1 + 1) { + wpa_printf(MSG_DEBUG, + "FT: Too short MLO BIGTK in FTE"); + return -1; + } + link_id = pos[2 + 6] & 0x0f; + wpa_printf(MSG_DEBUG, "FT: MLO BIGTK (Link ID %u)", + link_id); + if (link_id >= MAX_NUM_MLD_LINKS) + break; + parse->valid_mlo_bigtks |= BIT(link_id); + parse->mlo_bigtk[link_id] = pos; + parse->mlo_bigtk_len[link_id] = len; + break; default: wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id); break; @@ -1057,25 +1152,87 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, } -int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, - struct wpa_ft_ies *parse, int use_sha384) +static int wpa_ft_parse_fte(int key_mgmt, const u8 *ie, size_t len, + struct wpa_ft_ies *parse) +{ + size_t mic_len; + u8 mic_len_info; + const u8 *pos = ie; + const u8 *end = pos + len; + + wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control", pos, 2); + parse->fte_rsnxe_used = pos[0] & FTE_MIC_CTRL_RSNXE_USED; + mic_len_info = (pos[0] & FTE_MIC_CTRL_MIC_LEN_MASK) >> + FTE_MIC_CTRL_MIC_LEN_SHIFT; + parse->fte_elem_count = pos[1]; + pos += 2; + + if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) { + switch (mic_len_info) { + case FTE_MIC_LEN_16: + mic_len = 16; + break; + case FTE_MIC_LEN_24: + mic_len = 24; + break; + case FTE_MIC_LEN_32: + mic_len = 32; + break; + default: + wpa_printf(MSG_DEBUG, + "FT: Unknown MIC Length subfield value %u", + mic_len_info); + return -1; + } + } else { + mic_len = wpa_key_mgmt_sha384(key_mgmt) ? 24 : 16; + } + if (mic_len > (size_t) (end - pos)) { + wpa_printf(MSG_DEBUG, "FT: No room for %zu octet MIC in FTE", + mic_len); + return -1; + } + wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC", pos, mic_len); + parse->fte_mic = pos; + parse->fte_mic_len = mic_len; + pos += mic_len; + + if (2 * WPA_NONCE_LEN > end - pos) + return -1; + parse->fte_anonce = pos; + wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce", + parse->fte_anonce, WPA_NONCE_LEN); + pos += WPA_NONCE_LEN; + parse->fte_snonce = pos; + wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce", + parse->fte_snonce, WPA_NONCE_LEN); + pos += WPA_NONCE_LEN; + + return wpa_ft_parse_ftie(ie, len, parse, pos); +} + + +int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse, + int key_mgmt, bool reassoc_resp) { const u8 *end, *pos; struct wpa_ie_data data; int ret; - const struct rsn_ftie *ftie; int prot_ie_count = 0; - int update_use_sha384 = 0; - - if (use_sha384 < 0) { - use_sha384 = 0; - update_use_sha384 = 1; - } + const u8 *fte = NULL; + size_t fte_len = 0; + bool is_fte = false; + struct ieee802_11_elems elems; os_memset(parse, 0, sizeof(*parse)); if (ies == NULL) return 0; + if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed) { + wpa_printf(MSG_DEBUG, "FT: Failed to parse elements"); + goto fail; + } + pos = ies; end = ies + ies_len; while (end - pos >= 2) { @@ -1086,6 +1243,10 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, if (len > end - pos) break; + if (id != WLAN_EID_FAST_BSS_TRANSITION && + id != WLAN_EID_FRAGMENT) + is_fte = false; + switch (id) { case WLAN_EID_RSN: wpa_hexdump(MSG_DEBUG, "FT: RSNE", pos, len); @@ -1097,18 +1258,15 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, if (ret < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to parse " "RSN IE: %d", ret); - return -1; + goto fail; } parse->rsn_capab = data.capabilities; if (data.num_pmkid == 1 && data.pmkid) parse->rsn_pmkid = data.pmkid; parse->key_mgmt = data.key_mgmt; parse->pairwise_cipher = data.pairwise_cipher; - if (update_use_sha384) { - use_sha384 = - wpa_key_mgmt_sha384(parse->key_mgmt); - update_use_sha384 = 0; - } + if (!key_mgmt) + key_mgmt = parse->key_mgmt; break; case WLAN_EID_RSNX: wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len); @@ -1120,54 +1278,33 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, case WLAN_EID_MOBILITY_DOMAIN: wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len); if (len < sizeof(struct rsn_mdie)) - return -1; + goto fail; parse->mdie = pos; parse->mdie_len = len; break; case WLAN_EID_FAST_BSS_TRANSITION: wpa_hexdump(MSG_DEBUG, "FT: FTE", pos, len); - if (use_sha384) { - const struct rsn_ftie_sha384 *ftie_sha384; - - if (len < sizeof(*ftie_sha384)) - return -1; - ftie_sha384 = - (const struct rsn_ftie_sha384 *) pos; - wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control", - ftie_sha384->mic_control, 2); - wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC", - ftie_sha384->mic, - sizeof(ftie_sha384->mic)); - parse->fte_anonce = ftie_sha384->anonce; - wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce", - ftie_sha384->anonce, - WPA_NONCE_LEN); - parse->fte_snonce = ftie_sha384->snonce; - wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce", - ftie_sha384->snonce, - WPA_NONCE_LEN); - prot_ie_count = ftie_sha384->mic_control[1]; - if (wpa_ft_parse_ftie(pos, len, parse, 1) < 0) - return -1; - break; + /* The first two octets (MIC Control field) is in the + * same offset for all cases, but the second field (MIC) + * has variable length with three different values. + * In particular the FT-SAE-EXT-KEY is inconvinient to + * parse, so try to handle this in pieces instead of + * using the struct rsn_ftie* definitions. */ + + if (len < 2) + goto fail; + prot_ie_count = pos[1]; /* Element Count field in + * MIC Control */ + is_fte = true; + fte = pos; + fte_len = len; + break; + case WLAN_EID_FRAGMENT: + if (is_fte) { + wpa_hexdump(MSG_DEBUG, "FT: FTE fragment", + pos, len); + fte_len += 2 + len; } - - if (len < sizeof(*ftie)) - return -1; - ftie = (const struct rsn_ftie *) pos; - wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC Control", - ftie->mic_control, 2); - wpa_hexdump(MSG_DEBUG, "FT: FTE-MIC", - ftie->mic, sizeof(ftie->mic)); - parse->fte_anonce = ftie->anonce; - wpa_hexdump(MSG_DEBUG, "FT: FTE-ANonce", - ftie->anonce, WPA_NONCE_LEN); - parse->fte_snonce = ftie->snonce; - wpa_hexdump(MSG_DEBUG, "FT: FTE-SNonce", - ftie->snonce, WPA_NONCE_LEN); - prot_ie_count = ftie->mic_control[1]; - if (wpa_ft_parse_ftie(pos, len, parse, 0) < 0) - return -1; break; case WLAN_EID_TIMEOUT_INTERVAL: wpa_hexdump(MSG_DEBUG, "FT: Timeout Interval", @@ -1186,6 +1323,29 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, pos += len; } + if (fte) { + int res; + + if (fte_len < 255) { + res = wpa_ft_parse_fte(key_mgmt, fte, fte_len, parse); + } else { + parse->fte_buf = ieee802_11_defrag(fte, fte_len, false); + if (!parse->fte_buf) + goto fail; + res = wpa_ft_parse_fte(key_mgmt, + wpabuf_head(parse->fte_buf), + wpabuf_len(parse->fte_buf), + parse); + } + if (res < 0) + goto fail; + + /* FTE might be fragmented. If it is, the separate Fragment + * elements are included in MIC calculation as full elements. */ + parse->ftie = fte; + parse->ftie_len = fte_len; + } + if (prot_ie_count == 0) return 0; /* no MIC */ @@ -1193,24 +1353,39 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, * Check that the protected IE count matches with IEs included in the * frame. */ - if (parse->rsn) - prot_ie_count--; + if (reassoc_resp && elems.basic_mle) { + unsigned int link_id; + + /* TODO: This count should be done based on all _requested_, + * not _accepted_ links. */ + for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { + if (parse->mlo_gtk[link_id]) { + if (parse->rsn) + prot_ie_count--; + if (parse->rsnxe) + prot_ie_count--; + } + } + } else { + if (parse->rsn) + prot_ie_count--; + if (parse->rsnxe) + prot_ie_count--; + } if (parse->mdie) prot_ie_count--; if (parse->ftie) prot_ie_count--; - if (parse->rsnxe) - prot_ie_count--; if (prot_ie_count < 0) { wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " "the protected IE count"); - return -1; + goto fail; } if (prot_ie_count == 0 && parse->ric) { wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " "included in protected IE count"); - return -1; + goto fail; } /* Determine the end of the RIC IE(s) */ @@ -1226,11 +1401,25 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, if (prot_ie_count) { wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " "frame", (int) prot_ie_count); - return -1; + goto fail; } return 0; + +fail: + wpa_ft_parse_ies_free(parse); + return -1; +} + + +void wpa_ft_parse_ies_free(struct wpa_ft_ies *parse) +{ + if (!parse) + return; + wpabuf_free(parse->fte_buf); + parse->fte_buf = NULL; } + #endif /* CONFIG_IEEE80211R */ @@ -1249,7 +1438,7 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, * 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) +bool pasn_use_sha384(int akmp, int cipher) { return (akmp == WPA_KEY_MGMT_PASN && (cipher == WPA_CIPHER_CCMP_256 || cipher == WPA_CIPHER_GCMP_256)) || @@ -1383,6 +1572,62 @@ u8 pasn_mic_len(int akmp, int cipher) } +/** + * wpa_ltf_keyseed - Compute LTF keyseed from KDK + * @ptk: Buffer that holds pairwise transient key + * @akmp: Negotiated AKM + * @cipher: Negotiated pairwise cipher + * Returns: 0 on success, -1 on failure + */ +int wpa_ltf_keyseed(struct wpa_ptk *ptk, int akmp, int cipher) +{ + u8 *buf; + size_t buf_len; + u8 hash[SHA384_MAC_LEN]; + const u8 *kdk = ptk->kdk; + size_t kdk_len = ptk->kdk_len; + const char *label = "Secure LTF key seed"; + + if (!kdk || !kdk_len) { + wpa_printf(MSG_ERROR, "WPA: No KDK for LTF keyseed generation"); + return -1; + } + + buf = (u8 *)label; + buf_len = os_strlen(label); + + if (pasn_use_sha384(akmp, cipher)) { + wpa_printf(MSG_DEBUG, + "WPA: Secure LTF keyseed using HMAC-SHA384"); + + if (hmac_sha384(kdk, kdk_len, buf, buf_len, hash)) { + wpa_printf(MSG_ERROR, + "WPA: HMAC-SHA384 compute failed"); + return -1; + } + os_memcpy(ptk->ltf_keyseed, hash, SHA384_MAC_LEN); + ptk->ltf_keyseed_len = SHA384_MAC_LEN; + wpa_hexdump_key(MSG_DEBUG, "WPA: Secure LTF keyseed: ", + ptk->ltf_keyseed, ptk->ltf_keyseed_len); + + } else { + wpa_printf(MSG_DEBUG, "WPA: LTF keyseed using HMAC-SHA256"); + + if (hmac_sha256(kdk, kdk_len, buf, buf_len, hash)) { + wpa_printf(MSG_ERROR, + "WPA: HMAC-SHA256 compute failed"); + return -1; + } + os_memcpy(ptk->ltf_keyseed, hash, SHA256_MAC_LEN); + ptk->ltf_keyseed_len = SHA256_MAC_LEN; + wpa_hexdump_key(MSG_DEBUG, "WPA: Secure LTF keyseed: ", + ptk->ltf_keyseed, ptk->ltf_keyseed_len); + } + + return 0; +} + + /** * pasn_mic - Calculate PASN MIC * @kck: The key confirmation key for the PASN PTKSA @@ -1538,6 +1783,10 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s) return WPA_KEY_MGMT_FT_IEEE8021X_SHA384; #endif /* CONFIG_SHA384 */ #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_SHA384 + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA384) + return WPA_KEY_MGMT_IEEE8021X_SHA384; +#endif /* CONFIG_SHA384 */ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256) return WPA_KEY_MGMT_IEEE8021X_SHA256; if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256) @@ -1549,6 +1798,8 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s) return WPA_KEY_MGMT_SAE_EXT_KEY; if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE) return WPA_KEY_MGMT_FT_SAE; + if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY) + return WPA_KEY_MGMT_FT_SAE_EXT_KEY; #endif /* CONFIG_SAE */ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B) return WPA_KEY_MGMT_IEEE8021X_SUITE_B; @@ -1667,6 +1918,13 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, "%s: invalid group cipher 0x%x (%08x)", __func__, data->group_cipher, WPA_GET_BE32(pos)); +#ifdef CONFIG_NO_TKIP + if (RSN_SELECTOR_GET(pos) == RSN_CIPHER_SUITE_TKIP) { + wpa_printf(MSG_DEBUG, + "%s: TKIP as group cipher not supported in CONFIG_NO_TKIP=y build", + __func__); + } +#endif /* CONFIG_NO_TKIP */ return -1; } pos += RSN_SELECTOR_LEN; @@ -1923,30 +2181,40 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, const u8 *ssid, size_t ssid_len, const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name, - int use_sha384) + int key_mgmt) { u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 + FT_R0KH_ID_MAX_LEN + ETH_ALEN]; - u8 *pos, r0_key_data[64], hash[48]; + u8 *pos, r0_key_data[64 + 16], hash[64]; const u8 *addr[2]; size_t len[2]; - size_t q = use_sha384 ? 48 : 32; - size_t r0_key_data_len = q + 16; + size_t q, r0_key_data_len; + int res; + + if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + (xxkey_len == SHA256_MAC_LEN || xxkey_len == SHA384_MAC_LEN || + xxkey_len == SHA512_MAC_LEN)) + q = xxkey_len; + else if (wpa_key_mgmt_sha384(key_mgmt)) + q = SHA384_MAC_LEN; + else + q = SHA256_MAC_LEN; + r0_key_data_len = q + 16; /* - * R0-Key-Data = KDF-384(XXKey, "FT-R0", + * R0-Key-Data = KDF-Hash-Length(XXKey, "FT-R0", * SSIDlength || SSID || MDID || R0KHlength || * R0KH-ID || S0KH-ID) * XXKey is either the second 256 bits of MSK or PSK; or the first - * 384 bits of MSK for FT-EAP-SHA384. + * 384 bits of MSK for FT-EAP-SHA384; or PMK from SAE. * PMK-R0 = L(R0-Key-Data, 0, Q) * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128) - * Q = 384 for FT-EAP-SHA384; otherwise, 256 + * Q = 384 for FT-EAP-SHA384; the length of the digest generated by H() + * for FT-SAE-EXT-KEY; or otherwise, 256 */ if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN) return -1; - wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-%s", - use_sha384 ? "SHA384" : "SHA256"); + wpa_printf(MSG_DEBUG, "FT: Derive PMK-R0 using KDF-SHA%zu", q * 8); wpa_hexdump_key(MSG_DEBUG, "FT: XXKey", xxkey, xxkey_len); wpa_hexdump_ascii(MSG_DEBUG, "FT: SSID", ssid, ssid_len); wpa_hexdump(MSG_DEBUG, "FT: MDID", mdid, MOBILITY_DOMAIN_ID_LEN); @@ -1964,30 +2232,43 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, os_memcpy(pos, s0kh_id, ETH_ALEN); pos += ETH_ALEN; + res = -1; +#ifdef CONFIG_SHA512 + if (q == SHA512_MAC_LEN) { + if (xxkey_len != SHA512_MAC_LEN) { + wpa_printf(MSG_ERROR, + "FT: Unexpected XXKey length %d (expected %d)", + (int) xxkey_len, SHA512_MAC_LEN); + return -1; + } + res = sha512_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, + r0_key_data, r0_key_data_len); + } +#endif /* CONFIG_SHA512 */ #ifdef CONFIG_SHA384 - if (use_sha384) { + if (q == SHA384_MAC_LEN) { if (xxkey_len != SHA384_MAC_LEN) { wpa_printf(MSG_ERROR, "FT: Unexpected XXKey length %d (expected %d)", (int) xxkey_len, SHA384_MAC_LEN); return -1; } - if (sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, - r0_key_data, r0_key_data_len) < 0) - return -1; + res = sha384_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, + r0_key_data, r0_key_data_len); } #endif /* CONFIG_SHA384 */ - if (!use_sha384) { + if (q == SHA256_MAC_LEN) { if (xxkey_len != PMK_LEN) { wpa_printf(MSG_ERROR, "FT: Unexpected XXKey length %d (expected %d)", (int) xxkey_len, PMK_LEN); return -1; } - if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, - r0_key_data, r0_key_data_len) < 0) - return -1; + res = sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf, + r0_key_data, r0_key_data_len); } + if (res < 0) + return res; os_memcpy(pmk_r0, r0_key_data, q); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, q); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0Name-Salt", &r0_key_data[q], 16); @@ -2000,12 +2281,23 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, addr[1] = &r0_key_data[q]; len[1] = 16; + res = -1; +#ifdef CONFIG_SHA512 + if (q == SHA512_MAC_LEN) + res = sha512_vector(2, addr, len, hash); +#endif /* CONFIG_SHA512 */ #ifdef CONFIG_SHA384 - if (use_sha384 && sha384_vector(2, addr, len, hash) < 0) - return -1; + if (q == SHA384_MAC_LEN) + res = sha384_vector(2, addr, len, hash); #endif /* CONFIG_SHA384 */ - if (!use_sha384 && sha256_vector(2, addr, len, hash) < 0) - return -1; + if (q == SHA256_MAC_LEN) + res = sha256_vector(2, addr, len, hash); + if (res < 0) { + wpa_printf(MSG_DEBUG, + "FT: Failed to derive PMKR0Name (PMK-R0 len %zu)", + q); + return res; + } os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN); forced_memzero(r0_key_data, sizeof(r0_key_data)); @@ -2019,11 +2311,14 @@ int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, * IEEE Std 802.11r-2008 - 8.5.1.5.4 */ int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, - const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384) + const u8 *s1kh_id, u8 *pmk_r1_name, + size_t pmk_r1_len) { - u8 hash[48]; + u8 hash[64]; const u8 *addr[4]; size_t len[4]; + int res; + const char *title; /* * PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name || @@ -2038,14 +2333,31 @@ int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, addr[3] = s1kh_id; len[3] = ETH_ALEN; + res = -1; +#ifdef CONFIG_SHA512 + if (pmk_r1_len == SHA512_MAC_LEN) { + title = "FT: PMKR1Name (using SHA512)"; + res = sha512_vector(4, addr, len, hash); + } +#endif /* CONFIG_SHA512 */ #ifdef CONFIG_SHA384 - if (use_sha384 && sha384_vector(4, addr, len, hash) < 0) - return -1; + if (pmk_r1_len == SHA384_MAC_LEN) { + title = "FT: PMKR1Name (using SHA384)"; + res = sha384_vector(4, addr, len, hash); + } #endif /* CONFIG_SHA384 */ - if (!use_sha384 && sha256_vector(4, addr, len, hash) < 0) - return -1; + if (pmk_r1_len == SHA256_MAC_LEN) { + title = "FT: PMKR1Name (using SHA256)"; + res = sha256_vector(4, addr, len, hash); + } + if (res < 0) { + wpa_printf(MSG_DEBUG, + "FT: Failed to derive PMKR1Name (PMK-R1 len %zu)", + pmk_r1_len); + return res; + } os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN); + wpa_hexdump(MSG_DEBUG, title, pmk_r1_name, WPA_PMK_NAME_LEN); return 0; } @@ -2062,10 +2374,11 @@ int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len, { u8 buf[FT_R1KH_ID_LEN + ETH_ALEN]; u8 *pos; + int res; - /* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ - wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-%s", - pmk_r0_len == SHA384_MAC_LEN ? "SHA384" : "SHA256"); + /* PMK-R1 = KDF-Hash(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */ + wpa_printf(MSG_DEBUG, "FT: Derive PMK-R1 using KDF-SHA%zu", + pmk_r0_len * 8); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, pmk_r0_len); wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", r1kh_id, FT_R1KH_ID_LEN); wpa_printf(MSG_DEBUG, "FT: S1KH-ID: " MACSTR_SEC, MAC2STR_SEC(s1kh_id)); @@ -2075,26 +2388,28 @@ int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len, os_memcpy(pos, s1kh_id, ETH_ALEN); pos += ETH_ALEN; + res = -1; +#ifdef CONFIG_SHA512 + if (pmk_r0_len == SHA512_MAC_LEN) + res = sha512_prf(pmk_r0, pmk_r0_len, "FT-R1", + buf, pos - buf, pmk_r1, pmk_r0_len); +#endif /* CONFIG_SHA512 */ #ifdef CONFIG_SHA384 - if (pmk_r0_len == SHA384_MAC_LEN && - sha384_prf(pmk_r0, pmk_r0_len, "FT-R1", - buf, pos - buf, pmk_r1, pmk_r0_len) < 0) - return -1; + if (pmk_r0_len == SHA384_MAC_LEN) + res = sha384_prf(pmk_r0, pmk_r0_len, "FT-R1", + buf, pos - buf, pmk_r1, pmk_r0_len); #endif /* CONFIG_SHA384 */ - if (pmk_r0_len == PMK_LEN && - sha256_prf(pmk_r0, pmk_r0_len, "FT-R1", - buf, pos - buf, pmk_r1, pmk_r0_len) < 0) - return -1; - if (pmk_r0_len != SHA384_MAC_LEN && pmk_r0_len != PMK_LEN) { - wpa_printf(MSG_ERROR, "FT: Unexpected PMK-R0 length %d", - (int) pmk_r0_len); - return -1; + if (pmk_r0_len == SHA256_MAC_LEN) + res = sha256_prf(pmk_r0, pmk_r0_len, "FT-R1", + buf, pos - buf, pmk_r1, pmk_r0_len); + if (res < 0) { + wpa_printf(MSG_ERROR, "FT: Failed to derive PMK-R1"); + return res; } wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r0_len); return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, - pmk_r1_name, - pmk_r0_len == SHA384_MAC_LEN); + pmk_r1_name, pmk_r0_len); } @@ -2117,7 +2432,8 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_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); + size_t key_len; + int res; if (kdk_len > WPA_KDK_MAX_LEN) { wpa_printf(MSG_ERROR, @@ -2126,12 +2442,20 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, return -1; } + if (akmp == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + (pmk_r1_len == SHA256_MAC_LEN || pmk_r1_len == SHA384_MAC_LEN || + pmk_r1_len == SHA512_MAC_LEN)) + key_len = pmk_r1_len; + else if (wpa_key_mgmt_sha384(akmp)) + key_len = SHA384_MAC_LEN; + else + key_len = SHA256_MAC_LEN; + /* * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce || * BSSID || STA-ADDR) */ - wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-%s", - use_sha384 ? "SHA384" : "SHA256"); + wpa_printf(MSG_DEBUG, "FT: Derive PTK using KDF-SHA%zu", key_len * 8); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, pmk_r1_len); wpa_hexdump(MSG_DEBUG, "FT: SNonce", snonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN); @@ -2147,39 +2471,52 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, os_memcpy(pos, sta_addr, ETH_ALEN); pos += ETH_ALEN; - ptk->kck_len = wpa_kck_len(akmp, PMK_LEN); + ptk->kck_len = wpa_kck_len(akmp, key_len); ptk->kck2_len = wpa_kck2_len(akmp); - ptk->kek_len = wpa_kek_len(akmp, PMK_LEN); + ptk->kek_len = wpa_kek_len(akmp, key_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->kdk_len; + res = -1; +#ifdef CONFIG_SHA512 + if (key_len == SHA512_MAC_LEN) { + if (pmk_r1_len != SHA512_MAC_LEN) { + wpa_printf(MSG_ERROR, + "FT: Unexpected PMK-R1 length %d (expected %d)", + (int) pmk_r1_len, SHA512_MAC_LEN); + return -1; + } + res = sha512_prf(pmk_r1, pmk_r1_len, "FT-PTK", + buf, pos - buf, tmp, ptk_len); + } +#endif /* CONFIG_SHA512 */ #ifdef CONFIG_SHA384 - if (use_sha384) { + if (key_len == SHA384_MAC_LEN) { if (pmk_r1_len != SHA384_MAC_LEN) { wpa_printf(MSG_ERROR, "FT: Unexpected PMK-R1 length %d (expected %d)", (int) pmk_r1_len, SHA384_MAC_LEN); return -1; } - if (sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK", - buf, pos - buf, tmp, ptk_len) < 0) - return -1; + res = sha384_prf(pmk_r1, pmk_r1_len, "FT-PTK", + buf, pos - buf, tmp, ptk_len); } #endif /* CONFIG_SHA384 */ - if (!use_sha384) { + if (key_len == SHA256_MAC_LEN) { if (pmk_r1_len != PMK_LEN) { wpa_printf(MSG_ERROR, "FT: Unexpected PMK-R1 length %d (expected %d)", (int) pmk_r1_len, PMK_LEN); return -1; } - if (sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK", - buf, pos - buf, tmp, ptk_len) < 0) - return -1; + res = sha256_prf(pmk_r1, pmk_r1_len, "FT-PTK", + buf, pos - buf, tmp, ptk_len); } + if (res < 0) + return -1; wpa_hexdump_key(MSG_DEBUG, "FT: PTK", tmp, ptk_len); /* @@ -2248,7 +2585,7 @@ int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, size_t pmk_r1_len, * @akmp: Negotiated key management protocol * * IEEE Std 802.11-2016 - 12.7.1.3 Pairwise key hierarchy - * AKM: 00-0F-AC:5, 00-0F-AC:6, 00-0F-AC:14, 00-0F-AC:16 + * AKM: 00-0F-AC:3, 00-0F-AC:5, 00-0F-AC:6, 00-0F-AC:14, 00-0F-AC:16 * PMKID = Truncate-128(HMAC-SHA-256(PMK, "PMK Name" || AA || SPA)) * AKM: 00-0F-AC:11 * See rsn_pmkid_suite_b() @@ -2448,6 +2785,8 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto) return "SAE-EXT-KEY"; case WPA_KEY_MGMT_FT_SAE: return "FT-SAE"; + case WPA_KEY_MGMT_FT_SAE_EXT_KEY: + return "FT-SAE-EXT-KEY"; case WPA_KEY_MGMT_OSEN: return "OSEN"; case WPA_KEY_MGMT_IEEE8021X_SUITE_B: @@ -2468,6 +2807,8 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto) return "DPP"; case WPA_KEY_MGMT_PASN: return "PASN"; + case WPA_KEY_MGMT_IEEE8021X_SHA384: + return "WPA2-EAP-SHA384"; default: return "UNKNOWN"; } @@ -2482,6 +2823,8 @@ u32 wpa_akm_to_suite(int akm) return RSN_AUTH_KEY_MGMT_FT_802_1X; if (akm & WPA_KEY_MGMT_FT_PSK) return RSN_AUTH_KEY_MGMT_FT_PSK; + if (akm & WPA_KEY_MGMT_IEEE8021X_SHA384) + return RSN_AUTH_KEY_MGMT_802_1X_SHA384; if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256) return RSN_AUTH_KEY_MGMT_802_1X_SHA256; if (akm & WPA_KEY_MGMT_IEEE8021X) @@ -2512,6 +2855,8 @@ u32 wpa_akm_to_suite(int akm) return RSN_AUTH_KEY_MGMT_SAE_EXT_KEY; if (akm & WPA_KEY_MGMT_FT_SAE) return RSN_AUTH_KEY_MGMT_FT_SAE; + if (akm & WPA_KEY_MGMT_FT_SAE_EXT_KEY) + return RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY; if (akm & WPA_KEY_MGMT_OWE) return RSN_AUTH_KEY_MGMT_OWE; if (akm & WPA_KEY_MGMT_DPP) @@ -2557,7 +2902,7 @@ int wpa_compare_rsn_ie(int ft_initial_assoc, } -int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid) +int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid, bool replace) { u8 *start, *end, *rpos, *rend; int added = 0; @@ -2620,12 +2965,12 @@ int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid) if (rend - rpos < 2) return -1; num_pmkid = WPA_GET_LE16(rpos); + if (num_pmkid * PMKID_LEN > rend - rpos - 2) + return -1; /* PMKID-Count was included; use it */ - if (num_pmkid != 0) { + if (replace && num_pmkid != 0) { u8 *after; - if (num_pmkid * PMKID_LEN > rend - rpos - 2) - return -1; /* * PMKID may have been included in RSN IE in * (Re)Association Request frame, so remove the old @@ -2638,8 +2983,9 @@ int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid) os_memmove(rpos + 2, after, end - after); start[1] -= num_pmkid * PMKID_LEN; added -= num_pmkid * PMKID_LEN; + num_pmkid = 0; } - WPA_PUT_LE16(rpos, 1); + WPA_PUT_LE16(rpos, num_pmkid + 1); rpos += 2; os_memmove(rpos + PMKID_LEN, rpos, end + added - rpos); os_memcpy(rpos, pmkid, PMKID_LEN); @@ -2671,9 +3017,9 @@ int wpa_cipher_key_len(int cipher) return 16; case WPA_CIPHER_TKIP: return 32; + default: + return 0; } - - return 0; } @@ -2686,9 +3032,9 @@ int wpa_cipher_rsc_len(int cipher) case WPA_CIPHER_GCMP: case WPA_CIPHER_TKIP: return 6; + default: + return 0; } - - return 0; } @@ -2713,8 +3059,9 @@ enum wpa_alg wpa_cipher_to_alg(int cipher) return WPA_ALG_BIP_GMAC_256; case WPA_CIPHER_BIP_CMAC_256: return WPA_ALG_BIP_CMAC_256; + default: + return WPA_ALG_NONE; } - return WPA_ALG_NONE; } @@ -3117,7 +3464,7 @@ static void wpa_parse_vendor_specific(const u8 *pos, const u8 *end, } } -#ifdef CONFIG_MLD_PATCH + /** * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs * @pos: Pointer to the IE header @@ -3315,135 +3662,7 @@ static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie) return 2; } -#else -/** - * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs - * @pos: Pointer to the IE header - * @ie: Pointer to parsed IE data - * Returns: 0 on success, 1 if end mark is found, 2 if KDE is not recognized - */ -static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie) -{ - if (pos[1] == 0) - return 1; - if (pos[1] >= 6 && - RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && - pos[2 + WPA_SELECTOR_LEN] == 1 && - pos[2 + WPA_SELECTOR_LEN + 1] == 0) { - ie->wpa_ie = pos; - ie->wpa_ie_len = pos[1] + 2; - wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", - ie->wpa_ie, ie->wpa_ie_len); - return 0; - } - - if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) { - ie->osen = pos; - ie->osen_len = pos[1] + 2; - return 0; - } - - if (pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { - ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] >= RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_KEYID) { - ie->key_id = pos + 2 + RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { - ie->gtk = pos + 2 + RSN_SELECTOR_LEN; - ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { - ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; - ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { - ie->igtk = pos + 2 + RSN_SELECTOR_LEN; - ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_BIGTK) { - ie->bigtk = pos + 2 + RSN_SELECTOR_LEN; - ie->bigtk_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] >= RSN_SELECTOR_LEN + 1 && - RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) { - ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key", - ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN); - return 0; - } - - if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 && - RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) { - ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, - "WPA: IP Address Allocation in EAPOL-Key", - ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN); - return 0; - } - - if (pos[1] > RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) { - ie->oci = pos + 2 + RSN_SELECTOR_LEN; - ie->oci_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] >= RSN_SELECTOR_LEN + 1 && - RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) { - ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN; - ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, - "WPA: Transition Disable KDE in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - if (pos[1] >= RSN_SELECTOR_LEN + 2 && - RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_DPP) { - ie->dpp_kde = pos + 2 + RSN_SELECTOR_LEN; - ie->dpp_kde_len = pos[1] - RSN_SELECTOR_LEN; - wpa_hexdump(MSG_DEBUG, "WPA: DPP KDE in EAPOL-Key", - pos, pos[1] + 2); - return 0; - } - - return 2; -} -#endif /** * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs @@ -3456,15 +3675,17 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) { const u8 *pos, *end; int ret = 0; + size_t dlen = 0; os_memset(ie, 0, sizeof(*ie)); - for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) { + for (pos = buf, end = pos + len; end - pos > 1; pos += dlen) { if (pos[0] == 0xdd && ((pos == buf + len - 1) || pos[1] == 0)) { /* Ignore padding */ break; } - if (2 + pos[1] > end - pos) { + dlen = 2 + pos[1]; + if ((int) dlen > end - pos) { wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)", pos[0], pos[1], (int) (pos - buf)); @@ -3474,22 +3695,22 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) } if (*pos == WLAN_EID_RSN) { ie->rsn_ie = pos; - ie->rsn_ie_len = pos[1] + 2; + ie->rsn_ie_len = dlen; wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", ie->rsn_ie, ie->rsn_ie_len); } else if (*pos == WLAN_EID_RSNX) { ie->rsnxe = pos; - ie->rsnxe_len = pos[1] + 2; + ie->rsnxe_len = dlen; wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key", ie->rsnxe, ie->rsnxe_len); } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { ie->mdie = pos; - ie->mdie_len = pos[1] + 2; + ie->mdie_len = dlen; wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", ie->mdie, ie->mdie_len); } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { ie->ftie = pos; - ie->ftie_len = pos[1] + 2; + ie->ftie_len = dlen; wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", ie->ftie, ie->ftie_len); } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { @@ -3497,35 +3718,35 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) ie->reassoc_deadline = pos; wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " "in EAPOL-Key", - ie->reassoc_deadline, pos[1] + 2); + ie->reassoc_deadline, dlen); } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { ie->key_lifetime = pos; wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " "in EAPOL-Key", - ie->key_lifetime, pos[1] + 2); + ie->key_lifetime, dlen); } else { wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " "EAPOL-Key Key Data IE", - pos, 2 + pos[1]); + pos, dlen); } } else if (*pos == WLAN_EID_LINK_ID) { if (pos[1] >= 18) { ie->lnkid = pos; - ie->lnkid_len = pos[1] + 2; + ie->lnkid_len = dlen; } } else if (*pos == WLAN_EID_EXT_CAPAB) { ie->ext_capab = pos; - ie->ext_capab_len = pos[1] + 2; + ie->ext_capab_len = dlen; } else if (*pos == WLAN_EID_SUPP_RATES) { ie->supp_rates = pos; - ie->supp_rates_len = pos[1] + 2; + ie->supp_rates_len = dlen; } else if (*pos == WLAN_EID_EXT_SUPP_RATES) { ie->ext_supp_rates = pos; - ie->ext_supp_rates_len = pos[1] + 2; + ie->ext_supp_rates_len = dlen; } else if (*pos == WLAN_EID_HT_CAP && pos[1] >= sizeof(struct ieee80211_ht_capabilities)) { ie->ht_capabilities = pos + 2; - } else if (*pos == WLAN_EID_VHT_AID) { + } else if (*pos == WLAN_EID_AID) { if (pos[1] >= 2) ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff; } else if (*pos == WLAN_EID_VHT_CAP && @@ -3542,6 +3763,11 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) sizeof(struct ieee80211_he_6ghz_band_cap) && pos[2] == WLAN_EID_EXT_HE_6GHZ_BAND_CAP) { ie->he_6ghz_capabilities = pos + 3; + } else if (*pos == WLAN_EID_EXTENSION && + pos[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN && + pos[2] == WLAN_EID_EXT_EHT_CAPABILITIES) { + ie->eht_capabilities = pos + 3; + ie->eht_capab_len = pos[1] - 1; } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) { ie->qosinfo = pos[2]; } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) { @@ -3558,6 +3784,11 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) ie->supp_oper_classes = pos + 2; ie->supp_oper_classes_len = pos[1]; } + } else if (*pos == WLAN_EID_SSID) { + ie->ssid = pos + 2; + ie->ssid_len = pos[1]; + wpa_hexdump_ascii(MSG_DEBUG, "RSN: SSID in EAPOL-Key", + ie->ssid, ie->ssid_len); } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { ret = wpa_parse_generic(pos, ie); if (ret == 1) { @@ -3575,7 +3806,7 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) } else { wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key Key Data IE", - pos, 2 + pos[1]); + pos, dlen); } } @@ -3674,6 +3905,9 @@ int wpa_pasn_add_rsne(struct wpabuf *buf, const u8 *pmkid, int akmp, int cipher) case WPA_KEY_MGMT_SAE: RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); break; + case WPA_KEY_MGMT_SAE_EXT_KEY: + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY); + break; #endif /* CONFIG_SAE */ #ifdef CONFIG_FILS case WPA_KEY_MGMT_FILS_SHA256: @@ -3887,18 +4121,19 @@ int wpa_pasn_validate_rsne(const struct wpa_ie_data *data) switch (data->key_mgmt) { #ifdef CONFIG_SAE case WPA_KEY_MGMT_SAE: - /* fall through */ + case WPA_KEY_MGMT_SAE_EXT_KEY: + __attribute__((fallthrough)); #endif /* CONFIG_SAE */ #ifdef CONFIG_FILS case WPA_KEY_MGMT_FILS_SHA256: case WPA_KEY_MGMT_FILS_SHA384: - /* fall through */ + __attribute__((fallthrough)); #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 */ + __attribute__((fallthrough)); #endif /* CONFIG_IEEE80211R */ case WPA_KEY_MGMT_PASN: break; @@ -4040,4 +4275,27 @@ void wpa_pasn_add_rsnxe(struct wpabuf *buf, u16 capab) wpabuf_put_u8(buf, capab); } + +/* + * wpa_pasn_add_extra_ies - Add protocol specific IEs in Authentication + * frame for PASN. + * + * @buf: Buffer in which the elements will be added + * @extra_ies: Protocol specific elements to add + * @len: Length of the elements + * Returns: 0 on success, -1 on failure + */ + +int wpa_pasn_add_extra_ies(struct wpabuf *buf, const u8 *extra_ies, size_t len) +{ + if (!len || !extra_ies || !buf) + return 0; + + if (wpabuf_tailroom(buf) < sizeof(len)) + return -1; + + wpabuf_put_data(buf, extra_ies, len); + return 0; +} + #endif /* CONFIG_PASN */ diff --git a/wpa_supplicant-2.9_standard/src/common/wpa_common.h b/wpa_supplicant-2.9_standard/src/common/wpa_common.h index 4a1044dbda70fea2a39775a29a34c56ad7697e5f..31f0425aae5394d535f51260a11ba9c3725e98b3 100644 --- a/wpa_supplicant-2.9_standard/src/common/wpa_common.h +++ b/wpa_supplicant-2.9_standard/src/common/wpa_common.h @@ -9,15 +9,15 @@ #ifndef WPA_COMMON_H #define WPA_COMMON_H +#include "common/defs.h" + /* IEEE 802.11i */ #define PMKID_LEN 16 #define PMK_LEN 32 #define PMK_LEN_SUITE_B_192 48 #define PMK_LEN_MAX 64 #define WPA_REPLAY_COUNTER_LEN 8 -#ifdef CONFIG_MLD_PATCH #define RSN_PN_LEN 6 -#endif #define WPA_NONCE_LEN 32 #define WPA_KEY_RSC_LEN 8 #define WPA_GMK_LEN 32 @@ -86,8 +86,12 @@ 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_FT_PSK_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 19) +#define RSN_AUTH_KEY_MGMT_PSK_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 20) #define RSN_AUTH_KEY_MGMT_PASN RSN_SELECTOR(0x00, 0x0f, 0xac, 21) +#define RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384_UNRESTRICTED \ + RSN_SELECTOR(0x00, 0x0f, 0xac, 22) +#define RSN_AUTH_KEY_MGMT_802_1X_SHA384 RSN_SELECTOR(0x00, 0x0f, 0xac, 23) #define RSN_AUTH_KEY_MGMT_SAE_EXT_KEY RSN_SELECTOR(0x00, 0x0f, 0xac, 24) #define RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY RSN_SELECTOR(0x00, 0x0f, 0xac, 25) @@ -136,13 +140,10 @@ WPA_CIPHER_BIP_CMAC_256) #define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12) #define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13) #define RSN_KEY_DATA_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 14) - -#ifdef CONFIG_MLD_PATCH #define RSN_KEY_DATA_MLO_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 16) #define RSN_KEY_DATA_MLO_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 17) #define RSN_KEY_DATA_MLO_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 18) #define RSN_KEY_DATA_MLO_LINK RSN_SELECTOR(0x00, 0x0f, 0xac, 19) -#endif #define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4) #define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5) @@ -193,6 +194,18 @@ WPA_CIPHER_BIP_CMAC_256) #define FT_R1KH_ID_LEN 6 #define WPA_PMK_NAME_LEN 16 +/* FTE - MIC Control - RSNXE Used */ +#define FTE_MIC_CTRL_RSNXE_USED BIT(0) +#define FTE_MIC_CTRL_MIC_LEN_MASK (BIT(1) | BIT(2) | BIT(3)) +#define FTE_MIC_CTRL_MIC_LEN_SHIFT 1 + +/* FTE - MIC Length subfield values */ +enum ft_mic_len_subfield { + FTE_MIC_LEN_16 = 0, + FTE_MIC_LEN_24 = 1, + FTE_MIC_LEN_32 = 2, +}; + /* IEEE 802.11, 8.5.2 EAPOL-Key frames */ #define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2))) @@ -239,6 +252,7 @@ struct wpa_eapol_key { #define FILS_FT_MAX_LEN 48 #define WPA_PASN_KCK_LEN 32 #define WPA_PASN_MIC_MAX_LEN 24 +#define WPA_LTF_KEYSEED_MAX_LEN 48 /** * struct wpa_ptk - WPA Pairwise Transient Key @@ -251,12 +265,14 @@ struct wpa_ptk { 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 */ + u8 ltf_keyseed[WPA_LTF_KEYSEED_MAX_LEN]; /* LTF Key seed */ size_t kck_len; size_t kek_len; size_t tk_len; size_t kck2_len; size_t kek2_len; size_t kdk_len; + size_t ltf_keyseed_len; int installed; /* 1 if key has already been installed to driver */ }; @@ -328,26 +344,27 @@ struct rsn_ie_hdr { } STRUCT_PACKED; +#define KDE_HDR_LEN (1 + 1 + RSN_SELECTOR_LEN) + struct rsn_error_kde { be16 mui; be16 error_type; } STRUCT_PACKED; -#define WPA_IGTK_KDE_PREFIX_LEN (2 + 6) +#define WPA_IGTK_KDE_PREFIX_LEN (2 + RSN_PN_LEN) struct wpa_igtk_kde { u8 keyid[2]; - u8 pn[6]; + u8 pn[RSN_PN_LEN]; u8 igtk[WPA_IGTK_MAX_LEN]; } STRUCT_PACKED; -#define WPA_BIGTK_KDE_PREFIX_LEN (2 + 6) +#define WPA_BIGTK_KDE_PREFIX_LEN (2 + RSN_PN_LEN) struct wpa_bigtk_kde { u8 keyid[2]; - u8 pn[6]; + u8 pn[RSN_PN_LEN]; u8 bigtk[WPA_BIGTK_MAX_LEN]; } STRUCT_PACKED; -#ifdef CONFIG_MLD_PATCH #define RSN_MLO_GTK_KDE_PREFIX_LENGTH (1 + RSN_PN_LEN) #define RSN_MLO_GTK_KDE_PREFIX0_KEY_ID_MASK 0x03 #define RSN_MLO_GTK_KDE_PREFIX0_TX 0x04 @@ -374,14 +391,13 @@ struct rsn_mlo_bigtk_kde { u8 bigtk[WPA_BIGTK_MAX_LEN]; } STRUCT_PACKED; -#define RSN_MLO_LINK_KDE_FIXED_LENGTH (1 + 6) +#define RSN_MLO_LINK_KDE_FIXED_LENGTH (1 + ETH_ALEN) #define RSN_MLO_LINK_KDE_LINK_INFO_INDEX 0 #define RSN_MLO_LINK_KDE_LI_LINK_ID_SHIFT 0 #define RSN_MLO_LINK_KDE_LI_LINK_ID_MASK 0x0F #define RSN_MLO_LINK_KDE_LI_RSNE_INFO 0x10 #define RSN_MLO_LINK_KDE_LI_RSNXE_INFO 0x20 #define RSN_MLO_LINK_KDE_LINK_MAC_INDEX 1 -#endif struct rsn_mdie { u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; @@ -407,12 +423,23 @@ struct rsn_ftie_sha384 { /* followed by optional parameters */ } STRUCT_PACKED; +struct rsn_ftie_sha512 { + u8 mic_control[2]; + u8 mic[32]; + u8 anonce[WPA_NONCE_LEN]; + u8 snonce[WPA_NONCE_LEN]; + /* followed by optional parameters */ +} STRUCT_PACKED; + #define FTIE_SUBELEM_R1KH_ID 1 #define FTIE_SUBELEM_GTK 2 #define FTIE_SUBELEM_R0KH_ID 3 #define FTIE_SUBELEM_IGTK 4 #define FTIE_SUBELEM_OCI 5 #define FTIE_SUBELEM_BIGTK 6 +#define FTIE_SUBELEM_MLO_GTK 8 +#define FTIE_SUBELEM_MLO_IGTK 9 +#define FTIE_SUBELEM_MLO_BIGTK 10 struct rsn_rdie { u8 id; @@ -461,21 +488,23 @@ int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce, size_t *key_auth_len); #ifdef CONFIG_IEEE80211R -int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr, +int wpa_ft_mic(int key_mgmt, const u8 *kck, size_t kck_len, const u8 *sta_addr, const u8 *ap_addr, u8 transaction_seqnum, const u8 *mdie, size_t mdie_len, const u8 *ftie, size_t ftie_len, const u8 *rsnie, size_t rsnie_len, const u8 *ric, size_t ric_len, const u8 *rsnxe, size_t rsnxe_len, + const struct wpabuf *extra, u8 *mic); int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len, const u8 *ssid, size_t ssid_len, const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name, - int use_sha384); + int key_mgmt); int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id, - const u8 *s1kh_id, u8 *pmk_r1_name, int use_sha384); + const u8 *s1kh_id, u8 *pmk_r1_name, + size_t pmk_r1_len); int wpa_derive_pmk_r1(const u8 *pmk_r0, size_t pmk_r0_len, const u8 *pmk_r0_name, const u8 *r1kh_id, const u8 *s1kh_id, @@ -536,7 +565,7 @@ u32 wpa_akm_to_suite(int akm); int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len); -int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid); +int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid, bool replace); struct wpa_ft_ies { const u8 *mdie; @@ -550,6 +579,10 @@ struct wpa_ft_ies { size_t r0kh_id_len; const u8 *fte_anonce; const u8 *fte_snonce; + bool fte_rsnxe_used; + unsigned int fte_elem_count; + const u8 *fte_mic; + size_t fte_mic_len; const u8 *rsn; size_t rsn_len; u16 rsn_capab; @@ -570,6 +603,17 @@ struct wpa_ft_ies { int pairwise_cipher; const u8 *rsnxe; size_t rsnxe_len; + u16 valid_mlo_gtks; /* bitmap of valid link GTK subelements */ + const u8 *mlo_gtk[MAX_NUM_MLD_LINKS]; + size_t mlo_gtk_len[MAX_NUM_MLD_LINKS]; + u16 valid_mlo_igtks; /* bitmap of valid link IGTK subelements */ + const u8 *mlo_igtk[MAX_NUM_MLD_LINKS]; + size_t mlo_igtk_len[MAX_NUM_MLD_LINKS]; + u16 valid_mlo_bigtks; /* bitmap of valid link BIGTK subelements */ + const u8 *mlo_bigtk[MAX_NUM_MLD_LINKS]; + size_t mlo_bigtk_len[MAX_NUM_MLD_LINKS]; + + struct wpabuf *fte_buf; }; /* IEEE P802.11az/D2.6 - 9.4.2.303 PASN Parameters element */ @@ -605,7 +649,8 @@ struct wpa_pasn_params_data { #define WPA_PASN_PUBKEY_UNCOMPRESSED 0x04 int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse, - int use_sha384); + int key_mgmt, bool reassoc_resp); +void wpa_ft_parse_ies_free(struct wpa_ft_ies *parse); struct wpa_eapol_ie_parse { const u8 *wpa_ie; @@ -617,7 +662,6 @@ struct wpa_eapol_ie_parse { const u8 *gtk; size_t gtk_len; const u8 *mac_addr; - size_t mac_addr_len; const u8 *igtk; size_t igtk_len; const u8 *bigtk; @@ -653,16 +697,18 @@ struct wpa_eapol_ie_parse { const u8 *he_capabilities; size_t he_capab_len; const u8 *he_6ghz_capabilities; + const u8 *eht_capabilities; + size_t eht_capab_len; const u8 *supp_channels; size_t supp_channels_len; const u8 *supp_oper_classes; size_t supp_oper_classes_len; + const u8 *ssid; + size_t ssid_len; u8 qosinfo; u16 aid; const u8 *wmm; size_t wmm_len; -#ifdef CONFIG_MLD_PATCH -#define MAX_NUM_MLD_LINKS 15 u16 valid_mlo_gtks; /* bitmap of valid link GTK KDEs */ const u8 *mlo_gtk[MAX_NUM_MLD_LINKS]; size_t mlo_gtk_len[MAX_NUM_MLD_LINKS]; @@ -675,7 +721,6 @@ struct wpa_eapol_ie_parse { u16 valid_mlo_links; /* bitmap of valid MLO link KDEs */ const u8 *mlo_link[MAX_NUM_MLD_LINKS]; size_t mlo_link_len[MAX_NUM_MLD_LINKS]; -#endif }; int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie); @@ -706,6 +751,7 @@ int wpa_use_cmac(int akmp); int wpa_use_aes_key_wrap(int akmp); int fils_domain_name_hash(const char *domain, u8 *hash); +bool pasn_use_sha384(int akmp, int cipher); 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, @@ -719,6 +765,8 @@ int pasn_mic(const u8 *kck, int akmp, int cipher, const u8 *data, size_t data_len, const u8 *frame, size_t frame_len, u8 *mic); +int wpa_ltf_keyseed(struct wpa_ptk *ptk, int akmp, int cipher); + int pasn_auth_frame_hash(int akmp, int cipher, const u8 *data, size_t len, u8 *hash); @@ -742,5 +790,6 @@ 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); +int wpa_pasn_add_extra_ies(struct wpabuf *buf, const u8 *extra_ies, size_t len); #endif /* WPA_COMMON_H */ diff --git a/wpa_supplicant-2.9_standard/src/common/wpa_ctrl.c b/wpa_supplicant-2.9_standard/src/common/wpa_ctrl.c index 89a80dfb467330e0cdf77a28b0760b80f9fe4c69..802c60a1d960ba4548b112669cca4358a349243f 100644 --- a/wpa_supplicant-2.9_standard/src/common/wpa_ctrl.c +++ b/wpa_supplicant-2.9_standard/src/common/wpa_ctrl.c @@ -166,7 +166,7 @@ try_again: * no-deference-symlinks version to avoid races. */ fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); #endif /* ANDROID */ - fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, sizeof(ctrl->local)) < 0) { if (errno == EADDRINUSE && tries < 2) { @@ -555,7 +555,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, void (*msg_cb)(char *msg, size_t len)) { struct timeval tv; - struct os_reltime started_at; + struct os_reltime started_at, ending_at; int res; fd_set rfds; const char *_cmd; @@ -618,9 +618,19 @@ retry_send: } os_free(cmd_buf); + os_get_reltime(&ending_at); + ending_at.sec += 10; + for (;;) { - tv.tv_sec = 10; - tv.tv_usec = 0; + struct os_reltime diff; + + os_get_reltime(&started_at); + if (os_reltime_before(&ending_at, &started_at)) + return -2; + os_reltime_sub(&ending_at, &started_at, &diff); + tv.tv_sec = diff.sec; + tv.tv_usec = diff.usec; + FD_ZERO(&rfds); FD_SET(ctrl->s, &rfds); res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); diff --git a/wpa_supplicant-2.9_standard/src/common/wpa_ctrl.h b/wpa_supplicant-2.9_standard/src/common/wpa_ctrl.h index 7083713382950df7bb72186eccdb95f6f79ba9f5..edcfba36649c6710e7a4c5e0206a6d14c91ba955 100644 --- a/wpa_supplicant-2.9_standard/src/common/wpa_ctrl.h +++ b/wpa_supplicant-2.9_standard/src/common/wpa_ctrl.h @@ -87,6 +87,8 @@ extern "C" { #define WPA_EVENT_BEACON_LOSS "CTRL-EVENT-BEACON-LOSS " /** Regulatory domain channel */ #define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE " +/** Regulatory beacon hint */ +#define WPA_EVENT_REGDOM_BEACON_HINT "CTRL-EVENT-REGDOM-BEACON-HINT " /** Channel switch started (followed by freq= and other channel parameters) */ #define WPA_EVENT_CHANNEL_SWITCH_STARTED "CTRL-EVENT-STARTED-CHANNEL-SWITCH " @@ -94,7 +96,6 @@ extern "C" { #define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH " /** Chr report (followed by errCode=<>) */ #define WPA_EVENT_CHR_REPORT "CTRL-EVENT-CHR-REPORT " -#ifdef CONFIG_MLD_PATCH /** MLO link channel switch started (followed by freq= and other channel * parameters) */ @@ -104,7 +105,6 @@ extern "C" { * parameters) */ #define WPA_EVENT_LINK_CHANNEL_SWITCH "CTRL-EVENT-LINK-CHANNEL-SWITCH " -#endif /** SAE authentication failed due to unknown password identifier */ #define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \ "CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER " @@ -114,6 +114,10 @@ extern "C" { #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 " +/** TID-to-link mapping response event */ +#define WPA_EVENT_T2LM_UPDATE "CTRL-EVENT-T2LM-UPDATE " +/** MLO link reconfiguration event */ +#define WPA_EVENT_LINK_RECONFIG "CTRL-EVENT-LINK-RECONFIG " /** IP subnet status change notification * @@ -225,6 +229,17 @@ extern "C" { #define DPP_EVENT_BAND_SUPPORT "DPP-BAND-SUPPORT " #define DPP_EVENT_CSR "DPP-CSR " #define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX " +#define DPP_EVENT_CONF_NEEDED "DPP-CONF-NEEDED " +#define DPP_EVENT_PB_STATUS "DPP-PB-STATUS " +#define DPP_EVENT_PB_RESULT "DPP-PB-RESULT " +#define DPP_EVENT_RELAY_NEEDS_CONTROLLER "DPP-RELAY-NEEDS-CONTROLLER " + +/* Wi-Fi Aware (NAN USD) events */ +#define NAN_DISCOVERY_RESULT "NAN-DISCOVERY-RESULT " +#define NAN_REPLIED "NAN-REPLIED " +#define NAN_PUBLISH_TERMINATED "NAN-PUBLISH-TERMINATED " +#define NAN_SUBSCRIBE_TERMINATED "NAN-SUBSCRIBE-TERMINATED " +#define NAN_RECEIVE "NAN-RECEIVE " /* MESH events */ #define MESH_GROUP_STARTED "MESH-GROUP-STARTED " @@ -355,6 +370,7 @@ extern "C" { #define AP_EVENT_ENABLED "AP-ENABLED " #define AP_EVENT_DISABLED "AP-DISABLED " +#define AP_EVENT_NO_IR "AP-NO_IR" #define INTERFACE_ENABLED "INTERFACE-ENABLED " #define INTERFACE_DISABLED "INTERFACE-DISABLED " @@ -375,6 +391,9 @@ extern "C" { #define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED " #define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON " +/* BSS Transition Management Query frame received */ +#define BSS_TM_QUERY "BSS-TM-QUERY " + /* BSS Transition Management Response frame received */ #define BSS_TM_RESP "BSS-TM-RESP " @@ -396,6 +415,9 @@ extern "C" { /* parameters: */ #define BEACON_RESP_RX "BEACON-RESP-RX " +/* parameters: */ +#define LINK_MSR_RESP_RX "LINK-MSR-RESP-RX " + /* PMKSA cache entry added; parameters: */ #define PMKSA_CACHE_ADDED "PMKSA-CACHE-ADDED " /* PMKSA cache entry removed; parameters: */ @@ -467,6 +489,9 @@ extern "C" { #define WPA_BSS_MASK_UPDATE_IDX BIT(22) #define WPA_BSS_MASK_BEACON_IE BIT(23) #define WPA_BSS_MASK_FILS_INDICATION BIT(24) +#define WPA_BSS_MASK_RNR BIT(25) +#define WPA_BSS_MASK_ML BIT(26) +#define WPA_BSS_MASK_AP_MLD_ADDR BIT(27) #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(CONFIG_HILINK_OKC_STA) #define WPA_BSS_MASK_HILINK BIT(26) diff --git a/wpa_supplicant-2.9_standard/src/crypto/crypto.h b/wpa_supplicant-2.9_standard/src/crypto/crypto.h index 16a50430e69f9b54c8ad4360b284e5d6c4b2921c..4cd1e22e2ccf14ca120aa191f81cdab88950803e 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/crypto.h +++ b/wpa_supplicant-2.9_standard/src/crypto/crypto.h @@ -21,6 +21,8 @@ #ifndef CRYPTO_H #define CRYPTO_H +#define HMAC_VECTOR_MAX_ELEM 11 + /** * md4_vector - MD4 hash for data vector * @num_elem: Number of elements in the data vector @@ -664,15 +666,15 @@ int crypto_bignum_sqrmod(const struct crypto_bignum *a, struct crypto_bignum *c); /** - * crypto_bignum_sqrtmod - returns sqrt(a) (mod b) + * crypto_bignum_sqrmod - c = a^2 (mod b) * @a: Bignum * @b: Bignum - * @c: Bignum; used to store the result + * @c: Bignum; used to store the result of a^2 % b * Returns: 0 on success, -1 on failure */ -int crypto_bignum_sqrtmod(const struct crypto_bignum *a, - const struct crypto_bignum *b, - struct crypto_bignum *c); +int crypto_bignum_sqrmod(const struct crypto_bignum *a, + const struct crypto_bignum *b, + struct crypto_bignum *c); /** * crypto_bignum_rshift - r = a >> n @@ -955,7 +957,7 @@ void crypto_ec_point_debug_print(const struct crypto_ec *e, struct crypto_ec_key; /** - * struct crypto_ecdh - Elliptic Curve Diffie¨CHellman context + * struct crypto_ecdh - Elliptic Curve Diffie–Hellman context * * Internal data structure for ECDH. The contents is specific to the used * crypto library. @@ -963,7 +965,7 @@ struct crypto_ec_key; struct crypto_ecdh; /** - * crypto_ecdh_init - Initialize elliptic curve Diffie¨CHellman context + * crypto_ecdh_init - Initialize elliptic curve Diffie–Hellman context * @group: Identifying number for the ECC group (IANA "Group Description" * attribute registry for RFC 2409) * This function generates an ephemeral key pair. @@ -972,7 +974,7 @@ struct crypto_ecdh; struct crypto_ecdh * crypto_ecdh_init(int group); /** - * crypto_ecdh_init2 - Initialize elliptic curve Diffie¨CHellman context with a + * crypto_ecdh_init2 - Initialize elliptic curve Diffie–Hellman context with a * given EC key * @group: Identifying number for the ECC group (IANA "Group Description" * attribute registry for RFC 2409) @@ -1024,6 +1026,16 @@ size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh); */ struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len); +/** + * crypto_ec_key_set_priv - Initialize EC key pair from raw key data + * @group: Identifying number for the ECC group + * @raw: Raw key data + * @raw_len: Length of @raw buffer + * Returns: EC key or %NULL on failure + */ +struct crypto_ec_key * crypto_ec_key_set_priv(int group, + const u8 *raw, size_t raw_len); + /** * crypto_ec_key_parse_pub - Initialize EC key pair from SubjectPublicKeyInfo ASN.1 * @der: DER encoding of ASN.1 SubjectPublicKeyInfo @@ -1072,7 +1084,8 @@ void crypto_ec_key_deinit(struct crypto_ec_key *key); /** * crypto_ec_key_get_subject_public_key - Get SubjectPublicKeyInfo ASN.1 for an EC key * @key: EC key from crypto_ec_key_parse/set_pub/priv() or crypto_ec_key_gen() - * Returns: Buffer with DER encoding of ASN.1 SubjectPublicKeyInfo or %NULL on failure + * Returns: Buffer with DER encoding of ASN.1 SubjectPublicKeyInfo using + * compressed point format, or %NULL on failure */ struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key); @@ -1100,16 +1113,20 @@ struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key, * crypto_ec_key_get_public_key - Get EC public key as an EC point * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_parse_priv() * Returns: Public key as an EC point or %NULL on failure + * + * The caller needs to free the returned value with crypto_ec_point_deinit(). */ -const struct crypto_ec_point * +struct crypto_ec_point * crypto_ec_key_get_public_key(struct crypto_ec_key *key); /** * crypto_ec_key_get_private_key - Get EC private key as a bignum * @key: EC key from crypto_ec_key_parse/set_pub() or crypto_ec_key_parse_priv() * Returns: Private key as a bignum or %NULL on failure + * + * The caller needs to free the returned value with crypto_bignum_deinit(). */ -const struct crypto_bignum * +struct crypto_bignum * crypto_ec_key_get_private_key(struct crypto_ec_key *key); /** @@ -1289,4 +1306,98 @@ struct wpabuf * crypto_csr_sign(struct crypto_csr *csr, struct crypto_ec_key *key, enum crypto_hash_alg algo); +struct crypto_rsa_key; + +/** + * crypto_rsa_key_read - Read an RSA key + * @file: File from which to read (PEM encoded, can be X.509v3 certificate) + * @private_key: Whether to read the private key instead of public key + * Returns: RSA key or %NULL on failure + */ +struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key); + +/** + * crypto_rsa_oaep_sha256_encrypt - RSA-OAEP-SHA-256 encryption + * @key: RSA key from crypto_rsa_key_read() + * @in: Plaintext input data + * Returns: Encrypted output data or %NULL on failure + */ +struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key, + const struct wpabuf *in); + +/** + * crypto_rsa_oaep_sha256_decrypt - RSA-OAEP-SHA-256 decryption + * @key: RSA key from crypto_rsa_key_read() + * @in: Encrypted input data + * Returns: Decrypted output data or %NULL on failure + */ +struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key, + const struct wpabuf *in); + +/** + * crypto_rsa_key_free - Free an RSA key + * @key: RSA key from crypto_rsa_key_read() + */ +void crypto_rsa_key_free(struct crypto_rsa_key *key); + +enum hpke_mode { + HPKE_MODE_BASE = 0x00, + HPKE_MODE_PSK = 0x01, + HPKE_MODE_AUTH = 0x02, + HPKE_MODE_AUTH_PSK = 0x03, +}; + +enum hpke_kem_id { + HPKE_DHKEM_P256_HKDF_SHA256 = 0x0010, + HPKE_DHKEM_P384_HKDF_SHA384 = 0x0011, + HPKE_DHKEM_P521_HKDF_SHA512 = 0x0012, + HPKE_DHKEM_X5519_HKDF_SHA256 = 0x0020, + HPKE_DHKEM_X448_HKDF_SHA512 = 0x0021, +}; + +enum hpke_kdf_id { + HPKE_KDF_HKDF_SHA256 = 0x0001, + HPKE_KDF_HKDF_SHA384 = 0x0002, + HPKE_KDF_HKDF_SHA512 = 0x0003, +}; + +enum hpke_aead_id { + HPKE_AEAD_AES_128_GCM = 0x0001, + HPKE_AEAD_AES_256_GCM = 0x0002, + HPKE_AEAD_CHACHA20POLY1305 = 0x0003, +}; + +/** + * hpke_base_seal - HPKE base mode single-shot encrypt + * Returns: enc | ct; or %NULL on failure + */ +struct wpabuf * hpke_base_seal(enum hpke_kem_id kem_id, + enum hpke_kdf_id kdf_id, + enum hpke_aead_id aead_id, + struct crypto_ec_key *peer_pub, + const u8 *info, size_t info_len, + const u8 *aad, size_t aad_len, + const u8 *pt, size_t pt_len); + +/** + * hpke_base_open - HPKE base mode single-shot decrypt + * @enc_ct: enc | ct + * Returns: pt; or %NULL on failure + */ +struct wpabuf * hpke_base_open(enum hpke_kem_id kem_id, + enum hpke_kdf_id kdf_id, + enum hpke_aead_id aead_id, + struct crypto_ec_key *own_priv, + const u8 *info, size_t info_len, + const u8 *aad, size_t aad_len, + const u8 *enc_ct, size_t enc_ct_len); + +/** + * crypto_unload - Unload crypto resources + * + * This function is called just before the process exits to allow dynamic + * resource allocations to be freed. + */ +void crypto_unload(void); + #endif /* CRYPTO_H */ diff --git a/wpa_supplicant-2.9_standard/src/crypto/crypto_gnutls.c b/wpa_supplicant-2.9_standard/src/crypto/crypto_gnutls.c index 4ef11462b36e82d7dd5e5cfabb4496c681e4d179..a7a163f5cb2a3bb35255adf48ec14d2d42f4ae57 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/crypto_gnutls.c +++ b/wpa_supplicant-2.9_standard/src/crypto/crypto_gnutls.c @@ -504,3 +504,8 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx) gcry_cipher_close(ctx->dec); os_free(ctx); } + + +void crypto_unload(void) +{ +} diff --git a/wpa_supplicant-2.9_standard/src/crypto/crypto_internal.c b/wpa_supplicant-2.9_standard/src/crypto/crypto_internal.c index aad40af16e06e3cc9e7c1b53b2bacbabf1bb5412..d15c363c9ef66d22f0800befe17361552fa61de0 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/crypto_internal.c +++ b/wpa_supplicant-2.9_standard/src/crypto/crypto_internal.c @@ -326,3 +326,8 @@ int crypto_global_init(void) void crypto_global_deinit(void) { } + + +void crypto_unload(void) +{ +} diff --git a/wpa_supplicant-2.9_standard/src/crypto/crypto_libtomcrypt.c b/wpa_supplicant-2.9_standard/src/crypto/crypto_libtomcrypt.c index ed30efa021d76d4bde3df91c3355183580997024..fd79c1a40337ab10404dcb64cb1b4a9f7c2ef11e 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/crypto_libtomcrypt.c +++ b/wpa_supplicant-2.9_standard/src/crypto/crypto_libtomcrypt.c @@ -766,3 +766,8 @@ fail: } #endif /* CONFIG_MODEXP */ + + +void crypto_unload(void) +{ +} diff --git a/wpa_supplicant-2.9_standard/src/crypto/crypto_linux.c b/wpa_supplicant-2.9_standard/src/crypto/crypto_linux.c index 17244561b372f7612faa7b63c6db29f06766762e..9278e279795f791a33bdbede078137a2dd5d6808 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/crypto_linux.c +++ b/wpa_supplicant-2.9_standard/src/crypto/crypto_linux.c @@ -1007,3 +1007,8 @@ int crypto_global_init(void) void crypto_global_deinit(void) { } + + +void crypto_unload(void) +{ +} diff --git a/wpa_supplicant-2.9_standard/src/crypto/crypto_module_tests.c b/wpa_supplicant-2.9_standard/src/crypto/crypto_module_tests.c index fafb688b45f6105edb12a339406fa1d64e8139d9..ffeddbaddfacf103f8a084ea00ddbd6120845635 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/crypto_module_tests.c +++ b/wpa_supplicant-2.9_standard/src/crypto/crypto_module_tests.c @@ -2190,6 +2190,286 @@ static int test_extract_expand_hkdf(void) } +#ifdef CONFIG_DPP3 + +static const struct hpke_test { + const char *name; + enum hpke_mode mode; + enum hpke_kem_id kem_id; + enum hpke_kdf_id kdf_id; + enum hpke_aead_id aead_id; + const char *info; + int sk_r_group; + const char *pk_r; + const char *sk_r; + const char *enc; + const char *pt; + const char *aad; + const char *ct; +} hpke_tests[] = { + { + .name = "A.3. DHKEM(P-256, HKDF-SHA256), HKDF-SHA256, AES-128-GCM", + .mode = HPKE_MODE_BASE, + .kem_id = HPKE_DHKEM_P256_HKDF_SHA256, + .kdf_id = HPKE_KDF_HKDF_SHA256, + .aead_id = HPKE_AEAD_AES_128_GCM, + .info = "4f6465206f6e2061204772656369616e2055726e", + .sk_r_group = 19, + .pk_r = "04fe8c19ce0905191ebc298a9245792531f26f0cece2460639e8bc39cb7f706a826a779b4cf969b8a0e539c7f62fb3d30ad6aa8f80e30f1d128aafd68a2ce72ea0", + .sk_r = "f3ce7fdae57e1a310d87f1ebbde6f328be0a99cdbcadf4d6589cf29de4b8ffd2", + .enc = "04a92719c6195d5085104f469a8b9814d5838ff72b60501e2c4466e5e67b325ac98536d7b61a1af4b78e5b7f951c0900be863c403ce65c9bfcb9382657222d18c4", + .pt = "4265617574792069732074727574682c20747275746820626561757479", + .aad = "436f756e742d30", + .ct = "5ad590bb8baa577f8619db35a36311226a896e7342a6d836d8b7bcd2f20b6c7f9076ac232e3ab2523f39513434", + }, + { + .name = "A.4. DHKEM(P-256, HKDF-SHA256), HKDF-SHA512, AES-128-GCM", + .mode = HPKE_MODE_BASE, + .kem_id = HPKE_DHKEM_P256_HKDF_SHA256, + .kdf_id = HPKE_KDF_HKDF_SHA512, + .aead_id = HPKE_AEAD_AES_128_GCM, + .info = "4f6465206f6e2061204772656369616e2055726e", + .sk_r_group = 19, + .pk_r = "04085aa5b665dc3826f9650ccbcc471be268c8ada866422f739e2d531d4a8818a9466bc6b449357096232919ec4fe9070ccbac4aac30f4a1a53efcf7af90610edd", + .sk_r = "3ac8530ad1b01885960fab38cf3cdc4f7aef121eaa239f222623614b4079fb38", + .enc = "0493ed86735bdfb978cc055c98b45695ad7ce61ce748f4dd63c525a3b8d53a15565c6897888070070c1579db1f86aaa56deb8297e64db7e8924e72866f9a472580", + .pt = "4265617574792069732074727574682c20747275746820626561757479", + .aad = "436f756e742d30", + .ct = "d3cf4984931484a080f74c1bb2a6782700dc1fef9abe8442e44a6f09044c88907200b332003543754eb51917ba", + }, + { + .name = "A.6. DHKEM(P-521, HKDF-SHA512), HKDF-SHA512, AES-256-GCM", + .mode = HPKE_MODE_BASE, + .kem_id = HPKE_DHKEM_P521_HKDF_SHA512, + .kdf_id = HPKE_KDF_HKDF_SHA512, + .aead_id = HPKE_AEAD_AES_256_GCM, + .info = "4f6465206f6e2061204772656369616e2055726e", + .sk_r_group = 21, + .pk_r = "0401b45498c1714e2dce167d3caf162e45e0642afc7ed435df7902ccae0e84ba0f7d373f646b7738bbbdca11ed91bdeae3cdcba3301f2457be452f271fa6837580e661012af49583a62e48d44bed350c7118c0d8dc861c238c72a2bda17f64704f464b57338e7f40b60959480c0e58e6559b190d81663ed816e523b6b6a418f66d2451ec64", + .sk_r = "01462680369ae375e4b3791070a7458ed527842f6a98a79ff5e0d4cbde83c27196a3916956655523a6a2556a7af62c5cadabe2ef9da3760bb21e005202f7b2462847", + .enc = "040138b385ca16bb0d5fa0c0665fbbd7e69e3ee29f63991d3e9b5fa740aab8900aaeed46ed73a49055758425a0ce36507c54b29cc5b85a5cee6bae0cf1c21f2731ece2013dc3fb7c8d21654bb161b463962ca19e8c654ff24c94dd2898de12051f1ed0692237fb02b2f8d1dc1c73e9b366b529eb436e98a996ee522aef863dd5739d2f29b0", + .pt = "4265617574792069732074727574682c20747275746820626561757479", + .aad = "436f756e742d30", + .ct = "170f8beddfe949b75ef9c387e201baf4132fa7374593dfafa90768788b7b2b200aafcc6d80ea4c795a7c5b841a", + }, + { /* self-generated test vector for P-384 */ + .name = "custom DHKEM(P-384, HKDF-SHA384), HKDF-SHA384, AES-256-GCM", + .mode = HPKE_MODE_BASE, + .kem_id = HPKE_DHKEM_P384_HKDF_SHA384, + .kdf_id = HPKE_KDF_HKDF_SHA384, + .aead_id = HPKE_AEAD_AES_256_GCM, + .info = "4f6465206f6e2061204772656369616e2055726e", + .sk_r_group = 20, + .pk_r = "049c0e4dcbbb3c80715cafaa1839d0bc3c3adcc95eb8062f84175f9c3cec115e6b799061c65a0605907785c25b3571564706a8ba6a204452b38c7c205db17d328f2353df05d5f1c568e7503331178c36c2d37bbed48401295407face3f8dae5ed8", + .sk_r = "cabffb07d20ffcfdaa043e1de49e1654659e0f0aba5de56523e8b73dc80c579a9e5c89ed3810ec21c4bafcf74ad2a245", + .enc = "04b30bea96d0e51582033b02a4d676d0464a5eb2d858be86cda1c4e6f8b2aa9fb80f5365483f781b1b3a8b3b8efd50b0f7bca16f06d0435fa3da1d671ea0a318b40fe170a074923c651e5dc824966b7b98d0e36bdf932875dae7130369a793cecc", + .pt = "4265617574792069732074727574682c20747275746820626561757479", + .aad = "436f756e742d30", + .ct = "ae7feccfea0f8fcd620d15369a28db8701cdc90d55c20efff6296bd441697b0da34671d1f3c4864183e86d27fc", + }, + { /* self-generated test vector for BP-256 */ + .name = "custom PB-256 using DHKEM(P-256, HKDF-SHA256), HKDF-SHA256, AES-128-GCM", + .mode = HPKE_MODE_BASE, + .kem_id = HPKE_DHKEM_P256_HKDF_SHA256, + .kdf_id = HPKE_KDF_HKDF_SHA256, + .aead_id = HPKE_AEAD_AES_128_GCM, + .info = "4f6465206f6e2061204772656369616e2055726e", + .sk_r_group = 28, + .pk_r = "04a2cb9c4cae90cdc1c27516e9f84b6b166e4b1dcc517286268239ddb0bf74cca6390fed092ac4423ab2192b8bb41a4824d908d2053b93fc813830bebac5ce19b9", + .sk_r = "11d9db41c4341166ca52f5a1775595c0bdb4934350daeb7bce659c4b7a40e314", + .enc = "047a25e309c7ee50ec27f13d44734a3ccd8c703e3affcc728513df416511ef9bf02f5e7750e7415de8b5f306ebd3fc88ea9b9368523eb1733a8d82c1a877e5a0f4", + .pt = "4265617574792069732074727574682c20747275746820626561757479", + .aad = "436f756e742d30", + .ct = "17c84b3f07f6ffe08ff2be45c709ea782229504aa5b2253876725c6c39f8d8c992304fc5877994f79d6c10d462", + }, + { /* self-generated test vector for BP-384 */ + .name = "custom PB-384 using DHKEM(P-384, HKDF-SHA384), HKDF-SHA384, AES-256-GCM", + .mode = HPKE_MODE_BASE, + .kem_id = HPKE_DHKEM_P384_HKDF_SHA384, + .kdf_id = HPKE_KDF_HKDF_SHA384, + .aead_id = HPKE_AEAD_AES_256_GCM, + .info = "4f6465206f6e2061204772656369616e2055726e", + .sk_r_group = 29, + .pk_r = "041f4199ad28835908079c45d165d55630098be53eb4beede9921f5b2204fa396111f99ac54c56411f7cb2c43ec18d8e604d895027228cf975f5a4b598f189d8fb03e3fefe020258c40d4d1b15fd7587d209925d67a41f9659a8ed6f662fb441e4", + .sk_r = "7017cf8a5a9a81ad4e0d755ccbea27a378b787561f8d5662639850805fefcbaab6b9a15729872abb7dc53d19a6cf77e4", + .enc = "0415d49dedc5bc1ffe9f8de9022c266bb605ec6cd7b77b6ce68974095398856f8aefa4b7abbfbd496b99a2dda3a9c65f1a71b9d40255aa1c7c4205a8b4ef611b96ed29fd2d7b0cde4c0e82058805e6276025cc4fc606f6e5771c31bd9704e9ba0b", + .pt = "4265617574792069732074727574682c20747275746820626561757479", + .aad = "436f756e742d30", + .ct = "5f5e9f82bedadec0e9b01a1b304cb48b05c0d6d397b1c8a95ed541218ec54f634a41cbc4066910a409e47b254e", + }, + { /* self-generated test vector for BP-512 */ + .name = "custom PB-512 using DHKEM(P-521, HKDF-SHA512), HKDF-SHA512, AES-256-GCM", + .mode = HPKE_MODE_BASE, + .kem_id = HPKE_DHKEM_P521_HKDF_SHA512, + .kdf_id = HPKE_KDF_HKDF_SHA512, + .aead_id = HPKE_AEAD_AES_256_GCM, + .info = "4f6465206f6e2061204772656369616e2055726e", + .sk_r_group = 30, + .pk_r = "049e81046a531365a3b5215ac37e7b38f5fa34f86c4eb2e03113b197390a26c555bb007596e131c2541f336eb24a45f44283b5b53fedddfa5642675602fdec17d34120a35efffb44952e32dee7732f2f3245c3314269996b610703a63fb8555a75ca5092690a1125ae8712c1e31fd77aee42bd052e71f9f9459814d6f4065bcea0", + .sk_r = "483b6882608182b296843fa7dfffbdd61ed0372574d4aa32a035c8e33a493927aaf00d42bd9124ebe4df26010b38124668c02b35a749e74845d565734310cfe9", + .enc = "04158d18473aeb3b283d3345b1a87d3de2b192ff9e41b5a98f91daacfb24be72e698cbc04c33078681e507bf346c0ea70c927083a22ca9ea027f420067ee42285b798d95fea51002d097ce28371883202bfd300fb64943669e32c6f1a348087368bb480b757892ebd199a9389978c92cbc44076626d705a771fbbd90c030a6767e", + .pt = "4265617574792069732074727574682c20747275746820626561757479", + .aad = "436f756e742d30", + .ct = "033d91c4514857da5b833635180c1acc09f175cbf44777a7b71e177705cfd17437b1c85d671dd767bb4fe20e2e", + }, +}; + + +static int run_hpke_test(const struct hpke_test *test) +{ + struct wpabuf *info, *pk_r, *sk_r, *enc, *pt, *aad, *ct; + struct wpabuf *res_pt = NULL, *enc_ct = NULL, *res_ct = NULL; + struct crypto_ec_key *own_priv = NULL, *peer_pub = NULL; + int res = -1; + size_t coord_len; + + wpa_printf(MSG_INFO, "- %s", test->name); + + info = wpabuf_parse_bin(test->info); + pk_r = wpabuf_parse_bin(test->pk_r); + sk_r = wpabuf_parse_bin(test->sk_r); + enc = wpabuf_parse_bin(test->enc); + pt = wpabuf_parse_bin(test->pt); + aad = wpabuf_parse_bin(test->aad); + ct = wpabuf_parse_bin(test->ct); + if (!info || !pk_r || !sk_r || !enc || !pt || !aad || !ct) { + wpa_printf(MSG_ERROR, "Could not parse test data"); + goto fail; + } + + /* Receiver - decryption against the test vector */ + + enc_ct = wpabuf_concat(enc, ct); + enc = NULL; + ct = NULL; + if (!enc_ct) + goto fail; + + own_priv = crypto_ec_key_set_priv(test->sk_r_group, wpabuf_head(sk_r), + wpabuf_len(sk_r)); + if (!own_priv) { + wpa_printf(MSG_ERROR, + "HPKE base open - failed to set private key"); + goto fail; + } + + res_pt = hpke_base_open(test->kem_id, test->kdf_id, test->aead_id, + own_priv, + wpabuf_head(info), wpabuf_len(info), + wpabuf_head(aad), wpabuf_len(aad), + wpabuf_head(enc_ct), wpabuf_len(enc_ct)); + if (!res_pt) { + wpa_printf(MSG_ERROR, "HPKE base open - failed to decrypt"); + wpa_hexdump_buf(MSG_INFO, "pt", res_pt); + goto fail; + } + if (wpabuf_len(res_pt) != wpabuf_len(pt) || + os_memcmp(wpabuf_head(res_pt), wpabuf_head(pt), + wpabuf_len(pt)) != 0) { + wpa_printf(MSG_ERROR, + "HPKE base open - failed - decryption mismatch"); + goto fail; + } + + /* Sender - encryption (randomized algorithm) */ + + if (test->sk_r_group == 19) + coord_len = 32; + else if (test->sk_r_group == 20) + coord_len = 48; + else if (test->sk_r_group == 21) + coord_len = 66; + else if (test->sk_r_group == 28) + coord_len = 32; + else if (test->sk_r_group == 29) + coord_len = 48; + else if (test->sk_r_group == 30) + coord_len = 64; + else + goto fail; + if (wpabuf_len(pk_r) != 1 + 2 * coord_len) { + wpa_printf(MSG_ERROR, "Unexpected pkR length (%zu != %zu)", + wpabuf_len(pk_r), 1 + 2 * coord_len); + goto fail; + } + peer_pub = crypto_ec_key_set_pub(test->sk_r_group, + wpabuf_head_u8(pk_r) + 1, + wpabuf_head_u8(pk_r) + 1 + coord_len, + coord_len); + if (!peer_pub) { + wpa_printf(MSG_ERROR, + "HPKE base open - failed to set public key"); + goto fail; + } + + res_ct = hpke_base_seal(test->kem_id, test->kdf_id, test->aead_id, + peer_pub, + wpabuf_head(info), wpabuf_len(info), + wpabuf_head(aad), wpabuf_len(aad), + wpabuf_head(pt), wpabuf_len(pt)); + if (!res_ct) { + wpa_printf(MSG_ERROR, "HPKE base open - failed to encrypt"); + goto fail; + } + + /* Receiver - decryption (to verify own encryption) */ + + wpabuf_free(res_pt); + res_pt = hpke_base_open(test->kem_id, test->kdf_id, test->aead_id, + own_priv, + wpabuf_head(info), wpabuf_len(info), + wpabuf_head(aad), wpabuf_len(aad), + wpabuf_head(res_ct), wpabuf_len(res_ct)); + if (!res_pt) { + wpa_printf(MSG_ERROR, "HPKE base open - failed to decrypt own encrypted version"); + goto fail; + } + if (wpabuf_len(res_pt) != wpabuf_len(pt) || + os_memcmp(wpabuf_head(res_pt), wpabuf_head(pt), + wpabuf_len(pt)) != 0) { + wpa_printf(MSG_ERROR, + "HPKE base open - failed - decryption mismatch for own encrypted version"); + wpa_hexdump_buf(MSG_INFO, "pt", res_pt); + goto fail; + } + + res = 0; +fail: + wpabuf_free(info); + wpabuf_free(pk_r); + wpabuf_free(sk_r); + wpabuf_free(enc); + wpabuf_free(pt); + wpabuf_free(aad); + wpabuf_free(ct); + wpabuf_free(enc_ct); + wpabuf_free(res_pt); + wpabuf_free(res_ct); + crypto_ec_key_deinit(own_priv); + crypto_ec_key_deinit(peer_pub); + return res; +} + +#endif /* CONFIG_DPP3 */ + + +static int test_hpke(void) +{ +#ifdef CONFIG_DPP3 + unsigned int i; + + wpa_printf(MSG_INFO, "RFC 9180 - HPKE"); + for (i = 0; i < ARRAY_SIZE(hpke_tests); i++) { + if (run_hpke_test(&hpke_tests[i]) < 0) + return -1; + } + + wpa_printf(MSG_INFO, "HPKE base open test cases passed"); +#endif /* CONFIG_DPP3 */ + return 0; +} + + static int test_ms_funcs(void) { #ifndef CONFIG_FIPS @@ -2310,6 +2590,7 @@ int crypto_module_tests(void) test_sha384() || test_fips186_2_prf() || test_extract_expand_hkdf() || + test_hpke() || test_ms_funcs()) ret = -1; diff --git a/wpa_supplicant-2.9_standard/src/crypto/crypto_nettle.c b/wpa_supplicant-2.9_standard/src/crypto/crypto_nettle.c index f85d36532ea1921b0373f177765e8ad070a584f0..d745027727cd5ee12d3016871a7223df4b2a32f5 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/crypto_nettle.c +++ b/wpa_supplicant-2.9_standard/src/crypto/crypto_nettle.c @@ -467,3 +467,8 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx) { bin_clear_free(ctx, sizeof(*ctx)); } + + +void crypto_unload(void) +{ +} diff --git a/wpa_supplicant-2.9_standard/src/crypto/crypto_none.c b/wpa_supplicant-2.9_standard/src/crypto/crypto_none.c index 547919418af998f7d86f3f608951954342c2ec0e..a0dc0f52b00c76f4c75f2a0bc1c03bc67b10ecd6 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/crypto_none.c +++ b/wpa_supplicant-2.9_standard/src/crypto/crypto_none.c @@ -22,3 +22,8 @@ int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) { return 0; } + + +void crypto_unload(void) +{ +} diff --git a/wpa_supplicant-2.9_standard/src/crypto/crypto_openssl.c b/wpa_supplicant-2.9_standard/src/crypto/crypto_openssl.c index cacca7e16394627a4ce4096d8ab47f6e2e36c81d..ac4caa5859b71a123feee912fd11a6fdf9b9130a 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/crypto_openssl.c +++ b/wpa_supplicant-2.9_standard/src/crypto/crypto_openssl.c @@ -1,6 +1,6 @@ /* * Wrapper functions for OpenSSL libcrypto - * Copyright (c) 2004-2017, Jouni Malinen + * Copyright (c) 2004-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -16,17 +16,26 @@ #include #include #include -#ifdef CONFIG_OPENSSL_CMAC -#include -#endif /* CONFIG_OPENSSL_CMAC */ +#include +#include #ifdef CONFIG_ECC #include #include -#include #endif /* CONFIG_ECC */ #if OPENSSL_VERSION_NUMBER >= 0x30000000L #include +#include +#include +#include +#include +#else /* OpenSSL version >= 3.0 */ +#include #endif /* OpenSSL version >= 3.0 */ +#ifdef CONFIG_DPP3 +#if OPENSSL_VERSION_NUMBER >= 0x30200000L +#include +#endif +#endif /* CONFIG_DPP3 */ #include "common.h" #include "utils/const_time.h" @@ -40,9 +49,7 @@ #include "aes_wrap.h" #include "crypto.h" -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L /* Compatibility wrappers for older versions. */ static HMAC_CTX * HMAC_CTX_new(void) @@ -118,33 +125,98 @@ static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x) { return ASN1_STRING_data((ASN1_STRING *) x); } + + +static const ASN1_TIME * X509_get0_notBefore(const X509 *x) +{ + return X509_get_notBefore(x); +} + + +static const ASN1_TIME * X509_get0_notAfter(const X509 *x) +{ + return X509_get_notAfter(x); +} + #endif /* OpenSSL version < 1.1.0 */ -void openssl_load_legacy_provider(void) +#if OPENSSL_VERSION_NUMBER < 0x10101000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x30400000L) + +static int EC_POINT_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, BIGNUM *x, + BIGNUM *y, BN_CTX *ctx) +{ + return EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx); +} + + +static int EC_POINT_set_affine_coordinates(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + const BIGNUM *y, BN_CTX *ctx) +{ + return EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx); +} + +#endif /* OpenSSL version < 1.1.1 */ + + +#if OPENSSL_VERSION_NUMBER < 0x10101000L || \ + defined(OPENSSL_IS_BORINGSSL) || \ + (defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER < 0x30400000L) + +static int EC_POINT_set_compressed_coordinates(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + int y_bit, BN_CTX *ctx) { + return EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, + ctx); +} + + +static int EC_GROUP_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, + BIGNUM *b, BN_CTX *ctx) +{ + return EC_GROUP_get_curve_GFp(group, p, a, b, ctx); +} + +#endif /* OpenSSL version < 1.1.1 */ + + #if OPENSSL_VERSION_NUMBER >= 0x30000000L - static bool loaded = false; - OSSL_PROVIDER *legacy; +static OSSL_PROVIDER *openssl_legacy_provider = NULL; +#endif /* OpenSSL version >= 3.0 */ - if (loaded) +void openssl_load_legacy_provider(void) +{ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (openssl_legacy_provider) return; - legacy = OSSL_PROVIDER_load(NULL, "legacy"); + openssl_legacy_provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1); +#endif /* OpenSSL version >= 3.0 */ +} - if (legacy) { - OSSL_PROVIDER_load(NULL, "default"); - loaded = true; + +static void openssl_unload_legacy_provider(void) +{ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (openssl_legacy_provider) { + OSSL_PROVIDER_unload(openssl_legacy_provider); + openssl_legacy_provider = NULL; } #endif /* OpenSSL version >= 3.0 */ } +#if OPENSSL_VERSION_NUMBER < 0x30000000L + static BIGNUM * get_group5_prime(void) { -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !(defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L return BN_get_rfc3526_prime_1536(NULL); #elif !defined(OPENSSL_IS_BORINGSSL) return get_rfc3526_prime_1536(NULL); @@ -195,6 +267,8 @@ static BIGNUM * get_group5_order(void) return BN_bin2bn(RFC3526_ORDER_1536, sizeof(RFC3526_ORDER_1536), NULL); } +#endif /* OpenSSL version < 3.0 */ + #ifdef OPENSSL_NO_SHA256 #define NO_SHA256_WRAPPER @@ -244,12 +318,12 @@ static int openssl_digest_vector(const EVP_MD *type, size_t num_elem, #ifndef CONFIG_FIPS + int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { openssl_load_legacy_provider(); return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac); } -#endif /* CONFIG_FIPS */ int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) @@ -328,11 +402,11 @@ out: #endif /* CONFIG_NO_RC4 */ -#ifndef CONFIG_FIPS int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac); } + #endif /* CONFIG_FIPS */ @@ -378,9 +452,9 @@ static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen) return EVP_aes_192_ecb(); case 32: return EVP_aes_256_ecb(); + default: + return NULL; } - - return NULL; } @@ -402,11 +476,11 @@ void * aes_encrypt_init(const u8 *key, size_t len) ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return NULL; - if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) { - os_free(ctx); + if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1 || + EVP_CIPHER_CTX_set_padding(ctx, 0) != 1) { + EVP_CIPHER_CTX_free(ctx); return NULL; } - EVP_CIPHER_CTX_set_padding(ctx, 0); return ctx; } @@ -459,11 +533,11 @@ void * aes_decrypt_init(const u8 *key, size_t len) ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) return NULL; - if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) { + if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1 || + EVP_CIPHER_CTX_set_padding(ctx, 0) != 1) { EVP_CIPHER_CTX_free(ctx); return NULL; } - EVP_CIPHER_CTX_set_padding(ctx, 0); return ctx; } @@ -501,8 +575,52 @@ void aes_decrypt_deinit(void *ctx) #ifndef CONFIG_FIPS #ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static const EVP_CIPHER * aes_get_evp_wrap_cipher(size_t keylen) +{ + switch (keylen) { + case 16: + return EVP_aes_128_wrap(); + case 24: + return EVP_aes_192_wrap(); + case 32: + return EVP_aes_256_wrap(); + default: + return NULL; + } +} +#endif /* OpenSSL version >= 3.0 */ + + int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_CIPHER_CTX *ctx; + const EVP_CIPHER *type; + int ret = -1, len; + u8 buf[16]; + + if (TEST_FAIL()) + return -1; + + type = aes_get_evp_wrap_cipher(kek_len); + if (!type) + return -1; + + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + return -1; + + if (EVP_EncryptInit_ex(ctx, type, NULL, kek, NULL) == 1 && + EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 && + EVP_EncryptUpdate(ctx, cipher, &len, plain, n * 8) == 1 && + len == (n + 1) * 8 && + EVP_EncryptFinal_ex(ctx, buf, &len) == 1) + ret = 0; + + EVP_CIPHER_CTX_free(ctx); + return ret; +#else /* OpenSSL version >= 3.0 */ AES_KEY actx; int res; @@ -513,12 +631,40 @@ int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8); OPENSSL_cleanse(&actx, sizeof(actx)); return res <= 0 ? -1 : 0; +#endif /* OpenSSL version >= 3.0 */ } int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, u8 *plain) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_CIPHER_CTX *ctx; + const EVP_CIPHER *type; + int ret = -1, len; + u8 buf[16]; + + if (TEST_FAIL()) + return -1; + + type = aes_get_evp_wrap_cipher(kek_len); + if (!type) + return -1; + + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + return -1; + + if (EVP_DecryptInit_ex(ctx, type, NULL, kek, NULL) == 1 && + EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 && + EVP_DecryptUpdate(ctx, plain, &len, cipher, (n + 1) * 8) == 1 && + len == n * 8 && + EVP_DecryptFinal_ex(ctx, buf, &len) == 1) + ret = 0; + + EVP_CIPHER_CTX_free(ctx); + return ret; +#else /* OpenSSL version >= 3.0 */ AES_KEY actx; int res; @@ -529,6 +675,7 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8); OPENSSL_cleanse(&actx, sizeof(actx)); return res <= 0 ? -1 : 0; +#endif /* OpenSSL version >= 3.0 */ } #endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */ @@ -819,9 +966,7 @@ void crypto_cipher_deinit(struct crypto_cipher *ctx) void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L DH *dh; struct wpabuf *pubkey = NULL, *privkey = NULL; size_t publen, privlen; @@ -870,6 +1015,57 @@ err: wpabuf_clear_free(privkey); DH_free(dh); return NULL; +#elif OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *pkey = NULL; + OSSL_PARAM params[2]; + size_t pub_len = OSSL_PARAM_UNMODIFIED; + size_t priv_len; + struct wpabuf *pubkey = NULL, *privkey = NULL; + BIGNUM *priv_bn = NULL; + EVP_PKEY_CTX *gctx; + + *priv = NULL; + wpabuf_free(*publ); + *publ = NULL; + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + "modp_1536", 0); + params[1] = OSSL_PARAM_construct_end(); + + gctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + if (!gctx || + EVP_PKEY_keygen_init(gctx) != 1 || + EVP_PKEY_CTX_set_params(gctx, params) != 1 || + EVP_PKEY_generate(gctx, &pkey) != 1 || + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, + &priv_bn) != 1 || + EVP_PKEY_get_octet_string_param(pkey, + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, + NULL, 0, &pub_len) < 0 || + pub_len == OSSL_PARAM_UNMODIFIED || + (priv_len = BN_num_bytes(priv_bn)) == 0 || + !(pubkey = wpabuf_alloc(pub_len)) || + !(privkey = wpabuf_alloc(priv_len)) || + EVP_PKEY_get_octet_string_param(pkey, + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, + wpabuf_put(pubkey, pub_len), + pub_len, NULL) != 1) { + wpa_printf(MSG_INFO, "OpenSSL: failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + wpabuf_free(pubkey); + wpabuf_clear_free(privkey); + EVP_PKEY_free(pkey); + pkey = NULL; + } else { + BN_bn2bin(priv_bn, wpabuf_put(privkey, priv_len)); + + *priv = privkey; + *publ = pubkey; + } + + BN_clear_free(priv_bn); + EVP_PKEY_CTX_free(gctx); + return pkey; #else DH *dh; struct wpabuf *pubkey = NULL, *privkey = NULL; @@ -929,9 +1125,7 @@ err: void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L DH *dh; dh = DH_new(); @@ -962,6 +1156,39 @@ void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ) err: DH_free(dh); return NULL; +#elif OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *pkey = NULL; + OSSL_PARAM_BLD *bld; + OSSL_PARAM *params = NULL; + BIGNUM *priv_key, *pub_key; + EVP_PKEY_CTX *fctx; + + fctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL); + pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL); + bld = OSSL_PARAM_BLD_new(); + if (!fctx || !priv_key || !pub_key || !bld || + OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, + "modp_1536", 0) != 1 || + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, + priv_key) != 1 || + OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, + pub_key) != 1 || + !(params = OSSL_PARAM_BLD_to_param(bld)) || + EVP_PKEY_fromdata_init(fctx) != 1 || + EVP_PKEY_fromdata(fctx, &pkey, EVP_PKEY_KEYPAIR, params) != 1) { + wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_fromdata failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + EVP_PKEY_free(pkey); + pkey = NULL; + } + + BN_clear_free(priv_key); + BN_free(pub_key); + EVP_PKEY_CTX_free(fctx); + OSSL_PARAM_BLD_free(bld); + OSSL_PARAM_free(params); + return pkey; #else DH *dh; BIGNUM *p = NULL, *g, *priv_key = NULL, *pub_key = NULL; @@ -1004,6 +1231,36 @@ err: struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, const struct wpabuf *own_private) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *pkey = ctx; + EVP_PKEY *peer_pub; + size_t len; + struct wpabuf *res = NULL; + EVP_PKEY_CTX *dctx = NULL; + + peer_pub = EVP_PKEY_new(); + if (!pkey || !peer_pub || + EVP_PKEY_copy_parameters(peer_pub, pkey) != 1 || + EVP_PKEY_set1_encoded_public_key(peer_pub, wpabuf_head(peer_public), + wpabuf_len(peer_public)) != 1 || + !(dctx = EVP_PKEY_CTX_new(pkey, NULL)) || + EVP_PKEY_derive_init(dctx) != 1 || + EVP_PKEY_derive_set_peer(dctx, peer_pub) != 1 || + EVP_PKEY_derive(dctx, NULL, &len) != 1 || + !(res = wpabuf_alloc(len)) || + EVP_PKEY_derive(dctx, wpabuf_mhead(res), &len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + wpabuf_free(res); + res = NULL; + } else { + wpabuf_put(res, len); + } + + EVP_PKEY_free(peer_pub); + EVP_PKEY_CTX_free(dctx); + return res; +#else /* OpenSSL version >= 3.0 */ BIGNUM *pub_key; struct wpabuf *res = NULL; size_t rlen; @@ -1035,27 +1292,95 @@ err: BN_clear_free(pub_key); wpabuf_clear_free(res); return NULL; +#endif /* OpenSSL version >= 3.0 */ } void dh5_free(void *ctx) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *pkey = ctx; + + EVP_PKEY_free(pkey); +#else /* OpenSSL version >= 3.0 */ DH *dh; if (ctx == NULL) return; dh = ctx; DH_free(dh); +#endif /* OpenSSL version >= 3.0 */ } struct crypto_hash { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MAC_CTX *ctx; +#else /* OpenSSL version >= 3.0 */ HMAC_CTX *ctx; +#endif /* OpenSSL version >= 3.0 */ + bool failed; }; struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, size_t key_len) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + struct crypto_hash *ctx; + EVP_MAC *mac; + OSSL_PARAM params[2]; + char *a = NULL; + + switch (alg) { +#ifndef OPENSSL_NO_MD5 + case CRYPTO_HASH_ALG_HMAC_MD5: + a = "MD5"; + break; +#endif /* OPENSSL_NO_MD5 */ +#ifndef OPENSSL_NO_SHA + case CRYPTO_HASH_ALG_HMAC_SHA1: + a = "SHA1"; + break; +#endif /* OPENSSL_NO_SHA */ +#ifndef OPENSSL_NO_SHA256 +#ifdef CONFIG_SHA256 + case CRYPTO_HASH_ALG_HMAC_SHA256: + a = "SHA256"; + break; +#endif /* CONFIG_SHA256 */ +#endif /* OPENSSL_NO_SHA256 */ + default: + return NULL; + } + + mac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (!mac) + return NULL; + + params[0] = OSSL_PARAM_construct_utf8_string("digest", a, 0); + params[1] = OSSL_PARAM_construct_end(); + + ctx = os_zalloc(sizeof(*ctx)); + if (!ctx) + goto fail; + ctx->ctx = EVP_MAC_CTX_new(mac); + if (!ctx->ctx) { + os_free(ctx); + ctx = NULL; + goto fail; + } + + if (EVP_MAC_init(ctx->ctx, key, key_len, params) != 1) { + EVP_MAC_CTX_free(ctx->ctx); + bin_clear_free(ctx, sizeof(*ctx)); + ctx = NULL; + goto fail; + } + +fail: + EVP_MAC_free(mac); + return ctx; +#else /* OpenSSL version >= 3.0 */ struct crypto_hash *ctx; const EVP_MD *md; @@ -1097,6 +1422,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, } return ctx; +#endif /* OpenSSL version >= 3.0 */ } @@ -1104,14 +1430,59 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len) { if (ctx == NULL) return; - HMAC_Update(ctx->ctx, data, len); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (!EVP_MAC_update(ctx->ctx, data, len)) + ctx->failed = true; +#else /* OpenSSL version >= 3.0 */ + if (!HMAC_Update(ctx->ctx, data, len)) + ctx->failed = true; +#endif /* OpenSSL version >= 3.0 */ } int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + size_t mdlen; + int res; + bool failed; + + if (!ctx) + return -2; + + if (!mac || !len) { + EVP_MAC_CTX_free(ctx->ctx); + bin_clear_free(ctx, sizeof(*ctx)); + return 0; + } + + res = EVP_MAC_final(ctx->ctx, NULL, &mdlen, 0); + if (res != 1) { + EVP_MAC_CTX_free(ctx->ctx); + bin_clear_free(ctx, sizeof(*ctx)); + return -1; + } + res = EVP_MAC_final(ctx->ctx, mac, &mdlen, mdlen); + EVP_MAC_CTX_free(ctx->ctx); + failed = ctx->failed; + bin_clear_free(ctx, sizeof(*ctx)); + + if (TEST_FAIL()) + return -1; + + if (failed) + return -2; + + if (res == 1) { + *len = mdlen; + return 0; + } + + return -1; +#else /* OpenSSL version >= 3.0 */ unsigned int mdlen; int res; + bool failed; if (ctx == NULL) return -2; @@ -1125,47 +1496,68 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len) mdlen = *len; res = HMAC_Final(ctx->ctx, mac, &mdlen); HMAC_CTX_free(ctx->ctx); + failed = ctx->failed; bin_clear_free(ctx, sizeof(*ctx)); if (TEST_FAIL()) return -1; + if (failed) + return -2; + if (res == 1) { *len = mdlen; return 0; } return -1; +#endif /* OpenSSL version >= 3.0 */ } -static int openssl_hmac_vector(const EVP_MD *type, const u8 *key, +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +static int openssl_hmac_vector(char *digest, const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac, unsigned int mdlen) { - HMAC_CTX *ctx; - size_t i; + EVP_MAC *hmac; + OSSL_PARAM params[2]; + EVP_MAC_CTX *ctx; + size_t i, mlen; int res; if (TEST_FAIL()) return -1; - ctx = HMAC_CTX_new(); + hmac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (!hmac) + return -1; + + params[0] = OSSL_PARAM_construct_utf8_string("digest", digest, 0); + params[1] = OSSL_PARAM_construct_end(); + + ctx = EVP_MAC_CTX_new(hmac); + EVP_MAC_free(hmac); if (!ctx) return -1; - res = HMAC_Init_ex(ctx, key, key_len, type, NULL); - if (res != 1) - goto done; - for (i = 0; i < num_elem; i++) - HMAC_Update(ctx, addr[i], len[i]); + if (EVP_MAC_init(ctx, key, key_len, params) != 1) + goto fail; - res = HMAC_Final(ctx, mac, &mdlen); -done: - HMAC_CTX_free(ctx); + for (i = 0; i < num_elem; i++) { + if (EVP_MAC_update(ctx, addr[i], len[i]) != 1) + goto fail; + } + + res = EVP_MAC_final(ctx, mac, &mlen, mdlen); + EVP_MAC_CTX_free(ctx); return res == 1 ? 0 : -1; +fail: + EVP_MAC_CTX_free(ctx); + return -1; } @@ -1174,7 +1566,7 @@ done: int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { - return openssl_hmac_vector(EVP_md5(), key ,key_len, num_elem, addr, len, + return openssl_hmac_vector("MD5", key ,key_len, num_elem, addr, len, mac, 16); } @@ -1188,15 +1580,127 @@ int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, #endif /* CONFIG_FIPS */ -int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, - int iterations, u8 *buf, size_t buflen) +int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) { - if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid, - ssid_len, iterations, buflen, buf) != 1) + return openssl_hmac_vector("SHA1", key, key_len, num_elem, addr, + len, mac, 20); +} + + +int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac); +} + + +#ifdef CONFIG_SHA256 + +int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_hmac_vector("SHA256", key, key_len, num_elem, addr, + len, mac, 32); +} + + +int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); +} + +#endif /* CONFIG_SHA256 */ + + +#ifdef CONFIG_SHA384 + +int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_hmac_vector("SHA384", key, key_len, num_elem, addr, + len, mac, 48); +} + + +int hmac_sha384(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac); +} + +#endif /* CONFIG_SHA384 */ + + +#ifdef CONFIG_SHA512 + +int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_hmac_vector("SHA512", key, key_len, num_elem, addr, + len, mac, 64); +} + + +int hmac_sha512(const u8 *key, size_t key_len, const u8 *data, + size_t data_len, u8 *mac) +{ + return hmac_sha512_vector(key, key_len, 1, &data, &data_len, mac); +} + +#endif /* CONFIG_SHA512 */ + +#else /* OpenSSL version >= 3.0 */ + +static int openssl_hmac_vector(const EVP_MD *type, const u8 *key, + size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac, + unsigned int mdlen) +{ + HMAC_CTX *ctx; + size_t i; + int res; + + if (TEST_FAIL()) return -1; - return 0; + + ctx = HMAC_CTX_new(); + if (!ctx) + return -1; + res = HMAC_Init_ex(ctx, key, key_len, type, NULL); + if (res != 1) + goto done; + + for (i = 0; i < num_elem; i++) + HMAC_Update(ctx, addr[i], len[i]); + + res = HMAC_Final(ctx, mac, &mdlen); +done: + HMAC_CTX_free(ctx); + + return res == 1 ? 0 : -1; +} + + +#ifndef CONFIG_FIPS + +int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac) +{ + return openssl_hmac_vector(EVP_md5(), key ,key_len, num_elem, addr, len, + mac, 16); +} + + +int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len, + u8 *mac) +{ + return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac); } +#endif /* CONFIG_FIPS */ + int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) @@ -1269,6 +1773,18 @@ int hmac_sha512(const u8 *key, size_t key_len, const u8 *data, #endif /* CONFIG_SHA512 */ +#endif /* OpenSSL version >= 3.0 */ + + +int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid, + ssid_len, iterations, buflen, buf) != 1) + return -1; + return 0; +} + int crypto_get_random(void *buf, size_t len) { @@ -1277,11 +1793,51 @@ int crypto_get_random(void *buf, size_t len) return 0; } - #ifdef CONFIG_OPENSSL_CMAC int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MAC_CTX *ctx = NULL; + EVP_MAC *emac; + int ret = -1; + size_t outlen, i; + OSSL_PARAM params[2]; + char *cipher = NULL; + + if (TEST_FAIL()) + return -1; + + emac = EVP_MAC_fetch(NULL, "CMAC", NULL); + + if (key_len == 32) + cipher = "aes-256-cbc"; + else if (key_len == 24) + cipher = "aes-192-cbc"; + else if (key_len == 16) + cipher = "aes-128-cbc"; + + params[0] = OSSL_PARAM_construct_utf8_string("cipher", cipher, 0); + params[1] = OSSL_PARAM_construct_end(); + + if (!emac || !cipher || + !(ctx = EVP_MAC_CTX_new(emac)) || + EVP_MAC_init(ctx, key, key_len, params) != 1) + goto fail; + + for (i = 0; i < num_elem; i++) { + if (!EVP_MAC_update(ctx, addr[i], len[i])) + goto fail; + } + if (EVP_MAC_final(ctx, mac, &outlen, 16) != 1 || outlen != 16) + goto fail; + + ret = 0; +fail: + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(emac); + return ret; +#else /* OpenSSL version >= 3.0 */ CMAC_CTX *ctx; int ret = -1; size_t outlen, i; @@ -1296,6 +1852,9 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, if (key_len == 32) { if (!CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL)) goto fail; + } else if (key_len == 24) { + if (!CMAC_Init(ctx, key, 24, EVP_aes_192_cbc(), NULL)) + goto fail; } else if (key_len == 16) { if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL)) goto fail; @@ -1313,6 +1872,7 @@ int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem, fail: CMAC_CTX_free(ctx); return ret; +#endif /* OpenSSL version >= 3.0 */ } @@ -1335,7 +1895,6 @@ int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac) } #endif /* CONFIG_OPENSSL_CMAC */ - struct crypto_bignum * crypto_bignum_init(void) { if (TEST_FAIL()) @@ -1630,9 +2189,7 @@ int crypto_bignum_sqrtmod(const struct crypto_bignum *a, int crypto_bignum_rshift(const struct crypto_bignum *a, int n, struct crypto_bignum *r) { - /* Note: BN_rshift() does not modify the first argument even though it - * has not been marked const. */ - return BN_rshift((BIGNUM *) a, (BIGNUM *) r, n) == 1 ? 0 : -1; + return BN_rshift((BIGNUM *) r, (const BIGNUM *) a, n) == 1 ? 0 : -1; } @@ -1707,6 +2264,7 @@ fail: struct crypto_ec { EC_GROUP *group; int nid; + int iana_group; BN_CTX *bnctx; BIGNUM *prime; BIGNUM *order; @@ -1751,6 +2309,44 @@ static int crypto_ec_group_2_nid(int group) } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +static const char * crypto_ec_group_2_name(int group) +{ + /* Map from IANA registry for IKE D-H groups to OpenSSL group name */ + switch (group) { + case 19: + return "prime256v1"; + case 20: + return "secp384r1"; + case 21: + return "secp521r1"; + case 25: + return "prime192v1"; + case 26: + return "secp224r1"; +#ifdef NID_brainpoolP224r1 + case 27: + return "brainpoolP224r1"; +#endif /* NID_brainpoolP224r1 */ +#ifdef NID_brainpoolP256r1 + case 28: + return "brainpoolP256r1"; +#endif /* NID_brainpoolP256r1 */ +#ifdef NID_brainpoolP384r1 + case 29: + return "brainpoolP384r1"; +#endif /* NID_brainpoolP384r1 */ +#ifdef NID_brainpoolP512r1 + case 30: + return "brainpoolP512r1"; +#endif /* NID_brainpoolP512r1 */ + default: + return NULL; + } +} +#endif /* OpenSSL version >= 3.0 */ + + struct crypto_ec * crypto_ec_init(int group) { struct crypto_ec *e; @@ -1765,6 +2361,7 @@ struct crypto_ec * crypto_ec_init(int group) return NULL; e->nid = nid; + e->iana_group = group; e->bnctx = BN_CTX_new(); e->group = EC_GROUP_new_by_curve_name(nid); e->prime = BN_new(); @@ -1773,7 +2370,7 @@ struct crypto_ec * crypto_ec_init(int group) e->b = BN_new(); if (e->group == NULL || e->bnctx == NULL || e->prime == NULL || e->order == NULL || e->a == NULL || e->b == NULL || - !EC_GROUP_get_curve_GFp(e->group, e->prime, e->a, e->b, e->bnctx) || + !EC_GROUP_get_curve(e->group, e->prime, e->a, e->b, e->bnctx) || !EC_GROUP_get_order(e->group, e->order, e->bnctx)) { crypto_ec_deinit(e); e = NULL; @@ -1868,10 +2465,10 @@ void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear) int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p, struct crypto_bignum *x) { - return EC_POINT_get_affine_coordinates_GFp(e->group, - (const EC_POINT *) p, - (BIGNUM *) x, NULL, - e->bnctx) == 1 ? 0 : -1; + return EC_POINT_get_affine_coordinates(e->group, + (const EC_POINT *) p, + (BIGNUM *) x, NULL, + e->bnctx) == 1 ? 0 : -1; } @@ -1889,17 +2486,19 @@ int crypto_ec_point_to_bin(struct crypto_ec *e, y_bn = BN_new(); if (x_bn && y_bn && - EC_POINT_get_affine_coordinates_GFp(e->group, (EC_POINT *) point, - x_bn, y_bn, e->bnctx)) { + EC_POINT_get_affine_coordinates(e->group, (EC_POINT *) point, + x_bn, y_bn, e->bnctx)) { if (x) { - crypto_bignum_to_bin((struct crypto_bignum *) x_bn, - x, len, len); + ret = crypto_bignum_to_bin( + (struct crypto_bignum *) x_bn, x, len, len); } - if (y) { - crypto_bignum_to_bin((struct crypto_bignum *) y_bn, - y, len, len); + if (ret >= 0 && y) { + ret = crypto_bignum_to_bin( + (struct crypto_bignum *) y_bn, y, len, len); } - ret = 0; + + if (ret > 0) + ret = 0; } BN_clear_free(x_bn); @@ -1928,8 +2527,7 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e, return NULL; } - if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y, - e->bnctx)) { + if (!EC_POINT_set_affine_coordinates(e->group, elem, x, y, e->bnctx)) { EC_POINT_clear_free(elem); elem = NULL; } @@ -2030,8 +2628,8 @@ void crypto_ec_point_debug_print(const struct crypto_ec *e, x = BN_new(); y = BN_new(); if (!x || !y || - EC_POINT_get_affine_coordinates_GFp(e->group, (const EC_POINT *) p, - x, y, e->bnctx) != 1) + EC_POINT_get_affine_coordinates(e->group, (const EC_POINT *) p, + x, y, e->bnctx) != 1) goto fail; x_str = BN_bn2hex(x); @@ -2056,6 +2654,33 @@ struct crypto_ecdh { struct crypto_ecdh * crypto_ecdh_init(int group) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + struct crypto_ecdh *ecdh; + const char *name; + + ecdh = os_zalloc(sizeof(*ecdh)); + if (!ecdh) + goto fail; + + ecdh->ec = crypto_ec_init(group); + if (!ecdh->ec) + goto fail; + + name = OSSL_EC_curve_nid2name(ecdh->ec->nid); + if (!name) + goto fail; + + ecdh->pkey = EVP_EC_gen(name); + if (!ecdh->pkey) + goto fail; + +done: + return ecdh; +fail: + crypto_ecdh_deinit(ecdh); + ecdh = NULL; + goto done; +#else /* OpenSSL version >= 3.0 */ struct crypto_ecdh *ecdh; EVP_PKEY *params = NULL; EC_KEY *ec_params = NULL; @@ -2110,11 +2735,32 @@ fail: crypto_ecdh_deinit(ecdh); ecdh = NULL; goto done; +#endif /* OpenSSL version >= 3.0 */ } struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + struct crypto_ecdh *ecdh; + + ecdh = os_zalloc(sizeof(*ecdh)); + if (!ecdh) + goto fail; + + ecdh->ec = crypto_ec_init(group); + if (!ecdh->ec) + goto fail; + + ecdh->pkey = EVP_PKEY_dup((EVP_PKEY *) own_key); + if (!ecdh->pkey) + goto fail; + + return ecdh; +fail: + crypto_ecdh_deinit(ecdh); + return NULL; +#else /* OpenSSL version >= 3.0 */ struct crypto_ecdh *ecdh; ecdh = os_zalloc(sizeof(*ecdh)); @@ -2136,11 +2782,34 @@ struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key) fail: crypto_ecdh_deinit(ecdh); return NULL; +#endif /* OpenSSL version >= 3.0 */ } struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + struct wpabuf *buf = NULL; + unsigned char *pub; + size_t len, exp_len; + + len = EVP_PKEY_get1_encoded_public_key(ecdh->pkey, &pub); + if (len == 0) + return NULL; + + /* Encoded using SECG SEC 1, Sec. 2.3.4 format */ + exp_len = 1 + 2 * crypto_ec_prime_len(ecdh->ec); + if (len != exp_len) { + wpa_printf(MSG_ERROR, + "OpenSSL:%s: Unexpected encoded public key length %zu (expected %zu)", + __func__, len, exp_len); + goto fail; + } + buf = wpabuf_alloc_copy(pub + 1, inc_y ? len - 1 : len / 2); +fail: + OPENSSL_free(pub); + return buf; +#else /* OpenSSL version >= 3.0 */ struct wpabuf *buf = NULL; EC_KEY *eckey; const EC_POINT *pubkey; @@ -2166,10 +2835,10 @@ struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y) if (!x || !buf) goto fail; - if (EC_POINT_get_affine_coordinates_GFp(ecdh->ec->group, pubkey, - x, y, ecdh->ec->bnctx) != 1) { + if (EC_POINT_get_affine_coordinates(ecdh->ec->group, pubkey, + x, y, ecdh->ec->bnctx) != 1) { wpa_printf(MSG_ERROR, - "OpenSSL: EC_POINT_get_affine_coordinates_GFp failed: %s", + "OpenSSL: EC_POINT_get_affine_coordinates failed: %s", ERR_error_string(ERR_get_error(), NULL)); goto fail; } @@ -2196,12 +2865,59 @@ fail: wpabuf_free(buf); buf = NULL; goto done; +#endif /* OpenSSL version >= 3.0 */ } struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y, const u8 *key, size_t len) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY *peerkey = EVP_PKEY_new(); + EVP_PKEY_CTX *ctx; + size_t res_len; + struct wpabuf *res = NULL; + u8 *peer; + + /* Encode using SECG SEC 1, Sec. 2.3.4 format */ + peer = os_malloc(1 + len); + if (!peer) { + EVP_PKEY_free(peerkey); + return NULL; + } + peer[0] = inc_y ? 0x04 : 0x02; + os_memcpy(peer + 1, key, len); + + if (!peerkey || + EVP_PKEY_copy_parameters(peerkey, ecdh->pkey) != 1 || + EVP_PKEY_set1_encoded_public_key(peerkey, peer, 1 + len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_set1_encoded_public_key failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + EVP_PKEY_free(peerkey); + os_free(peer); + return NULL; + } + os_free(peer); + + ctx = EVP_PKEY_CTX_new(ecdh->pkey, NULL); + if (!ctx || + EVP_PKEY_derive_init(ctx) != 1 || + EVP_PKEY_derive_set_peer(ctx, peerkey) != 1 || + EVP_PKEY_derive(ctx, NULL, &res_len) != 1 || + !(res = wpabuf_alloc(res_len)) || + EVP_PKEY_derive(ctx, wpabuf_mhead(res), &res_len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL: EVP_PKEY_derive failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + wpabuf_free(res); + res = NULL; + } else { + wpabuf_put(res, res_len); + } + + EVP_PKEY_free(peerkey); + EVP_PKEY_CTX_free(ctx); + return res; +#else /* OpenSSL version >= 3.0 */ BIGNUM *x, *y = NULL; EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *peerkey = NULL; @@ -2219,19 +2935,18 @@ struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y, y = BN_bin2bn(key + len / 2, len / 2, NULL); if (!y) goto fail; - if (!EC_POINT_set_affine_coordinates_GFp(ecdh->ec->group, pub, - x, y, - ecdh->ec->bnctx)) { + if (!EC_POINT_set_affine_coordinates(ecdh->ec->group, pub, + x, y, ecdh->ec->bnctx)) { wpa_printf(MSG_ERROR, - "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s", + "OpenSSL: EC_POINT_set_affine_coordinates failed: %s", ERR_error_string(ERR_get_error(), NULL)); goto fail; } - } else if (!EC_POINT_set_compressed_coordinates_GFp(ecdh->ec->group, - pub, x, 0, - ecdh->ec->bnctx)) { + } else if (!EC_POINT_set_compressed_coordinates(ecdh->ec->group, + pub, x, 0, + ecdh->ec->bnctx)) { wpa_printf(MSG_ERROR, - "OpenSSL: EC_POINT_set_compressed_coordinates_GFp failed: %s", + "OpenSSL: EC_POINT_set_compressed_coordinates failed: %s", ERR_error_string(ERR_get_error(), NULL)); goto fail; } @@ -2291,6 +3006,7 @@ fail: wpabuf_free(secret); secret = NULL; goto done; +#endif /* OpenSSL version >= 3.0 */ } @@ -2312,12 +3028,37 @@ size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh) struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L EVP_PKEY *pkey = NULL; - EC_KEY *eckey; + OSSL_DECODER_CTX *ctx; - eckey = d2i_ECPrivateKey(NULL, &der, der_len); - if (!eckey) { - wpa_printf(MSG_INFO, "OpenSSL: d2i_ECPrivateKey() failed: %s", + ctx = OSSL_DECODER_CTX_new_for_pkey( + &pkey, "DER", NULL, "EC", + OSSL_KEYMGMT_SELECT_KEYPAIR | + OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + NULL, NULL); + if (!ctx || + OSSL_DECODER_from_data(ctx, &der, &der_len) != 1) { + wpa_printf(MSG_INFO, + "OpenSSL: Decoding EC private key (DER) failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + if (ctx) + OSSL_DECODER_CTX_free(ctx); + goto fail; + } + + OSSL_DECODER_CTX_free(ctx); + return (struct crypto_ec_key *) pkey; +fail: + crypto_ec_key_deinit((struct crypto_ec_key *) pkey); + return NULL; +#else /* OpenSSL version >= 3.0 */ + EVP_PKEY *pkey = NULL; + EC_KEY *eckey; + + eckey = d2i_ECPrivateKey(NULL, &der, der_len); + if (!eckey) { + wpa_printf(MSG_INFO, "OpenSSL: d2i_ECPrivateKey() failed: %s", ERR_error_string(ERR_get_error(), NULL)); goto fail; } @@ -2333,6 +3074,142 @@ struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len) fail: crypto_ec_key_deinit((struct crypto_ec_key *) pkey); return NULL; +#endif /* OpenSSL version >= 3.0 */ +} + + +struct crypto_ec_key * crypto_ec_key_set_priv(int group, + const u8 *raw, size_t raw_len) +{ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + const char *group_name; + OSSL_PARAM params[4]; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; + BIGNUM *priv; + EC_POINT *pub = NULL; + EC_GROUP *ec_group = NULL; + size_t len; + u8 *pub_bin = NULL; + u8 *priv_bin = NULL; + int priv_bin_len; + + group_name = crypto_ec_group_2_name(group); + if (!group_name) + return NULL; + + priv = BN_bin2bn(raw, raw_len, NULL); + if (!priv) + return NULL; + priv_bin = os_malloc(raw_len); + if (!priv_bin) + goto fail; + priv_bin_len = BN_bn2lebinpad(priv, priv_bin, raw_len); + if (priv_bin_len < 0) + goto fail; + + ec_group = EC_GROUP_new_by_curve_name(crypto_ec_group_2_nid(group)); + if (!ec_group) + goto fail; + pub = EC_POINT_new(ec_group); + if (!pub || + EC_POINT_mul(ec_group, pub, priv, NULL, NULL, NULL) != 1) + goto fail; + len = EC_POINT_point2oct(ec_group, pub, POINT_CONVERSION_UNCOMPRESSED, + NULL, 0, NULL); + if (len == 0) + goto fail; + pub_bin = os_malloc(len); + if (!pub_bin) + goto fail; + len = EC_POINT_point2oct(ec_group, pub, POINT_CONVERSION_UNCOMPRESSED, + pub_bin, len, NULL); + if (len == 0) + goto fail; + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + (char *) group_name, 0); + params[1] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_PRIV_KEY, + priv_bin, priv_bin_len); + params[2] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, + pub_bin, len); + params[3] = OSSL_PARAM_construct_end(); + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (!ctx || + EVP_PKEY_fromdata_init(ctx) <= 0 || + EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0) + goto fail; + +out: + bin_clear_free(priv_bin, raw_len); + os_free(pub_bin); + BN_clear_free(priv); + EVP_PKEY_CTX_free(ctx); + EC_POINT_free(pub); + EC_GROUP_free(ec_group); + return (struct crypto_ec_key *) pkey; + +fail: + EVP_PKEY_free(pkey); + pkey = NULL; + goto out; +#else /* OpenSSL version >= 3.0 */ + EC_KEY *eckey = NULL; + EVP_PKEY *pkey = NULL; + BIGNUM *priv = NULL; + int nid; + const EC_GROUP *ec_group; + EC_POINT *pub = NULL; + + nid = crypto_ec_group_2_nid(group); + if (nid < 0) { + wpa_printf(MSG_ERROR, "OpenSSL: Unsupported group %d", group); + return NULL; + } + + eckey = EC_KEY_new_by_curve_name(nid); + priv = BN_bin2bn(raw, raw_len, NULL); + if (!eckey || !priv || + EC_KEY_set_private_key(eckey, priv) != 1) { + wpa_printf(MSG_ERROR, + "OpenSSL: Failed to set EC_KEY: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto fail; + } + + ec_group = EC_KEY_get0_group(eckey); + if (!ec_group) + goto fail; + pub = EC_POINT_new(ec_group); + if (!pub || + EC_POINT_mul(ec_group, pub, priv, NULL, NULL, NULL) != 1 || + EC_KEY_set_public_key(eckey, pub) != 1) { + wpa_printf(MSG_ERROR, + "OpenSSL: Failed to set EC_KEY(pub): %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_assign_EC_KEY(pkey, eckey) != 1) { + wpa_printf(MSG_ERROR, "OpenSSL: Could not create EVP_PKEY"); + goto fail; + } + +out: + BN_clear_free(priv); + EC_POINT_free(pub); + return (struct crypto_ec_key *) pkey; + +fail: + EC_KEY_free(eckey); + EVP_PKEY_free(pkey); + pkey = NULL; + goto out; +#endif /* OpenSSL version >= 3.0 */ } @@ -2348,8 +3225,13 @@ struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len) } /* Ensure this is an EC key */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (!EVP_PKEY_is_a(pkey, "EC")) + goto fail; +#else /* OpenSSL version >= 3.0 */ if (!EVP_PKEY_get0_EC_KEY(pkey)) goto fail; +#endif /* OpenSSL version >= 3.0 */ return (struct crypto_ec_key *) pkey; fail: crypto_ec_key_deinit((struct crypto_ec_key *) pkey); @@ -2360,6 +3242,47 @@ fail: struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *buf_x, const u8 *buf_y, size_t len) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + const char *group_name; + OSSL_PARAM params[3]; + u8 *pub; + EVP_PKEY_CTX *ctx; + EVP_PKEY *pkey = NULL; + + group_name = crypto_ec_group_2_name(group); + if (!group_name) + return NULL; + + pub = os_malloc(1 + len * 2); + if (!pub) + return NULL; + pub[0] = 0x04; /* uncompressed */ + os_memcpy(pub + 1, buf_x, len); + os_memcpy(pub + 1 + len, buf_y, len); + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + (char *) group_name, 0); + params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, + pub, 1 + len * 2); + params[2] = OSSL_PARAM_construct_end(); + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (!ctx) { + os_free(pub); + return NULL; + } + if (EVP_PKEY_fromdata_init(ctx) <= 0 || + EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) { + os_free(pub); + EVP_PKEY_CTX_free(ctx); + return NULL; + } + + os_free(pub); + EVP_PKEY_CTX_free(ctx); + + return (struct crypto_ec_key *) pkey; +#else /* OpenSSL version >= 3.0 */ EC_KEY *eckey = NULL; EVP_PKEY *pkey = NULL; EC_GROUP *ec_group = NULL; @@ -2391,9 +3314,9 @@ struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *buf_x, if (!x || !y || !point) goto fail; - if (!EC_POINT_set_affine_coordinates_GFp(ec_group, point, x, y, ctx)) { + if (!EC_POINT_set_affine_coordinates(ec_group, point, x, y, ctx)) { wpa_printf(MSG_ERROR, - "OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s", + "OpenSSL: EC_POINT_set_affine_coordinates failed: %s", ERR_error_string(ERR_get_error(), NULL)); goto fail; } @@ -2434,6 +3357,7 @@ fail: EVP_PKEY_free(pkey); pkey = NULL; goto out; +#endif /* OpenSSL version >= 3.0 */ } @@ -2441,6 +3365,24 @@ struct crypto_ec_key * crypto_ec_key_set_pub_point(struct crypto_ec *ec, const struct crypto_ec_point *pub) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + int len = BN_num_bytes(ec->prime); + struct crypto_ec_key *key; + u8 *buf; + + buf = os_malloc(2 * len); + if (!buf) + return NULL; + if (crypto_ec_point_to_bin(ec, pub, buf, buf + len) < 0) { + os_free(buf); + return NULL; + } + + key = crypto_ec_key_set_pub(ec->iana_group, buf, buf + len, len); + os_free(buf); + + return key; +#else /* OpenSSL version >= 3.0 */ EC_KEY *eckey; EVP_PKEY *pkey = NULL; @@ -2469,11 +3411,41 @@ fail: EC_KEY_free(eckey); pkey = NULL; goto out; +#endif /* OpenSSL version >= 3.0 */ } struct crypto_ec_key * crypto_ec_key_gen(int group) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_PKEY_CTX *ctx; + OSSL_PARAM params[2]; + const char *group_name; + EVP_PKEY *pkey = NULL; + + group_name = crypto_ec_group_2_name(group); + if (!group_name) + return NULL; + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + (char *) group_name, 0); + params[1] = OSSL_PARAM_construct_end(); + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (!ctx || + EVP_PKEY_keygen_init(ctx) != 1 || + EVP_PKEY_CTX_set_params(ctx, params) != 1 || + EVP_PKEY_generate(ctx, &pkey) != 1) { + wpa_printf(MSG_INFO, + "OpenSSL: failed to generate EC keypair: %s", + ERR_error_string(ERR_get_error(), NULL)); + pkey = NULL; + } + + EVP_PKEY_CTX_free(ctx); + + return (struct crypto_ec_key *) pkey; +#else /* OpenSSL version >= 3.0 */ EVP_PKEY_CTX *kctx = NULL; EC_KEY *ec_params = NULL, *eckey; EVP_PKEY *params = NULL, *key = NULL; @@ -2521,6 +3493,7 @@ fail: EVP_PKEY_free(params); EVP_PKEY_CTX_free(kctx); return (struct crypto_ec_key *) key; +#endif /* OpenSSL version >= 3.0 */ } @@ -2559,6 +3532,54 @@ IMPLEMENT_ASN1_FUNCTIONS(EC_COMP_PUBKEY); struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key) { + EVP_PKEY *pkey = (EVP_PKEY *) key; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_ENCODER_CTX *ctx; + int selection; + unsigned char *pdata = NULL; + size_t pdata_len = 0; + EVP_PKEY *copy = NULL; + struct wpabuf *buf = NULL; + + if (EVP_PKEY_get_ec_point_conv_form(pkey) != + POINT_CONVERSION_COMPRESSED) { + copy = EVP_PKEY_dup(pkey); + if (!copy) + return NULL; + if (EVP_PKEY_set_utf8_string_param( + copy, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, + OSSL_PKEY_EC_POINT_CONVERSION_FORMAT_COMPRESSED) != + 1) { + wpa_printf(MSG_INFO, + "OpenSSL: Failed to set compressed format"); + EVP_PKEY_free(copy); + return NULL; + } + pkey = copy; + } + + selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS | + OSSL_KEYMGMT_SELECT_PUBLIC_KEY; + + ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "DER", + "SubjectPublicKeyInfo", + NULL); + if (!ctx || OSSL_ENCODER_to_data(ctx, &pdata, &pdata_len) != 1) { + wpa_printf(MSG_INFO, + "OpenSSL: Failed to encode SubjectPublicKeyInfo: %s", + ERR_error_string(ERR_get_error(), NULL)); + pdata = NULL; + } + OSSL_ENCODER_CTX_free(ctx); + if (pdata) { + buf = wpabuf_alloc_copy(pdata, pdata_len); + OPENSSL_free(pdata); + } + + EVP_PKEY_free(copy); + + return buf; +#else /* OpenSSL version >= 3.0 */ #ifdef OPENSSL_IS_BORINGSSL unsigned char *der = NULL; int der_len; @@ -2572,7 +3593,7 @@ struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key) int nid; ctx = BN_CTX_new(); - eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key); + eckey = EVP_PKEY_get0_EC_KEY(pkey); if (!ctx || !eckey) goto fail; @@ -2625,33 +3646,16 @@ fail: int der_len; struct wpabuf *buf; EC_KEY *eckey; -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - EVP_PKEY *tmp; -#endif /* OpenSSL version >= 3.0 */ - eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key); + eckey = EVP_PKEY_get1_EC_KEY(pkey); if (!eckey) return NULL; /* For now, all users expect COMPRESSED form */ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED); -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - tmp = EVP_PKEY_new(); - if (!tmp) - return NULL; - if (EVP_PKEY_set1_EC_KEY(tmp, eckey) != 1) { - EVP_PKEY_free(tmp); - return NULL; - } - key = (struct crypto_ec_key *) tmp; -#endif /* OpenSSL version >= 3.0 */ - der_len = i2d_PUBKEY((EVP_PKEY *) key, &der); EC_KEY_free(eckey); -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - EVP_PKEY_free(tmp); -#endif /* OpenSSL version >= 3.0 */ if (der_len <= 0) { wpa_printf(MSG_INFO, "OpenSSL: i2d_PUBKEY() failed: %s", ERR_error_string(ERR_get_error(), NULL)); @@ -2662,19 +3666,58 @@ fail: OPENSSL_free(der); return buf; #endif /* OPENSSL_IS_BORINGSSL */ +#endif /* OpenSSL version >= 3.0 */ } struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key, bool include_pub) { + EVP_PKEY *pkey = (EVP_PKEY *) key; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_ENCODER_CTX *ctx; + int selection; + unsigned char *pdata = NULL; + size_t pdata_len = 0; + struct wpabuf *buf; + EVP_PKEY *copy = NULL; + + selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS | + OSSL_KEYMGMT_SELECT_PRIVATE_KEY; + if (include_pub) { + selection |= OSSL_KEYMGMT_SELECT_PUBLIC_KEY; + } else { + /* Not including OSSL_KEYMGMT_SELECT_PUBLIC_KEY does not seem + * to really be sufficient, so clone the key and explicitly + * mark it not to include the public key. */ + copy = EVP_PKEY_dup(pkey); + if (!copy) + return NULL; + EVP_PKEY_set_int_param(copy, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC, + 0); + pkey = copy; + } + + ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "DER", + "type-specific", NULL); + if (!ctx || OSSL_ENCODER_to_data(ctx, &pdata, &pdata_len) != 1) { + OSSL_ENCODER_CTX_free(ctx); + EVP_PKEY_free(copy); + return NULL; + } + OSSL_ENCODER_CTX_free(ctx); + buf = wpabuf_alloc_copy(pdata, pdata_len); + OPENSSL_free(pdata); + EVP_PKEY_free(copy); + return buf; +#else /* OpenSSL version >= 3.0 */ EC_KEY *eckey; unsigned char *der = NULL; int der_len; struct wpabuf *buf; unsigned int key_flags; - eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key); + eckey = EVP_PKEY_get1_EC_KEY(pkey); if (!eckey) return NULL; @@ -2695,18 +3738,53 @@ struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key, OPENSSL_free(der); return buf; +#endif /* OpenSSL version >= 3.0 */ } struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key, int prefix) { + EVP_PKEY *pkey = (EVP_PKEY *) key; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + struct wpabuf *buf; + unsigned char *pos; + size_t pub_len = OSSL_PARAM_UNMODIFIED; + + buf = NULL; + if (!EVP_PKEY_is_a(pkey, "EC") || + EVP_PKEY_get_octet_string_param(pkey, + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, + NULL, 0, &pub_len) < 0 || + pub_len == OSSL_PARAM_UNMODIFIED || + !(buf = wpabuf_alloc(pub_len)) || + EVP_PKEY_get_octet_string_param(pkey, + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, + wpabuf_put(buf, pub_len), + pub_len, NULL) != 1 || + wpabuf_head_u8(buf)[0] != 0x04) { + wpa_printf(MSG_INFO, + "OpenSSL: Failed to get encoded public key: %s", + ERR_error_string(ERR_get_error(), NULL)); + wpabuf_free(buf); + return NULL; + } + + if (!prefix) { + /* Remove 0x04 prefix if requested */ + pos = wpabuf_mhead(buf); + os_memmove(pos, pos + 1, pub_len - 1); + buf->used--; + } + + return buf; +#else /* OpenSSL version >= 3.0 */ int len, res; EC_KEY *eckey; struct wpabuf *buf; unsigned char *pos; - eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key); + eckey = EVP_PKEY_get1_EC_KEY(pkey); if (!eckey) return NULL; EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED); @@ -2743,30 +3821,92 @@ struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key, } return buf; +#endif /* OpenSSL version >= 3.0 */ } -const struct crypto_ec_point * +struct crypto_ec_point * crypto_ec_key_get_public_key(struct crypto_ec_key *key) { + EVP_PKEY *pkey = (EVP_PKEY *) key; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + char group[64]; + unsigned char pub[256]; + size_t len; + EC_POINT *point = NULL; + EC_GROUP *grp; + int res = 0; + OSSL_PARAM params[2]; + + if (!EVP_PKEY_is_a(pkey, "EC") || + EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, + group, sizeof(group), &len) != 1 || + EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, + pub, sizeof(pub), &len) != 1) + return NULL; + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + group, 0); + params[1] = OSSL_PARAM_construct_end(); + grp = EC_GROUP_new_from_params(params, NULL, NULL); + if (!grp) + goto fail; + point = EC_POINT_new(grp); + if (!point) + goto fail; + res = EC_POINT_oct2point(grp, point, pub, len, NULL); + +fail: + if (res != 1) { + EC_POINT_free(point); + point = NULL; + } + + EC_GROUP_free(grp); + + return (struct crypto_ec_point *) point; +#else /* OpenSSL version >= 3.0 */ const EC_KEY *eckey; + const EC_POINT *point; + const EC_GROUP *group; - eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key); + eckey = EVP_PKEY_get0_EC_KEY(pkey); if (!eckey) return NULL; - return (const struct crypto_ec_point *) EC_KEY_get0_public_key(eckey); + group = EC_KEY_get0_group(eckey); + if (!group) + return NULL; + point = EC_KEY_get0_public_key(eckey); + if (!point) + return NULL; + return (struct crypto_ec_point *) EC_POINT_dup(point, group); +#endif /* OpenSSL version >= 3.0 */ } -const struct crypto_bignum * +struct crypto_bignum * crypto_ec_key_get_private_key(struct crypto_ec_key *key) { + EVP_PKEY *pkey = (EVP_PKEY *) key; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + BIGNUM *bn = NULL; + + if (!EVP_PKEY_is_a(pkey, "EC") || + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bn) != 1) + return NULL; + return (struct crypto_bignum *) bn; +#else /* OpenSSL version >= 3.0 */ const EC_KEY *eckey; + const BIGNUM *bn; - eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key); + eckey = EVP_PKEY_get0_EC_KEY(pkey); if (!eckey) return NULL; - return (const struct crypto_bignum *) EC_KEY_get0_private_key(eckey); + bn = EC_KEY_get0_private_key(eckey); + if (!bn) + return NULL; + return (struct crypto_bignum *) BN_dup(bn); +#endif /* OpenSSL version >= 3.0 */ } @@ -2798,37 +3938,74 @@ struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data, } -struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, - const u8 *data, size_t len) +static int openssl_evp_pkey_ec_prime_len(struct crypto_ec_key *key) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + char gname[50]; + int nid; + EC_GROUP *group; + BIGNUM *prime = NULL; + int prime_len = -1; + + if (EVP_PKEY_get_group_name((EVP_PKEY *) key, gname, sizeof(gname), + NULL) != 1) + return -1; + nid = OBJ_txt2nid(gname); + group = EC_GROUP_new_by_curve_name(nid); + prime = BN_new(); + if (!group || !prime) + goto fail; + if (EC_GROUP_get_curve(group, prime, NULL, NULL, NULL) == 1) + prime_len = BN_num_bytes(prime); +fail: + EC_GROUP_free(group); + BN_free(prime); + return prime_len; +#else const EC_GROUP *group; const EC_KEY *eckey; BIGNUM *prime = NULL; - ECDSA_SIG *sig = NULL; - const BIGNUM *r, *s; - u8 *r_buf, *s_buf; - struct wpabuf *buf; - const unsigned char *p; - int prime_len; - - buf = crypto_ec_key_sign(key, data, len); - if (!buf) - return NULL; + int prime_len = -1; - /* Extract (r,s) from Ecdsa-Sig-Value */ eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key); if (!eckey) goto fail; group = EC_KEY_get0_group(eckey); prime = BN_new(); if (!prime || !group || - !EC_GROUP_get_curve_GFp(group, prime, NULL, NULL, NULL)) + !EC_GROUP_get_curve(group, prime, NULL, NULL, NULL)) goto fail; prime_len = BN_num_bytes(prime); +fail: + BN_free(prime); + return prime_len; +#endif +} - p = wpabuf_head(buf); - sig = d2i_ECDSA_SIG(NULL, &p, wpabuf_len(buf)); - if (!sig) + +struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, + const u8 *data, size_t len) +{ + ECDSA_SIG *sig = NULL; + const BIGNUM *r, *s; + u8 *r_buf, *s_buf; + struct wpabuf *buf; + const unsigned char *p; + int prime_len; + + prime_len = openssl_evp_pkey_ec_prime_len(key); + if (prime_len < 0) + return NULL; + + buf = crypto_ec_key_sign(key, data, len); + if (!buf) + return NULL; + + /* Extract (r,s) from Ecdsa-Sig-Value */ + + p = wpabuf_head(buf); + sig = d2i_ECDSA_SIG(NULL, &p, wpabuf_len(buf)); + if (!sig) goto fail; ECDSA_SIG_get0(sig, &r, &s); @@ -2843,7 +4020,6 @@ struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, goto fail; out: - BN_free(prime); ECDSA_SIG_free(sig); return buf; fail: @@ -2914,6 +4090,15 @@ fail: int crypto_ec_key_group(struct crypto_ec_key *key) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + char gname[50]; + int nid; + + if (EVP_PKEY_get_group_name((EVP_PKEY *) key, gname, sizeof(gname), + NULL) != 1) + return -1; + nid = OBJ_txt2nid(gname); +#else const EC_KEY *eckey; const EC_GROUP *group; int nid; @@ -2925,6 +4110,7 @@ int crypto_ec_key_group(struct crypto_ec_key *key) if (!group) return -1; nid = EC_GROUP_get_curve_name(group); +#endif switch (nid) { case NID_X9_62_prime256v1: return 19; @@ -2944,17 +4130,24 @@ int crypto_ec_key_group(struct crypto_ec_key *key) case NID_brainpoolP512r1: return 30; #endif /* NID_brainpoolP512r1 */ + default: + wpa_printf(MSG_ERROR, + "OpenSSL: Unsupported curve (nid=%d) in EC key", + nid); + return -1; } - wpa_printf(MSG_ERROR, "OpenSSL: Unsupported curve (nid=%d) in EC key", - nid); - return -1; } int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2) { +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (EVP_PKEY_eq((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1) + return -1; +#else if (EVP_PKEY_cmp((EVP_PKEY *) key1, (EVP_PKEY *) key2) != 1) return -1; +#endif return 0; } @@ -3263,3 +4456,1150 @@ struct wpabuf * crypto_csr_sign(struct crypto_csr *csr, } #endif /* CONFIG_ECC */ + + +static EVP_PKEY * crypto_rsa_key_read_public(FILE *f) +{ + EVP_PKEY *pkey; + X509 *x509; + const ASN1_TIME *not_before, *not_after; + int res_before, res_after; + + pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL); + if (pkey) + return pkey; + + rewind(f); + x509 = PEM_read_X509(f, NULL, NULL, NULL); + if (!x509) + return NULL; + + not_before = X509_get0_notBefore(x509); + not_after = X509_get0_notAfter(x509); + if (!not_before || !not_after) + goto fail; + res_before = X509_cmp_current_time(not_before); + res_after = X509_cmp_current_time(not_after); + if (!res_before || !res_after) + goto fail; + if (res_before > 0 || res_after < 0) { + wpa_printf(MSG_INFO, + "OpenSSL: Certificate for RSA public key is not valid at this time (%d %d)", + res_before, res_after); + goto fail; + } + + pkey = X509_get_pubkey(x509); + X509_free(x509); + + if (!pkey) + return NULL; + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { + wpa_printf(MSG_INFO, "OpenSSL: No RSA public key found"); + EVP_PKEY_free(pkey); + return NULL; + } + + return pkey; +fail: + X509_free(x509); + return NULL; +} + + +struct crypto_rsa_key * crypto_rsa_key_read(const char *file, bool private_key) +{ + FILE *f; + EVP_PKEY *pkey; + + f = fopen(file, "r"); + if (!f) + return NULL; + if (private_key) + pkey = PEM_read_PrivateKey(f, NULL, NULL, NULL); + else + pkey = crypto_rsa_key_read_public(f); + fclose(f); + return (struct crypto_rsa_key *) pkey; +} + + +#ifndef OPENSSL_NO_SHA256 + +struct wpabuf * crypto_rsa_oaep_sha256_encrypt(struct crypto_rsa_key *key, + const struct wpabuf *in) +{ +#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L + EVP_PKEY *pkey = (EVP_PKEY *) key; + EVP_PKEY_CTX *pkctx; + struct wpabuf *res = NULL; + size_t outlen; + + pkctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pkctx) + goto fail; + + if (EVP_PKEY_encrypt_init(pkctx) != 1 || + EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, EVP_sha256()) <= 0 || + EVP_PKEY_encrypt(pkctx, NULL, &outlen, wpabuf_head(in), + wpabuf_len(in)) != 1 || + !(res = wpabuf_alloc(outlen)) || + EVP_PKEY_encrypt(pkctx, wpabuf_put(res, 0), &outlen, + wpabuf_head(in), wpabuf_len(in)) != 1) { + wpabuf_free(res); + res = NULL; + goto fail; + } + wpabuf_put(res, outlen); + +fail: + EVP_PKEY_CTX_free(pkctx); + return res; +#else + wpa_printf(MSG_ERROR, "%s() not supported", __func__); + return NULL; +#endif +} + + +struct wpabuf * crypto_rsa_oaep_sha256_decrypt(struct crypto_rsa_key *key, + const struct wpabuf *in) +{ +#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L + EVP_PKEY *pkey = (EVP_PKEY *) key; + EVP_PKEY_CTX *pkctx; + struct wpabuf *res = NULL; + size_t outlen; + + pkctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pkctx) + goto fail; + + if (EVP_PKEY_decrypt_init(pkctx) != 1 || + EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_CTX_set_rsa_oaep_md(pkctx, EVP_sha256()) <= 0 || + EVP_PKEY_decrypt(pkctx, NULL, &outlen, wpabuf_head(in), + wpabuf_len(in)) != 1 || + !(res = wpabuf_alloc(outlen)) || + EVP_PKEY_decrypt(pkctx, wpabuf_put(res, 0), &outlen, + wpabuf_head(in), wpabuf_len(in)) != 1) { + wpabuf_free(res); + res = NULL; + goto fail; + } + wpabuf_put(res, outlen); + +fail: + EVP_PKEY_CTX_free(pkctx); + return res; +#else + wpa_printf(MSG_ERROR, "%s() not supported", __func__); + return NULL; +#endif +} + +#endif /* OPENSSL_NO_SHA256 */ + + +void crypto_rsa_key_free(struct crypto_rsa_key *key) +{ + EVP_PKEY_free((EVP_PKEY *) key); +} + + +#ifdef CONFIG_DPP3 + +#define HPKE_MAX_SHARED_SECRET_LEN 66 +#define HPKE_MAX_HASH_LEN 64 +#define HPKE_MAX_KEY_LEN 32 +#define HPKE_MAX_NONCE_LEN 12 +#define HPKE_MAX_PUB_LEN (1 + 2 * 66) + +struct hpke_context { + /* KEM */ + enum hpke_kem_id kem_id; + int kem_nid; + int iana_group; + size_t n_pk; + size_t n_secret; + const EVP_MD *kem_h; + size_t kem_n_h; + + /* KDF */ + enum hpke_kdf_id kdf_id; + const EVP_MD *kdf_h; + size_t n_h; + + /* AEAD */ + enum hpke_aead_id aead_id; + const EVP_CIPHER *cipher; + size_t n_k; + size_t n_n; + size_t n_t; + u8 key[HPKE_MAX_KEY_LEN]; + u8 base_nonce[HPKE_MAX_NONCE_LEN]; +}; + + +static void hpke_free_context(struct hpke_context *ctx) +{ + bin_clear_free(ctx, sizeof(*ctx)); +} + + +static struct hpke_context * hpke_get_context(enum hpke_kem_id kem_id, + enum hpke_kdf_id kdf_id, + enum hpke_aead_id aead_id, + struct crypto_ec_key *key) +{ + struct hpke_context *ctx; + int group; + + ctx = os_zalloc(sizeof(*ctx)); + if (!ctx) + return NULL; + + ctx->kem_id = kem_id; + switch (kem_id) { + case HPKE_DHKEM_P256_HKDF_SHA256: + ctx->kem_nid = NID_X9_62_prime256v1; + ctx->iana_group = 19; + ctx->n_pk = 65; + ctx->n_secret = 32; + ctx->kem_h = EVP_sha256(); + ctx->kem_n_h = 32; + break; + case HPKE_DHKEM_P384_HKDF_SHA384: + ctx->kem_nid = NID_secp384r1; + ctx->iana_group = 20; + ctx->n_pk = 97; + ctx->n_secret = 48; + ctx->kem_h = EVP_sha384(); + ctx->kem_n_h = 48; + break; + case HPKE_DHKEM_P521_HKDF_SHA512: + ctx->kem_nid = NID_secp521r1; + ctx->iana_group = 21; + ctx->n_pk = 133; + ctx->n_secret = 64; + ctx->kem_h = EVP_sha512(); + ctx->kem_n_h = 64; + break; + default: + goto fail; + } + + ctx->kdf_id = kdf_id; + switch (kdf_id) { + case HPKE_KDF_HKDF_SHA256: + ctx->kdf_h = EVP_sha256(); + ctx->n_h = 32; + break; + case HPKE_KDF_HKDF_SHA384: + ctx->kdf_h = EVP_sha384(); + ctx->n_h = 48; + break; + case HPKE_KDF_HKDF_SHA512: + ctx->kdf_h = EVP_sha512(); + ctx->n_h = 64; + break; + default: + goto fail; + } + + ctx->aead_id = aead_id; + switch (aead_id) { + case HPKE_AEAD_AES_128_GCM: + ctx->cipher = EVP_aes_128_gcm(); + ctx->n_k = 16; + ctx->n_n = 12; + ctx->n_t = 16; + break; + case HPKE_AEAD_AES_256_GCM: + ctx->cipher = EVP_aes_256_gcm(); + ctx->n_k = 32; + ctx->n_n = 12; + ctx->n_t = 16; + break; + default: + goto fail; + } + + /* Convert BP-256/384/512 to P-256/384/521 for DPP */ + group = crypto_ec_key_group(key); + if (group == 28 && ctx->iana_group == 19) { + ctx->iana_group = 28; + } else if (group == 29 && ctx->iana_group == 20) { + ctx->iana_group = 29; + } else if (group == 30 && ctx->iana_group == 21) { + ctx->iana_group = 30; + ctx->n_pk = 129; + } + if (group != ctx->iana_group) { + wpa_printf(MSG_INFO, "OpenSSL:%s:group mismatch (%d != %d)", + __func__, group, ctx->iana_group); + goto fail; + } + + return ctx; +fail: + hpke_free_context(ctx); + return NULL; +} + + +static size_t hpke_suite_id(struct hpke_context *ctx, bool kem, u8 *suite_id) +{ + size_t suite_id_len; + + if (kem) { + os_memcpy(suite_id, "KEM", 3); + WPA_PUT_BE16(&suite_id[3], ctx->kem_id); + suite_id_len = 5; + } else { + os_memcpy(suite_id, "HPKE", 4); + WPA_PUT_BE16(&suite_id[4], ctx->kem_id); + WPA_PUT_BE16(&suite_id[6], ctx->kdf_id); + WPA_PUT_BE16(&suite_id[8], ctx->aead_id); + suite_id_len = 10; + } + return suite_id_len; +} + + +static int hpke_labeled_extract(struct hpke_context *ctx, bool kem, + const u8 *salt, size_t salt_len, + const char *label, + const u8 *ikm, size_t ikm_len, u8 *prk) +{ + u8 zero[HPKE_MAX_HASH_LEN]; + u8 suite_id[10]; + size_t suite_id_len; + unsigned int mdlen = kem ? ctx->kem_n_h : ctx->n_h; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MAC *hmac; + OSSL_PARAM params[2]; + EVP_MAC_CTX *hctx; + size_t mlen; + int res; +#else /* OpenSSL version >= 3.0 */ + HMAC_CTX *hctx; + int res; +#endif /* OpenSSL version >= 3.0 */ + + if (!salt || !salt_len) { + salt_len = mdlen; + os_memset(zero, 0, salt_len); + salt = zero; + } + + suite_id_len = hpke_suite_id(ctx, kem, suite_id); + + /* labeled_ikm = concat("HPKE-v1", suite_id, label, ikm) + * return Extract(salt, labeled_ikm) */ + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + hmac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (!hmac) + return -1; + + params[0] = OSSL_PARAM_construct_utf8_string( + "digest", + (char *) EVP_MD_get0_name(kem ? ctx->kem_h : ctx->kdf_h), 0); + params[1] = OSSL_PARAM_construct_end(); + + hctx = EVP_MAC_CTX_new(hmac); + EVP_MAC_free(hmac); + if (!hctx) + return -1; + + if (EVP_MAC_init(hctx, salt, salt_len, params) != 1) + goto fail; + + if (EVP_MAC_update(hctx, (const unsigned char *) "HPKE-v1", 7) != 1 || + EVP_MAC_update(hctx, suite_id, suite_id_len) != 1 || + EVP_MAC_update(hctx, (const unsigned char *) label, + os_strlen(label)) != 1 || + EVP_MAC_update(hctx, ikm, ikm_len) != 1) + goto fail; + + res = EVP_MAC_final(hctx, prk, &mlen, mdlen); + EVP_MAC_CTX_free(hctx); + + return res == 1 ? 0 : -1; +fail: + EVP_MAC_CTX_free(hctx); + return -1; +#else /* OpenSSL version >= 3.0 */ + hctx = HMAC_CTX_new(); + if (!hctx) + return -1; + res = HMAC_Init_ex(hctx, salt, salt_len, kem ? ctx->kem_h : ctx->kdf_h, + NULL); + if (res != 1) + goto done; + + HMAC_Update(hctx, (const unsigned char *) "HPKE-v1", 7); + HMAC_Update(hctx, suite_id, suite_id_len); + HMAC_Update(hctx, (const unsigned char *) label, os_strlen(label)); + HMAC_Update(hctx, ikm, ikm_len); + + res = HMAC_Final(hctx, prk, &mdlen); +done: + HMAC_CTX_free(hctx); + + return res == 1 ? 0 : -1; +#endif /* OpenSSL version >= 3.0 */ +} + + +static int +hpke_labeled_expand(struct hpke_context *ctx, bool kem, const u8 *prk, + const char *label, const u8 *info, size_t info_len, + u8 *out, size_t out_len) +{ + u8 suite_id[10]; + size_t suite_id_len; + u8 hash[HPKE_MAX_HASH_LEN]; + u8 iter = 0; + size_t label_len = os_strlen(label); + u8 *pos; + size_t left = out_len, clen; + int res = -1; + u8 *labeled_info; + size_t labeled_info_len; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MAC *hmac; + OSSL_PARAM params[2]; + EVP_MAC_CTX *hctx = NULL; + size_t mdlen; +#else /* OpenSSL version >= 3.0 */ + HMAC_CTX *hctx; + unsigned int mdlen; +#endif /* OpenSSL version >= 3.0 */ + + /* labeled_info = concat(I2OSP(L, 2), "HPKE-v1", suite_id, + * label, info) + * return Expand(prk, labeled_info, L) */ + suite_id_len = hpke_suite_id(ctx, kem, suite_id); + labeled_info_len = 2 + 7 + suite_id_len + label_len + info_len; + labeled_info = os_malloc(labeled_info_len); + if (!labeled_info) + return -1; + pos = labeled_info; + WPA_PUT_BE16(pos, out_len); + pos += 2; + os_memcpy(pos, "HPKE-v1", 7); + pos += 7; + os_memcpy(pos, suite_id, suite_id_len); + pos += suite_id_len; + os_memcpy(pos, label, label_len); + pos += label_len; + if (info && info_len) + os_memcpy(pos, info, info_len); + + pos = out; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + hmac = EVP_MAC_fetch(NULL, "HMAC", NULL); + if (!hmac) + goto fail; + + params[0] = OSSL_PARAM_construct_utf8_string( + "digest", + (char *) EVP_MD_get0_name(kem ? ctx->kem_h : ctx->kdf_h), 0); + params[1] = OSSL_PARAM_construct_end(); +#else /* OpenSSL version >= 3.0 */ + hctx = HMAC_CTX_new(); + if (!hctx) + goto fail; +#endif /* OpenSSL version >= 3.0 */ + + while (left > 0) { + mdlen = kem ? ctx->kem_n_h : ctx->n_h; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MAC_CTX_free(hctx); + hctx = EVP_MAC_CTX_new(hmac); + if (!hctx) + goto fail; + + if (EVP_MAC_init(hctx, prk, mdlen, params) != 1) + goto fail; + + if (iter > 0 && EVP_MAC_update(hctx, hash, mdlen) != 1) + goto fail; + if (iter == 255) + goto fail; + iter++; + + if (EVP_MAC_update(hctx, labeled_info, labeled_info_len) != 1 || + EVP_MAC_update(hctx, &iter, sizeof(iter)) != 1) + goto fail; + + if (EVP_MAC_final(hctx, hash, &mdlen, mdlen) != 1) + goto fail; +#else /* OpenSSL version >= 3.0 */ + if (HMAC_Init_ex(hctx, prk, mdlen, + kem ? ctx->kem_h : ctx->kdf_h, + NULL) != 1) + goto fail; + + if (iter > 0) + HMAC_Update(hctx, hash, mdlen); + if (iter == 255) + goto fail; + iter++; + HMAC_Update(hctx, labeled_info, labeled_info_len); + HMAC_Update(hctx, &iter, sizeof(iter)); + + if (HMAC_Final(hctx, hash, &mdlen) != 1) + goto fail; + HMAC_CTX_reset(hctx); +#endif /* OpenSSL version >= 3.0 */ + + clen = left > mdlen ? mdlen : left; + os_memcpy(pos, hash, clen); + pos += clen; + left -= clen; + } + res = 0; +fail: +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MAC_free(hmac); + EVP_MAC_CTX_free(hctx); +#else /* OpenSSL version >= 3.0 */ + HMAC_CTX_free(hctx); +#endif /* OpenSSL version >= 3.0 */ + os_free(labeled_info); + + return res; +} + + +static int hpke_extract_and_expand(struct hpke_context *ctx, + const u8 *dhss, size_t dhss_len, + const u8 *enc, size_t enc_len, + const u8 *pk_rm, size_t pk_rm_len, + u8 *shared_secret) +{ + u8 kem_context[2 * HPKE_MAX_PUB_LEN]; + u8 eae_prk[HPKE_MAX_HASH_LEN]; + + /* eae_prk = LabeledExtract("", "eae_prk", dh) */ + if (hpke_labeled_extract(ctx, true, NULL, 0, "eae_prk", dhss, dhss_len, + eae_prk) < 0) + return -1; + + if (enc_len > HPKE_MAX_PUB_LEN || pk_rm_len > HPKE_MAX_PUB_LEN) + return -1; + /* kem_context = concat(enc, pkRm) */ + os_memcpy(kem_context, enc, enc_len); + os_memcpy(&kem_context[enc_len], pk_rm, pk_rm_len); + + /* shared_secret = LabeledExpand(eae_prk, "shared_secret", + * kem_context, Nsecret) */ + if (hpke_labeled_expand(ctx, true, eae_prk, "shared_secret", + kem_context, enc_len + pk_rm_len, + shared_secret, ctx->n_secret) < 0) + return -1; + + forced_memzero(eae_prk, sizeof(eae_prk)); + return 0; +} + + +static int hpke_key_schedule(struct hpke_context *ctx, const u8 *shared_secret, + const u8 *info, size_t info_len) +{ + u8 key_schedule_context[1 + 2 * HPKE_MAX_HASH_LEN]; + u8 secret[HPKE_MAX_HASH_LEN]; + int res = -1; + + /* key_schedule_context = concat(mode, psk_id_hash, info_hash) */ + key_schedule_context[0] = HPKE_MODE_BASE; + + /* psk_id_hash = LabeledExtract("", "psk_id_hash", psk_id) */ + if (hpke_labeled_extract(ctx, false, NULL, 0, "psk_id_hash", + NULL, 0, &key_schedule_context[1]) < 0) + goto fail; + + /* info_hash = LabeledExtract("", "info_hash", info) */ + if (hpke_labeled_extract(ctx, false, NULL, 0, "info_hash", + info, info_len, + &key_schedule_context[1 + ctx->n_h]) < 0) + goto fail; + + /* secret = LabeledExtract(shared_secret, "secret", psk) */ + if (hpke_labeled_extract(ctx, false, shared_secret, ctx->n_secret, + "secret", NULL, 0, secret) < 0) + goto fail; + + /* key = LabeledExpand(secret, "key", key_schedule_context, Nk) */ + if (hpke_labeled_expand(ctx, false, secret, "key", + key_schedule_context, 1 + 2 * ctx->n_h, + ctx->key, ctx->n_k) < 0) + goto fail; + + /* base_nonce = LabeledExpand(secret, "base_nonce", + * key_schedule_context, Nn) */ + if (hpke_labeled_expand(ctx, false, secret, "base_nonce", + key_schedule_context, 1 + 2 * ctx->n_h, + ctx->base_nonce, ctx->n_n) < 0) + goto fail; + res = 0; +fail: + forced_memzero(key_schedule_context, sizeof(key_schedule_context)); + forced_memzero(secret, sizeof(secret)); + return res; +} + + +static int hpke_encap(struct hpke_context *ctx, struct crypto_ec_key *pk_r, + u8 *shared_secret, u8 *enc) +{ + EVP_PKEY_CTX *pctx = NULL; + struct crypto_ec_key *sk_e; + int res = -1; + u8 *dhss = NULL; + size_t dhss_len = 0; + struct wpabuf *enc_buf = NULL, *pk_rm = NULL; + + /* skE, pkE = GenerateKeyPair() */ + sk_e = crypto_ec_key_gen(ctx->iana_group); + if (!sk_e) { + wpa_printf(MSG_INFO, "OpenSSL:%s:Could not generate key pair", + __func__); + goto fail; + } + + /* dh = DH(skE, pkR) */ + dhss_len = sizeof(dhss); + pctx = EVP_PKEY_CTX_new((EVP_PKEY *) sk_e, NULL); + if (!pctx || + EVP_PKEY_derive_init(pctx) != 1 || + EVP_PKEY_derive_set_peer(pctx, (EVP_PKEY *) pk_r) != 1 || + EVP_PKEY_derive(pctx, NULL, &dhss_len) != 1 || + !(dhss = os_malloc(dhss_len)) || + EVP_PKEY_derive(pctx, dhss, &dhss_len) != 1 || + dhss_len > HPKE_MAX_SHARED_SECRET_LEN) { + wpa_printf(MSG_INFO, + "OpenSSL: hpke_encap: EVP_PKEY_derive failed (dhss_len=%zu): %s", + dhss_len, ERR_error_string(ERR_get_error(), NULL)); + goto fail; + } + + /* enc = SerializePublicKey(pkE) */ + enc_buf = crypto_ec_key_get_pubkey_point(sk_e, 1); + if (!enc_buf) + goto fail; + os_memcpy(enc, wpabuf_head(enc_buf), wpabuf_len(enc_buf)); + + /* pkRm = SerializePublicKey(pkR) */ + pk_rm = crypto_ec_key_get_pubkey_point(pk_r, 1); + if (!pk_rm) + goto fail; + + /* kem_context = concat(enc, pkRm) */ + /* shared_secret = ExtractAndExpand(dh, kem_context) */ + /* return shared_secret, enc */ + res = hpke_extract_and_expand(ctx, dhss, dhss_len, enc, ctx->n_pk, + wpabuf_head(pk_rm), + wpabuf_len(pk_rm), shared_secret); +fail: + bin_clear_free(dhss, dhss_len); + crypto_ec_key_deinit(sk_e); + EVP_PKEY_CTX_free(pctx); + wpabuf_free(enc_buf); + wpabuf_free(pk_rm); + return res; +} + + +static struct wpabuf * +hpke_aead_seal(struct hpke_context *ctx, const u8 *aad, size_t aad_len, + const u8 *pt, size_t pt_len) +{ + EVP_CIPHER_CTX *cctx; + int len = 0; + struct wpabuf *ct = NULL; + + /* No need to xor in sequence number since we support only the + * single-shot API, i.e., base_nonce can be used as-is. */ + + cctx = EVP_CIPHER_CTX_new(); + if (!cctx || + EVP_EncryptInit_ex(cctx, ctx->cipher, NULL, ctx->key, + ctx->base_nonce) != 1) { + wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptInit_ex failed", + __func__); + goto fail; + } + if (aad && aad_len && + EVP_EncryptUpdate(cctx, NULL, &len, aad, aad_len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_EncryptUpdate(AAD) failed", + __func__); + goto fail; + } + ct = wpabuf_alloc(pt_len + AES_BLOCK_SIZE + ctx->n_t); + if (!ct) + goto fail; + if (EVP_EncryptUpdate(cctx, wpabuf_put(ct, 0), &len, pt, pt_len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_EncryptUpdate failed", + __func__); + goto fail; + } + wpabuf_put(ct, len); + + if (EVP_EncryptFinal(cctx, wpabuf_put(ct, 0), &len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptFinal failed", + __func__); + wpabuf_free(ct); + ct = NULL; + goto fail; + } + + if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_GET_TAG, ctx->n_t, + wpabuf_put(ct, ctx->n_t)) != 1) { + wpa_printf(MSG_INFO, "OpenSSL:%s:Could not get tag", + __func__); + wpabuf_free(ct); + ct = NULL; + goto fail; + } +fail: + EVP_CIPHER_CTX_free(cctx); + return ct; +} + + +static struct wpabuf * hpke_base_seal_int(enum hpke_kem_id kem_id, + enum hpke_kdf_id kdf_id, + enum hpke_aead_id aead_id, + struct crypto_ec_key *peer_pub, + const u8 *info, size_t info_len, + const u8 *aad, size_t aad_len, + const u8 *pt, size_t pt_len) +{ + struct hpke_context *ctx; + u8 shared_secret[HPKE_MAX_SHARED_SECRET_LEN]; + u8 enc[1 + 2 * HPKE_MAX_PUB_LEN]; + struct wpabuf *ct = NULL, *enc_ct = NULL; + + ctx = hpke_get_context(kem_id, kdf_id, aead_id, peer_pub); + if (!ctx) + return NULL; + + /* shared_secret, enc = Encap(pkR) */ + if (hpke_encap(ctx, peer_pub, shared_secret, enc) < 0) + goto fail; + + /* KeyScheduleS(mode_base, shared_secret, info, + * default_psk, default_psk_id) */ + if (hpke_key_schedule(ctx, shared_secret, info, info_len) < 0) + goto fail; + + /* ct = ctx.Seal(aad, pt) */ + ct = hpke_aead_seal(ctx, aad, aad_len, pt, pt_len); + if (!ct) + goto fail; + + /* return enc, ct */ + enc_ct = wpabuf_alloc(ctx->n_pk + wpabuf_len(ct)); + if (!enc_ct) + goto fail; + wpabuf_put_data(enc_ct, enc, ctx->n_pk); + wpabuf_put_buf(enc_ct, ct); + +fail: + forced_memzero(shared_secret, sizeof(shared_secret)); + hpke_free_context(ctx); + wpabuf_free(ct); + return enc_ct; +} + + +static int hpke_decap(struct hpke_context *ctx, const u8 *enc, + size_t enc_ct_len, struct crypto_ec_key *sk_r, + u8 *shared_secret) +{ + EVP_PKEY_CTX *pctx = NULL; + struct wpabuf *pk_rm = NULL; + size_t len; + int res = -1; + struct crypto_ec_key *pk_e = NULL; + u8 *dhss = NULL; + size_t dhss_len = 0; + + /* pkE = DeserializePublicKey(enc) */ + if (enc_ct_len < ctx->n_pk) + return -1; /* not enough room for enc */ + if (enc[0] != 0x04) + return -1; /* not in uncompressed form */ + len = (ctx->n_pk - 1) / 2; + pk_e = crypto_ec_key_set_pub(ctx->iana_group, &enc[1], + &enc[1 + len], len); + if (!pk_e) + return -1; /* invalid public key point */ + /* dh = DH(skR, pkE) */ + pctx = EVP_PKEY_CTX_new((EVP_PKEY *) sk_r, NULL); + if (!pctx || + EVP_PKEY_derive_init(pctx) != 1 || + EVP_PKEY_derive_set_peer(pctx, (EVP_PKEY *) pk_e) != 1 || + EVP_PKEY_derive(pctx, NULL, &dhss_len) != 1 || + !(dhss = os_malloc(dhss_len)) || + EVP_PKEY_derive(pctx, dhss, &dhss_len) != 1 || + dhss_len > HPKE_MAX_SHARED_SECRET_LEN) { + wpa_printf(MSG_INFO, + "OpenSSL: hpke_decap: EVP_PKEY_derive failed (dhss_len=%zu): %s", + dhss_len, ERR_error_string(ERR_get_error(), NULL)); + goto fail; + } + + /* pkRm = SerializePublicKey(pk(skR)) */ + pk_rm = crypto_ec_key_get_pubkey_point(sk_r, 1); + if (!pk_rm) + goto fail; + + /* kem_context = concat(enc, pkRm) */ + /* shared_secret = ExtractAndExpand(dh, kem_context) */ + res = hpke_extract_and_expand(ctx, dhss, dhss_len, enc, ctx->n_pk, + wpabuf_head(pk_rm), + wpabuf_len(pk_rm), shared_secret); +fail: + bin_clear_free(dhss, dhss_len); + crypto_ec_key_deinit(pk_e); + EVP_PKEY_CTX_free(pctx); + wpabuf_free(pk_rm); + return res; +} + + +static struct wpabuf * +hpke_aead_open(struct hpke_context *ctx, const u8 *aad, size_t aad_len, + const u8 *ct, size_t ct_len) +{ + EVP_CIPHER_CTX *cctx; + int len = 0; + const u8 *tag; + struct wpabuf *pt = NULL; + + if (ct_len < ctx->n_t) + return NULL; + tag = ct + ct_len - ctx->n_t; + ct_len -= ctx->n_t; + + /* No need to xor in sequence number since we support only the + * single-shot API, i.e., base_nonce can be used as-is. */ + + cctx = EVP_CIPHER_CTX_new(); + if (!cctx || + EVP_DecryptInit_ex(cctx, ctx->cipher, NULL, ctx->key, + ctx->base_nonce) != 1) { + wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptInit_ex failed", + __func__); + goto fail; + } + if (aad && aad_len && + EVP_DecryptUpdate(cctx, NULL, &len, aad, aad_len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptUpdate(AAD) failed", + __func__); + goto fail; + } + pt = wpabuf_alloc(ct_len + AES_BLOCK_SIZE); + if (!pt) + goto fail; + if (EVP_DecryptUpdate(cctx, wpabuf_put(pt, 0), &len, ct, ct_len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptUpdate failed", + __func__); + goto fail; + } + wpabuf_put(pt, len); + + if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_SET_TAG, ctx->n_t, + (void *) tag) != 1) { + wpa_printf(MSG_INFO, "OpenSSL:%s:Could not set tag", + __func__); + wpabuf_free(pt); + pt = NULL; + goto fail; + } + + if (EVP_DecryptFinal(cctx, wpabuf_put(pt, 0), &len) != 1) { + wpa_printf(MSG_INFO, "OpenSSL:%s:EVP_DecryptFinal failed", + __func__); + wpabuf_free(pt); + pt = NULL; + } +fail: + EVP_CIPHER_CTX_free(cctx); + return pt; +} + + +static struct wpabuf * hpke_base_open_int(enum hpke_kem_id kem_id, + enum hpke_kdf_id kdf_id, + enum hpke_aead_id aead_id, + struct crypto_ec_key *own_priv, + const u8 *info, size_t info_len, + const u8 *aad, size_t aad_len, + const u8 *enc_ct, size_t enc_ct_len) +{ + struct hpke_context *ctx; + u8 shared_secret[HPKE_MAX_SHARED_SECRET_LEN]; + struct wpabuf *pt = NULL; + + ctx = hpke_get_context(kem_id, kdf_id, aead_id, own_priv); + if (!ctx) + return NULL; + + /* shared_secret = Decap(enc, skR) */ + if (hpke_decap(ctx, enc_ct, enc_ct_len, own_priv, shared_secret) < 0) + goto fail; + + /* KeyScheduleR(mode_base, shared_secret, info, + * default_psk, default_psk_id) */ + if (hpke_key_schedule(ctx, shared_secret, info, info_len) < 0) + goto fail; + + /* return ctx.Open(aad, ct) */ + pt = hpke_aead_open(ctx, aad, aad_len, + &enc_ct[ctx->n_pk], enc_ct_len - ctx->n_pk); + +fail: + forced_memzero(shared_secret, sizeof(shared_secret)); + hpke_free_context(ctx); + return pt; +} + + +#if OPENSSL_VERSION_NUMBER >= 0x30200000L + +static bool hpke_set_suite(OSSL_HPKE_SUITE *suite, + enum hpke_kem_id kem_id, + enum hpke_kdf_id kdf_id, + enum hpke_aead_id aead_id) +{ + os_memset(suite, 0, sizeof(*suite)); + + switch (kem_id) { + case HPKE_DHKEM_P256_HKDF_SHA256: + suite->kem_id = OSSL_HPKE_KEM_ID_P256; + break; + case HPKE_DHKEM_P384_HKDF_SHA384: + suite->kem_id = OSSL_HPKE_KEM_ID_P384; + break; + case HPKE_DHKEM_P521_HKDF_SHA512: + suite->kem_id = OSSL_HPKE_KEM_ID_P521; + break; + default: + return false; + } + + switch (kdf_id) { + case HPKE_KDF_HKDF_SHA256: + suite->kdf_id = OSSL_HPKE_KDF_ID_HKDF_SHA256; + break; + case HPKE_KDF_HKDF_SHA384: + suite->kdf_id = OSSL_HPKE_KDF_ID_HKDF_SHA384; + break; + case HPKE_KDF_HKDF_SHA512: + suite->kdf_id = OSSL_HPKE_KDF_ID_HKDF_SHA512; + break; + default: + return false; + } + + switch (aead_id) { + case HPKE_AEAD_AES_128_GCM: + suite->aead_id = OSSL_HPKE_AEAD_ID_AES_GCM_128; + break; + case HPKE_AEAD_AES_256_GCM: + suite->aead_id = OSSL_HPKE_AEAD_ID_AES_GCM_256; + break; + default: + return false; + } + + if (!OSSL_HPKE_suite_check(*suite)) { + wpa_printf(MSG_INFO, + "OpenSSL: HPKE suite kem_id=%d kdf_id=%d aead_id=%d not supported", + kem_id, kdf_id, aead_id); + return false; + } + + return true; +} + + +struct wpabuf * hpke_base_seal(enum hpke_kem_id kem_id, + enum hpke_kdf_id kdf_id, + enum hpke_aead_id aead_id, + struct crypto_ec_key *peer_pub, + const u8 *info, size_t info_len, + const u8 *aad, size_t aad_len, + const u8 *pt, size_t pt_len) +{ + OSSL_HPKE_SUITE suite; + OSSL_HPKE_CTX *ctx = NULL; + struct wpabuf *res = NULL, *buf, *pub = NULL; + size_t enc_len, ct_len; + int group; + + group = crypto_ec_key_group(peer_pub); + if (group == 28 || group == 29 || group == 30) { + /* Use the internal routines for the special DPP use case with + * brainpool curves, */ + return hpke_base_seal_int(kem_id, kdf_id, aead_id, peer_pub, + info, info_len, aad, aad_len, + pt, pt_len); + } + + + if (!hpke_set_suite(&suite, kem_id, kdf_id, aead_id)) + return NULL; + + enc_len = OSSL_HPKE_get_public_encap_size(suite); + ct_len = OSSL_HPKE_get_ciphertext_size(suite, pt_len); + buf = wpabuf_alloc(enc_len + ct_len); + if (!buf) + goto out; + + pub = crypto_ec_key_get_pubkey_point(peer_pub, 1); + if (!pub) + goto out; + + ctx = OSSL_HPKE_CTX_new(OSSL_HPKE_MODE_BASE, suite, + OSSL_HPKE_ROLE_SENDER, NULL, NULL); + if (!ctx) + goto out; + + if (OSSL_HPKE_encap(ctx, wpabuf_put(buf, 0), &enc_len, + wpabuf_head(pub), wpabuf_len(pub), + info, info_len) != 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: OSSL_HPKE_encap failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto out; + } + wpabuf_put(buf, enc_len); + + if (OSSL_HPKE_seal(ctx, wpabuf_put(buf, 0), &ct_len, aad, aad_len, + pt, pt_len) != 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: OSSL_HPKE_seal failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto out; + } + wpabuf_put(buf, ct_len); + res = buf; + buf = NULL; + +out: + OSSL_HPKE_CTX_free(ctx); + wpabuf_free(buf); + wpabuf_free(pub); + return res; +} + + +struct wpabuf * hpke_base_open(enum hpke_kem_id kem_id, + enum hpke_kdf_id kdf_id, + enum hpke_aead_id aead_id, + struct crypto_ec_key *own_priv, + const u8 *info, size_t info_len, + const u8 *aad, size_t aad_len, + const u8 *enc_ct, size_t enc_ct_len) +{ + OSSL_HPKE_SUITE suite; + OSSL_HPKE_CTX *ctx; + struct wpabuf *buf = NULL, *res = NULL; + size_t len, enc_len; + int group; + + group = crypto_ec_key_group(own_priv); + if (group == 28 || group == 29 || group == 30) { + /* Use the internal routines for the special DPP use case with + * brainpool curves, */ + return hpke_base_open_int(kem_id, kdf_id, aead_id, own_priv, + info, info_len, aad, aad_len, + enc_ct, enc_ct_len); + } + + if (!hpke_set_suite(&suite, kem_id, kdf_id, aead_id)) + return NULL; + + enc_len = OSSL_HPKE_get_public_encap_size(suite); + if (enc_ct_len < enc_len) { + wpa_printf(MSG_DEBUG, "OpenSSL: Too short HPKE enc_ct data"); + return NULL; + } + + ctx = OSSL_HPKE_CTX_new(OSSL_HPKE_MODE_BASE, suite, + OSSL_HPKE_ROLE_RECEIVER, NULL, NULL); + if (!ctx) + goto out; + + if (OSSL_HPKE_decap(ctx, enc_ct, enc_len, (EVP_PKEY *) own_priv, + info, info_len) != 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: OSSL_HPKE_decap failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto out; + } + + len = enc_ct_len; + buf = wpabuf_alloc(len); + if (!buf) + goto out; + + if (OSSL_HPKE_open(ctx, wpabuf_put(buf, 0), &len, aad, aad_len, + enc_ct + enc_len, enc_ct_len - enc_len) != 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: OSSL_HPKE_open failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto out; + } + + wpabuf_put(buf, len); + res = buf; + buf = NULL; + +out: + OSSL_HPKE_CTX_free(ctx); + wpabuf_free(buf); + return res; +} + +#else /* OpenSSL < 3.2 */ + +struct wpabuf * hpke_base_seal(enum hpke_kem_id kem_id, + enum hpke_kdf_id kdf_id, + enum hpke_aead_id aead_id, + struct crypto_ec_key *peer_pub, + const u8 *info, size_t info_len, + const u8 *aad, size_t aad_len, + const u8 *pt, size_t pt_len) +{ + return hpke_base_seal_int(kem_id, kdf_id, aead_id, peer_pub, + info, info_len, aad, aad_len, pt, pt_len); +} + + +struct wpabuf * hpke_base_open(enum hpke_kem_id kem_id, + enum hpke_kdf_id kdf_id, + enum hpke_aead_id aead_id, + struct crypto_ec_key *own_priv, + const u8 *info, size_t info_len, + const u8 *aad, size_t aad_len, + const u8 *enc_ct, size_t enc_ct_len) +{ + return hpke_base_open_int(kem_id, kdf_id, aead_id, own_priv, + info, info_len, aad, aad_len, + enc_ct, enc_ct_len); +} + +#endif /* OpenSSL < 3.2 */ + +#endif /* CONFIG_DPP3 */ + + +void crypto_unload(void) +{ + openssl_unload_legacy_provider(); +} diff --git a/wpa_supplicant-2.9_standard/src/crypto/crypto_wolfssl.c b/wpa_supplicant-2.9_standard/src/crypto/crypto_wolfssl.c index d1b9f67e452407dc78bd74c6e122aa6ba019a457..16959d17bd3b4a885fc252e9ff8fbe30ca426408 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/crypto_wolfssl.c +++ b/wpa_supplicant-2.9_standard/src/crypto/crypto_wolfssl.c @@ -10,23 +10,148 @@ #include "common.h" #include "crypto.h" +#include "tls/asn1.h" /* wolfSSL headers */ -#include +#include /* options.h needs to be included first */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#ifdef CONFIG_FIPS +#ifndef HAVE_FIPS +#warning "You are compiling wpa_supplicant/hostapd in FIPS mode but wolfSSL is not configured for FIPS mode." +#endif /* HAVE_FIPS */ +#endif /* CONFIG_FIPS */ + + +#ifdef CONFIG_FIPS +#if !defined(HAVE_FIPS_VERSION) || HAVE_FIPS_VERSION <= 2 +#define WOLFSSL_OLD_FIPS +#endif +#endif + +#if LIBWOLFSSL_VERSION_HEX < 0x05004000 +static int wc_EccPublicKeyToDer_ex(ecc_key *key, byte *output, + word32 inLen, int with_AlgCurve, + int comp) +{ + return wc_EccPublicKeyToDer(key, output, inLen, with_AlgCurve); +} +#endif /* version < 5.4.0 */ + +#define LOG_WOLF_ERROR_VA(msg, ...) \ + wpa_printf(MSG_ERROR, "wolfSSL: %s:%d " msg, \ + __func__, __LINE__, __VA_ARGS__) + +#define LOG_WOLF_ERROR(msg) \ + LOG_WOLF_ERROR_VA("%s", (msg)) + +#define LOG_WOLF_ERROR_FUNC(func, err) \ + LOG_WOLF_ERROR_VA(#func " failed with err: %d %s", \ + (err), wc_GetErrorString(err)) + +#define LOG_WOLF_ERROR_FUNC_NULL(func) \ + LOG_WOLF_ERROR(#func " failed with NULL return") + +#define LOG_INVALID_PARAMETERS() \ + LOG_WOLF_ERROR("invalid input parameters") + + +/* Helper functions to make type allocation uniform */ + +static WC_RNG * wc_rng_init(void) +{ + WC_RNG *ret; + +#ifdef CONFIG_FIPS + ret = os_zalloc(sizeof(WC_RNG)); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(os_zalloc); + } else { + int err; + + err = wc_InitRng(ret); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_InitRng, err); + os_free(ret); + ret = NULL; + } + } +#else /* CONFIG_FIPS */ + ret = wc_rng_new(NULL, 0, NULL); + if (!ret) + LOG_WOLF_ERROR_FUNC_NULL(wc_rng_new); +#endif /* CONFIG_FIPS */ + + return ret; +} + + +static void wc_rng_deinit(WC_RNG *rng) +{ +#ifdef CONFIG_FIPS + wc_FreeRng(rng); + os_free(rng); +#else /* CONFIG_FIPS */ + wc_rng_free(rng); +#endif /* CONFIG_FIPS */ +} + + +static ecc_key * ecc_key_init(void) +{ + ecc_key *ret; +#ifdef CONFIG_FIPS + int err; + + ret = os_zalloc(sizeof(ecc_key)); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(os_zalloc); + } else { + err = wc_ecc_init_ex(ret, NULL, INVALID_DEVID); + if (err != 0) { + LOG_WOLF_ERROR("wc_ecc_init_ex failed"); + os_free(ret); + ret = NULL; + } + } +#else /* CONFIG_FIPS */ + ret = wc_ecc_key_new(NULL); + if (!ret) + LOG_WOLF_ERROR_FUNC_NULL(wc_ecc_key_new); +#endif /* CONFIG_FIPS */ + + return ret; +} + + +static void ecc_key_deinit(ecc_key *key) +{ +#ifdef CONFIG_FIPS + wc_ecc_free(key); + os_free(key); +#else /* CONFIG_FIPS */ + wc_ecc_key_free(key); +#endif /* CONFIG_FIPS */ +} + +/* end of helper functions */ #ifndef CONFIG_FIPS @@ -54,18 +179,36 @@ int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { wc_Md5 md5; size_t i; + int err; + int ret = -1; if (TEST_FAIL()) return -1; - wc_InitMd5(&md5); + err = wc_InitMd5(&md5); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_InitMd5, err); + return -1; + } - for (i = 0; i < num_elem; i++) - wc_Md5Update(&md5, addr[i], len[i]); + for (i = 0; i < num_elem; i++) { + err = wc_Md5Update(&md5, addr[i], len[i]); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_Md5Update, err); + goto fail; + } + } - wc_Md5Final(&md5, mac); + err = wc_Md5Final(&md5, mac); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_Md5Final, err); + goto fail; + } - return 0; + ret = 0; +fail: + wc_Md5Free(&md5); + return ret; } #endif /* CONFIG_FIPS */ @@ -75,18 +218,36 @@ int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) { wc_Sha sha; size_t i; + int err; + int ret = -1; if (TEST_FAIL()) return -1; - wc_InitSha(&sha); + err = wc_InitSha(&sha); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_InitSha, err); + return -1; + } - for (i = 0; i < num_elem; i++) - wc_ShaUpdate(&sha, addr[i], len[i]); + for (i = 0; i < num_elem; i++) { + err = wc_ShaUpdate(&sha, addr[i], len[i]); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_ShaUpdate, err); + goto fail; + } + } - wc_ShaFinal(&sha, mac); + err = wc_ShaFinal(&sha, mac); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_ShaFinal, err); + goto fail; + } - return 0; + ret = 0; +fail: + wc_ShaFree(&sha); + return ret; } @@ -96,18 +257,36 @@ int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len, { wc_Sha256 sha256; size_t i; + int err; + int ret = -1; if (TEST_FAIL()) return -1; - wc_InitSha256(&sha256); + err = wc_InitSha256(&sha256); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_InitSha256, err); + return -1; + } - for (i = 0; i < num_elem; i++) - wc_Sha256Update(&sha256, addr[i], len[i]); + for (i = 0; i < num_elem; i++) { + err = wc_Sha256Update(&sha256, addr[i], len[i]); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_Sha256Update, err); + goto fail; + } + } - wc_Sha256Final(&sha256, mac); + err = wc_Sha256Final(&sha256, mac); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_Sha256Final, err); + goto fail; + } - return 0; + ret = 0; +fail: + wc_Sha256Free(&sha256); + return ret; } #endif /* NO_SHA256_WRAPPER */ @@ -118,18 +297,36 @@ int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len, { wc_Sha384 sha384; size_t i; + int err; + int ret = -1; if (TEST_FAIL()) return -1; - wc_InitSha384(&sha384); + err = wc_InitSha384(&sha384); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_InitSha384, err); + return -1; + } - for (i = 0; i < num_elem; i++) - wc_Sha384Update(&sha384, addr[i], len[i]); + for (i = 0; i < num_elem; i++) { + err = wc_Sha384Update(&sha384, addr[i], len[i]); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_Sha384Update, err); + goto fail; + } + } - wc_Sha384Final(&sha384, mac); + err = wc_Sha384Final(&sha384, mac); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_Sha384Final, err); + goto fail; + } - return 0; + ret = 0; +fail: + wc_Sha384Free(&sha384); + return ret; } #endif /* CONFIG_SHA384 */ @@ -140,18 +337,36 @@ int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, { wc_Sha512 sha512; size_t i; + int err; + int ret = -1; if (TEST_FAIL()) return -1; - wc_InitSha512(&sha512); + err = wc_InitSha512(&sha512); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_InitSha512, err); + return -1; + } - for (i = 0; i < num_elem; i++) - wc_Sha512Update(&sha512, addr[i], len[i]); + for (i = 0; i < num_elem; i++) { + err = wc_Sha512Update(&sha512, addr[i], len[i]); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_Sha512Update, err); + goto fail; + } + } - wc_Sha512Final(&sha512, mac); + err = wc_Sha512Final(&sha512, mac); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_Sha512Final, err); + goto fail; + } - return 0; + ret = 0; +fail: + wc_Sha512Free(&sha512); + return ret; } #endif /* CONFIG_SHA512 */ @@ -163,20 +378,43 @@ static int wolfssl_hmac_vector(int type, const u8 *key, { Hmac hmac; size_t i; + int err; + int ret = -1; (void) mdlen; if (TEST_FAIL()) return -1; - if (wc_HmacSetKey(&hmac, type, key, (word32) key_len) != 0) - return -1; - for (i = 0; i < num_elem; i++) - if (wc_HmacUpdate(&hmac, addr[i], len[i]) != 0) - return -1; - if (wc_HmacFinal(&hmac, mac) != 0) + err = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_HmacInit, err); return -1; - return 0; + } + + err = wc_HmacSetKey(&hmac, type, key, (word32) key_len); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_HmacSetKey, err); + goto fail; + } + + for (i = 0; i < num_elem; i++) { + err = wc_HmacUpdate(&hmac, addr[i], len[i]); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_HmacUpdate, err); + goto fail; + } + } + err = wc_HmacFinal(&hmac, mac); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_HmacFinal, err); + goto fail; + } + + ret = 0; +fail: + wc_HmacFree(&hmac); + return ret; } @@ -274,9 +512,17 @@ int hmac_sha512(const u8 *key, size_t key_len, const u8 *data, int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, int iterations, u8 *buf, size_t buflen) { - if (wc_PBKDF2(buf, (const byte*)passphrase, os_strlen(passphrase), ssid, - ssid_len, iterations, buflen, WC_SHA) != 0) + int ret; + + ret = wc_PBKDF2(buf, (const byte *) passphrase, os_strlen(passphrase), + ssid, ssid_len, iterations, buflen, WC_SHA); + if (ret != 0) { + if (ret == HMAC_MIN_KEYLEN_E) { + LOG_WOLF_ERROR_VA("wolfSSL: Password is too short. Make sure your password is at least %d characters long. This is a requirement for FIPS builds.", + HMAC_FIPS_MIN_KEY); + } return -1; + } return 0; } @@ -308,15 +554,20 @@ int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) void * aes_encrypt_init(const u8 *key, size_t len) { Aes *aes; + int err; if (TEST_FAIL()) return NULL; aes = os_malloc(sizeof(Aes)); - if (!aes) + if (!aes) { + LOG_WOLF_ERROR_FUNC_NULL(os_malloc); return NULL; + } - if (wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION) < 0) { + err = wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION); + if (err < 0) { + LOG_WOLF_ERROR_FUNC(wc_AesSetKey, err); os_free(aes); return NULL; } @@ -327,7 +578,18 @@ void * aes_encrypt_init(const u8 *key, size_t len) int aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) { +#if defined(HAVE_FIPS) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION <= 2)) + /* Old FIPS has void return on this API */ wc_AesEncryptDirect(ctx, crypt, plain); +#else + int err = wc_AesEncryptDirect(ctx, crypt, plain); + + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_AesEncryptDirect, err); + return -1; + } +#endif return 0; } @@ -341,15 +603,20 @@ void aes_encrypt_deinit(void *ctx) void * aes_decrypt_init(const u8 *key, size_t len) { Aes *aes; + int err; if (TEST_FAIL()) return NULL; aes = os_malloc(sizeof(Aes)); - if (!aes) + if (!aes) { + LOG_WOLF_ERROR_FUNC_NULL(os_malloc); return NULL; + } - if (wc_AesSetKey(aes, key, len, NULL, AES_DECRYPTION) < 0) { + err = wc_AesSetKey(aes, key, len, NULL, AES_DECRYPTION); + if (err < 0) { + LOG_WOLF_ERROR_FUNC(wc_AesSetKey, err); os_free(aes); return NULL; } @@ -360,7 +627,18 @@ void * aes_decrypt_init(const u8 *key, size_t len) int aes_decrypt(void *ctx, const u8 *crypt, u8 *plain) { +#if defined(HAVE_FIPS) && \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION <= 2)) + /* Old FIPS has void return on this API */ wc_AesDecryptDirect(ctx, plain, crypt); +#else + int err = wc_AesDecryptDirect(ctx, plain, crypt); + + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_AesDecryptDirect, err); + return -1; + } +#endif return 0; } @@ -409,8 +687,11 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len) } +#ifndef CONFIG_FIPS +#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) { +#ifdef HAVE_AES_KEYWRAP int ret; if (TEST_FAIL()) @@ -419,12 +700,16 @@ int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) ret = wc_AesKeyWrap(kek, kek_len, plain, n * 8, cipher, (n + 1) * 8, NULL); return ret != (n + 1) * 8 ? -1 : 0; +#else /* HAVE_AES_KEYWRAP */ + return -1; +#endif /* HAVE_AES_KEYWRAP */ } int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, u8 *plain) { +#ifdef HAVE_AES_KEYWRAP int ret; if (TEST_FAIL()) @@ -433,7 +718,12 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, ret = wc_AesKeyUnWrap(kek, kek_len, cipher, (n + 1) * 8, plain, n * 8, NULL); return ret != n * 8 ? -1 : 0; +#else /* HAVE_AES_KEYWRAP */ + return -1; +#endif /* HAVE_AES_KEYWRAP */ } +#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */ +#endif /* CONFIG_FIPS */ #ifndef CONFIG_NO_RC4 @@ -670,6 +960,7 @@ void * dh5_init(struct wpabuf **priv, struct wpabuf **publ) != 0) goto done; + priv_sz = pub_sz = RFC3526_LEN; if (wc_DhGenerateKeyPair(dh, &rng, wpabuf_mhead(privkey), &priv_sz, wpabuf_mhead(pubkey), &pub_sz) != 0) goto done; @@ -803,6 +1094,7 @@ int crypto_dh_init(u8 generator, const u8 *prime, size_t prime_len, u8 *privkey, if (wc_DhSetKey(dh, prime, prime_len, &generator, 1) != 0) goto done; + priv_sz = pub_sz = prime_len; if (wc_DhGenerateKeyPair(dh, &rng, privkey, &priv_sz, pubkey, &pub_sz) != 0) goto done; @@ -919,7 +1211,8 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key, goto done; } - if (wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0) + if (wc_HmacInit(&hash->hmac, NULL, INVALID_DEVID) != 0 || + wc_HmacSetKey(&hash->hmac, type, key, key_len) != 0) goto done; ret = hash; @@ -1310,17 +1603,52 @@ int crypto_bignum_legendre(const struct crypto_bignum *a, #ifdef CONFIG_ECC +static int crypto_ec_group_2_id(int group) +{ + switch (group) { + case 19: + return ECC_SECP256R1; + case 20: + return ECC_SECP384R1; + case 21: + return ECC_SECP521R1; + case 25: + return ECC_SECP192R1; + case 26: + return ECC_SECP224R1; +#ifdef HAVE_ECC_BRAINPOOL + case 27: + return ECC_BRAINPOOLP224R1; + case 28: + return ECC_BRAINPOOLP256R1; + case 29: + return ECC_BRAINPOOLP384R1; + case 30: + return ECC_BRAINPOOLP512R1; +#endif /* HAVE_ECC_BRAINPOOL */ + default: + LOG_WOLF_ERROR_VA("Unsupported curve (id=%d) in EC key", group); + return ECC_CURVE_INVALID; + } +} + + int ecc_map(ecc_point *, mp_int *, mp_digit); int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, mp_int *a, mp_int *modulus, mp_digit mp); struct crypto_ec { - ecc_key key; + ecc_key *key; +#ifdef CONFIG_DPP + ecc_point *g; /* Only used in DPP for now */ +#endif /* CONFIG_DPP */ mp_int a; mp_int prime; mp_int order; mp_digit mont_b; mp_int b; + int curve_id; + bool own_key; /* Should we free the `key` */ }; @@ -1328,59 +1656,98 @@ struct crypto_ec * crypto_ec_init(int group) { int built = 0; struct crypto_ec *e; - int curve_id; + int curve_id = crypto_ec_group_2_id(group); + int err; - /* Map from IANA registry for IKE D-H groups to OpenSSL NID */ - switch (group) { - case 19: - curve_id = ECC_SECP256R1; - break; - case 20: - curve_id = ECC_SECP384R1; - break; - case 21: - curve_id = ECC_SECP521R1; - break; - case 25: - curve_id = ECC_SECP192R1; - break; - case 26: - curve_id = ECC_SECP224R1; - break; -#ifdef HAVE_ECC_BRAINPOOL - case 27: - curve_id = ECC_BRAINPOOLP224R1; - break; - case 28: - curve_id = ECC_BRAINPOOLP256R1; - break; - case 29: - curve_id = ECC_BRAINPOOLP384R1; - break; - case 30: - curve_id = ECC_BRAINPOOLP512R1; - break; -#endif /* HAVE_ECC_BRAINPOOL */ - default: + if (curve_id == ECC_CURVE_INVALID) { + LOG_INVALID_PARAMETERS(); return NULL; } e = os_zalloc(sizeof(*e)); - if (!e) + if (!e) { + LOG_WOLF_ERROR_FUNC_NULL(os_zalloc); return NULL; + } - if (wc_ecc_init(&e->key) != 0 || - wc_ecc_set_curve(&e->key, 0, curve_id) != 0 || - mp_init(&e->a) != MP_OKAY || - mp_init(&e->prime) != MP_OKAY || - mp_init(&e->order) != MP_OKAY || - mp_init(&e->b) != MP_OKAY || - mp_read_radix(&e->a, e->key.dp->Af, 16) != MP_OKAY || - mp_read_radix(&e->b, e->key.dp->Bf, 16) != MP_OKAY || - mp_read_radix(&e->prime, e->key.dp->prime, 16) != MP_OKAY || - mp_read_radix(&e->order, e->key.dp->order, 16) != MP_OKAY || - mp_montgomery_setup(&e->prime, &e->mont_b) != MP_OKAY) + e->curve_id = curve_id; + e->own_key = true; + e->key = ecc_key_init(); + if (!e->key) { + LOG_WOLF_ERROR_FUNC_NULL(ecc_key_init); + goto done; + } + + err = wc_ecc_set_curve(e->key, 0, curve_id); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_ecc_set_curve, err); + goto done; + } +#ifdef CONFIG_DPP + e->g = wc_ecc_new_point(); + if (!e->g) { + LOG_WOLF_ERROR_FUNC_NULL(wc_ecc_new_point); + goto done; + } +#ifdef CONFIG_FIPS + /* Setup generator manually in FIPS mode */ + if (!e->key->dp) { + LOG_WOLF_ERROR_FUNC_NULL(e->key->dp); goto done; + } + err = mp_read_radix(e->g->x, e->key->dp->Gx, MP_RADIX_HEX); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(mp_read_radix, err); + goto done; + } + err = mp_read_radix(e->g->y, e->key->dp->Gy, MP_RADIX_HEX); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(mp_read_radix, err); + goto done; + } + err = mp_set(e->g->z, 1); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(mp_set, err); + goto done; + } +#else /* CONFIG_FIPS */ + err = wc_ecc_get_generator(e->g, wc_ecc_get_curve_idx(curve_id)); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_get_generator, err); + goto done; + } +#endif /* CONFIG_FIPS */ +#endif /* CONFIG_DPP */ + err = mp_init_multi(&e->a, &e->prime, &e->order, &e->b, NULL, NULL); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(mp_init_multi, err); + goto done; + } + err = mp_read_radix(&e->a, e->key->dp->Af, 16); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(mp_read_radix, err); + goto done; + } + err = mp_read_radix(&e->b, e->key->dp->Bf, 16); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(mp_read_radix, err); + goto done; + } + err = mp_read_radix(&e->prime, e->key->dp->prime, 16); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(mp_read_radix, err); + goto done; + } + err = mp_read_radix(&e->order, e->key->dp->order, 16); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(mp_read_radix, err); + goto done; + } + err = mp_montgomery_setup(&e->prime, &e->mont_b); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(mp_montgomery_setup, err); + goto done; + } built = 1; done: @@ -1401,7 +1768,11 @@ void crypto_ec_deinit(struct crypto_ec* e) mp_clear(&e->order); mp_clear(&e->prime); mp_clear(&e->a); - wc_ecc_free(&e->key); +#ifdef CONFIG_DPP + wc_ecc_del_point(e->g); +#endif /* CONFIG_DPP */ + if (e->own_key) + ecc_key_deinit(e->key); os_free(e); } @@ -1466,14 +1837,26 @@ void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear) return; if (clear) { +#ifdef CONFIG_FIPS mp_forcezero(point->x); mp_forcezero(point->y); mp_forcezero(point->z); +#else /* CONFIG_FIPS */ + wc_ecc_forcezero_point(point); +#endif /* CONFIG_FIPS */ } wc_ecc_del_point(point); } +#ifdef CONFIG_DPP +const struct crypto_ec_point * crypto_ec_get_generator(struct crypto_ec *e) +{ + return (const struct crypto_ec_point *) e->g; +} +#endif /* CONFIG_DPP */ + + int crypto_ec_point_x(struct crypto_ec *e, const struct crypto_ec_point *p, struct crypto_bignum *x) { @@ -1485,27 +1868,41 @@ int crypto_ec_point_to_bin(struct crypto_ec *e, const struct crypto_ec_point *point, u8 *x, u8 *y) { ecc_point *p = (ecc_point *) point; + int len; + int err; if (TEST_FAIL()) return -1; if (!mp_isone(p->z)) { - if (ecc_map(p, &e->prime, e->mont_b) != MP_OKAY) + err = ecc_map(p, &e->prime, e->mont_b); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(ecc_map, err); return -1; + } + } + + len = wc_ecc_get_curve_size_from_id(e->curve_id); + if (len <= 0) { + LOG_WOLF_ERROR_FUNC(wc_ecc_get_curve_size_from_id, len); + LOG_WOLF_ERROR_VA("wc_ecc_get_curve_size_from_id error for curve_id %d", e->curve_id); + return -1; } if (x) { if (crypto_bignum_to_bin((struct crypto_bignum *)p->x, x, - e->key.dp->size, - e->key.dp->size) <= 0) + (size_t) len, (size_t) len) <= 0) { + LOG_WOLF_ERROR_FUNC(crypto_bignum_to_bin, -1); return -1; + } } if (y) { if (crypto_bignum_to_bin((struct crypto_bignum *) p->y, y, - e->key.dp->size, - e->key.dp->size) <= 0) + (size_t) len, (size_t) len) <= 0) { + LOG_WOLF_ERROR_FUNC(crypto_bignum_to_bin, -1); return -1; + } } return 0; @@ -1525,10 +1922,10 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e, if (!point) goto done; - if (mp_read_unsigned_bin(point->x, val, e->key.dp->size) != MP_OKAY) + if (mp_read_unsigned_bin(point->x, val, e->key->dp->size) != MP_OKAY) goto done; - val += e->key.dp->size; - if (mp_read_unsigned_bin(point->y, val, e->key.dp->size) != MP_OKAY) + val += e->key->dp->size; + if (mp_read_unsigned_bin(point->y, val, e->key->dp->size) != MP_OKAY) goto done; mp_set(point->z, 1); @@ -1643,35 +2040,21 @@ struct crypto_bignum * crypto_ec_point_compute_y_sqr(struct crypto_ec *e, const struct crypto_bignum *x) { - mp_int *y2 = NULL; - mp_int t; - int calced = 0; + mp_int *y2; if (TEST_FAIL()) return NULL; - if (mp_init(&t) != MP_OKAY) - return NULL; - + /* y^2 = x^3 + ax + b = (x^2 + a)x + b */ y2 = (mp_int *) crypto_bignum_init(); - if (!y2) - goto done; - - if (mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 || + if (!y2 || + mp_sqrmod((mp_int *) x, &e->prime, y2) != 0 || + mp_addmod(y2, &e->a, &e->prime, y2) != 0 || mp_mulmod((mp_int *) x, y2, &e->prime, y2) != 0 || - mp_mulmod((mp_int *) x, &e->a, &e->prime, &t) != 0 || - mp_addmod(y2, &t, &e->prime, y2) != 0 || - mp_addmod(y2, &e->b, &e->prime, y2) != 0) - goto done; - - calced = 1; -done: - if (!calced) { - if (y2) { - mp_clear(y2); - os_free(y2); - } - mp_clear(&t); + mp_addmod(y2, &e->b, &e->prime, y2) != 0) { + mp_clear(y2); + os_free(y2); + y2 = NULL; } return (struct crypto_bignum *) y2; @@ -1700,48 +2083,123 @@ int crypto_ec_point_cmp(const struct crypto_ec *e, return wc_ecc_cmp_point((ecc_point *) a, (ecc_point *) b); } +struct crypto_ec_key { + ecc_key *eckey; + WC_RNG *rng; /* Needs to be initialized before use. + * *NOT* initialized in crypto_ec_key_init */ +}; + struct crypto_ecdh { struct crypto_ec *ec; + WC_RNG *rng; }; -struct crypto_ecdh * crypto_ecdh_init(int group) +static struct crypto_ecdh * _crypto_ecdh_init(int group) { struct crypto_ecdh *ecdh = NULL; - WC_RNG rng; +#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS) int ret; - - if (wc_InitRng(&rng) != 0) - goto fail; +#endif /* ECC_TIMING_RESISTANT && !WOLFSSL_OLD_FIPS */ ecdh = os_zalloc(sizeof(*ecdh)); - if (!ecdh) + if (!ecdh) { + LOG_WOLF_ERROR_FUNC_NULL(os_zalloc); + return NULL; + } + + ecdh->rng = wc_rng_init(); + if (!ecdh->rng) { + LOG_WOLF_ERROR_FUNC_NULL(wc_rng_init); goto fail; + } ecdh->ec = crypto_ec_init(group); - if (!ecdh->ec) + if (!ecdh->ec) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_init); goto fail; + } - ret = wc_ecc_make_key_ex(&rng, ecdh->ec->key.dp->size, &ecdh->ec->key, - ecdh->ec->key.dp->id); - if (ret < 0) +#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS) + ret = wc_ecc_set_rng(ecdh->ec->key, ecdh->rng); + if (ret != 0) { + LOG_WOLF_ERROR_FUNC(wc_ecc_set_rng, ret); goto fail; - -done: - wc_FreeRng(&rng); + } +#endif /* ECC_TIMING_RESISTANT && !WOLFSSL_OLD_FIPS */ return ecdh; fail: crypto_ecdh_deinit(ecdh); - ecdh = NULL; - goto done; + return NULL; +} + + +struct crypto_ecdh * crypto_ecdh_init(int group) +{ + struct crypto_ecdh *ret = NULL; + int err; + + ret = _crypto_ecdh_init(group); + + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(_crypto_ecdh_init); + return NULL; + } + + err = wc_ecc_make_key_ex(ret->rng, 0, ret->ec->key, + crypto_ec_group_2_id(group)); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_make_key_ex, err); + crypto_ecdh_deinit(ret); + ret = NULL; + } + + return ret; +} + + +struct crypto_ecdh * crypto_ecdh_init2(int group, struct crypto_ec_key *own_key) +{ + struct crypto_ecdh *ret = NULL; + + if (!own_key || crypto_ec_key_group(own_key) != group) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + + ret = _crypto_ecdh_init(group); + if (ret) { + /* Already init'ed to the right group. Enough to substitute the + * key. */ + ecc_key_deinit(ret->ec->key); + ret->ec->key = own_key->eckey; + ret->ec->own_key = false; +#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS) + if (!ret->ec->key->rng) { + int err = wc_ecc_set_rng(ret->ec->key, ret->rng); + + if (err != 0) + LOG_WOLF_ERROR_FUNC(wc_ecc_set_rng, err); + } +#endif /* ECC_TIMING_RESISTANT && !CONFIG_FIPS */ + } + + return ret; } void crypto_ecdh_deinit(struct crypto_ecdh *ecdh) { if (ecdh) { +#if defined(ECC_TIMING_RESISTANT) && !defined(WOLFSSL_OLD_FIPS) + /* Disassociate the rng */ + if (ecdh->ec && ecdh->ec->key && + ecdh->ec->key->rng == ecdh->rng) + (void) wc_ecc_set_rng(ecdh->ec->key, NULL); +#endif /* ECC_TIMING_RESISTANT && !WOLFSSL_OLD_FIPS */ crypto_ec_deinit(ecdh->ec); + wc_rng_deinit(ecdh->rng); os_free(ecdh); } } @@ -1751,20 +2209,20 @@ struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y) { struct wpabuf *buf = NULL; int ret; - int len = ecdh->ec->key.dp->size; + int len = ecdh->ec->key->dp->size; buf = wpabuf_alloc(inc_y ? 2 * len : len); if (!buf) goto fail; ret = crypto_bignum_to_bin((struct crypto_bignum *) - ecdh->ec->key.pubkey.x, wpabuf_put(buf, len), + ecdh->ec->key->pubkey.x, wpabuf_put(buf, len), len, len); if (ret < 0) goto fail; if (inc_y) { ret = crypto_bignum_to_bin((struct crypto_bignum *) - ecdh->ec->key.pubkey.y, + ecdh->ec->key->pubkey.y, wpabuf_put(buf, len), len, len); if (ret < 0) goto fail; @@ -1785,35 +2243,47 @@ struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y, int ret; struct wpabuf *pubkey = NULL; struct wpabuf *secret = NULL; - word32 key_len = ecdh->ec->key.dp->size; + word32 key_len = ecdh->ec->key->dp->size; ecc_point *point = NULL; size_t need_key_len = inc_y ? 2 * key_len : key_len; - if (len < need_key_len) + if (len < need_key_len) { + LOG_WOLF_ERROR("key len too small"); goto fail; + } pubkey = wpabuf_alloc(1 + 2 * key_len); - if (!pubkey) + if (!pubkey) { + LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc); goto fail; + } wpabuf_put_u8(pubkey, inc_y ? ECC_POINT_UNCOMP : ECC_POINT_COMP_EVEN); wpabuf_put_data(pubkey, key, need_key_len); point = wc_ecc_new_point(); - if (!point) + if (!point) { + LOG_WOLF_ERROR_FUNC_NULL(wc_ecc_new_point); goto fail; + } ret = wc_ecc_import_point_der(wpabuf_mhead(pubkey), 1 + 2 * key_len, - ecdh->ec->key.idx, point); - if (ret != MP_OKAY) + ecdh->ec->key->idx, point); + if (ret != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_import_point_der, ret); goto fail; + } secret = wpabuf_alloc(key_len); - if (!secret) + if (!secret) { + LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc); goto fail; + } - ret = wc_ecc_shared_secret_ex(&ecdh->ec->key, point, + ret = wc_ecc_shared_secret_ex(ecdh->ec->key, point, wpabuf_put(secret, key_len), &key_len); - if (ret != MP_OKAY) + if (ret != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_shared_secret_ex, ret); goto fail; + } done: wc_ecc_del_point(point); @@ -1831,4 +2301,1269 @@ size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh) return crypto_ec_prime_len(ecdh->ec); } +static struct crypto_ec_key * crypto_ec_key_init(void) +{ + struct crypto_ec_key *key; + + key = os_zalloc(sizeof(struct crypto_ec_key)); + if (key) { + key->eckey = ecc_key_init(); + /* Omit key->rng initialization because it seeds itself and thus + * consumes entropy that may never be used. Lazy initialize when + * necessary. */ + if (!key->eckey) { + LOG_WOLF_ERROR_FUNC_NULL(ecc_key_init); + crypto_ec_key_deinit(key); + key = NULL; + } + } + return key; +} + + +void crypto_ec_key_deinit(struct crypto_ec_key *key) +{ + if (key) { + ecc_key_deinit(key->eckey); + wc_rng_deinit(key->rng); + os_free(key); + } +} + + +static WC_RNG * crypto_ec_key_init_rng(struct crypto_ec_key *key) +{ + if (!key->rng) { + /* Lazy init key->rng */ + key->rng = wc_rng_init(); + if (!key->rng) + LOG_WOLF_ERROR_FUNC_NULL(wc_rng_init); + } + return key->rng; +} + + +struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len) +{ + struct crypto_ec_key *ret; + word32 idx = 0; + int err; + + ret = crypto_ec_key_init(); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init); + goto fail; + } + + err = wc_EccPrivateKeyDecode(der, &idx, ret->eckey, (word32) der_len); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_EccPrivateKeyDecode, err); + goto fail; + } + + return ret; +fail: + if (ret) + crypto_ec_key_deinit(ret); + return NULL; +} + + +int crypto_ec_key_group(struct crypto_ec_key *key) +{ + + if (!key || !key->eckey || !key->eckey->dp) { + LOG_INVALID_PARAMETERS(); + return -1; + } + + switch (key->eckey->dp->id) { + case ECC_SECP256R1: + return 19; + case ECC_SECP384R1: + return 20; + case ECC_SECP521R1: + return 21; + case ECC_SECP192R1: + return 25; + case ECC_SECP224R1: + return 26; +#ifdef HAVE_ECC_BRAINPOOL + case ECC_BRAINPOOLP224R1: + return 27; + case ECC_BRAINPOOLP256R1: + return 28; + case ECC_BRAINPOOLP384R1: + return 29; + case ECC_BRAINPOOLP512R1: + return 30; +#endif /* HAVE_ECC_BRAINPOOL */ + } + + LOG_WOLF_ERROR_VA("Unsupported curve (id=%d) in EC key", + key->eckey->dp->id); + return -1; +} + + +static int crypto_ec_key_gen_public_key(struct crypto_ec_key *key) +{ + int err; + +#ifdef WOLFSSL_OLD_FIPS + err = wc_ecc_make_pub(key->eckey, NULL); +#else /* WOLFSSL_OLD_FIPS */ + /* Have wolfSSL generate the public key to make it available for output + */ + if (!crypto_ec_key_init_rng(key)) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng); + return -1; + } + + err = wc_ecc_make_pub_ex(key->eckey, NULL, key->rng); +#endif /* WOLFSSL_OLD_FIPS */ + + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_make_pub_ex, err); + return -1; + } + + return 0; +} + + +struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key) +{ + int der_len; + struct wpabuf *ret = NULL; + int err; + + if (!key || !key->eckey) { + LOG_INVALID_PARAMETERS(); + goto fail; + } + +#ifdef WOLFSSL_OLD_FIPS + if (key->eckey->type == ECC_PRIVATEKEY_ONLY && + crypto_ec_key_gen_public_key(key) != 0) { + LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1); + goto fail; + } +#endif /* WOLFSSL_OLD_FIPS */ + + der_len = err = wc_EccPublicKeyToDer_ex(key->eckey, NULL, 0, 1, 1); + if (err == ECC_PRIVATEONLY_E) { + if (crypto_ec_key_gen_public_key(key) != 0) { + LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1); + goto fail; + } + der_len = err = wc_EccPublicKeyToDer_ex(key->eckey, NULL, 0, 1, + 1); + } + if (err <= 0) { + LOG_WOLF_ERROR_FUNC(wc_EccPublicKeyDerSize, err); + goto fail; + } + + ret = wpabuf_alloc(der_len); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc); + goto fail; + } + + err = wc_EccPublicKeyToDer_ex(key->eckey, wpabuf_mhead(ret), der_len, 1, + 1); + if (err == ECC_PRIVATEONLY_E) { + if (crypto_ec_key_gen_public_key(key) != 0) { + LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1); + goto fail; + } + err = wc_EccPublicKeyToDer_ex(key->eckey, wpabuf_mhead(ret), + der_len, 1, 1); + } + if (err <= 0) { + LOG_WOLF_ERROR_FUNC(wc_EccPublicKeyToDer, err); + goto fail; + } + der_len = err; + wpabuf_put(ret, der_len); + + return ret; + +fail: + wpabuf_free(ret); + return NULL; +} + + +struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len) +{ + word32 idx = 0; + struct crypto_ec_key *ret = NULL; + int err; + + ret = crypto_ec_key_init(); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init); + goto fail; + } + + err = wc_EccPublicKeyDecode(der, &idx, ret->eckey, (word32) der_len); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_EccPublicKeyDecode, err); + goto fail; + } + + return ret; +fail: + crypto_ec_key_deinit(ret); + return NULL; +} + + +struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data, + size_t len) +{ + int der_len; + int err; + word32 w32_der_len; + struct wpabuf *ret = NULL; + + if (!key || !key->eckey || !data || len == 0) { + LOG_INVALID_PARAMETERS(); + goto fail; + } + + if (!crypto_ec_key_init_rng(key)) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng); + goto fail; + } + + der_len = wc_ecc_sig_size(key->eckey); + if (der_len <= 0) { + LOG_WOLF_ERROR_FUNC(wc_ecc_sig_size, der_len); + goto fail; + } + + ret = wpabuf_alloc(der_len); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc); + goto fail; + } + + w32_der_len = (word32) der_len; + err = wc_ecc_sign_hash(data, len, wpabuf_mhead(ret), &w32_der_len, + key->rng, key->eckey); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_ecc_sign_hash, err); + goto fail; + } + wpabuf_put(ret, w32_der_len); + + return ret; +fail: + wpabuf_free(ret); + return NULL; +} + + +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 res = 0; + + if (!key || !key->eckey || !data || len == 0 || !sig || sig_len == 0) { + LOG_INVALID_PARAMETERS(); + return -1; + } + + if (wc_ecc_verify_hash(sig, sig_len, data, len, &res, key->eckey) != 0) + { + LOG_WOLF_ERROR("wc_ecc_verify_hash failed"); + return -1; + } + + if (res != 1) + LOG_WOLF_ERROR("crypto_ec_key_verify_signature failed"); + + return res; +} + #endif /* CONFIG_ECC */ + +#ifdef CONFIG_DPP + +struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key, + bool include_pub) +{ + int len; + int err; + struct wpabuf *ret = NULL; + + if (!key || !key->eckey) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + +#ifdef WOLFSSL_OLD_FIPS + if (key->eckey->type != ECC_PRIVATEKEY && + key->eckey->type != ECC_PRIVATEKEY_ONLY) { + LOG_INVALID_PARAMETERS(); + return NULL; + } +#endif /* WOLFSSL_OLD_FIPS */ + + len = err = wc_EccKeyDerSize(key->eckey, include_pub); + if (err == ECC_PRIVATEONLY_E && include_pub) { + if (crypto_ec_key_gen_public_key(key) != 0) { + LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1); + return NULL; + } + len = err = wc_EccKeyDerSize(key->eckey, include_pub); + } + if (err <= 0) { + /* Exception for BAD_FUNC_ARG because higher levels blindly call + * this function to determine if this is a private key or not. + * BAD_FUNC_ARG most probably means that key->eckey is a public + * key not private. */ + if (err != BAD_FUNC_ARG) + LOG_WOLF_ERROR_FUNC(wc_EccKeyDerSize, err); + return NULL; + } + + ret = wpabuf_alloc(len); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc); + return NULL; + } + + if (include_pub) + err = wc_EccKeyToDer(key->eckey, wpabuf_put(ret, len), len); + else + err = wc_EccPrivateKeyToDer(key->eckey, wpabuf_put(ret, len), + len); + + if (err != len) { + LOG_WOLF_ERROR_VA("%s failed with err: %d", include_pub ? + "wc_EccKeyToDer" : "wc_EccPrivateKeyToDer", + err); + wpabuf_free(ret); + ret = NULL; + } + + return ret; +} + + +struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key, + int prefix) +{ + int err; + word32 len = 0; + struct wpabuf *ret = NULL; + + if (!key || !key->eckey) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + + err = wc_ecc_export_x963(key->eckey, NULL, &len); + if (err != LENGTH_ONLY_E) { + LOG_WOLF_ERROR_FUNC(wc_ecc_export_x963, err); + goto fail; + } + + ret = wpabuf_alloc(len); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc); + goto fail; + } + + err = wc_ecc_export_x963(key->eckey, wpabuf_mhead(ret), &len); + if (err == ECC_PRIVATEONLY_E) { + if (crypto_ec_key_gen_public_key(key) != 0) { + LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1); + goto fail; + } + err = wc_ecc_export_x963(key->eckey, wpabuf_mhead(ret), &len); + } + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_export_x963, err); + goto fail; + } + + if (!prefix) + os_memmove(wpabuf_mhead(ret), wpabuf_mhead_u8(ret) + 1, + (size_t)--len); + wpabuf_put(ret, len); + + return ret; + +fail: + wpabuf_free(ret); + return NULL; +} + + +struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *x, + const u8 *y, size_t len) +{ + struct crypto_ec_key *ret = NULL; + int curve_id = crypto_ec_group_2_id(group); + int err; + + if (!x || !y || len == 0 || curve_id == ECC_CURVE_INVALID || + wc_ecc_get_curve_size_from_id(curve_id) != (int) len) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + + ret = crypto_ec_key_init(); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init); + return NULL; + } + + /* Cast necessary for FIPS API */ + err = wc_ecc_import_unsigned(ret->eckey, (u8 *) x, (u8 *) y, NULL, + curve_id); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_import_unsigned, err); + crypto_ec_key_deinit(ret); + return NULL; + } + + return ret; +} + + +int crypto_ec_key_cmp(struct crypto_ec_key *key1, struct crypto_ec_key *key2) +{ + int ret; + struct wpabuf *key1_buf = crypto_ec_key_get_subject_public_key(key1); + struct wpabuf *key2_buf = crypto_ec_key_get_subject_public_key(key2); + + if ((key1 && !key1_buf) || (key2 && !key2_buf)) { + LOG_WOLF_ERROR("crypto_ec_key_get_subject_public_key failed"); + return -1; + } + + ret = wpabuf_cmp(key1_buf, key2_buf); + if (ret != 0) + ret = -1; /* Default to -1 for different keys */ + + wpabuf_clear_free(key1_buf); + wpabuf_clear_free(key2_buf); + return ret; +} + + +/* wolfSSL doesn't have a pretty print function for keys so just print out the + * PEM of the private key. */ +void crypto_ec_key_debug_print(const struct crypto_ec_key *key, + const char *title) +{ + struct wpabuf * key_buf; + struct wpabuf * out = NULL; + int err; + int pem_len; + + if (!key || !key->eckey) { + LOG_INVALID_PARAMETERS(); + return; + } + + if (key->eckey->type == ECC_PUBLICKEY) + key_buf = crypto_ec_key_get_subject_public_key( + (struct crypto_ec_key *) key); + else + key_buf = crypto_ec_key_get_ecprivate_key( + (struct crypto_ec_key *) key, 1); + + if (!key_buf) { + LOG_WOLF_ERROR_VA("%s has returned NULL", + key->eckey->type == ECC_PUBLICKEY ? + "crypto_ec_key_get_subject_public_key" : + "crypto_ec_key_get_ecprivate_key"); + goto fail; + } + + if (!title) + title = ""; + + err = wc_DerToPem(wpabuf_head(key_buf), wpabuf_len(key_buf), NULL, 0, + ECC_TYPE); + if (err <= 0) { + LOG_WOLF_ERROR_FUNC(wc_DerToPem, err); + goto fail; + } + pem_len = err; + + out = wpabuf_alloc(pem_len + 1); + if (!out) { + LOG_WOLF_ERROR_FUNC_NULL(wc_DerToPem); + goto fail; + } + + err = wc_DerToPem(wpabuf_head(key_buf), wpabuf_len(key_buf), + wpabuf_mhead(out), pem_len, ECC_TYPE); + if (err <= 0) { + LOG_WOLF_ERROR_FUNC(wc_DerToPem, err); + goto fail; + } + + wpabuf_mhead_u8(out)[err] = '\0'; + wpabuf_put(out, err + 1); + wpa_printf(MSG_DEBUG, "%s:\n%s", title, + (const char *) wpabuf_head(out)); + +fail: + wpabuf_clear_free(key_buf); + wpabuf_clear_free(out); +} + + +void crypto_ec_point_debug_print(const struct crypto_ec *e, + const struct crypto_ec_point *p, + const char *title) +{ + u8 x[ECC_MAXSIZE]; + u8 y[ECC_MAXSIZE]; + int coord_size; + int err; + + if (!p || !e) { + LOG_INVALID_PARAMETERS(); + return; + } + + coord_size = e->key->dp->size; + + if (!title) + title = ""; + + err = crypto_ec_point_to_bin((struct crypto_ec *)e, p, x, y); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(crypto_ec_point_to_bin, err); + return; + } + + wpa_hexdump(MSG_DEBUG, title, x, coord_size); + wpa_hexdump(MSG_DEBUG, title, y, coord_size); +} + + +struct crypto_ec_key * crypto_ec_key_gen(int group) +{ + int curve_id = crypto_ec_group_2_id(group); + int err; + struct crypto_ec_key * ret = NULL; + + if (curve_id == ECC_CURVE_INVALID) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + + ret = crypto_ec_key_init(); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init); + return NULL; + } + + if (!crypto_ec_key_init_rng(ret)) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng); + goto fail; + } + + err = wc_ecc_make_key_ex(ret->rng, 0, ret->eckey, curve_id); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_make_key_ex, err); + goto fail; + } + + return ret; +fail: + crypto_ec_key_deinit(ret); + return NULL; +} + + +int crypto_ec_key_verify_signature_r_s(struct crypto_ec_key *key, + const u8 *data, size_t len, + const u8 *r, size_t r_len, + const u8 *s, size_t s_len) +{ + int err; + u8 sig[ECC_MAX_SIG_SIZE]; + word32 sig_len = ECC_MAX_SIG_SIZE; + + if (!key || !key->eckey || !data || !len || !r || !r_len || + !s || !s_len) { + LOG_INVALID_PARAMETERS(); + return -1; + } + + err = wc_ecc_rs_raw_to_sig(r, r_len, s, s_len, sig, &sig_len); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_rs_raw_to_sig, err); + return -1; + } + + return crypto_ec_key_verify_signature(key, data, len, sig, sig_len); +} + + +struct crypto_ec_point * crypto_ec_key_get_public_key(struct crypto_ec_key *key) +{ + ecc_point *point = NULL; + int err; + u8 *der = NULL; + word32 der_len = 0; + + if (!key || !key->eckey || !key->eckey->dp) { + LOG_INVALID_PARAMETERS(); + goto fail; + } + + err = wc_ecc_export_x963(key->eckey, NULL, &der_len); + if (err != LENGTH_ONLY_E) { + LOG_WOLF_ERROR_FUNC(wc_ecc_export_x963, err); + goto fail; + } + + der = os_malloc(der_len); + if (!der) { + LOG_WOLF_ERROR_FUNC_NULL(os_malloc); + goto fail; + } + + err = wc_ecc_export_x963(key->eckey, der, &der_len); + if (err == ECC_PRIVATEONLY_E) { + if (crypto_ec_key_gen_public_key(key) != 0) { + LOG_WOLF_ERROR_FUNC(crypto_ec_key_gen_public_key, -1); + goto fail; + } + err = wc_ecc_export_x963(key->eckey, der, &der_len); + } + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_export_x963, err); + goto fail; + } + + point = wc_ecc_new_point(); + if (!point) { + LOG_WOLF_ERROR_FUNC_NULL(wc_ecc_new_point); + goto fail; + } + + err = wc_ecc_import_point_der(der, der_len, key->eckey->idx, point); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_import_point_der, err); + goto fail; + } + + os_free(der); + return (struct crypto_ec_point *) point; + +fail: + os_free(der); + if (point) + wc_ecc_del_point(point); + return NULL; +} + + +struct crypto_bignum * crypto_ec_key_get_private_key(struct crypto_ec_key *key) +{ + u8 priv[ECC_MAXSIZE]; + word32 priv_len = ECC_MAXSIZE; +#ifdef WOLFSSL_OLD_FIPS + /* Needed to be compliant with the old API */ + u8 qx[ECC_MAXSIZE]; + word32 qx_len = ECC_MAXSIZE; + u8 qy[ECC_MAXSIZE]; + word32 qy_len = ECC_MAXSIZE; +#endif /* WOLFSSL_OLD_FIPS */ + struct crypto_bignum *ret = NULL; + int err; + + if (!key || !key->eckey) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + +#ifndef WOLFSSL_OLD_FIPS + err = wc_ecc_export_private_raw(key->eckey, NULL, NULL, NULL, NULL, + priv, &priv_len); +#else /* WOLFSSL_OLD_FIPS */ + err = wc_ecc_export_private_raw(key->eckey, qx, &qx_len, qy, &qy_len, + priv, &priv_len); +#endif /* WOLFSSL_OLD_FIPS */ + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_export_private_raw, err); + return NULL; + } + + ret = crypto_bignum_init_set(priv, priv_len); + forced_memzero(priv, priv_len); + return ret; +} + + +struct wpabuf * crypto_ec_key_sign_r_s(struct crypto_ec_key *key, + const u8 *data, size_t len) +{ + int err; + u8 success = 0; + mp_int r; + mp_int s; + u8 rs_init = 0; + int sz; + struct wpabuf * ret = NULL; + + if (!key || !key->eckey || !key->eckey->dp || !data || !len) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + + sz = key->eckey->dp->size; + + if (!crypto_ec_key_init_rng(key)) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng); + goto fail; + } + + err = mp_init_multi(&r, &s, NULL, NULL, NULL, NULL); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(mp_init_multi, err); + goto fail; + } + rs_init = 1; + + err = wc_ecc_sign_hash_ex(data, len, key->rng, key->eckey, &r, &s); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_sign_hash_ex, err); + goto fail; + } + + if (mp_unsigned_bin_size(&r) > sz || mp_unsigned_bin_size(&s) > sz) { + LOG_WOLF_ERROR_VA("Unexpected size of r or s (%d %d %d)", sz, + mp_unsigned_bin_size(&r), + mp_unsigned_bin_size(&s)); + goto fail; + } + + ret = wpabuf_alloc(2 * sz); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc); + goto fail; + } + + err = mp_to_unsigned_bin_len(&r, wpabuf_put(ret, sz), sz); + if (err == MP_OKAY) + err = mp_to_unsigned_bin_len(&s, wpabuf_put(ret, sz), sz); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_sign_hash_ex, err); + goto fail; + } + + success = 1; +fail: + if (rs_init) { + mp_free(&r); + mp_free(&s); + } + if (!success) { + wpabuf_free(ret); + ret = NULL; + } + + return ret; +} + + +struct crypto_ec_key * +crypto_ec_key_set_pub_point(struct crypto_ec *e, + const struct crypto_ec_point *pub) +{ + struct crypto_ec_key *ret = NULL; + int err; + byte *buf = NULL; + word32 buf_len = 0; + + if (!e || !pub) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + + /* Export to DER to not mess with wolfSSL internals */ + err = wc_ecc_export_point_der(wc_ecc_get_curve_idx(e->curve_id), + (ecc_point *) pub, NULL, &buf_len); + if (err != LENGTH_ONLY_E || !buf_len) { + LOG_WOLF_ERROR_FUNC(wc_ecc_export_point_der, err); + goto fail; + } + + buf = os_malloc(buf_len); + if (!buf) { + LOG_WOLF_ERROR_FUNC_NULL(os_malloc); + goto fail; + } + + err = wc_ecc_export_point_der(wc_ecc_get_curve_idx(e->curve_id), + (ecc_point *) pub, buf, &buf_len); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_export_point_der, err); + goto fail; + } + + ret = crypto_ec_key_init(); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init); + goto fail; + } + + err = wc_ecc_import_x963_ex(buf, buf_len, ret->eckey, e->curve_id); + if (err != MP_OKAY) { + LOG_WOLF_ERROR_FUNC(wc_ecc_import_x963_ex, err); + goto fail; + } + + os_free(buf); + return ret; + +fail: + os_free(buf); + crypto_ec_key_deinit(ret); + return NULL; +} + + +struct wpabuf * crypto_pkcs7_get_certificates(const struct wpabuf *pkcs7) +{ + PKCS7 *p7 = NULL; + struct wpabuf *ret = NULL; + int err = 0; + int total_sz = 0; + int i; + + if (!pkcs7) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + + p7 = wc_PKCS7_New(NULL, INVALID_DEVID); + if (!p7) { + LOG_WOLF_ERROR_FUNC_NULL(wc_PKCS7_New); + return NULL; + } + + err = wc_PKCS7_VerifySignedData(p7, (byte *) wpabuf_head(pkcs7), + wpabuf_len(pkcs7)); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_PKCS7_VerifySignedData, err); + wc_PKCS7_Free(p7); + goto fail; + } + + /* Need to access p7 members directly */ + for (i = 0; i < MAX_PKCS7_CERTS; i++) { + if (p7->certSz[i] == 0) + continue; + err = wc_DerToPem(p7->cert[i], p7->certSz[i], NULL, 0, + CERT_TYPE); + if (err > 0) { + total_sz += err; + } else { + LOG_WOLF_ERROR_FUNC(wc_DerToPem, err); + goto fail; + } + } + + if (total_sz == 0) { + LOG_WOLF_ERROR("No certificates found in PKCS7 input"); + goto fail; + } + + ret = wpabuf_alloc(total_sz); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc); + goto fail; + } + + /* Need to access p7 members directly */ + for (i = 0; i < MAX_PKCS7_CERTS; i++) { + if (p7->certSz[i] == 0) + continue; + /* Not using wpabuf_put() here so that wpabuf_overflow() isn't + * called in case of a size mismatch. wc_DerToPem() checks if + * the output is large enough internally. */ + err = wc_DerToPem(p7->cert[i], p7->certSz[i], + wpabuf_mhead_u8(ret) + wpabuf_len(ret), + wpabuf_tailroom(ret), + CERT_TYPE); + if (err > 0) { + wpabuf_put(ret, err); + } else { + LOG_WOLF_ERROR_FUNC(wc_DerToPem, err); + wpabuf_free(ret); + ret = NULL; + goto fail; + } + } + +fail: + if (p7) + wc_PKCS7_Free(p7); + return ret; +} + + +/* BEGIN Certificate Signing Request (CSR) APIs */ + +enum cert_type { + cert_type_none = 0, + cert_type_decoded_cert, + cert_type_cert, +}; + +struct crypto_csr { + union { + /* For parsed csr should be read-only for higher levels */ + DecodedCert dc; + Cert c; /* For generating a csr */ + } req; + enum cert_type type; + struct crypto_ec_key *pubkey; +}; + + +/* Helper function to make sure that the correct type is initialized */ +static void crypto_csr_init_type(struct crypto_csr *csr, enum cert_type type, + const byte *source, word32 in_sz) +{ + int err; + + if (csr->type == type) + return; /* Already correct type */ + + switch (csr->type) { + case cert_type_decoded_cert: + wc_FreeDecodedCert(&csr->req.dc); + break; + case cert_type_cert: +#ifdef WOLFSSL_CERT_GEN_CACHE + wc_SetCert_Free(&csr->req.c); +#endif /* WOLFSSL_CERT_GEN_CACHE */ + break; + case cert_type_none: + break; + } + + switch (type) { + case cert_type_decoded_cert: + wc_InitDecodedCert(&csr->req.dc, source, in_sz, NULL); + break; + case cert_type_cert: + err = wc_InitCert(&csr->req.c); + if (err != 0) + LOG_WOLF_ERROR_FUNC(wc_InitCert, err); + break; + case cert_type_none: + break; + } + + csr->type = type; +} + + +struct crypto_csr * crypto_csr_init(void) +{ + struct crypto_csr *ret = os_malloc(sizeof(struct crypto_csr)); + + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(os_malloc); + return NULL; + } + + ret->type = cert_type_none; + crypto_csr_init_type(ret, cert_type_cert, NULL, 0); + ret->pubkey = NULL; + + return ret; +} + + +void crypto_csr_deinit(struct crypto_csr *csr) +{ + if (csr) { + crypto_csr_init_type(csr, cert_type_none, NULL, 0); + crypto_ec_key_deinit(csr->pubkey); + os_free(csr); + } +} + + +int crypto_csr_set_ec_public_key(struct crypto_csr *csr, + struct crypto_ec_key *key) +{ + struct wpabuf *der = NULL; + + if (!csr || !key || !key->eckey) { + LOG_INVALID_PARAMETERS(); + return -1; + } + + if (csr->pubkey) { + crypto_ec_key_deinit(csr->pubkey); + csr->pubkey = NULL; + } + + /* Create copy of key to mitigate use-after-free errors */ + der = crypto_ec_key_get_subject_public_key(key); + if (!der) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_get_subject_public_key); + return -1; + } + + csr->pubkey = crypto_ec_key_parse_pub(wpabuf_head(der), + wpabuf_len(der)); + wpabuf_free(der); + if (!csr->pubkey) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_parse_pub); + return -1; + } + + return 0; +} + + +int crypto_csr_set_name(struct crypto_csr *csr, enum crypto_csr_name type, + const char *name) +{ + int name_len; + char *dest; + + if (!csr || !name) { + LOG_INVALID_PARAMETERS(); + return -1; + } + + if (csr->type != cert_type_cert) { + LOG_WOLF_ERROR_VA("csr is incorrect type (%d)", csr->type); + return -1; + } + + name_len = os_strlen(name); + if (name_len >= CTC_NAME_SIZE) { + LOG_WOLF_ERROR("name input too long"); + return -1; + } + + switch (type) { + case CSR_NAME_CN: + dest = csr->req.c.subject.commonName; + break; + case CSR_NAME_SN: + dest = csr->req.c.subject.sur; + break; + case CSR_NAME_C: + dest = csr->req.c.subject.country; + break; + case CSR_NAME_O: + dest = csr->req.c.subject.org; + break; + case CSR_NAME_OU: + dest = csr->req.c.subject.unit; + break; + default: + LOG_INVALID_PARAMETERS(); + return -1; + } + + os_memcpy(dest, name, name_len); + dest[name_len] = '\0'; + + return 0; +} + + +int crypto_csr_set_attribute(struct crypto_csr *csr, enum crypto_csr_attr attr, + int attr_type, const u8 *value, size_t len) +{ + if (!csr || attr_type != ASN1_TAG_UTF8STRING || !value || + len >= CTC_NAME_SIZE) { + LOG_INVALID_PARAMETERS(); + return -1; + } + + if (csr->type != cert_type_cert) { + LOG_WOLF_ERROR_VA("csr is incorrect type (%d)", csr->type); + return -1; + } + + switch (attr) { + case CSR_ATTR_CHALLENGE_PASSWORD: + os_memcpy(csr->req.c.challengePw, value, len); + csr->req.c.challengePw[len] = '\0'; + break; + default: + return -1; + } + + return 0; +} + + +const u8 * crypto_csr_get_attribute(struct crypto_csr *csr, + enum crypto_csr_attr attr, + size_t *len, int *type) +{ + if (!csr || !len || !type) { + LOG_INVALID_PARAMETERS(); + return NULL;; + } + + switch (attr) { + case CSR_ATTR_CHALLENGE_PASSWORD: + switch (csr->type) { + case cert_type_decoded_cert: + *type = ASN1_TAG_UTF8STRING; + *len = csr->req.dc.cPwdLen; + return (const u8 *) csr->req.dc.cPwd; + case cert_type_cert: + *type = ASN1_TAG_UTF8STRING; + *len = os_strlen(csr->req.c.challengePw); + return (const u8 *) csr->req.c.challengePw; + case cert_type_none: + return NULL; + } + break; + } + return NULL; +} + + +struct wpabuf * crypto_csr_sign(struct crypto_csr *csr, + struct crypto_ec_key *key, + enum crypto_hash_alg algo) +{ + int err; + int len; + u8 *buf = NULL; + int buf_len; + struct wpabuf *ret = NULL; + + if (!csr || !key || !key->eckey) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + + if (csr->type != cert_type_cert) { + LOG_WOLF_ERROR_VA("csr is incorrect type (%d)", csr->type); + return NULL; + } + + if (!crypto_ec_key_init_rng(key)) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_ec_key_init_rng); + return NULL; + } + + switch (algo) { + case CRYPTO_HASH_ALG_SHA256: + csr->req.c.sigType = CTC_SHA256wECDSA; + break; + case CRYPTO_HASH_ALG_SHA384: + csr->req.c.sigType = CTC_SHA384wECDSA; + break; + case CRYPTO_HASH_ALG_SHA512: + csr->req.c.sigType = CTC_SHA512wECDSA; + break; + default: + LOG_INVALID_PARAMETERS(); + return NULL; + } + + /* Pass in large value that is guaranteed to be larger than the + * necessary buffer */ + err = wc_MakeCertReq(&csr->req.c, NULL, 100000, NULL, + csr->pubkey->eckey); + if (err <= 0) { + LOG_WOLF_ERROR_FUNC(wc_MakeCertReq, err); + goto fail; + } + len = err; + + buf_len = len + MAX_SEQ_SZ * 2 + MAX_ENCODED_SIG_SZ; + buf = os_malloc(buf_len); + if (!buf) { + LOG_WOLF_ERROR_FUNC_NULL(os_malloc); + goto fail; + } + + err = wc_MakeCertReq(&csr->req.c, buf, buf_len, NULL, + csr->pubkey->eckey); + if (err <= 0) { + LOG_WOLF_ERROR_FUNC(wc_MakeCertReq, err); + goto fail; + } + len = err; + + err = wc_SignCert(len, csr->req.c.sigType, buf, buf_len, NULL, + key->eckey, key->rng); + if (err <= 0) { + LOG_WOLF_ERROR_FUNC(wc_SignCert, err); + goto fail; + } + len = err; + + ret = wpabuf_alloc_copy(buf, len); + if (!ret) { + LOG_WOLF_ERROR_FUNC_NULL(wpabuf_alloc_copy); + goto fail; + } + +fail: + os_free(buf); + return ret; +} + + +struct crypto_csr * crypto_csr_verify(const struct wpabuf *req) +{ + struct crypto_csr *csr = NULL; + int err; + + if (!req) { + LOG_INVALID_PARAMETERS(); + return NULL; + } + + csr = crypto_csr_init(); + if (!csr) { + LOG_WOLF_ERROR_FUNC_NULL(crypto_csr_init); + goto fail; + } + + crypto_csr_init_type(csr, cert_type_decoded_cert, + wpabuf_head(req), wpabuf_len(req)); + err = wc_ParseCert(&csr->req.dc, CERTREQ_TYPE, VERIFY, NULL); + if (err != 0) { + LOG_WOLF_ERROR_FUNC(wc_ParseCert, err); + goto fail; + } + + return csr; +fail: + crypto_csr_deinit(csr); + return NULL; +} + +/* END Certificate Signing Request (CSR) APIs */ + +#endif /* CONFIG_DPP */ + + +void crypto_unload(void) +{ +} diff --git a/wpa_supplicant-2.9_standard/src/crypto/fips_prf_internal.c b/wpa_supplicant-2.9_standard/src/crypto/fips_prf_internal.c index a4bf50a47f44575854c43b10c73814e2ccbb7782..f9347d0df55e8eba9049f2e60518fe3ce5e67e5e 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/fips_prf_internal.c +++ b/wpa_supplicant-2.9_standard/src/crypto/fips_prf_internal.c @@ -17,10 +17,11 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) { u8 xkey[64]; - u32 t[5], _t[5]; + u32 _t[5]; int i, j, m, k; u8 *xpos = x; u32 carry; + struct SHA1Context ctx; if (seed_len < sizeof(xkey)) os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len); @@ -30,11 +31,7 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) /* FIPS 186-2 + change notice 1 */ os_memcpy(xkey, seed, seed_len); - t[0] = 0x67452301; - t[1] = 0xEFCDAB89; - t[2] = 0x98BADCFE; - t[3] = 0x10325476; - t[4] = 0xC3D2E1F0; + SHA1Init(&ctx); m = xlen / 40; for (j = 0; j < m; j++) { @@ -43,7 +40,7 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) /* XVAL = (XKEY + XSEED_j) mod 2^b */ /* w_i = G(t, XVAL) */ - os_memcpy(_t, t, 20); + os_memcpy(_t, ctx.state, 20); SHA1Transform(_t, xkey); _t[0] = host_to_be32(_t[0]); _t[1] = host_to_be32(_t[1]); diff --git a/wpa_supplicant-2.9_standard/src/crypto/fips_prf_openssl.c b/wpa_supplicant-2.9_standard/src/crypto/fips_prf_openssl.c index 4697e041093a8e94098c5cde7e3a1fb52fdcfc01..484f772094f32c9c3c7f48f7df9e0c5df99d2303 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/fips_prf_openssl.c +++ b/wpa_supplicant-2.9_standard/src/crypto/fips_prf_openssl.c @@ -7,6 +7,19 @@ */ #include "includes.h" +#include + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + +/* OpenSSL 3.0 has deprecated the low-level SHA1 functions and does not + * include an upper layer interface that could be used to use the + * SHA1_Transform() function. Use the internal SHA-1 implementation instead + * as a workaround. */ +#include "sha1-internal.c" +#include "fips_prf_internal.c" + +#else /* OpenSSL version >= 3.0 */ + #include #include "common.h" @@ -97,3 +110,5 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen) return 0; } + +#endif /* OpenSSL version >= 3.0 */ diff --git a/wpa_supplicant-2.9_standard/src/crypto/sha1-pbkdf2.c b/wpa_supplicant-2.9_standard/src/crypto/sha1-pbkdf2.c index b2cad5a8875f5ef7dcc1d0d895b80dda70c8f772..6aab9510d4e18d7e1cd5c15ad08a8603b3339371 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/sha1-pbkdf2.c +++ b/wpa_supplicant-2.9_standard/src/crypto/sha1-pbkdf2.c @@ -50,6 +50,8 @@ static int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid, for (j = 0; j < SHA1_MAC_LEN; j++) digest[j] ^= tmp2[j]; } + forced_memzero(tmp, SHA1_MAC_LEN); + forced_memzero(tmp2, SHA1_MAC_LEN); return 0; } @@ -87,6 +89,7 @@ __attribute__ ((visibility ("default"))) int pbkdf2_sha1(const char *passphrase, pos += plen; left -= plen; } + forced_memzero(digest, SHA1_MAC_LEN); return 0; } diff --git a/wpa_supplicant-2.9_standard/src/crypto/sha256-internal.c b/wpa_supplicant-2.9_standard/src/crypto/sha256-internal.c index ff1e2ba1686d3014b011aaf577af86a8ac473329..81e6e5e9c2f36fea9ff024a30376437781d9873b 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/sha256-internal.c +++ b/wpa_supplicant-2.9_standard/src/crypto/sha256-internal.c @@ -76,9 +76,6 @@ static const unsigned long K[64] = { #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) #define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) -#ifndef MIN -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -#endif /* compress 512-bits */ static int sha256_compress(struct sha256_state *md, unsigned char *buf) diff --git a/wpa_supplicant-2.9_standard/src/crypto/sha256.c b/wpa_supplicant-2.9_standard/src/crypto/sha256.c index 17af964ad049f1efd7a0cac5a877dfa1e766cad7..1e8a122176c8e8a8488f5254871418f3cd1c401c 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/sha256.c +++ b/wpa_supplicant-2.9_standard/src/crypto/sha256.c @@ -28,10 +28,11 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, { unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ unsigned char tk[32]; - const u8 *_addr[11]; - size_t _len[11], i; + const u8 *_addr[HMAC_VECTOR_MAX_ELEM + 1]; + size_t _len[HMAC_VECTOR_MAX_ELEM + 1], i; + int ret; - if (num_elem > 10) { + if (num_elem > HMAC_VECTOR_MAX_ELEM) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). @@ -70,8 +71,9 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, _addr[i + 1] = addr[i]; _len[i + 1] = len[i]; } - if (sha256_vector(1 + num_elem, _addr, _len, mac) < 0) - return -1; + ret = sha256_vector(1 + num_elem, _addr, _len, mac); + if (ret < 0) + goto fail; os_memset(k_pad, 0, sizeof(k_pad)); os_memcpy(k_pad, key, key_len); @@ -84,7 +86,14 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, _len[0] = 64; _addr[1] = mac; _len[1] = SHA256_MAC_LEN; - return sha256_vector(2, _addr, _len, mac); + + ret = sha256_vector(2, _addr, _len, mac); + +fail: + forced_memzero(k_pad, sizeof(k_pad)); + forced_memzero(tk, sizeof(tk)); + + return ret; } diff --git a/wpa_supplicant-2.9_standard/src/crypto/sha384.c b/wpa_supplicant-2.9_standard/src/crypto/sha384.c index fd84b82b1afac5a95d67813d22606f0dd13743f8..be07e9c84c2f5c8734b478c1ac09e174bb6315b6 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/sha384.c +++ b/wpa_supplicant-2.9_standard/src/crypto/sha384.c @@ -28,10 +28,10 @@ int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem, { unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */ unsigned char tk[48]; - const u8 *_addr[11]; - size_t _len[11], i; + const u8 *_addr[HMAC_VECTOR_MAX_ELEM + 1]; + size_t _len[HMAC_VECTOR_MAX_ELEM + 1], i; - if (num_elem > 10) { + if (num_elem > HMAC_VECTOR_MAX_ELEM) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). diff --git a/wpa_supplicant-2.9_standard/src/crypto/sha512-internal.c b/wpa_supplicant-2.9_standard/src/crypto/sha512-internal.c index c0263941c123c3b0358c6c17b693ac59f0fa46e3..8e98a9cf0532f6d99dbc4a181b4f372e83677203 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/sha512-internal.c +++ b/wpa_supplicant-2.9_standard/src/crypto/sha512-internal.c @@ -97,9 +97,6 @@ static const u64 K[80] = { #define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) #define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) #define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) -#ifndef MIN -#define MIN(x, y) (((x) < (y)) ? (x) : (y)) -#endif #define ROR64c(x, y) \ ( ((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) (y) & CONST64(63))) | \ diff --git a/wpa_supplicant-2.9_standard/src/crypto/sha512.c b/wpa_supplicant-2.9_standard/src/crypto/sha512.c index f60a5767234626a4fa61dc24d3e05780a0ffb290..73b54c73b691993cf97cf3d4f575946ca02d3ab5 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/sha512.c +++ b/wpa_supplicant-2.9_standard/src/crypto/sha512.c @@ -28,10 +28,10 @@ int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem, { unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */ unsigned char tk[64]; - const u8 *_addr[11]; - size_t _len[11], i; + const u8 *_addr[HMAC_VECTOR_MAX_ELEM + 1]; + size_t _len[HMAC_VECTOR_MAX_ELEM + 1], i; - if (num_elem > 10) { + if (num_elem > HMAC_VECTOR_MAX_ELEM) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). diff --git a/wpa_supplicant-2.9_standard/src/crypto/tls.h b/wpa_supplicant-2.9_standard/src/crypto/tls.h index a38794db3ea42f101271ea6c4d5977963b8f0479..f839f9dfbef9b7e0af22ee82fcd1cb3a41414fe1 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/tls.h +++ b/wpa_supplicant-2.9_standard/src/crypto/tls.h @@ -22,7 +22,8 @@ enum tls_event { TLS_CERT_CHAIN_SUCCESS, TLS_CERT_CHAIN_FAILURE, TLS_PEER_CERTIFICATE, - TLS_ALERT + TLS_ALERT, + TLS_UNSAFE_RENEGOTIATION_DISABLED, }; /* @@ -118,6 +119,7 @@ struct tls_config { #define TLS_CONN_ENABLE_TLSv1_1 BIT(15) #define TLS_CONN_ENABLE_TLSv1_2 BIT(16) #define TLS_CONN_TEAP_ANON_DH BIT(17) +#define TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION BIT(18) /** * struct tls_connection_params - Parameters for TLS connection @@ -154,8 +156,6 @@ struct tls_config { * @private_key_passwd: Passphrase for decrypted private key, %NULL if no * passphrase is used. * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used - * @dh_blob: dh_file as inlined data or %NULL if not used - * @dh_blob_len: dh_blob length * @engine: 1 = use engine (e.g., a smartcard) for private key operations * (this is OpenSSL specific for now) * @engine_id: engine id string (this is OpenSSL specific for now) @@ -204,8 +204,6 @@ struct tls_connection_params { const char *private_key_passwd; const char *private_key_passwd2; const char *dh_file; - const u8 *dh_blob; - size_t dh_blob_len; /* OpenSSL specific variables */ int engine; @@ -361,7 +359,9 @@ int __must_check tls_global_set_verify(void *tls_ctx, int check_crl, * tls_connection_set_verify - Set certificate verification options * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() - * @verify_peer: 1 = verify peer certificate + * @verify_peer: 0 = do not verify peer certificate, 1 = verify peer + * certificate (require it to be provided), 2 = verify peer certificate if + * provided * @flags: Connection flags (TLS_CONN_*) * @session_ctx: Session caching context or %NULL to use default * @session_ctx_len: Length of @session_ctx in bytes. diff --git a/wpa_supplicant-2.9_standard/src/crypto/tls_gnutls.c b/wpa_supplicant-2.9_standard/src/crypto/tls_gnutls.c index daa01d9ed4f64a900102d36a834e72ff298289e9..e3f5b5a4227c05d8ab9fe0fd0ca02fb38484f6c0 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/tls_gnutls.c +++ b/wpa_supplicant-2.9_standard/src/crypto/tls_gnutls.c @@ -1766,6 +1766,7 @@ int tls_get_library_version(char *buf, size_t buf_len) void tls_connection_set_success_data(struct tls_connection *conn, struct wpabuf *data) { + wpabuf_free(data); } diff --git a/wpa_supplicant-2.9_standard/src/crypto/tls_internal.c b/wpa_supplicant-2.9_standard/src/crypto/tls_internal.c index 8095b43bd21bc70ad2beb463900ee7bafb4c3906..f3e05ce3417ac630e71d2f068b348c252b3b7cfd 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/tls_internal.c +++ b/wpa_supplicant-2.9_standard/src/crypto/tls_internal.c @@ -281,13 +281,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, return -1; } - if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob, - params->dh_blob_len)) { - wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters"); - tlsv1_cred_free(cred); - return -1; - } - if (tlsv1_client_set_cred(conn->client, cred) < 0) { tlsv1_cred_free(cred); return -1; @@ -342,8 +335,7 @@ int tls_global_set_params(void *tls_ctx, return -1; } - if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob, - params->dh_blob_len)) { + if (tlsv1_set_dhparams(cred, params->dh_file, NULL, 0)) { wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters"); return -1; } @@ -791,6 +783,7 @@ int tls_get_library_version(char *buf, size_t buf_len) void tls_connection_set_success_data(struct tls_connection *conn, struct wpabuf *data) { + wpabuf_free(data); } diff --git a/wpa_supplicant-2.9_standard/src/crypto/tls_none.c b/wpa_supplicant-2.9_standard/src/crypto/tls_none.c index 6d6fb0cafd31cd997ea3f261071a62d671b39821..87f45f8868528fa0ba51bd5c0df113ae85b2a6c0 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/tls_none.c +++ b/wpa_supplicant-2.9_standard/src/crypto/tls_none.c @@ -212,6 +212,7 @@ int tls_get_library_version(char *buf, size_t buf_len) void tls_connection_set_success_data(struct tls_connection *conn, struct wpabuf *data) { + wpabuf_free(data); } diff --git a/wpa_supplicant-2.9_standard/src/crypto/tls_openssl.c b/wpa_supplicant-2.9_standard/src/crypto/tls_openssl.c index b9128acd0e111f2100487af372fdde8ec3a95b84..fd5c98ffd7f1fa84c9d8d13e916f18ad943dfab0 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/tls_openssl.c +++ b/wpa_supplicant-2.9_standard/src/crypto/tls_openssl.c @@ -7,6 +7,9 @@ */ #include "includes.h" +#ifdef CONFIG_TESTING_OPTIONS +#include +#endif /* CONFIG_TESTING_OPTIONS */ #ifndef CONFIG_SMARTCARD #ifndef OPENSSL_NO_ENGINE @@ -16,22 +19,31 @@ #endif #endif +#ifndef OPENSSL_NO_ENGINE +/* OpenSSL 3.0 has moved away from the engine API */ +#define OPENSSL_SUPPRESS_DEPRECATED +#include +#endif /* OPENSSL_NO_ENGINE */ #include #include #include #include #include -#ifndef OPENSSL_NO_ENGINE -#include -#endif /* OPENSSL_NO_ENGINE */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#include +#else /* OpenSSL version >= 3.0 */ #ifndef OPENSSL_NO_DSA #include #endif #ifndef OPENSSL_NO_DH #include #endif +#endif /* OpenSSL version >= 3.0 */ #include "common.h" +#include "utils/list.h" #include "crypto.h" #include "sha1.h" #include "sha256.h" @@ -70,9 +82,7 @@ typedef int stack_index_t; #endif /* OPENSSL_NO_TLSEXT */ #endif /* SSL_set_tlsext_status_type */ -#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L)) && \ +#if OPENSSL_VERSION_NUMBER < 0x10100000L && \ !defined(BORINGSSL_API_VERSION) /* * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL @@ -116,17 +126,7 @@ static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, #endif -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) -#ifdef CONFIG_SUITEB -static int RSA_bits(const RSA *r) -{ - return BN_num_bits(r->n); -} -#endif /* CONFIG_SUITEB */ - - +#if OPENSSL_VERSION_NUMBER < 0x10100000L static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x) { return ASN1_STRING_data((ASN1_STRING *) x); @@ -212,12 +212,18 @@ static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx, static int tls_openssl_ref_count = 0; static int tls_ex_idx_session = -1; +struct tls_session_data { + struct dl_list list; + struct wpabuf *buf; +}; + struct tls_context { void (*event_cb)(void *ctx, enum tls_event ev, union tls_event_data *data); void *cb_ctx; int cert_in_cb; char *ocsp_stapling_response; + struct dl_list sessions; /* struct tls_session_data */ }; static struct tls_context *tls_global = NULL; @@ -232,6 +238,7 @@ struct tls_data { unsigned int crl_reload_interval; struct os_reltime crl_last_reload; char *check_cert_subject; + char *openssl_ciphers; }; struct tls_connection { @@ -285,6 +292,7 @@ static struct tls_context * tls_context_new(const struct tls_config *conf) struct tls_context *context = os_zalloc(sizeof(*context)); if (context == NULL) return NULL; + dl_list_init(&context->sessions); if (conf) { context->event_cb = conf->event_cb; context->cb_ctx = conf->cb_ctx; @@ -936,21 +944,53 @@ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path) #endif /* OPENSSL_NO_ENGINE */ +static struct tls_session_data * get_session_data(struct tls_context *context, + const struct wpabuf *buf) +{ + struct tls_session_data *data; + + dl_list_for_each(data, &context->sessions, struct tls_session_data, + list) { + if (data->buf == buf) + return data; + } + + return NULL; +} + + static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess) { struct wpabuf *buf; + struct tls_context *context; + struct tls_session_data *found; + + wpa_printf(MSG_DEBUG, + "OpenSSL: Remove session %p (tls_ex_idx_session=%d)", sess, + tls_ex_idx_session); if (tls_ex_idx_session < 0) return; buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); if (!buf) return; + + context = SSL_CTX_get_app_data(ctx); + SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL); + found = get_session_data(context, buf); + if (!found) { + wpa_printf(MSG_DEBUG, + "OpenSSL: Do not free application session data %p (sess %p)", + buf, sess); + return; + } + + dl_list_del(&found->list); + os_free(found); wpa_printf(MSG_DEBUG, "OpenSSL: Free application session data %p (sess %p)", buf, sess); wpabuf_free(buf); - - SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL); } @@ -1017,9 +1057,7 @@ void * tls_init(const struct tls_config *conf) } #endif /* OPENSSL_FIPS */ #endif /* CONFIG_FIPS */ -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_load_error_strings(); SSL_library_init(); #ifndef OPENSSL_NO_SHA256 @@ -1096,8 +1134,19 @@ void * tls_init(const struct tls_config *conf) SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER); SSL_CTX_set_timeout(ssl, data->tls_session_lifetime); SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb); +#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \ + !defined(LIBRESSL_VERSION_NUMBER) && \ + !defined(OPENSSL_IS_BORINGSSL) + /* One session ticket is sufficient for EAP-TLS */ + SSL_CTX_set_num_tickets(ssl, 1); +#endif } else { SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF); +#if OPENSSL_VERSION_NUMBER >= 0x10101000L && \ + !defined(LIBRESSL_VERSION_NUMBER) && \ + !defined(OPENSSL_IS_BORINGSSL) + SSL_CTX_set_num_tickets(ssl, 0); +#endif } if (tls_ex_idx_session < 0) { @@ -1145,12 +1194,26 @@ void tls_deinit(void *ssl_ctx) struct tls_data *data = ssl_ctx; SSL_CTX *ssl = data->ssl; struct tls_context *context = SSL_CTX_get_app_data(ssl); + struct tls_session_data *sess_data; + + if (data->tls_session_lifetime > 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions"); + SSL_CTX_flush_sessions(ssl, 0); + wpa_printf(MSG_DEBUG, "OpenSSL: Flush sessions - done"); + } + while ((sess_data = dl_list_first(&context->sessions, + struct tls_session_data, list))) { + wpa_printf(MSG_DEBUG, + "OpenSSL: Freeing not-flushed session data %p", + sess_data->buf); + wpabuf_free(sess_data->buf); + dl_list_del(&sess_data->list); + os_free(sess_data); + } if (context != tls_global && context != NULL) { os_free(context); context = NULL; } - if (data->tls_session_lifetime > 0) - SSL_CTX_flush_sessions(ssl, 0); os_free(data->ca_cert); if (ssl) { SSL_CTX_free(ssl); @@ -1159,9 +1222,7 @@ void tls_deinit(void *ssl_ctx) tls_openssl_ref_count--; if (tls_openssl_ref_count == 0) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L #ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); #endif /* OPENSSL_NO_ENGINE */ @@ -1178,6 +1239,7 @@ void tls_deinit(void *ssl_ctx) os_free(data->check_cert_subject); data->check_cert_subject = NULL; + os_free(data->openssl_ciphers); os_free(data); data = NULL; wpa_printf(MSG_INFO, "Leave tls_deinit"); @@ -1531,6 +1593,15 @@ static void tls_msg_cb(int write_p, int version, int content_type, struct tls_connection *conn = arg; const u8 *pos = buf; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if ((SSL_version(ssl) == TLS1_VERSION || + SSL_version(ssl) == TLS1_1_VERSION) && + SSL_get_security_level(ssl) > 0) { + wpa_printf(MSG_DEBUG, + "OpenSSL: Drop security level to 0 to allow TLS 1.0/1.1 use of MD5-SHA1 signature algorithm"); + SSL_set_security_level(ssl, 0); + } +#endif /* OpenSSL version >= 3.0 */ if (write_p == 2) { wpa_printf(MSG_DEBUG, "OpenSSL: session ver=0x%x content_type=%d", @@ -1566,6 +1637,63 @@ static void tls_msg_cb(int write_p, int version, int content_type, } +#ifdef CONFIG_TESTING_OPTIONS +#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) +/* + * By setting the environment variable SSLKEYLOGFILE to a filename keying + * material will be exported that you may use with Wireshark to decode any + * TLS flows. Please see the following for more details: + * + * https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption + * + * Example logging sessions are (you should delete the file on each run): + * + * rm -f /tmp/sslkey.log + * env SSLKEYLOGFILE=/tmp/sslkey.log hostapd ... + * + * rm -f /tmp/sslkey.log + * env SSLKEYLOGFILE=/tmp/sslkey.log wpa_supplicant ... + * + * rm -f /tmp/sslkey.log + * env SSLKEYLOGFILE=/tmp/sslkey.log eapol_test ... + */ +static void tls_keylog_cb(const SSL *ssl, const char *line) +{ + int fd; + const char *filename; + struct iovec iov[2]; + + filename = getenv("SSLKEYLOGFILE"); + if (!filename) + return; + + fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); + if (fd < 0) { + wpa_printf(MSG_ERROR, + "OpenSSL: Failed to open keylog file %s: %s", + filename, strerror(errno)); + return; + } + + /* Assume less than _POSIX_PIPE_BUF (512) where writes are guaranteed + * to be atomic for O_APPEND. */ + iov[0].iov_base = (void *) line; + iov[0].iov_len = os_strlen(line); + iov[1].iov_base = "\n"; + iov[1].iov_len = 1; + + if (writev(fd, iov, ARRAY_SIZE(iov)) < 01) { + wpa_printf(MSG_DEBUG, + "OpenSSL: Failed to write to keylog file %s: %s", + filename, strerror(errno)); + } + + close(fd); +} +#endif +#endif /* CONFIG_TESTING_OPTIONS */ + + struct tls_connection * tls_connection_init(void *ssl_ctx) { struct tls_data *data = ssl_ctx; @@ -1623,6 +1751,14 @@ struct tls_connection * tls_connection_init(void *ssl_ctx) SSL_clear_options(conn->ssl, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); #endif +#ifdef CONFIG_TESTING_OPTIONS +#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) + /* Set the keylog file if the admin requested it. */ + if (getenv("SSLKEYLOGFILE")) + SSL_CTX_set_keylog_callback(conn->ssl_ctx, tls_keylog_cb); +#endif +#endif /* CONFIG_TESTING_OPTIONS */ + conn->ssl_in = BIO_new(BIO_s_mem()); if (!conn->ssl_in) { tls_show_errors(MSG_INFO, __func__, @@ -2561,16 +2697,11 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) #ifdef CONFIG_SUITEB if (conn->flags & TLS_CONN_SUITEB) { EVP_PKEY *pk; - RSA *rsa; int len = -1; pk = X509_get_pubkey(err_cert); if (pk) { - rsa = EVP_PKEY_get1_RSA(pk); - if (rsa) { - len = RSA_bits(rsa); - RSA_free(rsa); - } + len = EVP_PKEY_bits(pk); EVP_PKEY_free(pk); } @@ -2958,7 +3089,6 @@ static int tls_connection_set_subject_match(struct tls_connection *conn, #ifdef CONFIG_SUITEB -#if OPENSSL_VERSION_NUMBER >= 0x10002000L static int suiteb_cert_cb(SSL *ssl, void *arg) { struct tls_connection *conn = arg; @@ -2985,7 +3115,6 @@ static int suiteb_cert_cb(SSL *ssl, void *arg) conn->server_dh_prime_len); return 0; } -#endif /* OPENSSL_VERSION_NUMBER */ #endif /* CONFIG_SUITEB */ @@ -3001,6 +3130,11 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, SSL_clear_options(ssl, SSL_OP_NO_TICKET); #endif /* SSL_OP_NO_TICKET */ +#ifdef SSL_OP_LEGACY_SERVER_CONNECT + if (flags & TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION) + SSL_set_options(ssl, SSL_OP_LEGACY_SERVER_CONNECT); +#endif /* SSL_OP_LEGACY_SERVER_CONNECT */ + #ifdef SSL_OP_NO_TLSv1 if (flags & TLS_CONN_DISABLE_TLSv1_0) SSL_set_options(ssl, SSL_OP_NO_TLSv1); @@ -3075,12 +3209,14 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, } #endif + if (!openssl_ciphers) + openssl_ciphers = conn->data->openssl_ciphers; + #ifdef CONFIG_SUITEB #ifdef OPENSSL_IS_BORINGSSL /* Start with defaults from BoringSSL */ SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, NULL, 0); #endif /* OPENSSL_IS_BORINGSSL */ -#if OPENSSL_VERSION_NUMBER >= 0x10002000L if (flags & TLS_CONN_SUITEB_NO_ECDH) { const char *ciphers = "DHE-RSA-AES256-GCM-SHA384"; @@ -3096,7 +3232,9 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, return -1; } } else if (flags & TLS_CONN_SUITEB) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L EC_KEY *ecdh; +#endif const char *ciphers = "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384"; int nid[1] = { NID_secp384r1 }; @@ -3113,6 +3251,14 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, return -1; } +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (SSL_set1_groups(ssl, nid, 1) != 1) { + wpa_printf(MSG_INFO, + "OpenSSL: Failed to set Suite B groups"); + return -1; + } + +#else if (SSL_set1_curves(ssl, nid, 1) != 1) { wpa_printf(MSG_INFO, "OpenSSL: Failed to set Suite B curves"); @@ -3127,20 +3273,35 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, return -1; } EC_KEY_free(ecdh); +#endif } if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) { #ifdef OPENSSL_IS_BORINGSSL - uint16_t sigalgs[1] = { SSL_SIGN_RSA_PKCS1_SHA384 }; + uint16_t sigalgs[3] = { SSL_SIGN_RSA_PKCS1_SHA384 }; + int num = 1; + + if (!(flags & TLS_CONN_DISABLE_TLSv1_3)) { +#ifdef SSL_SIGN_ECDSA_SECP384R1_SHA384 + sigalgs[num++] = SSL_SIGN_ECDSA_SECP384R1_SHA384; +#endif +#ifdef SSL_SIGN_RSA_PSS_RSAE_SHA384 + sigalgs[num++] = SSL_SIGN_RSA_PSS_RSAE_SHA384; +#endif + } if (SSL_CTX_set_verify_algorithm_prefs(conn->ssl_ctx, sigalgs, - 1) != 1) { + num) != 1) { wpa_printf(MSG_INFO, "OpenSSL: Failed to set Suite B sigalgs"); return -1; } #else /* OPENSSL_IS_BORINGSSL */ /* ECDSA+SHA384 if need to add EC support here */ - if (SSL_set1_sigalgs_list(ssl, "RSA+SHA384") != 1) { + const char *algs = "RSA+SHA384"; + + if (!(flags & TLS_CONN_DISABLE_TLSv1_3)) + algs = "RSA+SHA384:ecdsa_secp384r1_sha384:rsa_pss_rsae_sha384"; + if (SSL_set1_sigalgs_list(ssl, algs) != 1) { wpa_printf(MSG_INFO, "OpenSSL: Failed to set Suite B sigalgs"); return -1; @@ -3151,13 +3312,6 @@ static int tls_set_conn_flags(struct tls_connection *conn, unsigned int flags, SSL_set_options(ssl, SSL_OP_NO_TLSv1_1); SSL_set_cert_cb(ssl, suiteb_cert_cb, conn); } -#else /* OPENSSL_VERSION_NUMBER < 0x10002000L */ - if (flags & (TLS_CONN_SUITEB | TLS_CONN_SUITEB_NO_ECDH)) { - wpa_printf(MSG_ERROR, - "OpenSSL: Suite B RSA case not supported with this OpenSSL version"); - return -1; - } -#endif /* OPENSSL_VERSION_NUMBER */ #ifdef OPENSSL_IS_BORINGSSL if (openssl_ciphers && os_strcmp(openssl_ciphers, "SUITEB192") == 0) { @@ -3291,14 +3445,14 @@ static int tls_connection_client_cert(struct tls_connection *conn, return 0; #ifdef PKCS12_FUNCS -#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER) +#ifdef LIBRESSL_VERSION_NUMBER /* * Clear previously set extra chain certificates, if any, from PKCS#12 - * processing in tls_parse_pkcs12() to allow OpenSSL to build a new + * processing in tls_parse_pkcs12() to allow LibreSSL to build a new * chain properly. */ SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx); -#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */ +#endif /* LIBRESSL_VERSION_NUMBER */ #endif /* PKCS12_FUNCS */ if (client_cert_blob && @@ -3537,7 +3691,7 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12, } if (certs) { -#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) +#ifndef LIBRESSL_VERSION_NUMBER if (ssl) SSL_clear_chain_certs(ssl); else @@ -3586,7 +3740,7 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12, * the extra certificates not to be required. */ res = 0; -#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ +#else /* LIBRESSL_VERSION_NUMBER */ SSL_CTX_clear_extra_chain_certs(data->ssl); while ((cert = sk_X509_pop(certs)) != NULL) { X509_NAME_oneline(X509_get_subject_name(cert), buf, @@ -3605,7 +3759,7 @@ static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12, } } sk_X509_pop_free(certs, X509_free); -#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ +#endif /* LIBRSESSL_VERSION_NUMBER */ } PKCS12_free(p12); @@ -3924,6 +4078,7 @@ static int tls_connection_private_key(struct tls_data *data, } #endif /* OPENSSL_NO_EC */ +#if OPENSSL_VERSION_NUMBER < 0x30000000L if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, (u8 *) private_key_blob, private_key_blob_len) == 1) { @@ -3932,6 +4087,7 @@ static int tls_connection_private_key(struct tls_data *data, ok = 1; break; } +#endif bio = BIO_new_mem_buf((u8 *) private_key_blob, private_key_blob_len); @@ -3974,7 +4130,6 @@ static int tls_connection_private_key(struct tls_data *data, break; } #endif - if (tls_use_private_key_file(data, conn->ssl, private_key, private_key_passwd) == 0) { ok = 1; @@ -4046,7 +4201,46 @@ static int tls_global_private_key(struct tls_data *data, } -static int tls_connection_dh(struct tls_connection *conn, const char *dh_file) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#ifndef OPENSSL_NO_DH +#ifndef OPENSSL_NO_DSA +/* This is needed to replace the deprecated DSA_dup_DH() function */ +static EVP_PKEY * openssl_dsa_to_dh(EVP_PKEY *dsa) +{ + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *params = NULL; + BIGNUM *p = NULL, *q = NULL, *g = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; + + if (!EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_P, &p) || + !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_Q, &q) || + !EVP_PKEY_get_bn_param(dsa, OSSL_PKEY_PARAM_FFC_G, &g) || + !(bld = OSSL_PARAM_BLD_new()) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q) || + !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) || + !(params = OSSL_PARAM_BLD_to_param(bld)) || + !(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DHX", NULL)) || + EVP_PKEY_fromdata_init(ctx) != 1 || + EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEY_PARAMETERS, + params) != 1) + wpa_printf(MSG_INFO, + "TLS: Failed to convert DSA parameters to DH parameters"); + + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(bld); + BN_free(p); + BN_free(q); + BN_free(g); + return pkey; +} +#endif /* !OPENSSL_NO_DSA */ +#endif /* OPENSSL_NO_DH */ +#endif /* OpenSSL version >= 3.0 */ + +static int tls_global_dh(struct tls_data *data, const char *dh_file) { #ifdef OPENSSL_NO_DH if (dh_file == NULL) @@ -4055,89 +4249,90 @@ static int tls_connection_dh(struct tls_connection *conn, const char *dh_file) "dh_file specified"); return -1; #else /* OPENSSL_NO_DH */ - DH *dh; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + SSL_CTX *ssl_ctx = data->ssl; BIO *bio; + OSSL_DECODER_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL, *tmpkey = NULL; + bool dsa = false; - /* TODO: add support for dh_blob */ - if (dh_file == NULL) - return 0; - if (conn == NULL) + if (!ssl_ctx) return -1; + if (!dh_file) { + SSL_CTX_set_dh_auto(ssl_ctx, 1); + return 0; + } bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) { + if (!bio) { wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s", dh_file, ERR_error_string(ERR_get_error(), NULL)); return -1; } - dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); - BIO_free(bio); -#ifndef OPENSSL_NO_DSA - while (dh == NULL) { - DSA *dsa; - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -" - " trying to parse as DSA params", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - bio = BIO_new_file(dh_file, "r"); - if (bio == NULL) - break; - dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL); + ctx = OSSL_DECODER_CTX_new_for_pkey( + &tmpkey, "PEM", NULL, NULL, + OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, NULL, NULL); + if (!ctx || + OSSL_DECODER_from_bio(ctx, bio) != 1) { + wpa_printf(MSG_INFO, + "TLS: Failed to decode domain parameters from '%s': %s", + dh_file, ERR_error_string(ERR_get_error(), NULL)); BIO_free(bio); - if (!dsa) { - wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file " - "'%s': %s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - break; - } + OSSL_DECODER_CTX_free(ctx); + return -1; + } + OSSL_DECODER_CTX_free(ctx); + BIO_free(bio); - wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format"); - dh = DSA_dup_DH(dsa); - DSA_free(dsa); - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to convert DSA " - "params into DH params"); - break; - } - break; + if (!tmpkey) { + wpa_printf(MSG_INFO, "TLS: Failed to load domain parameters"); + return -1; + } + +#ifndef OPENSSL_NO_DSA + if (EVP_PKEY_is_a(tmpkey, "DSA")) { + pkey = openssl_dsa_to_dh(tmpkey); + EVP_PKEY_free(tmpkey); + if (!pkey) + return -1; + dsa = true; } #endif /* !OPENSSL_NO_DSA */ - if (dh == NULL) { - wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file " - "'%s'", dh_file); - return -1; + if (!dsa) { + if (EVP_PKEY_is_a(tmpkey, "DH") || + EVP_PKEY_is_a(tmpkey, "DHX")) { + } else { + wpa_printf(MSG_INFO, + "TLS: No DH parameters found in %s", + dh_file); + EVP_PKEY_free(tmpkey); + return -1; + } + pkey = tmpkey; + tmpkey = NULL; } - if (SSL_set_tmp_dh(conn->ssl, dh) != 1) { - wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': " - "%s", dh_file, - ERR_error_string(ERR_get_error(), NULL)); - DH_free(dh); + if (SSL_CTX_set0_tmp_dh_pkey(ssl_ctx, pkey) != 1) { + wpa_printf(MSG_INFO, + "TLS: Failed to set DH params from '%s': %s", + dh_file, ERR_error_string(ERR_get_error(), NULL)); + EVP_PKEY_free(pkey); return -1; } - DH_free(dh); return 0; -#endif /* OPENSSL_NO_DH */ -} - - -static int tls_global_dh(struct tls_data *data, const char *dh_file) -{ -#ifdef OPENSSL_NO_DH - if (dh_file == NULL) - return 0; - wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but " - "dh_file specified"); - return -1; -#else /* OPENSSL_NO_DH */ +#else /* OpenSSL version >= 3.0 */ SSL_CTX *ssl_ctx = data->ssl; DH *dh; BIO *bio; - /* TODO: add support for dh_blob */ - if (dh_file == NULL) - return 0; - if (ssl_ctx == NULL) + if (!ssl_ctx) return -1; + if (!dh_file) { +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) + SSL_CTX_set_dh_auto(ssl_ctx, 1); +#endif + return 0; + } bio = BIO_new_file(dh_file, "r"); if (bio == NULL) { @@ -4191,6 +4386,7 @@ static int tls_global_dh(struct tls_data *data, const char *dh_file) } DH_free(dh); return 0; +#endif /* OpenSSL version >= 3.0 */ #endif /* OPENSSL_NO_DH */ } @@ -4221,9 +4417,7 @@ int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn, #ifdef OPENSSL_NEED_EAP_FAST_PRF static int openssl_get_keyblock_size(SSL *ssl) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L const EVP_CIPHER *c; const EVP_MD *h; int md_size; @@ -4391,6 +4585,7 @@ int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn, static struct wpabuf * openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data) { + struct tls_context *context = conn->context; int res; struct wpabuf *out_data; @@ -4420,7 +4615,19 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data) wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " "write"); else { + unsigned long error = ERR_peek_last_error(); + tls_show_errors(MSG_INFO, __func__, "SSL_connect"); + + if (context->event_cb && + ERR_GET_LIB(error) == ERR_LIB_SSL && + ERR_GET_REASON(error) == + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED) { + context->event_cb( + context->cb_ctx, + TLS_UNSAFE_RENEGOTIATION_DISABLED, + NULL); + } conn->failed++; if (!conn->server && !conn->client_hello_generated) { /* The server would not understand TLS Alert @@ -4443,8 +4650,6 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data) if ((conn->flags & TLS_CONN_SUITEB) && !conn->server && os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 && conn->server_dh_prime_len < 3072) { - struct tls_context *context = conn->context; - /* * This should not be reached since earlier cert_cb should have * terminated the handshake. Keep this check here for extra @@ -4936,6 +5141,21 @@ static int ocsp_resp_cb(SSL *s, void *arg) len = SSL_get_tlsext_status_ocsp_resp(s, &p); if (!p) { +#if OPENSSL_VERSION_NUMBER >= 0x10101000L +#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x30400000L + if (SSL_version(s) == TLS1_3_VERSION && SSL_session_reused(s)) { + /* TLS 1.3 sends the OCSP response with the server + * Certificate message. Since that Certificate message + * is not sent when resuming a session, there can be no + * new OCSP response. Allow this since the OCSP response + * was validated when checking the initial certificate + * exchange. */ + wpa_printf(MSG_DEBUG, + "OpenSSL: Allow no OCSP response when using TLS 1.3 and a resumed session"); + return 1; + } +#endif +#endif wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received"); return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1; } @@ -5284,6 +5504,10 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, __func__, ERR_error_string(err, NULL)); } + if (tls_set_conn_flags(conn, params->flags, + params->openssl_ciphers) < 0) + return -1; + if (engine_id) { wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s", engine_id); @@ -5331,12 +5555,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, return -1; } - if (tls_connection_dh(conn, params->dh_file)) { - wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", - params->dh_file); - return -1; - } - ciphers = params->openssl_ciphers; #ifdef CONFIG_SUITEB #ifdef OPENSSL_IS_BORINGSSL @@ -5358,22 +5576,21 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, if (!params->openssl_ecdh_curves) { #ifndef OPENSSL_IS_BORINGSSL #ifndef OPENSSL_NO_EC -#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \ - (OPENSSL_VERSION_NUMBER < 0x10100000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L if (SSL_set_ecdh_auto(conn->ssl, 1) != 1) { wpa_printf(MSG_INFO, "OpenSSL: Failed to set ECDH curves to auto"); return -1; } -#endif /* >= 1.0.2 && < 1.1.0 */ +#endif /* < 1.1.0 */ #endif /* OPENSSL_NO_EC */ #endif /* OPENSSL_IS_BORINGSSL */ } else if (params->openssl_ecdh_curves[0]) { -#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L) +#ifdef OPENSSL_IS_BORINGSSL wpa_printf(MSG_INFO, - "OpenSSL: ECDH configuration nnot supported"); + "OpenSSL: ECDH configuration not supported"); return -1; -#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */ +#else /* !OPENSSL_IS_BORINGSSL */ #ifndef OPENSSL_NO_EC if (SSL_set1_curves_list(conn->ssl, params->openssl_ecdh_curves) != 1) { @@ -5389,10 +5606,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, #endif /* OPENSSL_IS_BORINGSSL */ } - if (tls_set_conn_flags(conn, params->flags, - params->openssl_ciphers) < 0) - return -1; - #ifdef OPENSSL_IS_BORINGSSL if (params->flags & TLS_CONN_REQUEST_OCSP) { SSL_enable_ocsp_stapling(conn->ssl); @@ -5465,8 +5678,9 @@ static const char * openssl_pkey_type_str(const EVP_PKEY *pkey) return "DH"; case EVP_PKEY_EC: return "EC"; + default: + return "?"; } - return "?"; } @@ -5570,6 +5784,14 @@ int tls_global_set_params(void *tls_ctx, return -1; } + os_free(data->openssl_ciphers); + if (params->openssl_ciphers) { + data->openssl_ciphers = os_strdup(params->openssl_ciphers); + if (!data->openssl_ciphers) + return -1; + } else { + data->openssl_ciphers = NULL; + } if (params->openssl_ciphers && SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) { wpa_printf(MSG_INFO, @@ -5581,22 +5803,21 @@ int tls_global_set_params(void *tls_ctx, if (!params->openssl_ecdh_curves) { #ifndef OPENSSL_IS_BORINGSSL #ifndef OPENSSL_NO_EC -#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) && \ - (OPENSSL_VERSION_NUMBER < 0x10100000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L if (SSL_CTX_set_ecdh_auto(ssl_ctx, 1) != 1) { wpa_printf(MSG_INFO, "OpenSSL: Failed to set ECDH curves to auto"); return -1; } -#endif /* >= 1.0.2 && < 1.1.0 */ +#endif /* < 1.1.0 */ #endif /* OPENSSL_NO_EC */ #endif /* OPENSSL_IS_BORINGSSL */ } else if (params->openssl_ecdh_curves[0]) { -#if defined(OPENSSL_IS_BORINGSSL) || (OPENSSL_VERSION_NUMBER < 0x10002000L) +#ifdef OPENSSL_IS_BORINGSSL wpa_printf(MSG_INFO, - "OpenSSL: ECDH configuration nnot supported"); + "OpenSSL: ECDH configuration not supported"); return -1; -#else /* OPENSSL_IS_BORINGSSL || < 1.0.2 */ +#else /* !OPENSSL_IS_BORINGSSL */ #ifndef OPENSSL_NO_EC #if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_CTX_set_ecdh_auto(ssl_ctx, 1); @@ -5658,9 +5879,7 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, struct tls_connection *conn = arg; int ret; -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && \ - LIBRESSL_VERSION_NUMBER < 0x20700000L) +#if OPENSSL_VERSION_NUMBER < 0x10100000L if (conn == NULL || conn->session_ticket_cb == NULL) return 0; @@ -5771,6 +5990,7 @@ void tls_connection_set_success_data(struct tls_connection *conn, { SSL_SESSION *sess; struct wpabuf *old; + struct tls_session_data *sess_data = NULL; if (tls_ex_idx_session < 0) goto fail; @@ -5779,20 +5999,35 @@ void tls_connection_set_success_data(struct tls_connection *conn, goto fail; old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); if (old) { - wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p", - old); - wpabuf_free(old); + struct tls_session_data *found; + + found = get_session_data(conn->context, old); + wpa_printf(MSG_DEBUG, + "OpenSSL: Replacing old success data %p (sess %p)%s", + old, sess, found ? "" : " (not freeing)"); + if (found) { + dl_list_del(&found->list); + os_free(found); + wpabuf_free(old); + } } - if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1) + + sess_data = os_zalloc(sizeof(*sess_data)); + if (!sess_data || + SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1) goto fail; - wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data); + sess_data->buf = data; + dl_list_add(&conn->context->sessions, &sess_data->list); + wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p (sess %p)", + data, sess); conn->success_data = 1; return; fail: wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data"); wpabuf_free(data); + os_free(sess_data); } diff --git a/wpa_supplicant-2.9_standard/src/crypto/tls_openssl_ocsp.c b/wpa_supplicant-2.9_standard/src/crypto/tls_openssl_ocsp.c index 8b37b34e7890123f9a8d49dec3ecfec0b70dc32a..4e4c2ac8e15ef6e1e856f32a32c77d40b33774c6 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/tls_openssl_ocsp.c +++ b/wpa_supplicant-2.9_standard/src/crypto/tls_openssl_ocsp.c @@ -216,13 +216,7 @@ ASN1_SEQUENCE(BasicOCSPResponse) = { IMPLEMENT_ASN1_FUNCTIONS(BasicOCSPResponse); -#define sk_SingleResponse_num(sk) \ -sk_num(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk)) - -#define sk_SingleResponse_value(sk, i) \ - ((SingleResponse *) \ - sk_value(CHECKED_CAST(_STACK *, STACK_OF(SingleResponse) *, sk), (i))) - +DEFINE_STACK_OF(SingleResponse) static char * mem_bio_to_str(BIO *out) { @@ -502,7 +496,7 @@ enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert, enum ocsp_result result = OCSP_INVALID; X509_STORE *store; STACK_OF(X509) *untrusted = NULL, *certs = NULL, *chain = NULL; - X509_STORE_CTX ctx; + X509_STORE_CTX *ctx = NULL; X509 *signer, *tmp_cert; int signer_trusted = 0; EVP_PKEY *skey; @@ -643,12 +637,13 @@ enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert, "OpenSSL: Found OCSP signer certificate %s and verified BasicOCSPResponse signature", buf); - if (!X509_STORE_CTX_init(&ctx, store, signer, untrusted)) + ctx = X509_STORE_CTX_new(); + if (!ctx || !X509_STORE_CTX_init(ctx, store, signer, untrusted)) goto fail; - X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER); - ret = X509_verify_cert(&ctx); - chain = X509_STORE_CTX_get1_chain(&ctx); - X509_STORE_CTX_cleanup(&ctx); + X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_OCSP_HELPER); + ret = X509_verify_cert(ctx); + chain = X509_STORE_CTX_get1_chain(ctx); + X509_STORE_CTX_cleanup(ctx); if (ret <= 0) { wpa_printf(MSG_DEBUG, "OpenSSL: Could not validate OCSP signer certificate"); @@ -662,8 +657,8 @@ enum ocsp_result check_ocsp_resp(SSL_CTX *ssl_ctx, SSL *ssl, X509 *cert, if (!signer_trusted) { X509_check_purpose(signer, -1, 0); - if ((signer->ex_flags & EXFLAG_XKUSAGE) && - (signer->ex_xkusage & XKU_OCSP_SIGN)) { + if ((X509_get_extension_flags(signer) & EXFLAG_XKUSAGE) && + (X509_get_extended_key_usage(signer) & XKU_OCSP_SIGN)) { wpa_printf(MSG_DEBUG, "OpenSSL: OCSP signer certificate delegation OK"); } else { @@ -839,6 +834,7 @@ fail: sk_X509_pop_free(certs, X509_free); BasicOCSPResponse_free(basic); OCSPResponse_free(resp); + X509_STORE_CTX_free(ctx); return result; } diff --git a/wpa_supplicant-2.9_standard/src/crypto/tls_wolfssl.c b/wpa_supplicant-2.9_standard/src/crypto/tls_wolfssl.c index cf482bfc3a16aef27882c58e33813ae470268f01..0b2947daf9b7ec150b1b54a3d5875eb9adbe739e 100644 --- a/wpa_supplicant-2.9_standard/src/crypto/tls_wolfssl.c +++ b/wpa_supplicant-2.9_standard/src/crypto/tls_wolfssl.c @@ -26,6 +26,10 @@ #include #endif +#ifdef CONFIG_FIPS +#include +#endif /* CONFIG_FIPS */ + #if !defined(CONFIG_FIPS) && \ (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || \ defined(EAP_SERVER_FAST)) @@ -58,6 +62,7 @@ struct tls_context { void *cb_ctx; int cert_in_cb; char *ocsp_stapling_response; + unsigned int tls_session_lifetime; }; static struct tls_context *tls_global = NULL; @@ -94,6 +99,7 @@ struct tls_connection { WOLFSSL_X509 *peer_cert; WOLFSSL_X509 *peer_issuer; WOLFSSL_X509 *peer_issuer_issuer; + char *peer_subject; /* peer subject info for authenticated peer */ }; @@ -190,6 +196,33 @@ static void remove_session_cb(WOLFSSL_CTX *ctx, WOLFSSL_SESSION *sess) } +#if defined(CONFIG_FIPS) && defined(HAVE_FIPS) +static void wcFipsCb(int ok, int err, const char *hash) +{ + wpa_printf(MSG_INFO, + "wolfFIPS: wolfCrypt Fips error callback, ok = %d, err = %d", + ok, err); + wpa_printf(MSG_INFO, "wolfFIPS: message = %s", wc_GetErrorString(err)); + wpa_printf(MSG_INFO, "wolfFIPS: hash = %s", hash); + if (err == IN_CORE_FIPS_E) { + wpa_printf(MSG_ERROR, + "wolfFIPS: In core integrity hash check failure, copy above hash"); + wpa_printf(MSG_ERROR, "wolfFIPS: into verifyCore[] in fips_test.c and rebuild"); + } +} +#endif /* CONFIG_FIPS && HAVE_FIPS */ + + +#ifdef DEBUG_WOLFSSL +static void wolfSSL_logging_cb(const int log_level, + const char * const log_message) +{ + (void) log_level; + wpa_printf(MSG_DEBUG, "wolfSSL log:%s", log_message); +} +#endif /* DEBUG_WOLFSSL */ + + void * tls_init(const struct tls_config *conf) { WOLFSSL_CTX *ssl_ctx; @@ -197,6 +230,7 @@ void * tls_init(const struct tls_config *conf) const char *ciphers; #ifdef DEBUG_WOLFSSL + wolfSSL_SetLoggingCb(wolfSSL_logging_cb); wolfSSL_Debugging_ON(); #endif /* DEBUG_WOLFSSL */ @@ -209,7 +243,9 @@ void * tls_init(const struct tls_config *conf) if (wolfSSL_Init() < 0) return NULL; - /* wolfSSL_Debugging_ON(); */ +#if defined(CONFIG_FIPS) && defined(HAVE_FIPS) + wolfCrypt_SetCb_fips(wcFipsCb); +#endif /* CONFIG_FIPS && HAVE_FIPS */ } tls_ref_count++; @@ -227,23 +263,28 @@ void * tls_init(const struct tls_config *conf) } wolfSSL_SetIORecv(ssl_ctx, wolfssl_receive_cb); wolfSSL_SetIOSend(ssl_ctx, wolfssl_send_cb); + context->tls_session_lifetime = conf->tls_session_lifetime; wolfSSL_CTX_set_ex_data(ssl_ctx, 0, context); if (conf->tls_session_lifetime > 0) { + wolfSSL_CTX_set_session_id_context(ssl_ctx, + (const unsigned char *) + "hostapd", 7); wolfSSL_CTX_set_quiet_shutdown(ssl_ctx, 1); wolfSSL_CTX_set_session_cache_mode(ssl_ctx, - SSL_SESS_CACHE_SERVER); + WOLFSSL_SESS_CACHE_SERVER); wolfSSL_CTX_set_timeout(ssl_ctx, conf->tls_session_lifetime); wolfSSL_CTX_sess_set_remove_cb(ssl_ctx, remove_session_cb); } else { wolfSSL_CTX_set_session_cache_mode(ssl_ctx, - SSL_SESS_CACHE_CLIENT); + WOLFSSL_SESS_CACHE_OFF); } if (conf && conf->openssl_ciphers) ciphers = conf->openssl_ciphers; else ciphers = "ALL"; + wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", ciphers); if (wolfSSL_CTX_set_cipher_list(ssl_ctx, ciphers) != 1) { wpa_printf(MSG_ERROR, "wolfSSL: Failed to set cipher string '%s'", @@ -336,6 +377,7 @@ void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn) os_free(conn->alt_subject_match); os_free(conn->suffix_match); os_free(conn->domain_match); + os_free(conn->peer_subject); /* self */ os_free(conn); @@ -369,10 +411,13 @@ int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn) wolfSSL_set_quiet_shutdown(conn->ssl, 1); wolfSSL_shutdown(conn->ssl); - session = wolfSSL_get_session(conn->ssl); - if (wolfSSL_clear(conn->ssl) != 1) + session = wolfSSL_get1_session(conn->ssl); + if (wolfSSL_clear(conn->ssl) != 1) { + wolfSSL_SESSION_free(session); return -1; + } wolfSSL_set_session(conn->ssl, session); + wolfSSL_SESSION_free(session); return 0; } @@ -420,44 +465,6 @@ static int tls_connection_set_subject_match(struct tls_connection *conn, } -static int tls_connection_dh(struct tls_connection *conn, const char *dh_file, - const u8 *dh_blob, size_t blob_len) -{ - if (!dh_file && !dh_blob) - return 0; - - wolfSSL_set_accept_state(conn->ssl); - - if (dh_blob) { - if (wolfSSL_SetTmpDH_buffer(conn->ssl, dh_blob, blob_len, - SSL_FILETYPE_ASN1) < 0) { - wpa_printf(MSG_INFO, "SSL: use DH DER blob failed"); - return -1; - } - wpa_printf(MSG_DEBUG, "SSL: use DH blob OK"); - return 0; - } - - if (dh_file) { - wpa_printf(MSG_INFO, "SSL: use DH PEM file: %s", dh_file); - if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file, - SSL_FILETYPE_PEM) < 0) { - wpa_printf(MSG_INFO, "SSL: use DH PEM file failed"); - if (wolfSSL_SetTmpDH_file(conn->ssl, dh_file, - SSL_FILETYPE_ASN1) < 0) { - wpa_printf(MSG_INFO, - "SSL: use DH DER file failed"); - return -1; - } - } - wpa_printf(MSG_DEBUG, "SSL: use DH file OK"); - return 0; - } - - return 0; -} - - static int tls_connection_client_cert(struct tls_connection *conn, const char *client_cert, const u8 *client_cert_blob, @@ -472,7 +479,13 @@ static int tls_connection_client_cert(struct tls_connection *conn, SSL_FILETYPE_ASN1) != SSL_SUCCESS) { wpa_printf(MSG_INFO, "SSL: use client cert DER blob failed"); - return -1; + if (wolfSSL_use_certificate_chain_buffer_format( + conn->ssl, client_cert_blob, blob_len, + SSL_FILETYPE_PEM) != SSL_SUCCESS) { + wpa_printf(MSG_INFO, + "SSL: use client cert PEM blob failed"); + return -1; + } } wpa_printf(MSG_DEBUG, "SSL: use client cert blob OK"); return 0; @@ -534,23 +547,35 @@ 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) != + SSL_SUCCESS) { wpa_printf(MSG_INFO, "SSL: use private DER blob failed"); + if (wolfSSL_use_PrivateKey_buffer( + conn->ssl, + private_key_blob, blob_len, + SSL_FILETYPE_PEM) != SSL_SUCCESS) { + wpa_printf(MSG_INFO, + "SSL: use private PEM blob failed"); + } else { + ok = 1; + } } else { - wpa_printf(MSG_DEBUG, "SSL: use private key blob OK"); ok = 1; } + if (ok) + wpa_printf(MSG_DEBUG, "SSL: use private key blob OK"); } if (!ok && private_key) { if (wolfSSL_use_PrivateKey_file(conn->ssl, private_key, - SSL_FILETYPE_PEM) <= 0) { + SSL_FILETYPE_PEM) != + SSL_SUCCESS) { 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) != + SSL_SUCCESS) { wpa_printf(MSG_INFO, "SSL: use private key DER file failed"); } else { @@ -721,8 +746,7 @@ static int tls_match_suffix_helper(WOLFSSL_X509 *cert, const char *match, WOLFSSL_X509_NAME_ENTRY *e; WOLFSSL_ASN1_STRING *cn; - i = wolfSSL_X509_NAME_get_index_by_NID(name, ASN_COMMON_NAME, - i); + i = wolfSSL_X509_NAME_get_index_by_NID(name, NID_commonName, i); if (i == -1) break; e = wolfSSL_X509_NAME_get_entry(name, i); @@ -1134,6 +1158,11 @@ static int tls_verify_cb(int preverify_ok, WOLFSSL_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; } @@ -1194,8 +1223,14 @@ static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn, if (wolfSSL_CTX_load_verify_buffer(ctx, ca_cert_blob, blob_len, SSL_FILETYPE_ASN1) != SSL_SUCCESS) { - wpa_printf(MSG_INFO, "SSL: failed to load CA blob"); - return -1; + wpa_printf(MSG_INFO, "SSL: failed to load DER CA blob"); + if (wolfSSL_CTX_load_verify_buffer( + ctx, ca_cert_blob, blob_len, + SSL_FILETYPE_PEM) != SSL_SUCCESS) { + wpa_printf(MSG_INFO, + "SSL: failed to load PEM CA blob"); + return -1; + } } wpa_printf(MSG_DEBUG, "SSL: use CA cert blob OK"); return 0; @@ -1238,10 +1273,8 @@ static int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn, static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags) { #ifdef HAVE_SESSION_TICKET -#if 0 if (!(flags & TLS_CONN_DISABLE_SESSION_TICKET)) wolfSSL_UseSessionTicket(ssl); -#endif #endif /* HAVE_SESSION_TICKET */ if (flags & TLS_CONN_DISABLE_TLSv1_0) @@ -1250,6 +1283,8 @@ static void tls_set_conn_flags(WOLFSSL *ssl, unsigned int flags) wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_1); if (flags & TLS_CONN_DISABLE_TLSv1_2) wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_2); + if (flags & TLS_CONN_DISABLE_TLSv1_3) + wolfSSL_set_options(ssl, SSL_OP_NO_TLSv1_3); } @@ -1289,12 +1324,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, return -1; } - if (tls_connection_dh(conn, params->dh_file, params->dh_blob, - params->dh_blob_len) < 0) { - wpa_printf(MSG_INFO, "Error setting DH"); - return -1; - } - + wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", + params->openssl_ciphers ? params->openssl_ciphers : "N/A"); if (params->openssl_ciphers && wolfSSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) { wpa_printf(MSG_INFO, @@ -1311,7 +1342,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, WOLFSSL_CSR_OCSP_USE_NONCE) != SSL_SUCCESS) return -1; - wolfSSL_CTX_EnableOCSP(tls_ctx, 0); + if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS) + return -1; } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 @@ -1320,7 +1352,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, WOLFSSL_CSR2_OCSP_MULTI, 0) != SSL_SUCCESS) return -1; - wolfSSL_CTX_EnableOCSP(tls_ctx, 0); + if (wolfSSL_EnableOCSPStapling(conn->ssl) != SSL_SUCCESS) + return -1; } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ #if !defined(HAVE_CERTIFICATE_STATUS_REQUEST) && \ @@ -1427,25 +1460,10 @@ static int tls_global_private_key(void *ssl_ctx, const char *private_key, } -static int tls_global_dh(void *ssl_ctx, const char *dh_file, - const u8 *dh_blob, size_t blob_len) +static int tls_global_dh(void *ssl_ctx, const char *dh_file) { WOLFSSL_CTX *ctx = ssl_ctx; - if (!dh_file && !dh_blob) - return 0; - - if (dh_blob) { - if (wolfSSL_CTX_SetTmpDH_buffer(ctx, dh_blob, blob_len, - SSL_FILETYPE_ASN1) < 0) { - wpa_printf(MSG_INFO, - "SSL: global use DH DER blob failed"); - return -1; - } - wpa_printf(MSG_DEBUG, "SSL: global use DH blob OK"); - return 0; - } - if (dh_file) { if (wolfSSL_CTX_SetTmpDH_file(ctx, dh_file, SSL_FILETYPE_PEM) < 0) { @@ -1532,13 +1550,14 @@ int tls_global_set_params(void *tls_ctx, return -1; } - if (tls_global_dh(tls_ctx, params->dh_file, params->dh_blob, - params->dh_blob_len) < 0) { + if (tls_global_dh(tls_ctx, params->dh_file) < 0) { wpa_printf(MSG_INFO, "SSL: Failed to load DH file '%s'", params->dh_file); return -1; } + wpa_printf(MSG_DEBUG, "wolfSSL: cipher suites: %s", + params->openssl_ciphers ? params->openssl_ciphers : "N/A"); if (params->openssl_ciphers && wolfSSL_CTX_set_cipher_list(tls_ctx, params->openssl_ciphers) != 1) { @@ -1590,6 +1609,9 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, int verify_peer, unsigned int flags, const u8 *session_ctx, size_t session_ctx_len) { + static int counter = 0; + struct tls_context *context; + if (!conn) return -1; @@ -1607,6 +1629,22 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, wolfSSL_set_accept_state(conn->ssl); + context = wolfSSL_CTX_get_ex_data((WOLFSSL_CTX *) ssl_ctx, 0); + if (context && context->tls_session_lifetime == 0) { + /* + * Set session id context to a unique value to make sure + * session resumption cannot be used either through session + * caching or TLS ticket extension. + */ + counter++; + wolfSSL_set_session_id_context(conn->ssl, + (const unsigned char *) &counter, + sizeof(counter)); + } else { + wolfSSL_set_session_id_context(conn->ssl, session_ctx, + session_ctx_len); + } + /* TODO: do we need to fake a session like OpenSSL does here? */ return 0; @@ -1632,20 +1670,31 @@ static struct wpabuf * wolfssl_handshake(struct tls_connection *conn, wpa_printf(MSG_DEBUG, "SSL: wolfSSL_connect: %d", res); } - if (res != 1) { + if (res != WOLFSSL_SUCCESS) { int err = wolfSSL_get_error(conn->ssl, res); - if (err == SSL_ERROR_WANT_READ) { + if (err == WOLFSSL_ERROR_NONE) { + wpa_printf(MSG_DEBUG, + "SSL: %s - WOLFSSL_ERROR_NONE (%d)", + server ? "wolfSSL_accept" : + "wolfSSL_connect", res); + } else if (err == WOLFSSL_ERROR_WANT_READ) { wpa_printf(MSG_DEBUG, - "SSL: wolfSSL_connect - want more data"); - } else if (err == SSL_ERROR_WANT_WRITE) { + "SSL: %s - want more data", + server ? "wolfSSL_accept" : + "wolfSSL_connect"); + } else if (err == WOLFSSL_ERROR_WANT_WRITE) { wpa_printf(MSG_DEBUG, - "SSL: wolfSSL_connect - want to write"); + "SSL: %s - want to write", + server ? "wolfSSL_accept" : + "wolfSSL_connect"); } else { char msg[80]; wpa_printf(MSG_DEBUG, - "SSL: wolfSSL_connect - failed %s", + "SSL: %s - failed %s", + server ? "wolfSSL_accept" : + "wolfSSL_connect", wolfSSL_ERR_error_string(err, msg)); conn->failed++; } @@ -1997,11 +2046,21 @@ int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn, const char *label, const u8 *context, size_t context_len, u8 *out, size_t out_len) { - if (context) + if (!conn) return -1; - if (!conn || wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0) +#if LIBWOLFSSL_VERSION_HEX >= 0x04007000 + if (wolfSSL_export_keying_material(conn->ssl, out, out_len, + label, os_strlen(label), + context, context_len, + context != NULL) != WOLFSSL_SUCCESS) return -1; return 0; +#else + if (context || + wolfSSL_make_eap_keys(conn->ssl, out, out_len, label) != 0) + return -1; +#endif + return 0; } @@ -2046,9 +2105,15 @@ int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn, _out, skip + out_len); ret = 0; } else { +#ifdef CONFIG_FIPS + wpa_printf(MSG_ERROR, + "wolfSSL: Can't use sha1_md5 in FIPS build"); + ret = -1; +#else /* CONFIG_FIPS */ ret = tls_prf_sha1_md5(master_key, master_key_len, "key expansion", seed, sizeof(seed), _out, skip + out_len); +#endif /* CONFIG_FIPS */ } forced_memzero(master_key, master_key_len); @@ -2160,6 +2225,39 @@ void tls_connection_remove_session(struct tls_connection *conn) } +int tls_get_tls_unique(struct tls_connection *conn, u8 *buf, size_t max_len) +{ + size_t len; + int reused; + + reused = wolfSSL_session_reused(conn->ssl); + if ((wolfSSL_is_server(conn->ssl) && !reused) || + (!wolfSSL_is_server(conn->ssl) && reused)) + len = wolfSSL_get_peer_finished(conn->ssl, buf, max_len); + else + len = wolfSSL_get_finished(conn->ssl, buf, max_len); + + if (len == 0 || len > max_len) + return -1; + + return len; +} + + +u16 tls_connection_get_cipher_suite(struct tls_connection *conn) +{ + return (u16) wolfSSL_get_current_cipher_suite(conn->ssl); +} + + +const char * tls_connection_get_peer_subject(struct tls_connection *conn) +{ + if (conn) + return conn->peer_subject; + return NULL; +} + + void tls_connection_set_success_data(struct tls_connection *conn, struct wpabuf *data) { @@ -2206,3 +2304,11 @@ tls_connection_get_success_data(struct tls_connection *conn) return NULL; return wolfSSL_SESSION_get_ex_data(sess, tls_ex_idx_session); } + + +bool tls_connection_get_own_cert_used(struct tls_connection *conn) +{ + if (conn) + return wolfSSL_get_certificate(conn->ssl) != NULL; + return false; +} diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver.h b/wpa_supplicant-2.9_standard/src/drivers/driver.h index b61366e5c083ecc3619e4f9e9c64faa136421b7b..bc6b2e8c133b1af3d138c7763faea2abd500e0cd 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver.h +++ b/wpa_supplicant-2.9_standard/src/drivers/driver.h @@ -41,23 +41,13 @@ #define HOSTAPD_CHAN_DFS_AVAILABLE 0x00000300 #define HOSTAPD_CHAN_DFS_MASK 0x00000300 -#define HOSTAPD_CHAN_VHT_10_70 0x00000800 -#define HOSTAPD_CHAN_VHT_30_50 0x00001000 -#define HOSTAPD_CHAN_VHT_50_30 0x00002000 -#define HOSTAPD_CHAN_VHT_70_10 0x00004000 +#define HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL 0x00000800 +#define HOSTAPD_CHAN_VHT_160MHZ_SUBCHANNEL 0x00001000 +#define HOSTAPD_CHAN_EHT_320MHZ_SUBCHANNEL 0x00002000 #define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000 #define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000 -#define HOSTAPD_CHAN_VHT_10_150 0x00100000 -#define HOSTAPD_CHAN_VHT_30_130 0x00200000 -#define HOSTAPD_CHAN_VHT_50_110 0x00400000 -#define HOSTAPD_CHAN_VHT_70_90 0x00800000 -#define HOSTAPD_CHAN_VHT_90_70 0x01000000 -#define HOSTAPD_CHAN_VHT_110_50 0x02000000 -#define HOSTAPD_CHAN_VHT_130_30 0x04000000 -#define HOSTAPD_CHAN_VHT_150_10 0x08000000 - /* Allowed bandwidth mask */ enum hostapd_chan_width_attr { HOSTAPD_CHAN_WIDTH_10 = BIT(0), @@ -66,6 +56,7 @@ enum hostapd_chan_width_attr { HOSTAPD_CHAN_WIDTH_40M = BIT(3), HOSTAPD_CHAN_WIDTH_80 = BIT(4), HOSTAPD_CHAN_WIDTH_160 = BIT(5), + HOSTAPD_CHAN_WIDTH_320 = BIT(6), }; /* Filter gratuitous ARP */ @@ -180,6 +171,11 @@ struct hostapd_channel_data { * wmm_rules - WMM regulatory rules */ struct hostapd_wmm_rule wmm_rules[WMM_AC_NUM]; + + /** + * punct_bitmap - RU puncturing bitmap + */ + u16 punct_bitmap; }; #define HE_MAC_CAPAB_0 0 @@ -200,8 +196,18 @@ struct he_capabilities { u16 he_6ghz_capa; }; +/* struct eht_capabilities - IEEE 802.11be EHT capabilities */ +struct eht_capabilities { + bool eht_supported; + u16 mac_cap; + u8 phy_cap[EHT_PHY_CAPAB_LEN]; + u8 mcs[EHT_MCS_NSS_CAPAB_LEN]; + u8 ppet[EHT_PPE_THRESH_CAPAB_LEN]; +}; + #define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0) #define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1) +#define HOSTAPD_MODE_FLAG_HE_INFO_KNOWN BIT(2) enum ieee80211_op_mode { @@ -241,6 +247,11 @@ struct hostapd_hw_modes { */ enum hostapd_hw_mode mode; + /** + * is_6ghz - Whether the mode information is for the 6 GHz band + */ + bool is_6ghz; + /** * num_channels - Number of entries in the channels array */ @@ -298,6 +309,11 @@ struct hostapd_hw_modes { * for IEEE 802.11ay EDMG configuration. */ struct ieee80211_edmg_config edmg; + + /** + * eht_capab - EHT (IEEE 802.11be) capabilities + */ + struct eht_capabilities eht_capab[IEEE80211_MODE_NUM]; }; @@ -328,6 +344,8 @@ struct hostapd_hw_modes { * @flags: information flags about the BSS/IBSS (WPA_SCAN_*) * @bssid: BSSID * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1) + * @max_cw: the max channel width of the connection (calculated during scan + * result processing) * @beacon_int: beacon interval in TUs (host byte order) * @caps: capability information field in host byte order * @qual: signal quality @@ -342,6 +360,7 @@ struct hostapd_hw_modes { * @parent_tsf: Time when the Beacon/Probe Response frame was received in terms * of TSF of the BSS specified by %tsf_bssid. * @tsf_bssid: The BSS that %parent_tsf TSF time refers to. + * @beacon_newer: Whether the Beacon frame data is known to be newer * @ie_len: length of the following IE field in octets * @beacon_ie_len: length of the following Beacon IE field in octets * @@ -363,6 +382,7 @@ struct wpa_scan_res { unsigned int flags; u8 bssid[ETH_ALEN]; int freq; + enum chan_width max_cw; u16 beacon_int; u16 caps; int qual; @@ -380,6 +400,7 @@ struct wpa_scan_res { #ifdef CONFIG_MAGICLINK_PC int legacyGO; #endif + bool beacon_newer; size_t ie_len; #ifdef CONFIG_WAPI u8 wapi_ie[SSID_MAX_WAPI_IE_LEN]; @@ -432,6 +453,18 @@ struct wpa_driver_scan_ssid { size_t ssid_len; }; +struct t2lm_mapping { + /** + * downlink - Bitmap of TIDs mapped with a link in downlink direction + */ + u8 downlink; + + /** + * uplink - Bitmap of TIDs mapped with a link in uplink direction + */ + u8 uplink; +}; + /** * struct wpa_driver_scan_params - Scan parameters * Data for struct wpa_driver_ops::scan2(). @@ -665,6 +698,31 @@ struct wpa_driver_scan_params { */ unsigned int p2p_include_6ghz:1; + /** + * non_coloc_6ghz - Force scanning of non-PSC 6 GHz channels + * + * If this is set, the driver should scan non-PSC channels from the + * scan request even if neighbor reports from 2.4/5 GHz APs did not + * report a co-located AP on these channels. The default is to scan + * non-PSC channels only if a co-located AP was reported on the channel. + */ + unsigned int non_coloc_6ghz:1; + + /** + * min_probe_req_content - Minimize probe request content to only have + * minimal requirement elements, e.g., supported rates etc., and no + * additional elements other then those provided by user space. + */ + unsigned int min_probe_req_content:1; + + /** + * link_id - Specify the link that is requesting the scan on an MLD + * + * This is set when operating as an AP MLD and doing an OBSS scan. + * -1 indicates that no particular link ID is set. + */ + s8 link_id; + /* * NOTE: Whenever adding new parameters here, please make sure * wpa_scan_clone_params() and wpa_scan_free_params() get updated with @@ -707,7 +765,7 @@ struct wpa_driver_auth_params { * auth_data_len - Length of auth_data buffer in octets */ size_t auth_data_len; -#ifdef CONFIG_MLD_PATCH + /** * mld - Establish an MLD connection */ @@ -722,7 +780,6 @@ struct wpa_driver_auth_params { * The MLD AP address */ const u8 *ap_mld_addr; -#endif }; /** @@ -812,6 +869,21 @@ struct hostapd_freq_params { * for IEEE 802.11ay EDMG configuration. */ struct ieee80211_edmg_config edmg; + + /** + * radar_background - Whether radar/CAC background is requested + */ + bool radar_background; + + /** + * eht_enabled - Whether EHT is enabled + */ + bool eht_enabled; + + /** + * link_id: If >=0 indicates the link of the AP MLD to configure + */ + int link_id; }; /** @@ -875,7 +947,7 @@ struct wpa_driver_sta_auth_params { */ size_t fils_kek_len; }; -#ifdef CONFIG_MLD_PATCH_EXT + struct wpa_driver_mld_params { /** * mld_addr - AP's MLD address @@ -905,9 +977,11 @@ struct wpa_driver_mld_params { const u8 *bssid; const u8 *ies; size_t ies_len; + int error; + bool disabled; } mld_links[MAX_NUM_MLD_LINKS]; }; -#endif + /** * struct wpa_driver_associate_params - Association parameters * Data for struct wpa_driver_ops::associate(). @@ -1024,6 +1098,17 @@ struct wpa_driver_associate_params { */ unsigned int key_mgmt_suite; + /** + * allowed_key_mgmts - Bitfield of allowed key management suites + * (WPA_KEY_MGMT_*) other than @key_mgmt_suite for the current + * connection + * + * SME in the driver may choose key_mgmt from this list for the initial + * connection or roaming. The driver which doesn't support this + * ignores this parameter. + */ + unsigned int allowed_key_mgmts; + /** * auth_alg - Allowed authentication algorithms * Bit field of WPA_AUTH_ALG_* @@ -1076,6 +1161,23 @@ struct wpa_driver_associate_params { */ const u8 *psk; + /** + * sae_password - Password for SAE authentication + * + * This value is made available only for WPA3-Personal (SAE) and only + * for drivers that set WPA_DRIVER_FLAGS2_SAE_OFFLOAD. + */ + const char *sae_password; + + /** + * sae_password_id - Password Identifier for SAE authentication + * + * This value is made available only for WPA3-Personal (SAE) and only + * for drivers that set WPA_DRIVER_FLAGS2_SAE_OFFLOAD. If %NULL, SAE + * password identifier is not used. + */ + const char *sae_password_id; + /** * drop_unencrypted - Enable/disable unencrypted frame filtering * @@ -1098,7 +1200,7 @@ struct wpa_driver_associate_params { * * If the driver needs to do special configuration for WPS association, * this variable provides more information on what type of association - * is being requested. Most drivers should not need ot use this. + * is being requested. Most drivers should not need to use this. */ enum wps_mode wps; @@ -1264,7 +1366,13 @@ struct wpa_driver_associate_params { * 1 = hash-to-element only * 2 = both hunting-and-pecking loop and hash-to-element enabled */ - int sae_pwe; + enum sae_pwe sae_pwe; + + /** + * disable_eht - Disable EHT for this connection + */ + int disable_eht; + #ifdef CONFIG_MLD_PATCH /** * enable mld - Enable MLD for this connection @@ -1272,12 +1380,10 @@ struct wpa_driver_associate_params { int enable_mld; #endif -#ifdef CONFIG_MLD_PATCH_EXT /* * mld_params - MLD association parameters */ struct wpa_driver_mld_params mld_params; -#endif }; enum hide_ssid { @@ -1301,6 +1407,23 @@ struct wowlan_triggers { u8 rfkill_release; }; +struct unsol_bcast_probe_resp { + /** + * 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_ap_params { /** * head - Beacon head from IEEE 802.11 header to IEs before TIM IE @@ -1621,7 +1744,7 @@ struct wpa_driver_ap_params { * 1 = hash-to-element only * 2 = both hunting-and-pecking loop and hash-to-element enabled */ - int sae_pwe; + enum sae_pwe sae_pwe; /** * FILS Discovery frame minimum interval in TUs @@ -1644,19 +1767,108 @@ struct wpa_driver_ap_params { size_t fd_frame_tmpl_len; /** - * Unsolicited broadcast Probe Response interval in TUs + * mbssid_tx_iface - Transmitting interface of the MBSSID set */ - unsigned int unsol_bcast_probe_resp_interval; + const char *mbssid_tx_iface; /** - * Unsolicited broadcast Probe Response template data + * mbssid_index - The index of this BSS in the MBSSID set */ - u8 *unsol_bcast_probe_resp_tmpl; + unsigned int mbssid_index; /** - * Unsolicited broadcast Probe Response template length + * mbssid_elem - Buffer containing all MBSSID elements */ - size_t unsol_bcast_probe_resp_tmpl_len; + u8 *mbssid_elem; + + /** + * mbssid_elem_len - Total length of all MBSSID elements + */ + size_t mbssid_elem_len; + + /** + * mbssid_elem_count - The number of MBSSID elements + */ + u8 mbssid_elem_count; + + /** + * mbssid_elem_offset - Offsets to elements in mbssid_elem. + * Kernel will use these offsets to generate multiple BSSID beacons. + */ + u8 **mbssid_elem_offset; + + /** + * ema - Enhanced MBSSID advertisements support. + */ + bool ema; + + /** + * punct_bitmap - Preamble puncturing bitmap + * Each bit corresponds to a 20 MHz subchannel, the lowest bit for the + * channel with the lowest frequency. A bit set to 1 indicates that the + * subchannel is punctured, otherwise active. + */ + u16 punct_bitmap; + + /** + * rnr_elem - This buffer contains all of reduced neighbor report (RNR) + * elements + */ + u8 *rnr_elem; + + /** + * rnr_elem_len - Length of rnr_elem buffer + */ + size_t rnr_elem_len; + + /** + * rnr_elem_count - Number of RNR elements + */ + unsigned int rnr_elem_count; + + /** + * rnr_elem_offset - The offsets to the elements in rnr_elem. + * The driver will use these to include RNR elements in EMA beacons. + */ + u8 **rnr_elem_offset; + + /* Unsolicited broadcast Probe Response data */ + struct unsol_bcast_probe_resp ubpr; + + /** + * allowed_freqs - List of allowed 20 MHz channel center frequencies in + * MHz for AP operation. Drivers which support this parameter will + * generate a new list based on this provided list by filtering out + * channels that cannot be used at that time due to regulatory or other + * constraints. The resulting list is used as the list of all allowed + * channels whenever performing operations like ACS and DFS. + */ + int *allowed_freqs; + + /* + * mld_ap - Whether operating as an AP MLD + */ + bool mld_ap; + + /** + * mld_link_id - Link id for MLD BSS's + */ + u8 mld_link_id; + + /** + * psk - PSK passed to the driver for 4-way handshake offload + */ + u8 psk[PMK_LEN]; + + /** + * psk_len - PSK length in bytes (0 = not set) + */ + size_t psk_len; + + /** + * sae_password - SAE password for SAE offload + */ + const char *sae_password; }; struct wpa_driver_mesh_bss_params { @@ -1810,13 +2022,12 @@ struct wpa_driver_set_key_params { * %KEY_FLAG_RX_TX * RX/TX key. */ enum key_flag key_flag; -#ifdef CONFIG_MLD_PATCH + /** * link_id - MLO Link ID * * Set to a valid Link ID (0-14) when applicable, otherwise -1. */ int link_id; -#endif }; enum wpa_driver_if_type { @@ -1857,7 +2068,7 @@ enum wpa_driver_if_type { WPA_IF_P2P_GROUP, /** - * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the + * WPA_IF_P2P_DEVICE - P2P Device interface is used to identify the * abstracted P2P Device function in the driver */ WPA_IF_P2P_DEVICE, @@ -1915,6 +2126,7 @@ struct wpa_driver_capa { #define WPA_DRIVER_CAPA_KEY_MGMT_CCKM 0x00400000 #define WPA_DRIVER_CAPA_KEY_MGMT_OSEN 0x00800000 #define WPA_DRIVER_CAPA_KEY_MGMT_SAE_EXT_KEY 0x01000000 +#define WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE_EXT_KEY 0x02000000 /** Bitfield of supported key management suites */ unsigned int key_mgmt; unsigned int key_mgmt_iftype[WPA_IF_MAX]; @@ -2093,15 +2305,15 @@ struct wpa_driver_capa { #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 secure LTF in AP mode */ +#define WPA_DRIVER_FLAGS2_SEC_LTF_AP 0x0000000000000004ULL +/** Driver supports secure RTT measurement exchange in AP mode */ +#define WPA_DRIVER_FLAGS2_SEC_RTT_AP 0x0000000000000008ULL /** * Driver supports protection of range negotiation and measurement management - * frames + * frames in AP mode */ -#define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG 0x0000000000000010ULL +#define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP 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 */ @@ -2110,12 +2322,35 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS2_OCV 0x0000000000000080ULL /** Driver expects user space implementation of SME in AP mode */ #define WPA_DRIVER_FLAGS2_AP_SME 0x0000000000000100ULL - -#ifdef CONFIG_MLD_PATCH +/** Driver handles SA Query procedures in AP mode */ +#define WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP 0x0000000000000200ULL +/** Driver supports background radar/CAC detection */ +#define WPA_DRIVER_FLAGS2_RADAR_BACKGROUND 0x0000000000000400ULL +/** Driver supports secure LTF in STA mode */ +#define WPA_DRIVER_FLAGS2_SEC_LTF_STA 0x0000000000000800ULL +/** Driver supports secure RTT measurement exchange in STA mode */ +#define WPA_DRIVER_FLAGS2_SEC_RTT_STA 0x0000000000001000ULL +/** + * Driver supports protection of range negotiation and measurement management + * frames in STA mode + */ +#define WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA 0x0000000000002000ULL /** Driver supports MLO in station/AP mode */ #define WPA_DRIVER_FLAGS2_MLO 0x0000000000004000ULL -#endif - +/** Driver supports minimal scan request probe content */ +#define WPA_DRIVER_FLAGS2_SCAN_MIN_PREQ 0x0000000000008000ULL +/** Driver supports SAE authentication offload in STA mode */ +#define WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA 0x0000000000010000ULL +/** Driver support AP_PSK authentication offload */ +#define WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK 0x0000000000020000ULL +/** Driver supports OWE STA offload */ +#define WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA 0x0000000000040000ULL +/** Driver supports OWE AP offload */ +#define WPA_DRIVER_FLAGS2_OWE_OFFLOAD_AP 0x0000000000080000ULL +/** Driver support AP SAE authentication offload */ +#define WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP 0x0000000000100000ULL +/** Driver supports TWT responder in HT and VHT modes */ +#define WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER 0x0000000000200000ULL u64 flags2; #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \ @@ -2228,11 +2463,26 @@ struct wpa_driver_capa { /* Maximum number of supported CSA counters */ u16 max_csa_counters; + + /* Maximum number of supported AKM suites in commands */ + unsigned int max_num_akms; + + /* Maximum number of interfaces supported for MBSSID advertisement */ + unsigned int mbssid_max_interfaces; + /* Maximum profile periodicity for enhanced MBSSID advertisement */ + unsigned int ema_max_periodicity; }; struct hostapd_data; +enum guard_interval { + GUARD_INTERVAL_0_4 = 1, + GUARD_INTERVAL_0_8 = 2, + GUARD_INTERVAL_1_6 = 3, + GUARD_INTERVAL_3_2 = 4, +}; + #define STA_DRV_DATA_TX_MCS BIT(0) #define STA_DRV_DATA_RX_MCS BIT(1) #define STA_DRV_DATA_TX_VHT_MCS BIT(2) @@ -2243,14 +2493,23 @@ struct hostapd_data; #define STA_DRV_DATA_RX_SHORT_GI BIT(7) #define STA_DRV_DATA_LAST_ACK_RSSI BIT(8) #define STA_DRV_DATA_CONN_TIME BIT(9) +#define STA_DRV_DATA_TX_HE_MCS BIT(10) +#define STA_DRV_DATA_RX_HE_MCS BIT(11) +#define STA_DRV_DATA_TX_HE_NSS BIT(12) +#define STA_DRV_DATA_RX_HE_NSS BIT(13) +#define STA_DRV_DATA_TX_HE_DCM BIT(14) +#define STA_DRV_DATA_RX_HE_DCM BIT(15) +#define STA_DRV_DATA_TX_HE_GI BIT(16) +#define STA_DRV_DATA_RX_HE_GI BIT(17) struct hostap_sta_driver_data { unsigned long rx_packets, tx_packets; unsigned long long rx_bytes, tx_bytes; unsigned long long rx_airtime, tx_airtime; + unsigned long long beacons_count; int bytes_64bit; /* whether 64-bit byte counters are supported */ - unsigned long current_tx_rate; - unsigned long current_rx_rate; + unsigned long current_tx_rate; /* in kbps */ + unsigned long current_rx_rate; /* in kbps */ unsigned long inactive_msec; unsigned long connected_sec; unsigned long flags; /* bitfield of STA_DRV_DATA_* */ @@ -2260,13 +2519,27 @@ struct hostap_sta_driver_data { s8 last_ack_rssi; unsigned long backlog_packets; unsigned long backlog_bytes; - s8 signal; + unsigned long fcs_error_count; + unsigned long beacon_loss_count; + unsigned long expected_throughput; + unsigned long rx_drop_misc; + unsigned long rx_mpdus; + int signal; /* dBm; or -WPA_INVALID_NOISE */ + u8 rx_hemcs; + u8 tx_hemcs; u8 rx_vhtmcs; u8 tx_vhtmcs; u8 rx_mcs; u8 tx_mcs; + u8 rx_he_nss; + u8 tx_he_nss; u8 rx_vht_nss; u8 tx_vht_nss; + s8 avg_signal; /* dBm */ + s8 avg_beacon_signal; /* dBm */ + s8 avg_ack_signal; /* dBm */ + enum guard_interval rx_guard_interval, tx_guard_interval; + u8 rx_dcm, tx_dcm; }; struct hostapd_sta_add_params { @@ -2283,6 +2556,8 @@ struct hostapd_sta_add_params { const struct ieee80211_he_capabilities *he_capab; size_t he_capab_len; const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab; + const struct ieee80211_eht_capabilities *eht_capab; + size_t eht_capab_len; u32 flags; /* bitmask of WPA_STA_* flags */ u32 flags_mask; /* unset bits in flags */ #ifdef CONFIG_MESH @@ -2298,6 +2573,10 @@ struct hostapd_sta_add_params { const u8 *supp_oper_classes; size_t supp_oper_classes_len; int support_p2p_ps; + + bool mld_link_sta; + s8 mld_link_id; + const u8 *mld_link_addr; }; struct mac_address { @@ -2391,11 +2670,8 @@ enum smps_mode { * @frequency: control frequency * @above_threshold: true if the above threshold was crossed * (relevant for a CQM event) - * @current_signal: in dBm - * @avg_signal: in dBm - * @avg_beacon_signal: in dBm + * @data: STA information * @current_noise: %WPA_INVALID_NOISE if not supported - * @current_txrate: current TX rate * @chanwidth: channel width * @center_frq1: center frequency for the first segment * @center_frq2: center frequency for the second segment (if relevant) @@ -2403,21 +2679,18 @@ enum smps_mode { struct wpa_signal_info { u32 frequency; int above_threshold; - int current_signal; - int avg_signal; - int avg_beacon_signal; + struct hostap_sta_driver_data data; int current_noise; - int current_txrate; enum chan_width chanwidth; int center_frq1; int center_frq2; }; -#ifdef CONFIG_MLD_PATCH_EXT + struct wpa_mlo_signal_info { u16 valid_links; struct wpa_signal_info links[MAX_NUM_MLD_LINKS]; }; -#endif + /** * struct wpa_channel_info - Information about the current channel * @frequency: Center frequency of the primary 20 MHz channel @@ -2478,6 +2751,9 @@ struct beacon_data { * @beacon_after: Next beacon/probe resp/asooc resp info * @counter_offset_beacon: Offset to the count field in beacon's tail * @counter_offset_presp: Offset to the count field in probe resp. + * @punct_bitmap - Preamble puncturing bitmap + * @link_id: Link ID to determine the link for MLD; -1 for non-MLD + * @ubpr: Unsolicited broadcast Probe Response frame data */ struct csa_settings { u8 cs_count; @@ -2489,6 +2765,38 @@ struct csa_settings { u16 counter_offset_beacon[2]; u16 counter_offset_presp[2]; + + u16 punct_bitmap; + int link_id; + + struct unsol_bcast_probe_resp ubpr; +}; + +/** + * struct cca_settings - Settings for color switch command + * @cca_count: Count in Beacon frames (TBTT) to perform the switch + * @cca_color: The new color that we are switching to + * @beacon_cca: Beacon/Probe Response/(Re)Association Response frame info for + * color switch period + * @beacon_after: Next Beacon/Probe Response/(Re)Association Response frame info + * @counter_offset_beacon: Offset to the count field in Beacon frame tail + * @counter_offset_presp: Offset to the count field in Probe Response frame + * @ubpr: Unsolicited broadcast Probe Response frame data + * @link_id: If >= 0 indicates the link of the AP MLD to configure + */ +struct cca_settings { + u8 cca_count; + u8 cca_color; + + struct beacon_data beacon_cca; + struct beacon_data beacon_after; + + u16 counter_offset_beacon; + u16 counter_offset_presp; + + struct unsol_bcast_probe_resp ubpr; + + int link_id; }; /* TDLS peer capabilities for send_tdls_mgmt() */ @@ -2527,6 +2835,7 @@ struct macsec_init_params { enum drv_br_port_attr { DRV_BR_PORT_ATTR_PROXYARP, DRV_BR_PORT_ATTR_HAIRPIN_MODE, + DRV_BR_PORT_ATTR_MCAST2UCAST, }; enum drv_br_net_param { @@ -2555,6 +2864,12 @@ struct drv_acs_params { /* Indicates whether EDMG is enabled */ int edmg_enabled; + + /* Indicates whether EHT is enabled */ + bool eht_enabled; + + /* Indicates the link if MLO case; -1 otherwise */ + int link_id; }; struct wpa_bss_trans_info { @@ -2609,6 +2924,7 @@ enum wpa_drv_update_connect_params_mask { * the real status code for failures. Used only for the request interface * from user space to the driver. * @pmkid: Generated PMKID as part of external auth exchange (e.g., SAE). + * @mld_addr: AP's MLD address or %NULL if MLO is not used */ struct external_auth { enum { @@ -2621,9 +2937,91 @@ struct external_auth { unsigned int key_mgmt_suite; u16 status; const u8 *pmkid; -#ifdef CONFIG_MLD_PATCH const u8 *mld_addr; -#endif +}; + +#define WPAS_MAX_PASN_PEERS 10 + +enum pasn_status { + PASN_STATUS_SUCCESS = 0, + PASN_STATUS_FAILURE = 1, +}; + +/** + * struct pasn_peer - PASN peer parameters + * + * Used to process the PASN authentication event from the driver to + * userspace and to send a response back. + * @own_addr: Own MAC address specified by the driver to use for PASN + * handshake. + * @peer_addr: MAC address of the peer with which PASN authentication is to be + * performed. + * @network_id: Unique id for the network. + * This identifier is used as a unique identifier for each network + * block when using the control interface. Each network is allocated an + * id when it is being created, either when reading the configuration + * file or when a new network is added through the control interface. + * @akmp: Authentication key management protocol type supported. + * @cipher: Cipher suite. + * @group: Finite cyclic group. Default group used is 19 (ECC). + * @ltf_keyseed_required: Indicates whether LTF keyseed generation is required + * @status: PASN response status, %PASN_STATUS_SUCCESS for successful + * authentication, use %PASN_STATUS_FAILURE if PASN authentication + * fails or if wpa_supplicant fails to set the security ranging context to + * the driver + */ +struct pasn_peer { + u8 own_addr[ETH_ALEN]; + u8 peer_addr[ETH_ALEN]; + int network_id; + int akmp; + int cipher; + int group; + bool ltf_keyseed_required; + enum pasn_status status; +}; + +/** + * struct pasn_auth - PASN authentication trigger parameters + * + * These are used across the PASN authentication event from the driver to + * userspace and to send a response to it. + * @action: Action type. Only significant for the event interface. + * @num_peers: The number of peers for which the PASN handshake is requested + * for. + * @peer: Holds the peer details. + */ +struct pasn_auth { + enum { + PASN_ACTION_AUTH, + PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT, + } action; + unsigned int num_peers; + struct pasn_peer peer[WPAS_MAX_PASN_PEERS]; +}; + +/** + * struct secure_ranging_params - Parameters required to set secure ranging + * context for a peer. + * + * @action: Add or delete a security context to the driver. + * @own_addr: Own MAC address used during key derivation. + * @peer_addr: Address of the peer device. + * @cipher: Cipher suite. + * @tk_len: Length of temporal key. + * @tk: Temporal key buffer. + * @ltf_keyseed_len: Length of LTF keyseed. + * @ltf_keyeed: LTF keyseed buffer. + */ +struct secure_ranging_params { + u32 action; + const u8 *own_addr; + const u8 *peer_addr; + u32 cipher; + u8 tk_len; + const u8 *tk; + u8 ltf_keyseed_len; + const u8 *ltf_keyseed; }; /* enum nested_attr - Used to specify if subcommand uses nested attributes */ @@ -2633,8 +3031,26 @@ enum nested_attr { NESTED_ATTR_UNSPECIFIED = 2, }; -#ifdef CONFIG_MLD_PATCH +/* Preferred channel list information */ + +/* GO role */ +#define WEIGHTED_PCL_GO BIT(0) +/* P2P Client role */ +#define WEIGHTED_PCL_CLI BIT(1) +/* Must be considered for operating channel */ +#define WEIGHTED_PCL_MUST_CONSIDER BIT(2) +/* Should be excluded in GO negotiation */ +#define WEIGHTED_PCL_EXCLUDE BIT(3) + +/* Preferred channel list with weight */ +struct weighted_pcl { + u32 freq; /* MHz */ + u8 weight; + u32 flag; /* bitmap for WEIGHTED_PCL_* */ +}; + struct driver_sta_mlo_info { + bool default_map; u16 req_links; /* bitmap of requested link IDs */ u16 valid_links; /* bitmap of accepted link IDs */ u8 assoc_link_id; @@ -2643,9 +3059,9 @@ struct driver_sta_mlo_info { u8 addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; unsigned int freq; + struct t2lm_mapping t2lmap; } links[MAX_NUM_MLD_LINKS]; }; -#endif /** * struct wpa_driver_ops - Driver interface API definition @@ -2710,7 +3126,7 @@ struct wpa_driver_ops { * some drivers may expect them in different order than wpa_supplicant * is using. If the TX/RX keys are swapped, all TKIP encrypted packets * will trigger Michael MIC errors. This can be fixed by changing the - * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key + * order of MIC keys by swapping the bytes 16..23 and 24..31 of the key * in driver_*.c set_key() implementation, see driver_ndis.c for an * example on how this can be done. */ @@ -2867,9 +3283,9 @@ struct wpa_driver_ops { * poll - Poll driver for association information * @priv: private driver interface data * - * This is an option callback that can be used when the driver does not - * provide event mechanism for association events. This is called when - * receiving WPA EAPOL-Key messages that require association + * This is an optional callback that can be used when the driver does + * not provide event mechanism for association events. This is called + * when receiving WPA/RSN EAPOL-Key messages that require association * information. The driver interface is supposed to generate associnfo * event before returning from this callback function. In addition, the * driver interface should generate an association event after having @@ -2992,12 +3408,13 @@ struct wpa_driver_ops { * @no_encrypt: Do not encrypt frame even if appropriate key exists * (used only for testing purposes) * @wait: Time to wait off-channel for a response (in ms), or zero + * @link_id: Link ID to use for TX, or -1 if not set * Returns: 0 on success, -1 on failure */ int (*send_mlme)(void *priv, const u8 *data, size_t data_len, int noack, unsigned int freq, const u16 *csa_offs, size_t csa_offs_len, int no_encrypt, - unsigned int wait); + unsigned int wait, int link_id); /** * update_ft_ies - Update FT (IEEE 802.11r) IEs @@ -3017,6 +3434,17 @@ struct wpa_driver_ops { int (*update_ft_ies)(void *priv, const u8 *md, const u8 *ies, size_t ies_len); + /** + * get_scan_results - Fetch the latest scan results + * @priv: Private driver interface data + * @bssid: Return results only for the specified BSSID, %NULL for all + * + * Returns: Allocated buffer of scan results (caller is responsible for + * freeing the data structure) on success, NULL on failure + */ + struct wpa_scan_results * (*get_scan_results)(void *priv, + const u8 *bssid); + /** * get_scan_results2 - Fetch the latest scan results * @priv: private driver interface data @@ -3203,6 +3631,7 @@ struct wpa_driver_ops { * @priv: Private driver interface data * @addr: MAC address of the station or %NULL for group keys * @idx: Key index + * @link_id: Link ID for a group key, or -1 if not set * @seq: Buffer for returning the latest used TSC/packet number * Returns: 0 on success, -1 on failure * @@ -3212,18 +3641,20 @@ struct wpa_driver_ops { * unicast keys (i.e., addr != %NULL). */ int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr, - int idx, u8 *seq); + int idx, int link_id, u8 *seq); /** * flush - Flush all association stations (AP only) * @priv: Private driver interface data + * @link_id: In case of MLO, valid link ID on which all associated + * stations will be flushed, -1 otherwise. * Returns: 0 on success, -1 on failure * * This function requests the driver to disassociate all associated * stations. This function does not need to be implemented if the * driver does not process association frames internally. */ - int (*flush)(void *priv); + int (*flush)(void *priv, int link_id); /** * set_generic_elem - Add IEs into Beacon/Probe Response frames (AP) @@ -3259,6 +3690,7 @@ struct wpa_driver_ops { * @buf: Frame payload starting from IEEE 802.1X header * @len: Frame payload length * @no_encrypt: Do not encrypt frame + * @link_id: Link ID to use for TX, or -1 if not set * * Returns 0 on success, else an error * @@ -3276,7 +3708,7 @@ struct wpa_driver_ops { */ int (*tx_control_port)(void *priv, const u8 *dest, u16 proto, const u8 *buf, size_t len, - int no_encrypt); + int no_encrypt, int link_id); /** * hapd_send_eapol - Send an EAPOL packet (AP only) @@ -3287,26 +3719,28 @@ struct wpa_driver_ops { * @encrypt: Whether the frame should be encrypted * @own_addr: Source MAC address * @flags: WPA_STA_* flags for the destination station + * @link_id: Link ID to use for TX, or -1 if not set * * Returns: 0 on success, -1 on failure */ int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr, u32 flags); + const u8 *own_addr, u32 flags, int link_id); /** * sta_deauth - Deauthenticate a station (AP only) * @priv: Private driver interface data * @own_addr: Source address and BSSID for the Deauthentication frame * @addr: MAC address of the station to deauthenticate - * @reason: Reason code for the Deauthentiation frame + * @reason: Reason code for the Deauthentication frame + * @link_id: Link ID to use for Deauthentication frame, or -1 if not set * Returns: 0 on success, -1 on failure * * This function requests a specific station to be deauthenticated and * a Deauthentication frame to be sent to it. */ int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr, - u16 reason); + u16 reason, int link_id); /** * sta_disassoc - Disassociate a station (AP only) @@ -3455,9 +3889,10 @@ struct wpa_driver_ops { * @cw_min: cwMin * @cw_max: cwMax * @burst_time: Maximum length for bursting in 0.1 msec units + * @link_id: Link ID to use, or -1 for non MLD. */ int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min, - int cw_max, int burst_time); + int cw_max, int burst_time, int link_id); /** * if_add - Add a virtual interface @@ -3500,6 +3935,7 @@ struct wpa_driver_ops { * @ifname: Interface (main or virtual BSS or VLAN) * @addr: MAC address of the associated station * @vlan_id: VLAN ID + * @link_id: The link ID or -1 for non-MLO * Returns: 0 on success, -1 on failure * * This function is used to bind a station to a specific virtual @@ -3509,7 +3945,7 @@ struct wpa_driver_ops { * domains to be used with a single BSS. */ int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname, - int vlan_id); + int vlan_id, int link_id); /** * commit - Optional commit changes handler (AP only) @@ -3815,6 +4251,8 @@ struct wpa_driver_ops { * @initiator: Is the current end the TDLS link initiator * @buf: TDLS IEs to add to the message * @len: Length of buf in octets + * @link_id: If >= 0 indicates the link of the AP MLD to specify the + * operating channel on which to send a TDLS Discovery Response frame. * Returns: 0 on success, negative (<0) on failure * * This optional function can be used to send packet to driver which is @@ -3822,7 +4260,8 @@ struct wpa_driver_ops { */ int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, - int initiator, const u8 *buf, size_t len); + int initiator, const u8 *buf, size_t len, + int link_id); /** * tdls_oper - Ask the driver to perform high-level TDLS operations @@ -3915,7 +4354,7 @@ struct wpa_driver_ops { * @signal_info: Connection info structure */ int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info); -#ifdef CONFIG_MLD_PATCH_EXT + /** * mlo_signal_poll - Get current MLO connection information * @priv: Private driver interface data @@ -3923,7 +4362,6 @@ struct wpa_driver_ops { */ int (*mlo_signal_poll)(void *priv, struct wpa_mlo_signal_info *mlo_signal_info); -#endif /** * channel_info - Get parameters of the current operating channel @@ -4122,6 +4560,17 @@ struct wpa_driver_ops { */ int (*switch_channel)(void *priv, struct csa_settings *settings); + /** + * switch_color - Announce color switch and migrate the BSS to the + * given color + * @priv: Private driver interface data + * @settings: Settings for CCA period and new color + * Returns: 0 on success, -1 on failure + * + * This function is used to move the BSS to its new color. + */ + int (*switch_color)(void *priv, struct cca_settings *settings); + /** * add_tx_ts - Add traffic stream * @priv: Private driver interface data @@ -4182,13 +4631,14 @@ struct wpa_driver_ops { /** * stop_ap - Removes beacon from AP * @priv: Private driver interface data + * @link_id: Link ID of the specified link; -1 for non-MLD * Returns: 0 on success, -1 on failure (or if not supported) * * This optional function can be used to disable AP mode related * configuration. Unlike deinit_ap, it does not change to station * mode. */ - int (*stop_ap)(void *priv); + int (*stop_ap)(void *priv, int link_id); /** * get_survey - Retrieve survey data @@ -4300,6 +4750,16 @@ struct wpa_driver_ops { */ int (*set_replay_protect)(void *priv, bool enabled, u32 window); + /** + * set_offload - Set MACsec hardware offload + * @priv: Private driver interface data + * @offload: 0 = MACSEC_OFFLOAD_OFF + * 1 = MACSEC_OFFLOAD_PHY + * 2 = MACSEC_OFFLOAD_MAC + * Returns: 0 on success, -1 on failure (or if not supported) + */ + int (*set_offload)(void *priv, u8 offload); + /** * set_current_cipher_suite - Set current cipher suite * @priv: Private driver interface data @@ -4512,14 +4972,17 @@ struct wpa_driver_ops { * @priv: Private driver interface data * @if_type: Interface type * @num: Number of channels - * @freq_list: Preferred channel frequency list encoded in MHz values + * @freq_list: Weighted preferred channel list * Returns 0 on success, -1 on failure * * This command can be used to query the preferred frequency list from - * the driver specific to a particular interface type. + * the driver specific to a particular interface type. The freq_list + * array needs to have room for *num entries. *num will be updated to + * indicate the number of entries fetched from the driver. */ int (*get_pref_freq_list)(void *priv, enum wpa_driver_if_type if_type, - unsigned int *num, unsigned int *freq_list); + unsigned int *num, + struct weighted_pcl *freq_list); /** * set_prob_oper_freq - Indicate probable P2P operating channel @@ -4565,6 +5028,17 @@ struct wpa_driver_ops { const u8 **ext_capab, const u8 **ext_capab_mask, unsigned int *ext_capab_len); + /** + * get_mld_capab - Get MLD capabilities for the specified interface + * @priv: Private driver interface data + * @type: Interface type for which to get MLD capabilities + * @eml_capa: EML capabilities + * @mld_capa_and_ops: MLD Capabilities and Operations + * Returns: 0 on success or -1 on failure + */ + int (*get_mld_capab)(void *priv, enum wpa_driver_if_type type, + u16 *eml_capa, u16 *mld_capa_and_ops); + /** * p2p_lo_start - Start offloading P2P listen to device * @priv: Private driver interface data @@ -4708,12 +5182,26 @@ struct wpa_driver_ops { */ int (*dpp_listen)(void *priv, bool enable); -#ifdef CONFIG_TESTING_OPTIONS - int (*register_frame)(void *priv, u16 type, - const u8 *match, size_t match_len, - bool multicast); -#endif /* CONFIG_TESTING_OPTIONS */ -#ifdef CONFIG_MLD_PATCH + /** + * set_secure_ranging_ctx - Add or delete secure ranging parameters of + * the specified peer to the driver. + * @priv: Private driver interface data + * @params: Secure ranging parameters + * Returns: 0 on success, -1 on failure + * + */ + int (*set_secure_ranging_ctx)(void *priv, + struct secure_ranging_params *params); + + /** + * send_pasn_resp - Send PASN response for a set of peers to the + * driver. + * @priv: Private driver interface data + * @params: Parameters holding peers and respective status. + * Returns: 0 on success, -1 on failure + */ + int (*send_pasn_resp)(void *priv, struct pasn_auth *params); + /** * get_sta_mlo_info - Get the current multi-link association info * @priv: Private driver interface data @@ -4730,10 +5218,50 @@ struct wpa_driver_ops { * @priv: Private driver interface data * @link_id: The link ID * @addr: The MAC address to use for the link + * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces * Returns: 0 on success, negative value on failure */ - int (*link_add)(void *priv, u8 link_id, const u8 *addr); -#endif + int (*link_add)(void *priv, u8 link_id, const u8 *addr, void *bss_ctx); + + /** + * link_remove - Remove a link from the AP MLD interface + * @priv: Private driver interface data + * @type: Interface type + * @ifname: Interface name of the virtual interface from where the link + * is to be removed. + * @link_id: Valid link ID to remove + * Returns: 0 on success, -1 on failure + */ + int (*link_remove)(void *priv, enum wpa_driver_if_type type, + const char *ifname, u8 link_id); + + /** + * is_drv_shared - Check whether the driver interface is shared + * @priv: Private driver interface data from init() + * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces + * + * Checks whether the driver interface is being used by other partner + * BSS(s) or not. This is used to decide whether the driver interface + * needs to be deinitilized when one interface is getting deinitialized. + * + * Returns: true if it is being used or else false. + */ + bool (*is_drv_shared)(void *priv, void *bss_ctx); + + /** + * link_sta_remove - Remove a link STA from an MLD STA + * @priv: Private driver interface data + * @link_id: The link ID which the link STA is using + * @addr: The MLD MAC address of the MLD STA + * Returns: 0 on success, negative value on failure + */ + int (*link_sta_remove)(void *priv, u8 link_id, const u8 *addr); + +#ifdef CONFIG_TESTING_OPTIONS + int (*register_frame)(void *priv, u16 type, + const u8 *match, size_t match_len, + bool multicast); +#endif /* CONFIG_TESTING_OPTIONS */ }; /** @@ -4772,7 +5300,7 @@ enum wpa_event_type { * This event must be delivered when a Michael MIC error is detected by * the local driver. Additional data for event processing is * provided with union wpa_event_data::michael_mic_failure. This - * information is used to request new encyption key and to initiate + * information is used to request new encryption key and to initiate * TKIP countermeasures if needed. */ EVENT_MICHAEL_MIC_FAILURE, @@ -5293,7 +5821,42 @@ enum wpa_event_type { * is required to provide more details of the frame. */ EVENT_UNPROT_BEACON, -#ifdef CONFIG_MLD_PATCH + + /** + * EVENT_TX_WAIT_EXPIRE - TX wait timed out + * + * This event is used to indicate when the driver has completed + * wait for a response frame based on a TX request that specified a + * non-zero wait time and that has not been explicitly cancelled. + */ + EVENT_TX_WAIT_EXPIRE, + + /** + * EVENT_BSS_COLOR_COLLISION - Notification of a BSS color collision + */ + EVENT_BSS_COLOR_COLLISION, + + /** + * EVENT_CCA_STARTED_NOTIFY - Notification that CCA has started + */ + EVENT_CCA_STARTED_NOTIFY, + + /** + * EVENT_CCA_ABORTED_NOTIFY - Notification that CCA has aborted + */ + EVENT_CCA_ABORTED_NOTIFY, + + /** + * EVENT_CCA_NOTIFY - Notification that CCA has completed + */ + EVENT_CCA_NOTIFY, + + /** + * EVENT_PASN_AUTH - This event is used by the driver that requests + * PASN authentication and secure ranging context for multiple peers. + */ + EVENT_PASN_AUTH, + /** * EVENT_LINK_CH_SWITCH - MLD AP link decided to switch channels * @@ -5312,6 +5875,21 @@ enum wpa_event_type { */ EVENT_LINK_CH_SWITCH_STARTED, + /** + * EVENT_TID_LINK_MAP - MLD event to set TID-to-link mapping + * + * This event is used by the driver to indicate the received TID-to-link + * mapping response from the associated AP MLD. + * + * Described in wpa_event_data.t2l_map_info. + */ + EVENT_TID_LINK_MAP, + + /** + * EVENT_LINK_RECONFIG - Notification that AP links removed + */ + EVENT_LINK_RECONFIG, +#ifdef CONFIG_MLD_PATCH /** * EVENT_LINK_SWITCH - MLD AP link switch to another link */ @@ -5573,6 +6151,17 @@ union wpa_event_data { * fils_pmkid - PMKID used or generated in FILS authentication */ const u8 *fils_pmkid; + + /** + * link_addr - Link address of the STA + */ + const u8 *link_addr; + + /** + * assoc_link_id - Association link id of the MLO association or + * -1 if MLO is not used + */ + int assoc_link_id; } assoc_info; /** @@ -5808,6 +6397,7 @@ union wpa_event_data { const u8 *data; size_t data_len; int ack; + int link_id; } tx_status; /** @@ -5836,6 +6426,14 @@ union wpa_event_data { */ void *drv_priv; + /** + * ctx - Pointer to store ctx of private BSS information + * + * If not set to NULL, this is used for forwarding the packet + * to right link BSS of ML BSS. + */ + void *ctx; + /** * freq - Frequency (in MHz) on which the frame was received */ @@ -5845,13 +6443,12 @@ union wpa_event_data { * ssi_signal - Signal strength in dBm (or 0 if not available) */ int ssi_signal; -#ifdef CONFIG_MLD_PATCH + /** * link_id - MLO link on which the frame was received or -1 for * non MLD. */ int link_id; -#endif } rx_mgmt; /** @@ -5887,6 +6484,8 @@ union wpa_event_data { * (if available). * @scan_start_tsf_bssid: The BSSID according to which %scan_start_tsf * is set. + * @scan_cookie: Unique identification representing the corresponding + * scan request. 0 if no unique identification is available. */ struct scan_info { int aborted; @@ -5898,6 +6497,7 @@ union wpa_event_data { int nl_scan_event; u64 scan_start_tsf; u8 scan_start_tsf_bssid[ETH_ALEN]; + u64 scan_cookie; } scan_info; /** @@ -5951,6 +6551,8 @@ union wpa_event_data { const u8 *src; const u8 *data; size_t data_len; + enum frame_encryption encrypted; + int link_id; } eapol_rx; /** @@ -6024,6 +6626,7 @@ union wpa_event_data { * @data: Data starting with IEEE 802.1X header (!) * @data_len: Length of data * @ack: Indicates ack or lost frame + * @link_id: MLD link id used to transmit the frame or -1 for non MLO * * This corresponds to hapd_send_eapol if the frame sent * there isn't just reported as EVENT_TX_STATUS. @@ -6033,6 +6636,7 @@ union wpa_event_data { const u8 *data; int data_len; int ack; + int link_id; } eapol_tx_status; /** @@ -6043,6 +6647,8 @@ union wpa_event_data { * @ch_width: Channel width * @cf1: Center frequency 1 * @cf2: Center frequency 2 + * @link_id: Link ID of the MLO link + * @punct_bitmap: Puncturing bitmap */ struct ch_switch { int freq; @@ -6051,10 +6657,8 @@ union wpa_event_data { enum chan_width ch_width; int cf1; int cf2; -#ifdef CONFIG_MLD_PATCH int link_id; u16 punct_bitmap; -#endif } ch_switch; /** @@ -6073,6 +6677,7 @@ union wpa_event_data { /** * struct dfs_event - Data for radar detected events * @freq: Frequency of the channel in MHz + * @link_id: If >= 0, Link ID of the MLO link */ struct dfs_event { int freq; @@ -6081,6 +6686,7 @@ union wpa_event_data { enum chan_width chan_width; int cf1; int cf2; + int link_id; } dfs_event; /** @@ -6099,11 +6705,22 @@ union wpa_event_data { * @initiator: Initiator of the regulatory change * @type: Regulatory change type * @alpha2: Country code (or "" if not available) + * @beacon_hint_before: Data for frequency attributes before beacon hint + * event if initiator == REGDOM_BEACON_HINT + * @beacon_hint_after: Data for frequency attributes after beacon hint + * event if initiator == REGDOM_BEACON_HINT */ struct channel_list_changed { enum reg_change_initiator initiator; enum reg_type type; char alpha2[3]; + struct frequency_attrs { + unsigned int freq; + unsigned int max_tx_power; + bool disabled; + bool no_ir; + bool radar; + } beacon_hint_before, beacon_hint_after; } channel_list_changed; /** @@ -6146,7 +6763,9 @@ union wpa_event_data { * @ch_width: Selected Channel width by driver. Driver may choose to * change hostapd configured ACS channel width due driver internal * channel restrictions. - * hw_mode: Selected band (used with hw_mode=any) + * @hw_mode: Selected band (used with hw_mode=any) + * @puncture_bitmap: Indicate the puncturing channels + * @link_id: Indicate the link id if operating as AP MLD; -1 otherwise */ struct acs_selected_channels { unsigned int pri_freq; @@ -6156,6 +6775,8 @@ union wpa_event_data { u8 vht_seg1_center_ch; u16 ch_width; enum hostapd_hw_mode hw_mode; + u16 puncture_bitmap; + int link_id; } acs_selected_channels; /** @@ -6217,6 +6838,8 @@ union wpa_event_data { const u8 *peer; const u8 *ie; size_t ie_len; + int assoc_link_id; + const u8 *link_addr; } update_dh; /** @@ -6226,6 +6849,45 @@ union wpa_event_data { const u8 *sa; } unprot_beacon; + /** + * struct bss_color_collision - Data for EVENT_BSS_COLOR_COLLISION + */ + struct bss_color_collision { + u64 bitmap; + int link_id; + } bss_color_collision; + + /** + * struct pasn_auth - Data for EVENT_PASN_AUTH + */ + struct pasn_auth pasn_auth; + + /** + * struct port_authorized - Data for EVENT_PORT_AUTHORIZED + * @td_bitmap: For STA mode, transition disable bitmap, if received in + * EAPOL-Key msg 3/4 + * @td_bitmap_len: For STA mode, length of td_bitmap + * @sta_addr: For AP mode, the MAC address of the associated STA + * + * This event is used to indicate that the port is authorized and + * open for normal data in STA and AP modes when 4-way handshake is + * offloaded to the driver. + */ + struct port_authorized { + const u8 *td_bitmap; + size_t td_bitmap_len; + const u8 *sta_addr; + } port_authorized; + + /** + * struct tid_link_map_info - Data for EVENT_TID_LINK_MAP + */ + struct tid_link_map_info { + bool default_map; + u8 valid_links; + struct t2lm_mapping t2lmap[MAX_NUM_MLD_LINKS]; + } t2l_map_info; + #ifdef CONFIG_MLD_PATCH /** * struct mlo_link_switch_event - Data for EVENT_MLO_LINK_SWITCH @@ -6277,15 +6939,21 @@ void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, * event indication for some of the common events. */ -static inline void drv_event_assoc(void *ctx, const u8 *addr, const u8 *ie, - size_t ielen, int reassoc) +static inline void drv_event_assoc(void *ctx, const u8 *addr, const u8 *req_ies, + size_t req_ielen, const u8 *resp_ies, + size_t resp_ielen, const u8 *link_addr, + int assoc_link_id, int reassoc) { union wpa_event_data event; os_memset(&event, 0, sizeof(event)); event.assoc_info.reassoc = reassoc; - event.assoc_info.req_ies = ie; - event.assoc_info.req_ies_len = ielen; + event.assoc_info.req_ies = req_ies; + event.assoc_info.req_ies_len = req_ielen; + event.assoc_info.resp_ies = resp_ies; + event.assoc_info.resp_ies_len = resp_ielen; event.assoc_info.addr = addr; + event.assoc_info.link_addr = link_addr; + event.assoc_info.assoc_link_id = assoc_link_id; wpa_supplicant_event(ctx, EVENT_ASSOC, &event); } @@ -6305,6 +6973,23 @@ static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data, event.eapol_rx.src = src; event.eapol_rx.data = data; event.eapol_rx.data_len = data_len; + event.eapol_rx.encrypted = FRAME_ENCRYPTION_UNKNOWN; + event.eapol_rx.link_id = -1; + wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event); +} + +static inline void drv_event_eapol_rx2(void *ctx, const u8 *src, const u8 *data, + size_t data_len, + enum frame_encryption encrypted, + int link_id) +{ + union wpa_event_data event; + os_memset(&event, 0, sizeof(event)); + event.eapol_rx.src = src; + event.eapol_rx.data = data; + event.eapol_rx.data_len = data_len; + event.eapol_rx.encrypted = encrypted; + event.eapol_rx.link_id = link_id; wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event); } @@ -6321,6 +7006,8 @@ int channel_width_to_int(enum chan_width width); int ht_supported(const struct hostapd_hw_modes *mode); int vht_supported(const struct hostapd_hw_modes *mode); +bool he_supported(const struct hostapd_hw_modes *hw_mode, + enum ieee80211_op_mode op_mode); struct wowlan_triggers * wpa_get_wowlan_triggers(const char *wowlan_triggers, diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_atheros.c b/wpa_supplicant-2.9_standard/src/drivers/driver_atheros.c index 58f58d6dda7fdac798a095008c919c1e807483c8..88d08695696fb28c6b51bcac8c54c44458059ef9 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_atheros.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_atheros.c @@ -17,7 +17,6 @@ #include "eloop.h" #include "common/ieee802_11_defs.h" #include "l2_packet/l2_packet.h" -#include "p2p/p2p.h" #include "common.h" #ifndef _BYTE_ORDER @@ -82,7 +81,7 @@ struct atheros_driver_data { }; static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - u16 reason_code); + u16 reason_code, int link_id); static int atheros_set_privacy(void *priv, int enabled); static const char * athr_get_ioctl_name(int op) @@ -587,7 +586,7 @@ atheros_set_key(void *priv, struct wpa_driver_set_key_params *params) static int atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, - u8 *seq) + int link_id, u8 *seq) { struct atheros_driver_data *drv = priv; struct ieee80211req_key wk; @@ -633,12 +632,12 @@ atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, static int -atheros_flush(void *priv) +atheros_flush(void *priv, int link_id) { u8 allsta[IEEE80211_ADDR_LEN]; os_memset(allsta, 0xff, IEEE80211_ADDR_LEN); return atheros_sta_deauth(priv, NULL, allsta, - IEEE80211_REASON_AUTH_LEAVE); + IEEE80211_REASON_AUTH_LEAVE, -1); } @@ -660,7 +659,7 @@ atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, &stats, sizeof(stats))) { wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr " MACSTR_SEC ")", __func__, MAC2STR_SEC(addr)); - if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { + if (ether_addr_equal(addr, drv->acct_mac)) { os_memcpy(data, &drv->acct_data, sizeof(*data)); return 0; } @@ -757,7 +756,7 @@ atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - u16 reason_code) + u16 reason_code, int link_id) { struct atheros_driver_data *drv = priv; struct ieee80211req_mlme mlme; @@ -893,7 +892,7 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, } if (stype == WLAN_FC_STYPE_ACTION && - (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) == 0 || + (ether_addr_equal(drv->own_addr, mgmt->bssid) || is_broadcast_ether_addr(mgmt->bssid))) { os_memset(&event, 0, sizeof(event)); event.rx_mgmt.frame = buf; @@ -902,7 +901,7 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, return; } - if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) { + if (!ether_addr_equal(drv->own_addr, mgmt->bssid)) { wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore", __func__); return; @@ -914,14 +913,16 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, break; ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); iebuf = mgmt->u.assoc_req.variable; - drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0); + drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, NULL, 0, + NULL, -1, 0); break; case WLAN_FC_STYPE_REASSOC_REQ: if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)) break; ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); iebuf = mgmt->u.reassoc_req.variable; - drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1); + drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, NULL, 0, + NULL, -1, 1); break; case WLAN_FC_STYPE_AUTH: if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) @@ -1223,9 +1224,9 @@ atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) ielen += 2; no_ie: - drv_event_assoc(hapd, addr, iebuf, ielen, 0); + drv_event_assoc(hapd, addr, iebuf, ielen, NULL, 0, NULL, -1, 0); - if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) { + if (ether_addr_equal(addr, drv->acct_mac)) { /* Cached accounting data is not valid anymore. */ os_memset(drv->acct_mac, 0, ETH_ALEN); os_memset(&drv->acct_data, 0, sizeof(drv->acct_data)); @@ -1645,7 +1646,7 @@ atheros_wireless_event_init(struct atheros_driver_data *drv) static int atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, - int encrypt, const u8 *own_addr, u32 flags) + int encrypt, const u8 *own_addr, u32 flags, int link_id) { struct atheros_driver_data *drv = priv; unsigned char buf[3000]; @@ -1965,7 +1966,7 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params) static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, int noack, unsigned int freq, const u16 *csa_offs, size_t csa_offs_len, - int no_encrypt, unsigned int wait) + int no_encrypt, unsigned int wait, int link_id) { struct atheros_driver_data *drv = priv; u8 buf[1510]; diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_bsd.c b/wpa_supplicant-2.9_standard/src/drivers/driver_bsd.c index df1430f8e3599db65e8e2ce1cadfb6717b3794ee..5ca338947583d36ffb329f34fd82c1bb00cab5f2 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_bsd.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_bsd.c @@ -553,12 +553,12 @@ bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN]) ielen += 2; no_ie: - drv_event_assoc(ctx, addr, iebuf, ielen, 0); + drv_event_assoc(ctx, addr, iebuf, ielen, NULL, 0, NULL, -1, 0); } static int bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, - int encrypt, const u8 *own_addr, u32 flags) + int encrypt, const u8 *own_addr, u32 flags, int link_id) { struct bsd_driver_data *drv = priv; @@ -882,7 +882,7 @@ bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) #undef WPA_OUI_TYPE static int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - u16 reason_code); + u16 reason_code, int link_id); static const char * ether_sprintf(const u8 *addr) @@ -906,7 +906,7 @@ bsd_set_privacy(void *priv, int enabled) static int bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, - u8 *seq) + int link_id, u8 *seq) { struct ieee80211req_key wk; @@ -946,12 +946,13 @@ bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, static int -bsd_flush(void *priv) +bsd_flush(void *priv, int link_id) { u8 allsta[IEEE80211_ADDR_LEN]; memset(allsta, 0xff, IEEE80211_ADDR_LEN); - return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE); + return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE, + -1); } @@ -974,7 +975,8 @@ bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, } static int -bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, u16 reason_code) +bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, u16 reason_code, + int link_id) { return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, addr); diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_common.c b/wpa_supplicant-2.9_standard/src/drivers/driver_common.c index 0fac15de86bfb8182508e19d303547846d3ceb0d..23397739c73a52a0079f2cf6216fc2ef33acaa0b 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_common.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_common.c @@ -90,11 +90,19 @@ const char * event_to_string(enum wpa_event_type event) E2S(WDS_STA_INTERFACE_STATUS); E2S(UPDATE_DH); E2S(UNPROT_BEACON); -#ifdef CONFIG_MLD_PATCH + E2S(TX_WAIT_EXPIRE); + E2S(BSS_COLOR_COLLISION); + E2S(CCA_STARTED_NOTIFY); + E2S(CCA_ABORTED_NOTIFY); + E2S(CCA_NOTIFY); + E2S(PASN_AUTH); E2S(LINK_CH_SWITCH); E2S(LINK_CH_SWITCH_STARTED); + E2S(TID_LINK_MAP); + E2S(LINK_RECONFIG); +#ifdef CONFIG_MLD_PATCH E2S(MLO_LINK_SWITCH); -#endif +#endif E2S(MLO_WORK_STATE); } @@ -118,6 +126,8 @@ const char * channel_width_to_string(enum chan_width width) return "80+80 MHz"; case CHAN_WIDTH_160: return "160 MHz"; + case CHAN_WIDTH_320: + return "320 MHz"; default: return "unknown"; } @@ -137,6 +147,8 @@ int channel_width_to_int(enum chan_width width) case CHAN_WIDTH_80P80: case CHAN_WIDTH_160: return 160; + case CHAN_WIDTH_320: + return 320; default: return 0; } @@ -179,6 +191,21 @@ int vht_supported(const struct hostapd_hw_modes *mode) } +bool he_supported(const struct hostapd_hw_modes *hw_mode, + enum ieee80211_op_mode op_mode) +{ + if (!(hw_mode->flags & HOSTAPD_MODE_FLAG_HE_INFO_KNOWN)) { + /* + * The driver did not indicate whether it supports HE. Assume + * it does to avoid connection issues. + */ + return true; + } + + return hw_mode->he_capab[op_mode].he_supported; +} + + static int wpa_check_wowlan_trigger(const char *start, const char *trigger, int capa_trigger, u8 *param_trigger) { @@ -335,6 +362,21 @@ const char * driver_flag2_to_string(u64 flag2) switch (flag2) { DF2S(CONTROL_PORT_RX); DF2S(CONTROL_PORT_TX_STATUS); + DF2S(SEC_LTF_AP); + DF2S(SEC_RTT_AP); + DF2S(PROT_RANGE_NEG_AP); + DF2S(BEACON_RATE_HE); + DF2S(BEACON_PROTECTION_CLIENT); + DF2S(OCV); + DF2S(AP_SME); + DF2S(SA_QUERY_OFFLOAD_AP); + DF2S(RADAR_BACKGROUND); + DF2S(SEC_LTF_STA); + DF2S(SEC_RTT_STA); + DF2S(PROT_RANGE_NEG_STA); + DF2S(MLO); + DF2S(SCAN_MIN_PREQ); + DF2S(SAE_OFFLOAD_STA); } return "UNKNOWN"; #undef DF2S diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_hostap.c b/wpa_supplicant-2.9_standard/src/drivers/driver_hostap.c index b9c42e4db48da734333d0e0b9943ffd87edc5f4f..3aa5860bc433eacaccd002bcc549e09ec924ff96 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_hostap.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_hostap.c @@ -264,7 +264,7 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr) static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack, unsigned int freq, const u16 *csa_offs, size_t csa_offs_len, - int no_encrypt, unsigned int wait) + int no_encrypt, unsigned int wait, int link_id) { struct hostap_driver_data *drv = priv; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg; @@ -281,7 +281,7 @@ static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack, static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, const u8 *own_addr, - u32 flags) + u32 flags, int link_id) { struct hostap_driver_data *drv = priv; struct ieee80211_hdr *hdr; @@ -313,7 +313,7 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, pos += 2; memcpy(pos, data, data_len); - res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0, 0, 0); + res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0, 0, 0, -1); if (res < 0) { wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - " "failed: %d (%s)", @@ -459,7 +459,7 @@ static int wpa_driver_hostap_set_key(void *priv, static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr, - int idx, u8 *seq) + int idx, int link_id, u8 *seq) { struct hostap_driver_data *drv = priv; struct prism2_hostapd_param *param; @@ -572,7 +572,7 @@ static int hostap_set_ssid(void *priv, const u8 *buf, int len) } -static int hostap_flush(void *priv) +static int hostap_flush(void *priv, int link_id) { struct hostap_driver_data *drv = priv; struct prism2_hostapd_param param; @@ -1032,7 +1032,7 @@ static void hostap_driver_deinit(void *priv) static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - u16 reason) + u16 reason, int link_id) { struct hostap_driver_data *drv = priv; struct ieee80211_mgmt mgmt; @@ -1055,7 +1055,7 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.deauth.reason_code = host_to_le16(reason); return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), 0, 0, NULL, 0, 0, 0); + sizeof(mgmt.u.deauth), 0, 0, NULL, 0, 0, 0, -1); } @@ -1093,7 +1093,8 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.disassoc.reason_code = host_to_le16(reason); return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc), 0, 0, NULL, 0, 0, 0); + sizeof(mgmt.u.disassoc), 0, 0, NULL, 0, 0, 0, + -1); } @@ -1173,7 +1174,8 @@ static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr, os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); - hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0, 0, 0); + hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0, 0, 0, + -1); } diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_macsec_linux.c b/wpa_supplicant-2.9_standard/src/drivers/driver_macsec_linux.c index 3605156a796aad4756c27c24132c3ada76bc4cec..7f5e8fed46abe3a886208e35965ac90709748f29 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_macsec_linux.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_macsec_linux.c @@ -32,6 +32,10 @@ #define UNUSED_SCI 0xffffffffffffffff +#if LIBNL_VER_NUM >= LIBNL_VER(3, 6) +#define LIBNL_HAS_OFFLOAD +#endif + struct cb_arg { struct macsec_drv_data *drv; u32 *pn; @@ -73,10 +77,18 @@ struct macsec_drv_data { bool replay_protect; bool replay_protect_set; +#ifdef LIBNL_HAS_OFFLOAD + enum macsec_offload offload; + bool offload_set; +#endif /* LIBNL_HAS_OFFLOAD */ + u32 replay_window; u8 encoding_sa; bool encoding_sa_set; + + u64 cipher_suite; + bool cipher_suite_set; }; @@ -225,6 +237,15 @@ static int try_commit(struct macsec_drv_data *drv) drv->replay_window); } +#ifdef LIBNL_HAS_OFFLOAD + if (drv->offload_set) { + wpa_printf(MSG_DEBUG, DRV_PREFIX + "%s: try_commit offload=%d", + drv->ifname, drv->offload); + rtnl_link_macsec_set_offload(drv->link, drv->offload); + } +#endif /* LIBNL_HAS_OFFLOAD */ + if (drv->encoding_sa_set) { wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: try_commit encoding_sa=%d", @@ -452,6 +473,36 @@ static int macsec_drv_set_replay_protect(void *priv, bool enabled, } +/** + * macsec_drv_set_offload - Set offload status + * @priv: Private driver interface data + * @offload: 0 = MACSEC_OFFLOAD_OFF + * 1 = MACSEC_OFFLOAD_PHY + * 2 = MACSEC_OFFLOAD_MAC + * Returns: 0 on success, -1 on failure (or if not supported) + */ +static int macsec_drv_set_offload(void *priv, u8 offload) +{ +#ifdef LIBNL_HAS_OFFLOAD + struct macsec_drv_data *drv = priv; + + wpa_printf(MSG_DEBUG, "%s -> %02" PRIx8, __func__, offload); + + drv->offload_set = true; + drv->offload = offload; + + return try_commit(drv); +#else /* LIBNL_HAS_OFFLOAD */ + if (offload == 0) + return 0; + wpa_printf(MSG_INFO, + "%s: libnl version does not include support for MACsec offload", + __func__); + return -1; +#endif /* LIBNL_HAS_OFFLOAD */ +} + + /** * macsec_drv_set_current_cipher_suite - Set current cipher suite * @priv: Private driver interface data @@ -460,8 +511,14 @@ static int macsec_drv_set_replay_protect(void *priv, bool enabled, */ static int macsec_drv_set_current_cipher_suite(void *priv, u64 cs) { + struct macsec_drv_data *drv = priv; + wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs); - return 0; + + drv->cipher_suite_set = true; + drv->cipher_suite = cs; + + return try_commit(drv); } @@ -1063,7 +1120,8 @@ static int macsec_drv_disable_receive_sa(void *priv, struct receive_sa *sa) } -static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci) +static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci, + u64 cs) { struct rtnl_link *needle; void *match; @@ -1074,6 +1132,8 @@ static struct rtnl_link * lookup_sc(struct nl_cache *cache, int parent, u64 sci) rtnl_link_set_link(needle, parent); rtnl_link_macsec_set_sci(needle, sci); + if (cs) + rtnl_link_macsec_set_cipher_suite(needle, cs); match = nl_cache_find(cache, (struct nl_object *) needle); rtnl_link_put(needle); @@ -1098,6 +1158,7 @@ static int macsec_drv_create_transmit_sc( char *ifname; u64 sci; int err; + u64 cs = 0; wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: create_transmit_sc -> " SCISTR " (conf_offset=%d)", @@ -1122,6 +1183,12 @@ static int macsec_drv_create_transmit_sc( drv->created_link = true; + if (drv->cipher_suite_set) { + cs = drv->cipher_suite; + drv->cipher_suite_set = false; + rtnl_link_macsec_set_cipher_suite(link, cs); + } + err = rtnl_link_add(drv->sk, link, NLM_F_CREATE); if (err == -NLE_BUSY) { wpa_printf(MSG_INFO, @@ -1137,7 +1204,7 @@ static int macsec_drv_create_transmit_sc( rtnl_link_put(link); nl_cache_refill(drv->sk, drv->link_cache); - link = lookup_sc(drv->link_cache, drv->parent_ifi, sci); + link = lookup_sc(drv->link_cache, drv->parent_ifi, sci, cs); if (!link) { wpa_printf(MSG_ERROR, DRV_PREFIX "couldn't find link"); return -1; @@ -1573,7 +1640,7 @@ static void macsec_drv_hapd_deinit(void *priv) static int macsec_drv_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr, u32 flags) + const u8 *own_addr, u32 flags, int link_id) { struct macsec_drv_data *drv = priv; struct ieee8023_hdr *hdr; @@ -1629,6 +1696,7 @@ const struct wpa_driver_ops wpa_driver_macsec_linux_ops = { .enable_protect_frames = macsec_drv_enable_protect_frames, .enable_encrypt = macsec_drv_enable_encrypt, .set_replay_protect = macsec_drv_set_replay_protect, + .set_offload = macsec_drv_set_offload, .set_current_cipher_suite = macsec_drv_set_current_cipher_suite, .enable_controlled_port = macsec_drv_enable_controlled_port, .get_receive_lowest_pn = macsec_drv_get_receive_lowest_pn, diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_macsec_qca.c b/wpa_supplicant-2.9_standard/src/drivers/driver_macsec_qca.c index 54964f37e3ed58aa5b87ee09d71b1d13d265a943..58c48c2f5e0d3bbf9cc6975ccc3aa6ffedf43976 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_macsec_qca.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_macsec_qca.c @@ -366,7 +366,7 @@ static void macsec_qca_hapd_deinit(void *priv) static int macsec_qca_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr, u32 flags) + const u8 *own_addr, u32 flags, int link_id) { struct macsec_qca_data *drv = priv; struct ieee8023_hdr *hdr; @@ -861,7 +861,7 @@ static int macsec_qca_get_available_transmit_sc(void *priv, u32 *channel) } } - wpa_printf(MSG_DEBUG, "%s: no avaiable channel", __func__); + wpa_printf(MSG_DEBUG, "%s: no available channel", __func__); return -1; } diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_ndis.c b/wpa_supplicant-2.9_standard/src/drivers/driver_ndis.c index ed05a1c228f503edb37ee96bb2edd79f658f521b..7a30fe46336440c51e12254c524a2e36bf039b8a 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_ndis.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_ndis.c @@ -1248,7 +1248,7 @@ static int wpa_driver_ndis_add_pmkid(void *priv, prev = NULL; entry = drv->pmkid; while (entry) { - if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0) + if (ether_addr_equal(entry->bssid, bssid)) break; prev = entry; entry = entry->next; @@ -1293,7 +1293,7 @@ static int wpa_driver_ndis_remove_pmkid(void *priv, entry = drv->pmkid; prev = NULL; while (entry) { - if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 && + if (ether_addr_equal(entry->bssid, bssid) && os_memcmp(entry->pmkid, pmkid, 16) == 0) { if (prev) prev->next = entry->next; @@ -1434,7 +1434,7 @@ static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv) pos = (char *) &b->Bssid[0]; for (i = 0; i < b->NumberOfItems; i++) { NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos; - if (os_memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 && + if (ether_addr_equal(drv->bssid, bss->MacAddress) && bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) { data.assoc_info.beacon_ies = ((u8 *) bss->IEs) + @@ -1477,7 +1477,7 @@ static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx) } } else { /* Connected */ - if (os_memcmp(drv->bssid, bssid, ETH_ALEN) != 0) { + if (!ether_addr_equal(drv->bssid, bssid)) { os_memcpy(drv->bssid, bssid, ETH_ALEN); wpa_driver_ndis_get_associnfo(drv); wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211.c b/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211.c index a63ef7d7c60a4551d09e027960d7bf8bbc1dbfc5..d9fef03e8afd86fcbdbbc5fdf6a3d962e16d83da 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211.c @@ -12,13 +12,12 @@ #include "includes.h" #include +#include #include #include #include #include -#ifdef CONFIG_LIBNL3_ROUTE -#include -#endif /* CONFIG_LIBNL3_ROUTE */ +#include #include #include #include @@ -31,6 +30,8 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_common.h" +#include "crypto/sha256.h" +#include "crypto/sha384.h" #include "netlink.h" #include "linux_defines.h" #include "linux_ioctl.h" @@ -42,7 +43,6 @@ #include "vendor_ext.h" #endif - #ifndef NETLINK_CAP_ACK #define NETLINK_CAP_ACK 10 #endif /* NETLINK_CAP_ACK */ @@ -179,9 +179,9 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, static int nl80211_send_frame_cmd(struct i802_bss *bss, unsigned int freq, unsigned int wait, const u8 *buf, size_t buf_len, - int save_cookie, - int no_cck, int no_ack, int offchanok, - const u16 *csa_offs, size_t csa_offs_len); + int save_cookie, int no_cck, int no_ack, + int offchanok, const u16 *csa_offs, + size_t csa_offs_len, int link_id); static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report); @@ -204,6 +204,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv, static int i802_set_iface_flags(struct i802_bss *bss, int up); static int nl80211_set_param(void *priv, const char *param); +static void nl80211_remove_links(struct i802_bss *bss); #ifdef CONFIG_MESH static int nl80211_put_mesh_config(struct nl_msg *msg, struct wpa_driver_mesh_bss_params *params); @@ -228,8 +229,11 @@ enum chan_width convert2width(int width) return CHAN_WIDTH_80P80; case NL80211_CHAN_WIDTH_160: return CHAN_WIDTH_160; + case NL80211_CHAN_WIDTH_320: + return CHAN_WIDTH_320; + default: + return CHAN_WIDTH_UNKNOWN; } - return CHAN_WIDTH_UNKNOWN; } @@ -279,16 +283,21 @@ void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv) if (drv->associated) os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN); drv->associated = 0; -#ifdef CONFIG_MLD_PATCH os_memset(&drv->sta_mlo_info, 0, sizeof(drv->sta_mlo_info)); -#endif os_memset(drv->bssid, 0, ETH_ALEN); - drv->first_bss->freq = 0; -#ifdef CONFIG_MLD_PATCH + drv->first_bss->flink->freq = 0; +#ifdef CONFIG_DRIVER_NL80211_QCA + os_free(drv->pending_roam_data); + drv->pending_roam_data = NULL; + os_free(drv->pending_t2lm_data); + drv->pending_t2lm_data = NULL; + os_free(drv->pending_link_reconfig_data); + drv->pending_link_reconfig_data = NULL; +#endif /* CONFIG_DRIVER_NL80211_QCA */ + drv->auth_mld = false; drv->auth_mld_link_id = -1; os_memset(drv->auth_ap_mld_addr, 0, ETH_ALEN); -#endif } @@ -344,17 +353,29 @@ static int finish_handler(struct nl_msg *msg, void *arg) return NL_SKIP; } +struct nl80211_ack_err_args { + int err; + struct nl_msg *orig_msg; + struct nl80211_err_info *err_info; +}; + static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) { + struct nl80211_ack_err_args *err_args = arg; struct nlmsghdr *nlh = (struct nlmsghdr *) err - 1; + struct nlmsghdr *orig_nlh = nlmsg_hdr(err_args->orig_msg); int len = nlh->nlmsg_len; struct nlattr *attrs; struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; - int *ret = arg; int ack_len = sizeof(*nlh) + sizeof(int) + sizeof(*nlh); + struct nlattr *mlo_links, *link_attr; + u32 offset; + int rem; - *ret = err->error; + err_args->err = err->error; + if (err_args->err_info) + err_args->err_info->link_id = -1; if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS)) return NL_SKIP; @@ -376,6 +397,41 @@ static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG])); } + if (!err_args->err_info) + return NL_SKIP; + + /* Check if it was a per-link error report */ + + if (!tb[NLMSGERR_ATTR_OFFS] || + os_memcmp(orig_nlh, &err->msg, sizeof(err->msg)) != 0) + return NL_SKIP; + + offset = nla_get_u32(tb[NLMSGERR_ATTR_OFFS]); + + mlo_links = nlmsg_find_attr(orig_nlh, GENL_HDRLEN, + NL80211_ATTR_MLO_LINKS); + if (!mlo_links) + return NL_SKIP; + + nla_for_each_nested(link_attr, mlo_links, rem) { + struct nlattr *link_id; + size_t link_offset = (u8 *) link_attr - (u8 *) orig_nlh; + + if (offset < link_offset || + offset >= link_offset + link_attr->nla_len) + continue; + + link_id = nla_find(nla_data(link_attr), nla_len(link_attr), + NL80211_ATTR_MLO_LINK_ID); + if (link_id) { + err_args->err_info->link_id = nla_get_u8(link_id); + wpa_printf(MSG_DEBUG, + "nl80211: kernel reports error for link: %d", + err_args->err_info->link_id); + break; + } + } + return NL_SKIP; } @@ -408,15 +464,52 @@ 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, - int (*ack_handler_custom)(struct nl_msg *, void *), - void *ack_data) +static int send_event_marker(struct wpa_driver_nl80211_data *drv) +{ + struct nl_sock *handle; + struct nl_msg *msg; + struct nlmsghdr *hdr; + int res = 0; + int err = -NLE_NOMEM; + + msg = nlmsg_alloc(); + if (!msg) + goto out; + + /* We only care about the returned sequence number for matching. */ + if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES)) + goto out; + + handle = (void *) (((intptr_t) drv->global->nl_event) ^ + ELOOP_SOCKET_INVALID); + + err = nl_send_auto_complete(handle, msg); + if (err < 0) + goto out; + + hdr = nlmsg_hdr(msg); + res = hdr->nlmsg_seq; + +out: + nlmsg_free(msg); + if (err) + wpa_printf(MSG_INFO, "nl80211: %s failed: %s", + __func__, nl_geterror(err)); + return res; +} + + +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, + int (*ack_handler_custom)(struct nl_msg *, void *), + void *ack_data, + struct nl80211_err_info *err_info) { - struct nl_cb *cb; - int err = -ENOMEM, opt; + struct nl_cb *cb, *s_nl_cb; + struct nl80211_ack_err_args err; + int opt; #ifdef OPEN_HARMONY_MIRACAST_SINK_OPT int recv_count = 0; @@ -425,7 +518,11 @@ static int send_and_recv(struct nl80211_global *global, if (!msg) return -ENOMEM; - cb = nl_cb_clone(global->nl_cb); + err.err = -ENOMEM; + + s_nl_cb = nl_socket_get_cb(nl_handle); + cb = nl_cb_clone(s_nl_cb); + nl_cb_put(s_nl_cb); if (!cb) goto out; @@ -439,26 +536,28 @@ static int send_and_recv(struct nl80211_global *global, setsockopt(nl_socket_get_fd(nl_handle), SOL_NETLINK, NETLINK_CAP_ACK, &opt, sizeof(opt)); - err = nl_send_auto_complete(nl_handle, msg); - if (err < 0) { + err.err = nl_send_auto_complete(nl_handle, msg); + if (err.err < 0) { wpa_printf(MSG_INFO, "nl80211: nl_send_auto_complete() failed: %s", - nl_geterror(err)); + nl_geterror(err.err)); /* Need to convert libnl error code to an errno value. For now, * just hardcode this to EBADF; the real error reason is shown * in that error print above. */ - err = -EBADF; + err.err = -EBADF; goto out; } - err = 1; + err.err = 1; + err.orig_msg = msg; + err.err_info = err_info; 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_FINISH, NL_CB_CUSTOM, finish_handler, &err.err); if (ack_handler_custom) { struct nl80211_ack_ext_arg *ext_arg = ack_data; - ext_arg->err = &err; + ext_arg->err = &err.err; nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_custom, ack_data); } else { @@ -469,7 +568,7 @@ static int send_and_recv(struct nl80211_global *global, nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data); - while (err > 0) { + while (err.err > 0) { int res = nl_recvmsgs(nl_handle, cb); if (res == -NLE_DUMP_INTR) { @@ -484,7 +583,7 @@ static int send_and_recv(struct nl80211_global *global, * will stop and return an error. */ wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN", nl_geterror(res)); - err = -EAGAIN; + err.err = -EAGAIN; } else if (res < 0) { wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d (%s)", @@ -506,94 +605,20 @@ static int send_and_recv(struct nl80211_global *global, /* Always clear the message as it can potentially contain keys */ nl80211_nlmsg_clear(msg); nlmsg_free(msg); - return err; -} - - -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, - 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, - ack_handler_custom, ack_data); + return err.err; } -/* Use this method to mark that it is necessary to own the connection/interface - * for this operation. - * handle may be set to NULL, to get the same behavior as send_and_recv_msgs(). - * set_owner can be used to mark this socket for receiving control port frames. - */ -static int send_and_recv_msgs_owner(struct wpa_driver_nl80211_data *drv, - struct nl_msg *msg, - struct nl_sock *handle, int set_owner, - int (*valid_handler)(struct nl_msg *, - void *), - void *valid_data, - int (*ack_handler_custom)(struct nl_msg *, - void *), - void *ack_data) +static int nl80211_put_control_port(struct wpa_driver_nl80211_data *drv, + struct nl_msg *msg) { - 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: - * validate_pae_over_nl80211(...) - * or final checks like: - * dev->ieee80211_ptr->conn_owner_nlportid != info->snd_portid - * - * Final operations (e.g., disassociate) don't need to set these - * attributes, but they have to be performed on the socket, which has - * the connection owner property set in the kernel. - */ - if ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) && - handle && set_owner && - (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) || - nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER) || - nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) || - nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH))) + if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT) || + nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) || + ((drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) && + (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_OVER_NL80211) || + nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_PREAUTH)))) return -1; - - return send_and_recv(drv->global, handle ? handle : drv->global->nl, - msg, valid_handler, valid_data, - ack_handler_custom, ack_data); -} - - -static int -send_and_recv_msgs_connect_handle(struct wpa_driver_nl80211_data *drv, - struct nl_msg *msg, struct i802_bss *bss, - int set_owner) -{ - struct nl_sock *nl_connect = get_connect_handle(bss); - - if (nl_connect) - return send_and_recv_msgs_owner(drv, msg, nl_connect, set_owner, - process_bss_event, bss, NULL, - NULL); - else - return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); -} - - -struct nl_sock * get_connect_handle(struct i802_bss *bss) -{ - if ((bss->drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) || - bss->use_nl_connect) { -#ifdef CONFIG_VENDOR_EXT - return wpa_vendor_ext_get_connec_handle(bss); -#else - return bss->nl_connect; -#endif - } - - return NULL; + return 0; } @@ -652,7 +677,7 @@ static int nl_get_multicast_id(struct nl80211_global *global, } ret = send_and_recv(global, global->nl, msg, family_handler, &res, - NULL, NULL); + NULL, NULL, NULL); if (ret == 0) ret = res.id; return ret; @@ -780,8 +805,7 @@ 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, - NULL, NULL) == 0) + if (send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data) == 0) return data.wiphy_idx; return -1; } @@ -804,8 +828,7 @@ 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, - NULL, NULL) == 0) + if (send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data) == 0) return data.nlmode; return NL80211_IFTYPE_UNSPECIFIED; } @@ -821,8 +844,7 @@ 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, - NULL, NULL); + return send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data); } @@ -834,8 +856,7 @@ static int nl80211_get_4addr(struct i802_bss *bss) }; if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)) || - send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data, - NULL, NULL)) + send_and_recv_resp(bss->drv, msg, netdev_info_handler, &data)) return -1; return data.use_4addr; } @@ -858,7 +879,7 @@ static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv, } ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL, - NULL, NULL); + NULL, NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Register beacons command " "failed: ret=%d (%s)", @@ -943,7 +964,7 @@ nl80211_get_wiphy_data_ap(struct i802_bss *bss) dl_list_init(&w->drvs); /* Beacon frames not supported in IEEE 802.11ad */ - if (ieee80211_freq_to_chan(bss->freq, &channel) != + if (ieee80211_freq_to_chan(bss->flink->freq, &channel) != HOSTAPD_MODE_IEEE80211AD) { w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); if (!w->nl_cb) { @@ -1056,7 +1077,7 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid) return drv->ssid_len; } -#ifdef CONFIG_MLD_PATCH + static int get_mlo_info(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; @@ -1101,6 +1122,7 @@ static int get_mlo_info(struct nl_msg *msg, void *arg) return NL_SKIP; } + static int nl80211_get_sta_mlo_info(void *priv, struct driver_sta_mlo_info *mlo_info) { @@ -1114,15 +1136,15 @@ static int nl80211_get_sta_mlo_info(void *priv, struct nl_msg *msg; msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE); - if (send_and_recv_msgs(drv, msg, get_mlo_info, - &drv->sta_mlo_info, NULL, NULL)) + if (send_and_recv_resp(drv, msg, get_mlo_info, + &drv->sta_mlo_info)) return -1; } os_memcpy(mlo_info, &drv->sta_mlo_info, sizeof(*mlo_info)); return 0; } -#endif + static void wpa_driver_nl80211_event_newlink( struct nl80211_global *global, struct wpa_driver_nl80211_data *drv, @@ -1272,12 +1294,13 @@ static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: %s: failed to re-read MAC address", bss->ifname); - } else if (bss && os_memcmp(addr, bss->addr, ETH_ALEN) != 0) { + } else if (bss && !ether_addr_equal(addr, bss->addr)) { wpa_printf(MSG_DEBUG, "nl80211: Own MAC address on ifindex %d (%s) changed from " MACSTR_SEC " to " MACSTR_SEC, ifindex, bss->ifname, MAC2STR_SEC(bss->addr), MAC2STR_SEC(addr)); + os_memcpy(bss->prev_addr, bss->addr, ETH_ALEN); os_memcpy(bss->addr, addr, ETH_ALEN); if (notify) wpa_supplicant_event(drv->ctx, @@ -1546,10 +1569,8 @@ struct nl80211_get_assoc_freq_arg { u8 assoc_bssid[ETH_ALEN]; u8 assoc_ssid[SSID_MAX_LEN]; u8 assoc_ssid_len; -#ifdef CONFIG_MLD_PATCH u8 bssid[MAX_NUM_MLD_LINKS][ETH_ALEN]; unsigned int freq[MAX_NUM_MLD_LINKS]; -#endif }; static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg) @@ -1562,15 +1583,11 @@ static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg) [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC }, [NL80211_BSS_STATUS] = { .type = NLA_U32 }, -#ifdef CONFIG_MLD_PATCH [NL80211_BSS_MLO_LINK_ID] = { .type = NLA_U8 }, -#endif }; struct nl80211_get_assoc_freq_arg *ctx = arg; enum nl80211_bss_status status; -#ifdef CONFIG_MLD_PATCH struct wpa_driver_nl80211_data *drv = ctx->drv; -#endif nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); @@ -1583,7 +1600,6 @@ static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg) status = nla_get_u32(bss[NL80211_BSS_STATUS]); if (status == NL80211_BSS_STATUS_ASSOCIATED && bss[NL80211_BSS_FREQUENCY]) { -#ifdef CONFIG_MLD_PATCH int link_id = -1; u32 freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); @@ -1603,11 +1619,6 @@ static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg) wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz", ctx->assoc_freq); } -#else - ctx->assoc_freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); -#endif - wpa_printf(MSG_EXCESSIVE, "nl80211: Associated on %u MHz", - ctx->assoc_freq); } if (status == NL80211_BSS_STATUS_IBSS_JOINED && bss[NL80211_BSS_FREQUENCY]) { @@ -1617,7 +1628,6 @@ static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg) } if (status == NL80211_BSS_STATUS_ASSOCIATED && bss[NL80211_BSS_BSSID]) { -#ifdef CONFIG_MLD_PATCH int link_id = -1; const u8 *bssid = nla_data(bss[NL80211_BSS_BSSID]); @@ -1637,12 +1647,7 @@ static int nl80211_get_assoc_freq_handler(struct nl_msg *msg, void *arg) wpa_printf(MSG_DEBUG, "nl80211: Associated with " MACSTR_SEC, MAC2STR_SEC(bssid)); } -#else - os_memcpy(ctx->assoc_bssid, - nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN); -#endif - wpa_printf(MSG_EXCESSIVE, "nl80211: Associated with " - MACSTR_SEC, MAC2STR_SEC(ctx->assoc_bssid)); + } if (status == NL80211_BSS_STATUS_ASSOCIATED && @@ -1674,8 +1679,8 @@ try_again: msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN); os_memset(&arg, 0, sizeof(arg)); arg.drv = drv; - ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler, - &arg, NULL, NULL); + ret = send_and_recv_resp(drv, msg, nl80211_get_assoc_freq_handler, + &arg); if (ret == -EAGAIN) { count++; if (count >= 10) { @@ -1708,8 +1713,8 @@ try_again: msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN); os_memset(&arg, 0, sizeof(arg)); arg.drv = drv; - ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler, - &arg, NULL, NULL); + ret = send_and_recv_resp(drv, msg, nl80211_get_assoc_freq_handler, + &arg); if (ret == -EAGAIN) { count++; if (count >= 10) { @@ -1745,86 +1750,6 @@ try_again: } -static int get_link_signal(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; - static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = { - [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, - [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 }, - [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 }, - }; - struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; - static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { - [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, - [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, - [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, - [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, - }; - struct wpa_signal_info *sig_change = arg; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - if (!tb[NL80211_ATTR_STA_INFO] || - nla_parse_nested(sinfo, NL80211_STA_INFO_MAX, - tb[NL80211_ATTR_STA_INFO], policy)) - return NL_SKIP; - if (!sinfo[NL80211_STA_INFO_SIGNAL]) - return NL_SKIP; - - sig_change->current_signal = - (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]); - - if (sinfo[NL80211_STA_INFO_SIGNAL_AVG]) - sig_change->avg_signal = - (s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]); - else - sig_change->avg_signal = 0; - - if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]) - sig_change->avg_beacon_signal = - (s8) - nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]); - else - sig_change->avg_beacon_signal = 0; - - if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { - if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, - sinfo[NL80211_STA_INFO_TX_BITRATE], - rate_policy)) { - sig_change->current_txrate = 0; - } else { - if (rinfo[NL80211_RATE_INFO_BITRATE]) { - sig_change->current_txrate = - nla_get_u16(rinfo[ - NL80211_RATE_INFO_BITRATE]) * 100; - } - } - } - - return NL_SKIP; -} - - -int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv, - struct wpa_signal_info *sig) -{ - struct nl_msg *msg; - - sig->current_signal = -WPA_INVALID_NOISE; - sig->current_txrate = 0; - - if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) || - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid)) { - nlmsg_free(msg); - return -ENOBUFS; - } - - return send_and_recv_msgs(drv, msg, get_link_signal, sig, NULL, NULL); -} - - static int get_link_noise(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; @@ -1878,8 +1803,7 @@ 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, - NULL, NULL); + return send_and_recv_resp(drv, msg, get_link_noise, sig_change); } @@ -1943,7 +1867,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, NULL, NULL); + return send_and_recv_resp(drv, msg, get_channel_info, ci); } @@ -1992,7 +1916,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, NULL, NULL)) + if (send_and_recv_cmd(drv, msg)) return -EINVAL; return 0; } @@ -2027,9 +1951,18 @@ static int wpa_driver_nl80211_get_country(void *priv, char *alpha2) return -ENOMEM; nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG); + + if (drv->capa.flags & WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY) { + /* put wiphy idx to get the interface specific country code + * instead of the global one. */ + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, drv->wiphy_idx)) { + nlmsg_free(msg); + return -1; + } + } + alpha2[0] = '\0'; - ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2, - NULL, NULL); + ret = send_and_recv_resp(drv, msg, nl80211_get_country, alpha2); if (!alpha2[0]) ret = -1; @@ -2039,6 +1972,8 @@ static int wpa_driver_nl80211_get_country(void *priv, char *alpha2) static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) { + struct nl_cache *cache = NULL; + struct genl_family *family = NULL; int ret; global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT); @@ -2110,6 +2045,29 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) /* Continue without vendor events */ } + /* Resolve maxattr for kernel support checks */ + ret = genl_ctrl_alloc_cache(global->nl, &cache); + if (ret < 0) { + wpa_printf(MSG_DEBUG, + "nl80211: Could not allocate genl cache: %d (%s)", + ret, nl_geterror(ret)); + goto err; + } + + family = genl_ctrl_search(cache, global->nl80211_id); + if (!family) { + wpa_printf(MSG_DEBUG, + "nl80211: Could not get nl80211 family from cache: %d (%s)", + ret, nl_geterror(ret)); + goto err; + } + + global->nl80211_maxattr = genl_family_get_maxattr(family); + wpa_printf(MSG_DEBUG, "nl80211: Maximum supported attribute ID: %u", + global->nl80211_maxattr); + genl_family_put(family); + nl_cache_free(cache); + nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, @@ -2122,6 +2080,8 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) return 0; err: + genl_family_put(family); + nl_cache_free(cache); nl_destroy_handles(&global->nl_event); nl_destroy_handles(&global->nl); nl_cb_put(global->nl_cb); @@ -2359,9 +2319,27 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, { struct wpa_driver_nl80211_data *drv; struct i802_bss *bss; -#ifdef CONFIG_MLD_PATCH - unsigned int i; -#endif + char path[128], buf[200], *pos; + ssize_t len; + int ret; + + ret = os_snprintf(path, sizeof(path), "/sys/class/net/%s/device/driver", + ifname); + if (!os_snprintf_error(sizeof(path), ret)) { + len = readlink(path, buf, sizeof(buf)); + if (len > 0 && (size_t) len < sizeof(buf)) { + buf[len] = '\0'; + pos = strrchr(buf, '/'); + if (pos) + pos++; + else + pos = buf; + wpa_printf(MSG_DEBUG, + "nl80211: Initialize interface %s (driver: %s)", + ifname, pos); + } + } + if (global_priv == NULL) return NULL; drv = os_zalloc(sizeof(*drv)); @@ -2442,7 +2420,7 @@ skip_wifi_status: dl_list_add(&drv->global->interfaces, &drv->list); drv->in_interface_list = 1; } -#ifdef CONFIG_MLD_PATCH + /* * Use link ID 0 for the single "link" of a non-MLD. */ @@ -2450,9 +2428,6 @@ skip_wifi_status: bss->flink = &bss->links[0]; os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN); - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) - bss->links[i].link_id = NL80211_DRV_LINK_ID_NA; -#endif return bss; failed: @@ -2502,7 +2477,7 @@ static int nl80211_register_frame(struct i802_bss *bss, } ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL, - NULL, NULL); + NULL, NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Register frame command " "failed (type=%u): ret=%d (%s)", @@ -2538,12 +2513,20 @@ static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss) } -static int nl80211_register_action_frame(struct i802_bss *bss, - const u8 *match, size_t match_len) +static int nl80211_register_action_frame2(struct i802_bss *bss, + const u8 *match, size_t match_len, + bool multicast) { u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4); return nl80211_register_frame(bss, bss->nl_mgmt, - type, match, match_len, false); + type, match, match_len, multicast); +} + + +static int nl80211_register_action_frame(struct i802_bss *bss, + const u8 *match, size_t match_len) +{ + return nl80211_register_action_frame2(bss, match, match_len, false); } @@ -2561,7 +2544,6 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) if (nl80211_alloc_mgmt_handle(bss)) return -1; - wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP " "handle %p", bss->nl_mgmt); @@ -2577,8 +2559,7 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) #ifdef CONFIG_PASN /* register for PASN Authentication frames */ - if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) && - nl80211_register_frame(bss, bss->nl_mgmt, type, + if (nl80211_register_frame(bss, bss->nl_mgmt, type, (u8 *) "\x07\x00", 2, false)) ret = -1; #endif /* CONFIG_PASN */ @@ -2626,6 +2607,17 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) 5) < 0) ret = -1; #endif /* CONFIG_P2P */ +#ifdef CONFIG_NAN_USD +#define NAN_PUB_ACTION ((u8 *) "\x04\x09\x50\x6f\x9a\x13") + /* NAN SDF Public Action */ + if (nl80211_register_action_frame2(bss, NAN_PUB_ACTION, 6, true) < 0) { + /* fallback to non-multicast */ + if (nl80211_register_action_frame2(bss, NAN_PUB_ACTION, 6, + false) < 0) + ret = -1; + } +#undef NAN_PUB_ACTION +#endif /* CONFIG_NAN_USD */ #ifdef CONFIG_DPP /* DPP Public Action */ if (nl80211_register_action_frame(bss, @@ -2771,7 +2763,7 @@ static int nl80211_register_spurious_class3(struct i802_bss *bss) msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME); ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL, - NULL, NULL); + NULL, NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 " "failed: ret=%d (%s)", @@ -2925,7 +2917,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, NULL, NULL); + ret = send_and_recv_cmd(bss->drv, msg); wpa_printf(MSG_EXCESSIVE, "nl80211: Delete P2P Device %s (0x%llx): %s", bss->ifname, (long long unsigned int) bss->wdev_id, @@ -2940,7 +2932,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, NULL, NULL); + ret = send_and_recv_cmd(bss->drv, msg); wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s", start ? "Start" : "Stop", @@ -3011,8 +3003,7 @@ 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, - NULL, NULL); + ret = send_and_recv_resp(drv, msg, qca_vendor_test_cmd_handler, drv); wpa_printf(MSG_DEBUG, "nl80211: QCA vendor test command returned %d (%s)", ret, strerror(-ret)); @@ -3053,7 +3044,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, if (driver_params && nl80211_set_param(bss, driver_params) < 0) return -1; - wpa_printf(MSG_INFO, "nl80211: interface %s in phy %s", + wpa_printf(MSG_EXCESSIVE, "nl80211: interface %s in phy %s", bss->ifname, drv->phyname); if (set_addr && @@ -3129,16 +3120,47 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, } -static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss) +static int wpa_driver_nl80211_del_beacon(struct i802_bss *bss, + int link_id) { struct nl_msg *msg; struct wpa_driver_nl80211_data *drv = bss->drv; + struct i802_link *link = nl80211_get_link(bss, link_id); + + if (!link->beacon_set) + return 0; wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)", - drv->ifindex); + bss->ifindex); + link->beacon_set = 0; + link->freq = 0; + 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, NULL, NULL); + msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_BEACON); + if (!msg) + return -ENOBUFS; + + if (link_id != NL80211_DRV_LINK_ID_NA) { + wpa_printf(MSG_DEBUG, + "nl80211: MLD: stop beaconing on link=%u", + link_id); + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) { + nlmsg_free(msg); + return -ENOBUFS; + } + } + + return send_and_recv_cmd(drv, msg); +} + + +static void wpa_driver_nl80211_del_beacon_all(struct i802_bss *bss) +{ + int link_id; + + for_each_link_default(bss->valid_links, link_id, NL80211_DRV_LINK_ID_NA) + wpa_driver_nl80211_del_beacon(bss, link_id); } @@ -3190,8 +3212,10 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss) nl80211_remove_monitor_interface(drv); - if (is_ap_interface(drv->nlmode)) - wpa_driver_nl80211_del_beacon(bss); + if (is_ap_interface(drv->nlmode)) { + wpa_driver_nl80211_del_beacon_all(bss); + nl80211_remove_links(bss); + } if (drv->eapol_sock >= 0) { eloop_unregister_read_sock(drv->eapol_sock); @@ -3259,9 +3283,9 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss) os_free(drv->extended_capa); os_free(drv->extended_capa_mask); - for (i = 0; i < drv->num_iface_ext_capa; i++) { - os_free(drv->iface_ext_capa[i].ext_capa); - os_free(drv->iface_ext_capa[i].ext_capa_mask); + for (i = 0; i < drv->num_iface_capa; i++) { + os_free(drv->iface_capa[i].ext_capa); + os_free(drv->iface_capa[i].ext_capa_mask); } os_free(drv->first_bss); #ifdef CONFIG_DRIVER_NL80211_QCA @@ -3335,9 +3359,9 @@ static u32 wpa_cipher_to_cipher_suite(unsigned int cipher) return RSN_CIPHER_SUITE_WEP40; case WPA_CIPHER_GTK_NOT_USED: return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; + default: + return 0; } - - return 0; } @@ -3381,7 +3405,9 @@ static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[], __AKM(IEEE8021X_SHA256, 802_1X_SHA256); __AKM(PSK_SHA256, PSK_SHA256); __AKM(SAE, SAE); + __AKM(SAE_EXT_KEY, SAE_EXT_KEY); __AKM(FT_SAE, FT_SAE); + __AKM(FT_SAE_EXT_KEY, FT_SAE_EXT_KEY); __AKM(CCKM, CCKM); __AKM(OSEN, OSEN); __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B); @@ -3393,6 +3419,7 @@ static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[], __AKM(OWE, OWE); __AKM(DPP, DPP); __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384); + __AKM(IEEE8021X_SHA384, 802_1X_SHA384); #undef __AKM return num_suites; @@ -3418,7 +3445,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, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Key management set key failed: ret=%d (%s)", @@ -3458,7 +3485,7 @@ static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv, return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Set PMK failed: ret=%d (%s)", ret, strerror(-ret)); @@ -3488,9 +3515,7 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss, size_t key_len = params->key_len; int vlan_id = params->vlan_id; enum key_flag key_flag = params->key_flag; -#ifdef CONFIG_MLD_PATCH int link_id = params->link_id; -#endif /* Ignore for P2P Device */ if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) @@ -3498,9 +3523,10 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss, ifindex = if_nametoindex(ifname); wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d " - "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x", + "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x link_id=%d", __func__, ifindex, ifname, alg, addr, key_idx, set_tx, - (unsigned long) seq_len, (unsigned long) key_len, key_flag); + (unsigned long) seq_len, (unsigned long) key_len, key_flag, + link_id); if (check_key_flag(key_flag)) { wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__); @@ -3634,14 +3660,14 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss, if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) goto fail; } -#ifdef CONFIG_MLD_PATCH + if (link_id != -1) { wpa_printf(MSG_DEBUG, "nl80211: Link ID %d", link_id); if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) goto fail; } -#endif - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + + ret = send_and_recv_cmd(drv, msg); if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE) ret = 0; if (ret) @@ -3702,15 +3728,15 @@ static int wpa_driver_nl80211_set_key(struct i802_bss *bss, if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) goto fail; } -#ifdef CONFIG_MLD_PATCH + if (link_id != -1) { wpa_printf(MSG_DEBUG, "nl80211: set_key default - Link ID %d", link_id); if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) goto fail; } -#endif - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + + ret = send_and_recv_cmd(drv, msg); if (ret) wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; err=%d %s", @@ -3828,7 +3854,6 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, { int ret; struct nl_msg *msg; - struct nl_sock *nl_connect = get_connect_handle(bss); if (!(msg = nl80211_drv_msg(drv, 0, cmd)) || nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) || @@ -3839,11 +3864,8 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, return -1; } - if (nl_connect) - ret = send_and_recv(drv->global, nl_connect, msg, - process_bss_event, bss, NULL, NULL); - else - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv(drv->global, bss->nl_connect, msg, + NULL, NULL, NULL, NULL, NULL); if (ret) { wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: MLME command failed reason=%u ret=%d (%s)", @@ -3858,7 +3880,6 @@ static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, struct i802_bss *bss) { int ret; - int drv_associated = drv->associated; wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code); nl80211_mark_disconnected(drv); @@ -3875,7 +3896,8 @@ static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, * For locally generated disconnect, supplicant already generates a * DEAUTH event, so ignore the event from NL80211. */ - drv->ignore_next_local_disconnect = drv_associated && (ret == 0); + if (ret == 0) + drv->ignore_next_local_disconnect = send_event_marker(drv); return ret; } @@ -3886,7 +3908,6 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss, { struct wpa_driver_nl80211_data *drv = bss->drv; int ret; - int drv_associated = drv->associated; if (drv->nlmode == NL80211_IFTYPE_ADHOC) { nl80211_mark_disconnected(drv); @@ -3907,7 +3928,8 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss, * For locally generated deauthenticate, supplicant already generates a * DEAUTH event, so ignore the event from NL80211. */ - drv->ignore_next_local_deauth = drv_associated && (ret == 0); + if (ret == 0) + drv->ignore_next_local_deauth = send_event_marker(drv); return ret; } @@ -3947,6 +3969,15 @@ static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv, } } + if (params->mld && params->ap_mld_addr) { + drv->auth_mld = params->mld; + drv->auth_mld_link_id = params->mld_link_id; + os_memcpy(drv->auth_ap_mld_addr, params->ap_mld_addr, ETH_ALEN); + } else { + drv->auth_mld = false; + drv->auth_mld_link_id = -1; + } + os_free(drv->auth_data); drv->auth_data = NULL; drv->auth_data_len = 0; @@ -4051,6 +4082,7 @@ retry: os_memset(&p, 0, sizeof(p)); p.ifname = bss->ifname; p.alg = WPA_ALG_WEP; + p.link_id = -1; for (i = 0; i < 4; i++) { if (!params->wep_key[i]) continue; @@ -4109,7 +4141,18 @@ retry: goto fail; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + if (params->mld && params->ap_mld_addr) { + wpa_printf(MSG_DEBUG, " * MLD: link_id=%u, MLD addr=" MACSTR, + params->mld_link_id, MAC2STR(params->ap_mld_addr)); + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, + params->mld_link_id) || + nla_put(msg, NL80211_ATTR_MLD_ADDR, ETH_ALEN, + params->ap_mld_addr)) + goto fail; + } + + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) { wpa_dbg(drv->ctx, MSG_DEBUG, @@ -4189,6 +4232,7 @@ int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv) { struct wpa_driver_auth_params params; struct i802_bss *bss = drv->first_bss; + u8 ap_mld_addr[ETH_ALEN]; int i; wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again"); @@ -4212,6 +4256,12 @@ int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv) params.ie_len = drv->auth_ie_len; params.auth_data = drv->auth_data; params.auth_data_len = drv->auth_data_len; + params.mld = drv->auth_mld; + params.mld_link_id = drv->auth_mld_link_id; + if (drv->auth_mld) { + os_memcpy(ap_mld_addr, drv->auth_ap_mld_addr, ETH_ALEN); + params.ap_mld_addr = ap_mld_addr; + } for (i = 0; i < 4; i++) { if (drv->auth_wep_key_len[i]) { @@ -4225,26 +4275,73 @@ int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv) } -static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data, - size_t data_len, int noack, - unsigned int freq, int no_cck, - int offchanok, - unsigned int wait_time, - const u16 *csa_offs, - size_t csa_offs_len, int no_encrypt) +struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id) { - struct wpa_driver_nl80211_data *drv = bss->drv; - struct ieee80211_mgmt *mgmt; - int encrypt = !no_encrypt; - u16 fc; - int use_cookie = 1; - int res; + if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS) + return bss->flink; + + if (BIT(link_id) & bss->valid_links) + return &bss->links[link_id]; + + return bss->flink; +} + + +static void nl80211_link_set_freq(struct i802_bss *bss, s8 link_id, int freq) +{ + struct i802_link *link = nl80211_get_link(bss, link_id); + + link->freq = freq; +} + + +static int nl80211_get_link_freq(struct i802_bss *bss, const u8 *addr, + bool bss_freq_debug) +{ + u8 i; + + for_each_link(bss->valid_links, i) { + if (ether_addr_equal(bss->links[i].addr, addr)) { + wpa_printf(MSG_DEBUG, + "nl80211: Use link freq=%d for address " + MACSTR, + bss->links[i].freq, MAC2STR(addr)); + return bss->links[i].freq; + } + } + + if (bss_freq_debug) + wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d", + bss->flink->freq); + + return bss->flink->freq; +} + + +static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data, + size_t data_len, int noack, + unsigned int freq, int no_cck, + int offchanok, + unsigned int wait_time, + const u16 *csa_offs, + size_t csa_offs_len, int no_encrypt, + int link_id) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct ieee80211_mgmt *mgmt; + int encrypt = !no_encrypt; + u16 fc; + int use_cookie = 1; + int res; + struct i802_link *link = nl80211_get_link(bss, link_id); mgmt = (struct ieee80211_mgmt *) data; fc = le_to_host16(mgmt->frame_control); - wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR_SEC + wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR_SEC " sa=" MACSTR_SEC + " bssid=" MACSTR_SEC " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u no_encrypt=%d fc=0x%x (%s) nlmode=%d", - MAC2STR_SEC(mgmt->da), noack, freq, no_cck, offchanok, wait_time, + MAC2STR_SEC(mgmt->da), MAC2STR_SEC(mgmt->sa), MAC2STR_SEC(mgmt->bssid), + noack, freq, no_cck, offchanok, wait_time, no_encrypt, fc, fc2str(fc), drv->nlmode); if ((is_sta_interface(drv->nlmode) || @@ -4269,13 +4366,15 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data, } if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) { - if (freq == 0) { - wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d", - bss->freq); - freq = bss->freq; - } - if ((int) freq == bss->freq) + unsigned int link_freq = nl80211_get_link_freq(bss, mgmt->sa, + !freq); + + if (!freq) + freq = link_freq; + + if (freq == link_freq) wait_time = 0; + goto send_frame_cmd; } @@ -4336,20 +4435,21 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data, } if (freq == 0) { wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u", - bss->freq); - freq = bss->freq; + link->freq); + freq = link->freq; } if (drv->use_monitor && is_ap_interface(drv->nlmode)) { wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor", - freq, bss->freq); + freq, link->freq); return nl80211_send_monitor(drv, data, data_len, encrypt, noack); } - if (noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || - WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) + if ((noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || + WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) && + link_id == NL80211_DRV_LINK_ID_NA) use_cookie = 0; send_frame_cmd: #ifdef CONFIG_TESTING_OPTIONS @@ -4368,7 +4468,9 @@ send_frame_cmd: wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd"); res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len, use_cookie, no_cck, noack, offchanok, - csa_offs, csa_offs_len); + csa_offs, csa_offs_len, link_id); + if (!res) + drv->send_frame_link_id = link_id; return res; } @@ -4392,7 +4494,7 @@ static int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates) static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble, int slot, int ht_opmode, int ap_isolate, - const int *basic_rates) + const int *basic_rates, int link_id) { struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; @@ -4408,12 +4510,14 @@ static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble, nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) || (ap_isolate >= 0 && nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) || - nl80211_put_basic_rates(msg, basic_rates)) { + nl80211_put_basic_rates(msg, basic_rates) || + (link_id != NL80211_DRV_LINK_ID_NA && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))) { nlmsg_free(msg); return -ENOBUFS; } - return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + return send_and_recv_cmd(drv, msg); } @@ -4472,7 +4576,7 @@ static int wpa_driver_nl80211_set_acl(void *priv, } nlmsg_free(acl); - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)", ret, strerror(-ret)); @@ -4524,7 +4628,7 @@ static int nl80211_set_mesh_config(void *priv, return ret; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_ERROR, "nl80211: Mesh config set failed: %d (%s)", @@ -4585,7 +4689,7 @@ static int nl80211_put_beacon_rate(struct nl_msg *msg, u64 flags, u64 flags2, } if (nla_put_u8(msg, NL80211_TXRATE_LEGACY, - (u8) params->beacon_rate / 5) || + (u8) (params->beacon_rate / 5)) || nla_put(msg, NL80211_TXRATE_HT, 0, NULL) || (params->freq->vht_enabled && nla_put(msg, NL80211_TXRATE_VHT, sizeof(vht_rate), @@ -4670,7 +4774,7 @@ static int nl80211_set_multicast_to_unicast(struct i802_bss *bss, return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); switch (ret) { case 0: @@ -4699,18 +4803,18 @@ 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) +static int nl80211_put_sae_pwe(struct nl_msg *msg, enum sae_pwe pwe) { u8 sae_pwe; wpa_printf(MSG_DEBUG, "nl802111: sae_pwe=%d", pwe); - if (pwe == 0) + if (pwe == SAE_PWE_HUNT_AND_PECK) sae_pwe = NL80211_SAE_PWE_HUNT_AND_PECK; - else if (pwe == 1) + else if (pwe == SAE_PWE_HASH_TO_ELEMENT) sae_pwe = NL80211_SAE_PWE_HASH_TO_ELEMENT; - else if (pwe == 2) + else if (pwe == SAE_PWE_BOTH) sae_pwe = NL80211_SAE_PWE_BOTH; - else if (pwe == 3) + else if (pwe == SAE_PWE_FORCE_HUNT_AND_PECK) return 0; /* special test mode */ else return -1; @@ -4753,9 +4857,10 @@ static int nl80211_fils_discovery(struct i802_bss *bss, struct nl_msg *msg, #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 unsol_bcast_probe_resp *ubpr) { struct nlattr *attr; @@ -4768,28 +4873,261 @@ static int nl80211_unsol_bcast_probe_resp(struct i802_bss *bss, wpa_printf(MSG_DEBUG, "nl80211: Unsolicited broadcast Probe Response frame interval: %u", - params->unsol_bcast_probe_resp_interval); + ubpr->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 && + ubpr->unsol_bcast_probe_resp_interval) || + (ubpr->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))) + ubpr->unsol_bcast_probe_resp_tmpl_len, + ubpr->unsol_bcast_probe_resp_tmpl))) return -1; nla_nest_end(msg, attr); return 0; } + + +static int nl80211_mbssid(struct nl_msg *msg, + struct wpa_driver_ap_params *params) +{ + struct nlattr *config, *elems; + int ifidx; + + if (!params->mbssid_tx_iface) + return 0; + + config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG); + if (!config || + nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_INDEX, + params->mbssid_index)) + return -1; + + if (params->mbssid_tx_iface) { + ifidx = if_nametoindex(params->mbssid_tx_iface); + if (ifidx <= 0 || + nla_put_u32(msg, NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX, + ifidx)) + return -1; + } + + if (params->ema && nla_put_flag(msg, NL80211_MBSSID_CONFIG_ATTR_EMA)) + return -1; + + nla_nest_end(msg, config); + + if (params->mbssid_elem_count && params->mbssid_elem_len && + params->mbssid_elem_offset && *params->mbssid_elem_offset) { + u8 i, **offs = params->mbssid_elem_offset; + + elems = nla_nest_start(msg, NL80211_ATTR_MBSSID_ELEMS); + if (!elems) + return -1; + + for (i = 0; i < params->mbssid_elem_count - 1; i++) { + if (nla_put(msg, i + 1, offs[i + 1] - offs[i], offs[i])) + return -1; + } + + if (nla_put(msg, i + 1, + *offs + params->mbssid_elem_len - offs[i], + offs[i])) + return -1; + + nla_nest_end(msg, elems); + } + + if (!params->ema) + return 0; + + if (params->rnr_elem_count && params->rnr_elem_len && + params->rnr_elem_offset && *params->rnr_elem_offset) { + u8 i, **offs = params->rnr_elem_offset; + + elems = nla_nest_start(msg, NL80211_ATTR_EMA_RNR_ELEMS); + if (!elems) + return -1; + + for (i = 0; i < params->rnr_elem_count - 1; i++) { + if (nla_put(msg, i + 1, offs[i + 1] - offs[i], offs[i])) + return -1; + } + + if (nla_put(msg, i + 1, *offs + params->rnr_elem_len - offs[i], + offs[i])) + return -1; + nla_nest_end(msg, elems); + } + + return 0; +} + #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_DRIVER_NL80211_QCA +static void qca_set_allowed_ap_freqs(struct wpa_driver_nl80211_data *drv, + const int *freqs, int num_freqs, + int link_id) +{ + struct nl_msg *msg; + struct nlattr *params, *freqs_list; + int i, ret; + + if (!drv->set_wifi_conf_vendor_cmd_avail || !drv->qca_ap_allowed_freqs) + return; + + wpa_printf(MSG_DEBUG, "nl80211: Set AP allowed frequency list"); + + 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_SET_WIFI_CONFIGURATION) || + !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA))) + goto err; + + if (link_id != NL80211_DRV_LINK_ID_NA && + nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID, link_id)) + goto err; + + freqs_list = nla_nest_start( + msg, QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST); + if (!freqs_list) + goto err; + + for (i = 0; i < num_freqs; i++) { + if (nla_put_u32(msg, i, freqs[i])) + goto err; + } + + nla_nest_end(msg, freqs_list); + nla_nest_end(msg, params); + + ret = send_and_recv_cmd(drv, msg); + if (ret) + wpa_printf(MSG_ERROR, + "nl80211: Failed set AP alllowed frequency list: %d (%s)", + ret, strerror(-ret)); + + return; +err: + nlmsg_free(msg); +} +#endif /* CONFIG_DRIVER_NL80211_QCA */ + + +static int nl80211_put_freq_params(struct nl_msg *msg, + const struct hostapd_freq_params *freq) +{ + enum hostapd_hw_mode hw_mode; + int is_24ghz; + u8 channel; + + wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq); + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq)) + return -ENOBUFS; + + wpa_printf(MSG_DEBUG, " * eht_enabled=%d", freq->eht_enabled); + wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled); + wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled); + wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled); + wpa_printf(MSG_DEBUG, " * radar_background=%d", + freq->radar_background); + + hw_mode = ieee80211_freq_to_chan(freq->freq, &channel); + is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G || + hw_mode == HOSTAPD_MODE_IEEE80211B; + + if (freq->vht_enabled || + ((freq->he_enabled || freq->eht_enabled) && !is_24ghz)) { + enum nl80211_chan_width cw; + + wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth); + switch (freq->bandwidth) { + case 20: + cw = NL80211_CHAN_WIDTH_20; + break; + case 40: + cw = NL80211_CHAN_WIDTH_40; + break; + case 80: + if (freq->center_freq2) + cw = NL80211_CHAN_WIDTH_80P80; + else + cw = NL80211_CHAN_WIDTH_80; + break; + case 160: + cw = NL80211_CHAN_WIDTH_160; + break; + case 320: + cw = NL80211_CHAN_WIDTH_320; + break; + default: + return -EINVAL; + } + + wpa_printf(MSG_DEBUG, " * channel_width=%d", cw); + wpa_printf(MSG_DEBUG, " * center_freq1=%d", + freq->center_freq1); + wpa_printf(MSG_DEBUG, " * center_freq2=%d", + freq->center_freq2); + if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) || + nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, + freq->center_freq1) || + (freq->center_freq2 && + nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, + freq->center_freq2))) + return -ENOBUFS; + } else if (freq->ht_enabled) { + enum nl80211_channel_type ct; + + wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d", + freq->sec_channel_offset); + switch (freq->sec_channel_offset) { + case -1: + ct = NL80211_CHAN_HT40MINUS; + break; + case 1: + ct = NL80211_CHAN_HT40PLUS; + break; + default: + ct = NL80211_CHAN_HT20; + break; + } + + wpa_printf(MSG_DEBUG, " * channel_type=%d", ct); + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct)) + return -ENOBUFS; + } else if (freq->edmg.channels && freq->edmg.bw_config) { + wpa_printf(MSG_DEBUG, + " * EDMG configuration: channels=0x%x bw_config=%d", + freq->edmg.channels, freq->edmg.bw_config); + if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS, + freq->edmg.channels) || + nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG, + freq->edmg.bw_config)) + return -1; + } else { + wpa_printf(MSG_DEBUG, " * channel_type=%d", + NL80211_CHAN_NO_HT); + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + NL80211_CHAN_NO_HT)) + return -ENOBUFS; + } + if (freq->radar_background && + nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND)) + return -ENOBUFS; + + return 0; +} + static int wpa_driver_nl80211_set_ap(void *priv, struct wpa_driver_ap_params *params) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; + struct i802_link *link = bss->flink; struct nl_msg *msg; u8 cmd = NL80211_CMD_NEW_BEACON; int ret = -ENOBUFS; @@ -4801,7 +5139,22 @@ static int wpa_driver_nl80211_set_ap(void *priv, struct wpa_driver_mesh_bss_params mesh_params; #endif /* CONFIG_MESH */ - beacon_set = params->reenable ? 0 : bss->beacon_set; + if (params->mld_ap) { + if (!nl80211_link_valid(bss->valid_links, + params->mld_link_id)) { + wpa_printf(MSG_DEBUG, + "nl80211: Link ID=%u invalid (valid: 0x%04x)", + params->mld_link_id, bss->valid_links); + return -EINVAL; + } + + link = nl80211_get_link(bss, params->mld_link_id); + } else if (bss->valid_links) { + wpa_printf(MSG_DEBUG, "nl80211: MLD configuration expected"); + return -EINVAL; + } + + beacon_set = params->reenable ? 0 : link->beacon_set; wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)", beacon_set); @@ -4833,6 +5186,20 @@ static int wpa_driver_nl80211_set_ap(void *priv, nl80211_put_dtim_period(msg, params->dtim_period) || nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid)) goto fail; + + if (params->mld_ap) { + wpa_printf(MSG_DEBUG, "nl80211: link_id=%u", + params->mld_link_id); + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, + params->mld_link_id)) + goto fail; + + if (params->freq) + nl80211_link_set_freq(bss, params->mld_link_id, + params->freq->freq); + } + if (params->proberesp && params->proberesp_len) { wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)", params->proberesp, params->proberesp_len); @@ -4892,27 +5259,59 @@ static int wpa_driver_nl80211_set_ap(void *priv, params->key_mgmt_suites); num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites, suites, ARRAY_SIZE(suites)); - if (num_suites > NL80211_MAX_NR_AKM_SUITES) + if ((unsigned int) num_suites > drv->capa.max_num_akms) wpa_printf(MSG_DEBUG, - "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)", - num_suites); + "nl80211: Not enough room for all AKM suites (num_suites=%d > %d)", + num_suites, drv->capa.max_num_akms); else if (num_suites && nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32), suites)) goto fail; + if (wpa_key_mgmt_wpa_psk_no_sae(params->key_mgmt_suites) && + (drv->capa.flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK) && + params->psk_len && + nla_put(msg, NL80211_ATTR_PMK, params->psk_len, params->psk)) + goto fail; + + if (wpa_key_mgmt_sae(params->key_mgmt_suites) && + (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP) && + params->sae_password && + nla_put(msg, NL80211_ATTR_SAE_PASSWORD, + os_strlen(params->sae_password), params->sae_password)) + goto fail; + + if (nl80211_put_control_port(drv, msg) < 0) + goto fail; + if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA && (!params->pairwise_ciphers || params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) && - (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) || - nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) + nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)) goto fail; - if (drv->device_ap_sme && - (params->key_mgmt_suites & (WPA_KEY_MGMT_SAE | - WPA_KEY_MGMT_SAE_EXT_KEY)) && - nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT)) - goto fail; + if (drv->device_ap_sme) { + u32 flags = 0; + + if (params->key_mgmt_suites & (WPA_KEY_MGMT_SAE | + WPA_KEY_MGMT_SAE_EXT_KEY)) { + /* Add the previously used flag attribute to support + * older kernel versions and the newer flag bit for + * newer kernels. */ + if (nla_put_flag(msg, + NL80211_ATTR_EXTERNAL_AUTH_SUPPORT)) + goto fail; + flags |= NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT; + } +#ifdef CONFIG_KERNEL_VERSION_ADAPTER + flags |= NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT; + + if (nl80211_attr_supported(drv, + NL80211_ATTR_AP_SETTINGS_FLAGS) && + nla_put_u32(msg, NL80211_ATTR_AP_SETTINGS_FLAGS, flags)) + goto fail; +#endif + } wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x", params->pairwise_ciphers); @@ -5007,6 +5406,9 @@ static int wpa_driver_nl80211_set_ap(void *priv, nla_nest_end(msg, ftm); } + if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0) + goto fail; + #ifdef CONFIG_IEEE80211AX if (params->he_spr_ctrl) { struct nlattr *spr; @@ -5041,7 +5443,8 @@ static int wpa_driver_nl80211_set_ap(void *priv, nla_nest_end(msg, spr); } - if (params->freq && params->freq->he_enabled) { + if (params->freq && params->freq->he_enabled && + nl80211_attr_supported(drv, NL80211_ATTR_HE_BSS_COLOR)) { struct nlattr *bss_color; bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR); @@ -5063,8 +5466,11 @@ static int wpa_driver_nl80211_set_ap(void *priv, goto fail; } - if (params->unsol_bcast_probe_resp_interval && - nl80211_unsol_bcast_probe_resp(bss, msg, params) < 0) + if (params->ubpr.unsol_bcast_probe_resp_interval && + nl80211_unsol_bcast_probe_resp(bss, msg, ¶ms->ubpr) < 0) + goto fail; + + if (nl80211_mbssid(msg, params) < 0) goto fail; #endif /* CONFIG_IEEE80211AX */ @@ -5079,153 +5485,80 @@ static int wpa_driver_nl80211_set_ap(void *priv, goto fail; #endif /* CONFIG_FILS */ - ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1); - if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", - ret, strerror(-ret)); - } else { - bss->beacon_set = 1; - nl80211_set_bss(bss, params->cts_protect, params->preamble, - params->short_slot_time, params->ht_opmode, - params->isolate, params->basic_rates); - nl80211_set_multicast_to_unicast(bss, - params->multicast_to_unicast); - if (beacon_set && params->freq && - params->freq->bandwidth != bss->bandwidth) { - wpa_printf(MSG_DEBUG, - "nl80211: Update BSS %s bandwidth: %d -> %d", - bss->ifname, bss->bandwidth, - params->freq->bandwidth); - ret = nl80211_set_channel(bss, params->freq, 1); - if (ret) { - wpa_printf(MSG_DEBUG, - "nl80211: Frequency set failed: %d (%s)", - ret, strerror(-ret)); - } else { - wpa_printf(MSG_DEBUG, - "nl80211: Frequency set succeeded for ht2040 coex"); - bss->bandwidth = params->freq->bandwidth; - } - } else if (!beacon_set && params->freq) { - /* - * cfg80211 updates the driver on frequence change in AP - * mode only at the point when beaconing is started, so - * set the initial value here. - */ - bss->bandwidth = params->freq->bandwidth; - } - } - -#ifdef CONFIG_MESH - if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) { - os_memset(&mesh_params, 0, sizeof(mesh_params)); - mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE; - mesh_params.ht_opmode = params->ht_opmode; - ret = nl80211_set_mesh_config(priv, &mesh_params); - if (ret < 0) - return ret; + if (params->punct_bitmap) { + wpa_printf(MSG_DEBUG, "nl80211: Puncturing bitmap=0x%04x", + params->punct_bitmap); + if (nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP, + params->punct_bitmap)) + goto fail; } -#endif /* CONFIG_MESH */ - return ret; -fail: - nlmsg_free(msg); - return ret; -} - - -static int nl80211_put_freq_params(struct nl_msg *msg, - const struct hostapd_freq_params *freq) -{ - enum hostapd_hw_mode hw_mode; - int is_24ghz; - u8 channel; - - wpa_printf(MSG_DEBUG, " * freq=%d", freq->freq); - if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq)) - return -ENOBUFS; - - wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled); - wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled); - wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled); - - hw_mode = ieee80211_freq_to_chan(freq->freq, &channel); - is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G || - hw_mode == HOSTAPD_MODE_IEEE80211B; - - if (freq->vht_enabled || (freq->he_enabled && !is_24ghz)) { - enum nl80211_chan_width cw; - - wpa_printf(MSG_DEBUG, " * bandwidth=%d", freq->bandwidth); - switch (freq->bandwidth) { - case 20: - cw = NL80211_CHAN_WIDTH_20; - break; - case 40: - cw = NL80211_CHAN_WIDTH_40; - break; - case 80: - if (freq->center_freq2) - cw = NL80211_CHAN_WIDTH_80P80; - else - cw = NL80211_CHAN_WIDTH_80; - break; - case 160: - cw = NL80211_CHAN_WIDTH_160; - break; - default: - return -EINVAL; - } +#ifdef CONFIG_DRIVER_NL80211_QCA + if (cmd == NL80211_CMD_NEW_BEACON && params->allowed_freqs) + qca_set_allowed_ap_freqs(drv, params->allowed_freqs, + int_array_len(params->allowed_freqs), + params->mld_ap ? params->mld_link_id : + NL80211_DRV_LINK_ID_NA); +#endif /* CONFIG_DRIVER_NL80211_QCA */ - wpa_printf(MSG_DEBUG, " * channel_width=%d", cw); - wpa_printf(MSG_DEBUG, " * center_freq1=%d", - freq->center_freq1); - wpa_printf(MSG_DEBUG, " * center_freq2=%d", - freq->center_freq2); - if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) || - nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, - freq->center_freq1) || - (freq->center_freq2 && - nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, - freq->center_freq2))) - return -ENOBUFS; - } else if (freq->ht_enabled) { - enum nl80211_channel_type ct; + if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER)) + goto fail; - wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d", - freq->sec_channel_offset); - switch (freq->sec_channel_offset) { - case -1: - ct = NL80211_CHAN_HT40MINUS; - break; - case 1: - ct = NL80211_CHAN_HT40PLUS; - break; - default: - ct = NL80211_CHAN_HT20; - break; + ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL, + NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", + ret, strerror(-ret)); + } else { + link->beacon_set = 1; + nl80211_set_bss(bss, params->cts_protect, params->preamble, + params->short_slot_time, params->ht_opmode, + params->isolate, params->basic_rates, + params->mld_ap ? params->mld_link_id : + NL80211_DRV_LINK_ID_NA); + nl80211_set_multicast_to_unicast(bss, + params->multicast_to_unicast); + if (beacon_set && params->freq && + params->freq->bandwidth != link->bandwidth) { + wpa_printf(MSG_DEBUG, + "nl80211: Update BSS %s bandwidth: %d -> %d", + bss->ifname, link->bandwidth, + params->freq->bandwidth); + ret = nl80211_set_channel(bss, params->freq, 1); + if (ret) { + wpa_printf(MSG_DEBUG, + "nl80211: Frequency set failed: %d (%s)", + ret, strerror(-ret)); + } else { + wpa_printf(MSG_DEBUG, + "nl80211: Frequency set succeeded for ht2040 coex"); + link->bandwidth = params->freq->bandwidth; + } + } else if (!beacon_set && params->freq) { + /* + * cfg80211 updates the driver on frequence change in AP + * mode only at the point when beaconing is started, so + * set the initial value here. + */ + link->bandwidth = params->freq->bandwidth; } + } - wpa_printf(MSG_DEBUG, " * channel_type=%d", ct); - if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct)) - return -ENOBUFS; - } else if (freq->edmg.channels && freq->edmg.bw_config) { - wpa_printf(MSG_DEBUG, - " * EDMG configuration: channels=0x%x bw_config=%d", - freq->edmg.channels, freq->edmg.bw_config); - if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS, - freq->edmg.channels) || - nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG, - freq->edmg.bw_config)) - return -1; - } else { - wpa_printf(MSG_DEBUG, " * channel_type=%d", - NL80211_CHAN_NO_HT); - if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_NO_HT)) - return -ENOBUFS; +#ifdef CONFIG_MESH + if (is_mesh_interface(drv->nlmode) && params->ht_opmode != -1) { + os_memset(&mesh_params, 0, sizeof(mesh_params)); + mesh_params.flags |= WPA_DRIVER_MESH_CONF_FLAG_HT_OP_MODE; + mesh_params.ht_opmode = params->ht_opmode; + ret = nl80211_set_mesh_config(priv, &mesh_params); + if (ret < 0) + return ret; } - return 0; +#endif /* CONFIG_MESH */ + + return ret; +fail: + nlmsg_free(msg); + return ret; } @@ -5240,9 +5573,10 @@ static int nl80211_set_channel(struct i802_bss *bss, int ret; wpa_printf(MSG_DEBUG, - "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)", - freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled, - freq->bandwidth, freq->center_freq1, freq->center_freq2); + "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, he_enabled=%d, eht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)", + freq->freq, freq->ht_enabled, freq->vht_enabled, + freq->he_enabled, freq->eht_enabled, freq->bandwidth, + freq->center_freq1, freq->center_freq2); msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL : NL80211_CMD_SET_WIPHY); @@ -5251,9 +5585,19 @@ static int nl80211_set_channel(struct i802_bss *bss, return -1; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + if (nl80211_link_valid(bss->valid_links, freq->link_id)) { + wpa_printf(MSG_DEBUG, "nl80211: Set link_id=%u for freq", + freq->link_id); + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, freq->link_id)) { + nlmsg_free(msg); + return -ENOBUFS; + } + } + + ret = send_and_recv_cmd(drv, msg); if (ret == 0) { - bss->freq = freq->freq; + nl80211_link_set_freq(bss, freq->link_id, freq->freq); return 0; } wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): " @@ -5320,16 +5664,29 @@ static int wpa_driver_nl80211_sta_add(void *priv, struct nl_msg *msg; struct nl80211_sta_flag_update upd; int ret = -ENOBUFS; + u8 cmd; + const char *cmd_string; if ((params->flags & WPA_STA_TDLS_PEER) && !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) return -EOPNOTSUPP; + if (params->mld_link_sta) { + cmd = params->set ? NL80211_CMD_MODIFY_LINK_STA : + NL80211_CMD_ADD_LINK_STA; + cmd_string = params->set ? "NL80211_CMD_MODIFY_LINK_STA" : + "NL80211_CMD_ADD_LINK_STA"; + } else { + cmd = params->set ? NL80211_CMD_SET_STATION : + NL80211_CMD_NEW_STATION; + cmd_string = params->set ? "NL80211_CMD_SET_STATION" : + "NL80211_CMD_NEW_STATION"; + } + wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR_SEC, - params->set ? "Set" : "Add", MAC2STR_SEC(params->addr)); - msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION : - NL80211_CMD_NEW_STATION); - if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr)) + cmd_string, MAC2STR_SEC(params->addr)); + msg = nl80211_bss_msg(bss, 0, cmd); + if (!msg) goto fail; /* @@ -5391,6 +5748,14 @@ static int wpa_driver_nl80211_sta_add(void *priv, goto fail; } + if (params->eht_capab) { + wpa_hexdump(MSG_DEBUG, " * eht_capab", + params->eht_capab, params->eht_capab_len); + if (nla_put(msg, NL80211_ATTR_EHT_CAPABILITY, + params->eht_capab_len, params->eht_capab)) + goto fail; + } + if (params->ext_capab) { wpa_hexdump(MSG_DEBUG, " * ext_capab", params->ext_capab, params->ext_capab_len); @@ -5539,12 +5904,43 @@ static int wpa_driver_nl80211_sta_add(void *priv, nla_nest_end(msg, wme); } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + /* In case we are an AP MLD need to always specify the link ID */ + if (params->mld_link_id >= 0) { + wpa_printf(MSG_DEBUG, " * mld_link_id=%d", + params->mld_link_id); + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, + params->mld_link_id)) + goto fail; + + /* + * If the link address is specified the station is a non-AP MLD + * and thus need to provide the MLD address as the station + * address, and the non-AP MLD link address as the link address. + */ + if (params->mld_link_addr) { + wpa_printf(MSG_DEBUG, " * mld_link_addr=" MACSTR, + MAC2STR(params->mld_link_addr)); + + if (nla_put(msg, NL80211_ATTR_MLD_ADDR, + ETH_ALEN, params->addr) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, + params->mld_link_addr)) + goto fail; + } else { + if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, + params->addr)) + goto fail; + } + } else { + if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr)) + goto fail; + } + + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) - wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION " - "result: %d (%s)", params->set ? "SET" : "NEW", ret, - strerror(-ret)); + wpa_printf(MSG_DEBUG, "nl80211: %s result: %d (%s)", + cmd_string, ret, strerror(-ret)); if (ret == -EEXIST) ret = 0; fail: @@ -5555,26 +5951,25 @@ fail: static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr) { -#ifdef CONFIG_LIBNL3_ROUTE struct wpa_driver_nl80211_data *drv = bss->drv; - struct rtnl_neigh *rn; - struct nl_addr *nl_addr; + struct ndmsg nhdr = { + .ndm_state = NUD_PERMANENT, + .ndm_ifindex = bss->ifindex, + .ndm_family = AF_BRIDGE, + }; + struct nl_msg *msg; int err; - rn = rtnl_neigh_alloc(); - if (!rn) + msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE); + if (!msg) return; - rtnl_neigh_set_family(rn, AF_BRIDGE); - rtnl_neigh_set_ifindex(rn, bss->ifindex); - nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN); - if (!nl_addr) { - rtnl_neigh_put(rn); - return; - } - rtnl_neigh_set_lladdr(rn, nl_addr); + if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 || + nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *) addr) || + nl_send_auto_complete(drv->rtnl_sk, msg) < 0) + goto errout; - err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0); + err = nl_wait_for_ack(drv->rtnl_sk); if (err < 0) { wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for " MACSTR_SEC " ifindex=%d failed: %s", MAC2STR_SEC(addr), @@ -5584,9 +5979,8 @@ static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr) MACSTR_SEC, MAC2STR_SEC(addr)); } - nl_addr_put(nl_addr); - rtnl_neigh_put(rn); -#endif /* CONFIG_LIBNL3_ROUTE */ +errout: + nlmsg_free(msg); } @@ -5611,7 +6005,7 @@ int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr, return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR_SEC " --> %d (%s)", bss->ifname, MAC2STR_SEC(addr), ret, strerror(-ret)); @@ -5642,7 +6036,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, NULL, NULL) == 0) + if (send_and_recv_cmd(drv, msg) == 0) return; wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx); } @@ -5726,7 +6120,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) goto fail; - ret = send_and_recv_msgs(drv, msg, handler, arg, NULL, NULL); + ret = send_and_recv_resp(drv, msg, handler, arg); msg = NULL; if (ret) { fail: @@ -5873,13 +6267,14 @@ static void nl80211_teardown_ap(struct i802_bss *bss) nl80211_mgmt_unsubscribe(bss, "AP teardown"); nl80211_put_wiphy_data_ap(bss); - bss->beacon_set = 0; + if (bss->flink) + bss->flink->beacon_set = 0; } static int nl80211_tx_control_port(void *priv, const u8 *dest, u16 proto, const u8 *buf, size_t len, - int no_encrypt) + int no_encrypt, int link_id) { struct nl80211_ack_ext_arg ext_arg; struct i802_bss *bss = priv; @@ -5898,15 +6293,17 @@ static int nl80211_tx_control_port(void *priv, const u8 *dest, nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) || nla_put(msg, NL80211_ATTR_FRAME, len, buf) || (no_encrypt && - nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) { + nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)) || + (link_id != NL80211_DRV_LINK_ID_NA && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))) { nlmsg_free(msg); return -ENOBUFS; } 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); + ret = send_and_recv(bss->drv->global, bss->drv->global->nl, msg, + NULL, NULL, ack_handler_cookie, &ext_arg, NULL); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: tx_control_port failed: ret=%d (%s)", @@ -5918,6 +6315,7 @@ static int nl80211_tx_control_port(void *priv, const u8 *dest, "nl80211: tx_control_port cookie=0x%llx", (long long unsigned int) cookie); drv->eapol_tx_cookie = cookie; + drv->eapol_tx_link_id = link_id; } return ret; @@ -5956,7 +6354,8 @@ static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; static int wpa_driver_nl80211_hapd_send_eapol( void *priv, const u8 *addr, const u8 *data, - size_t data_len, int encrypt, const u8 *own_addr, u32 flags) + size_t data_len, int encrypt, const u8 *own_addr, u32 flags, + int link_id) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -5971,7 +6370,8 @@ static int wpa_driver_nl80211_hapd_send_eapol( if (drv->control_port_ap && (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT)) return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL, - data, data_len, !encrypt); + data, data_len, !encrypt, + link_id); if (drv->device_ap_sme || !drv->use_monitor) return nl80211_send_eapol_data(bss, addr, data, data_len); @@ -6070,7 +6470,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, NULL, NULL); + return send_and_recv_cmd(bss->drv, msg); fail: nlmsg_free(msg); return -ENOBUFS; @@ -6093,7 +6493,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; - ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(bss->drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: SET_STATION[AIRTIME_WEIGHT] failed: ret=%d (%s)", @@ -6143,7 +6543,8 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv, int ret; msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS); - ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1); + ret = send_and_recv(drv->global, drv->first_bss->nl_connect, msg, NULL, + NULL, NULL, NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d " "(%s)", ret, strerror(-ret)); @@ -6209,6 +6610,12 @@ static int nl80211_ht_vht_overrides(struct nl_msg *msg, } #endif /* CONFIG_HE_OVERRIDES */ + if (params->disable_eht) { + wpa_printf(MSG_DEBUG, " * EHT disabled"); + if (nla_put_flag(msg, NL80211_ATTR_DISABLE_EHT)) + return -1; + } + return 0; } @@ -6264,9 +6671,10 @@ retry: if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || params->key_mgmt_suite == WPA_KEY_MGMT_PSK || params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 || - params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) { + params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 || + params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384) { wpa_printf(MSG_DEBUG, " * control port"); - if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT)) + if (nl80211_put_control_port(drv, msg)) goto fail; } @@ -6283,7 +6691,10 @@ retry: if (ret < 0) goto fail; - ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1); + if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER)) + goto fail; + ret = send_and_recv(drv->global, drv->first_bss->nl_connect, msg, NULL, + NULL, NULL, NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)", @@ -6348,15 +6759,24 @@ static int nl80211_put_fils_connect_params(struct wpa_driver_nl80211_data *drv, } +static unsigned int num_bits_set(u32 val) +{ + unsigned int c; + + for (c = 0; val; c++) + val &= val - 1; + + return c; +} + + static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params, struct nl_msg *msg) { -#ifdef CONFIG_MLD_PATCH_EXT if (params->mld_params.mld_addr && params->mld_params.valid_links > 0) { struct wpa_driver_mld_params *mld_params = ¶ms->mld_params; struct nlattr *links, *attr; - int i; u8 link_id; wpa_printf(MSG_DEBUG, " * MLD: MLD addr=" MACSTR_SEC, @@ -6372,52 +6792,31 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, if (!links) return -1; - attr = nla_nest_start(msg, 0); - if (!attr) - return -1; - - /* First add the association link ID */ - link_id = mld_params->assoc_link_id; - if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id) || - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, - mld_params->mld_links[link_id].bssid) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, - mld_params->mld_links[link_id].freq)) - return -1; - - os_memcpy(drv->sta_mlo_info.links[link_id].bssid, - mld_params->mld_links[link_id].bssid, ETH_ALEN); - - nla_nest_end(msg, attr); - - for (i = 1, link_id = 0; link_id < MAX_NUM_MLD_LINKS; - link_id++) { - if (!(mld_params->valid_links & BIT(link_id)) || - link_id == mld_params->assoc_link_id) - continue; - - attr = nla_nest_start(msg, i); + for_each_link(mld_params->valid_links, link_id) { + attr = nla_nest_start(msg, 0); if (!attr) - return -1; - - if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, - link_id) || - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, - mld_params->mld_links[link_id].bssid) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, + return -1; + + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, + link_id) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, + mld_params->mld_links[link_id].bssid) || + nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, mld_params->mld_links[link_id].freq) || - (mld_params->mld_links[link_id].ies && - mld_params->mld_links[i].ies_len && - nla_put(msg, NL80211_ATTR_IE, - mld_params->mld_links[link_id].ies_len, - mld_params->mld_links[link_id].ies))) + (mld_params->mld_links[link_id].disabled && + nla_put_flag(msg, + NL80211_ATTR_MLO_LINK_DISABLED)) || + (mld_params->mld_links[link_id].ies && + mld_params->mld_links[link_id].ies_len && + nla_put(msg, NL80211_ATTR_IE, + mld_params->mld_links[link_id].ies_len, + mld_params->mld_links[link_id].ies))) return -1; os_memcpy(drv->sta_mlo_info.links[link_id].bssid, mld_params->mld_links[link_id].bssid, ETH_ALEN); nla_nest_end(msg, attr); - i++; } nla_nest_end(msg, links); @@ -6427,14 +6826,11 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, drv->sta_mlo_info.assoc_link_id = mld_params->assoc_link_id; drv->sta_mlo_info.req_links = mld_params->valid_links; } -#endif + if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER)) return -1; -#ifdef CONFIG_MLD_PATCH_EXT + if (params->bssid && !params->mld_params.mld_addr) { -#else - if (params->bssid) { -#endif wpa_printf(MSG_DEBUG, " * bssid=" MACSTR_SEC, MAC2STR_SEC(params->bssid)); if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) @@ -6448,11 +6844,8 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, params->bssid_hint)) return -1; } -#ifdef CONFIG_MLD_PATCH_EXT + if (params->freq.freq && !params->mld_params.mld_addr) { -#else - if (params->freq.freq) { -#endif wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq); if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq.freq)) @@ -6510,8 +6903,18 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, if (params->wpa_proto & WPA_PROTO_WPA) ver |= NL80211_WPA_VERSION_1; - if (params->wpa_proto & WPA_PROTO_RSN) - ver |= NL80211_WPA_VERSION_2; + if (params->wpa_proto & WPA_PROTO_RSN) { + /* + * NL80211_ATTR_SAE_PASSWORD is related and was added + * at the same time as NL80211_WPA_VERSION_3. + */ + if (nl80211_attr_supported(drv, + NL80211_ATTR_SAE_PASSWORD) && + wpa_key_mgmt_sae(params->key_mgmt_suite)) + ver |= NL80211_WPA_VERSION_3; + else + ver |= NL80211_WPA_VERSION_2; + } wpa_printf(MSG_DEBUG, " * WPA Versions 0x%x", ver); if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver)) @@ -6551,6 +6954,7 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, params->key_mgmt_suite == WPA_KEY_MGMT_SAE || params->key_mgmt_suite == WPA_KEY_MGMT_SAE_EXT_KEY || params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE || + params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE_EXT_KEY || params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B || params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 || params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X_SHA384 || @@ -6559,75 +6963,116 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA256 || params->key_mgmt_suite == WPA_KEY_MGMT_FT_FILS_SHA384 || params->key_mgmt_suite == WPA_KEY_MGMT_OWE || - params->key_mgmt_suite == WPA_KEY_MGMT_DPP) { - int mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; + params->key_mgmt_suite == WPA_KEY_MGMT_DPP || + params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384) { + u32 *mgmt; + unsigned int akm_count = 1, i; + + /* + * Make sure the driver has capability to handle default AKM in + * key_mgmt_suite plus allowed AKMs in allowed_key_mgmts. + */ + if (drv->capa.max_num_akms <= + num_bits_set(params->allowed_key_mgmts)) { + wpa_printf(MSG_INFO, + "nl80211: Not enough support for the allowed AKMs (max_num_akms=%u <= num_bits_set=%u)", + drv->capa.max_num_akms, + num_bits_set(params->allowed_key_mgmts)); + return -1; + } + + mgmt = os_malloc(sizeof(u32) * drv->capa.max_num_akms); + if (!mgmt) + return -1; + + mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; switch (params->key_mgmt_suite) { case WPA_KEY_MGMT_CCKM: - mgmt = RSN_AUTH_KEY_MGMT_CCKM; + mgmt[0] = RSN_AUTH_KEY_MGMT_CCKM; break; case WPA_KEY_MGMT_IEEE8021X: - mgmt = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; + mgmt[0] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; break; case WPA_KEY_MGMT_FT_IEEE8021X: - mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X; break; case WPA_KEY_MGMT_FT_PSK: - mgmt = RSN_AUTH_KEY_MGMT_FT_PSK; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_PSK; break; case WPA_KEY_MGMT_IEEE8021X_SHA256: - mgmt = RSN_AUTH_KEY_MGMT_802_1X_SHA256; + mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SHA256; break; case WPA_KEY_MGMT_PSK_SHA256: - mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256; + mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_SHA256; break; case WPA_KEY_MGMT_OSEN: - mgmt = RSN_AUTH_KEY_MGMT_OSEN; + mgmt[0] = RSN_AUTH_KEY_MGMT_OSEN; break; case WPA_KEY_MGMT_SAE: - mgmt = RSN_AUTH_KEY_MGMT_SAE; + mgmt[0] = RSN_AUTH_KEY_MGMT_SAE; break; case WPA_KEY_MGMT_SAE_EXT_KEY: - mgmt = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY; + mgmt[0] = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY; break; case WPA_KEY_MGMT_FT_SAE: - mgmt = RSN_AUTH_KEY_MGMT_FT_SAE; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE; + break; + case WPA_KEY_MGMT_FT_SAE_EXT_KEY: + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY; break; case WPA_KEY_MGMT_IEEE8021X_SUITE_B: - mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B; + mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B; break; case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: - mgmt = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192; + mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192; break; case WPA_KEY_MGMT_FT_IEEE8021X_SHA384: - mgmt = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384; break; case WPA_KEY_MGMT_FILS_SHA256: - mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA256; + mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA256; break; case WPA_KEY_MGMT_FILS_SHA384: - mgmt = RSN_AUTH_KEY_MGMT_FILS_SHA384; + mgmt[0] = RSN_AUTH_KEY_MGMT_FILS_SHA384; break; case WPA_KEY_MGMT_FT_FILS_SHA256: - mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256; break; case WPA_KEY_MGMT_FT_FILS_SHA384: - mgmt = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384; + mgmt[0] = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384; break; case WPA_KEY_MGMT_OWE: - mgmt = RSN_AUTH_KEY_MGMT_OWE; + mgmt[0] = RSN_AUTH_KEY_MGMT_OWE; break; case WPA_KEY_MGMT_DPP: - mgmt = RSN_AUTH_KEY_MGMT_DPP; + mgmt[0] = RSN_AUTH_KEY_MGMT_DPP; + break; + case WPA_KEY_MGMT_IEEE8021X_SHA384: + mgmt[0] = RSN_AUTH_KEY_MGMT_802_1X_SHA384; break; case WPA_KEY_MGMT_PSK: default: - mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; + mgmt[0] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; break; } - wpa_printf(MSG_DEBUG, " * akm=0x%x", mgmt); - if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt)) + + if (drv->capa.max_num_akms > 1) { + akm_count += wpa_key_mgmt_to_suites( + params->allowed_key_mgmts, &mgmt[1], + drv->capa.max_num_akms - 1); + } + + for (i = 0; i < akm_count; i++) + wpa_printf(MSG_DEBUG, " * akm[%d]=0x%x", i, mgmt[i]); + + if (nla_put(msg, NL80211_ATTR_AKM_SUITES, + akm_count * sizeof(u32), mgmt)) { + os_free(mgmt); return -1; + } + + os_free(mgmt); } if (params->req_handshake_offload && @@ -6645,15 +7090,14 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, return -1; } - if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT)) + if (nl80211_put_control_port(drv, msg)) return -1; if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_NO_WPA && (params->pairwise_suite == WPA_CIPHER_NONE || params->pairwise_suite == WPA_CIPHER_WEP104 || params->pairwise_suite == WPA_CIPHER_WEP40) && - (nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, ETH_P_PAE) || - nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) + nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT)) return -1; if (params->rrm_used) { @@ -6692,19 +7136,16 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, nl80211_put_fils_connect_params(drv, params, msg) != 0) return -1; - if ((wpa_key_mgmt_sae(params->key_mgmt_suite)) && + if ((wpa_key_mgmt_sae(params->key_mgmt_suite) || + wpa_key_mgmt_sae(params->allowed_key_mgmts)) && (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) && nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT)) return -1; -#ifdef CONFIG_MLD_PATCH_EXT + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) && nla_put_flag(msg, NL80211_ATTR_MLO_SUPPORT)) return -1; -#endif -#ifdef CONFIG_MLD_PATCH - if (params->enable_mld && nla_put_flag(msg, NL80211_ATTR_MLO_SUPPORT)) - return -1; -#endif + return 0; } @@ -6721,9 +7162,8 @@ static int wpa_driver_nl80211_try_connect( #ifdef CONFIG_DRIVER_NL80211_QCA if (params->req_key_mgmt_offload && params->psk && - (params->key_mgmt_suite == WPA_KEY_MGMT_PSK || - params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 || - params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) { + (wpa_key_mgmt_wpa_psk_no_sae(params->key_mgmt_suite) || + wpa_key_mgmt_wpa_psk_no_sae(params->allowed_key_mgmts))) { wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK"); ret = issue_key_mgmt_set_key(drv, params->psk, 32); if (ret) @@ -6757,9 +7197,31 @@ static int wpa_driver_nl80211_try_connect( goto fail; #ifdef CONFIG_SAE - if ((wpa_key_mgmt_sae(params->key_mgmt_suite)) && + if ((wpa_key_mgmt_sae(params->key_mgmt_suite) || + wpa_key_mgmt_sae(params->allowed_key_mgmts)) && nl80211_put_sae_pwe(msg, params->sae_pwe) < 0) goto fail; + + /* Add SAE password in case of SAE authentication offload */ + if ((params->sae_password || params->passphrase) && + (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA)) { + const char *password; + size_t pwd_len; + + if (params->sae_password && params->sae_password_id) { + wpa_printf(MSG_INFO, + "nl80211: Use of SAE password identifiers not supported with driver-based SAE"); + goto fail; + } + + password = params->sae_password; + if (!password) + password = params->passphrase; + pwd_len = os_strlen(password); + wpa_printf(MSG_DEBUG, " * SAE password"); + if (nla_put(msg, NL80211_ATTR_SAE_PASSWORD, pwd_len, password)) + goto fail; + } #endif /* CONFIG_SAE */ algs = 0; @@ -6773,6 +7235,8 @@ static int wpa_driver_nl80211_try_connect( algs++; if (params->auth_alg & WPA_AUTH_ALG_FT) algs++; + if (params->auth_alg & WPA_AUTH_ALG_SAE) + algs++; if (algs > 1) { wpa_printf(MSG_DEBUG, " * Leave out Auth Type for automatic " "selection"); @@ -6797,7 +7261,10 @@ skip_auth_type: if (ret) goto fail; - ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1); + if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER)) + goto fail; + ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL, + NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d " @@ -6855,6 +7322,7 @@ static int wpa_driver_nl80211_associate( { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl80211_err_info err_info; int ret = -1; struct nl_msg *msg; @@ -6872,10 +7340,6 @@ static int wpa_driver_nl80211_associate( if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0) return -1; - if (wpa_key_mgmt_sae(params->key_mgmt_suite)) - bss->use_nl_connect = 1; - else - bss->use_nl_connect = 0; return wpa_driver_nl80211_connect(drv, params, bss); } @@ -6912,13 +7376,42 @@ static int wpa_driver_nl80211_associate( goto fail; } - ret = send_and_recv_msgs_connect_handle(drv, msg, drv->first_bss, 1); - msg = NULL; + if (!TEST_FAIL_TAG("assoc")) { + if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER)) + goto fail; + ret = send_and_recv(drv->global, drv->first_bss->nl_connect, + msg, NULL, NULL, NULL, NULL, &err_info); + msg = NULL; + } else { + int i; + + /* Error and force TEST_FAIL checking for each link */ + ret = -EINVAL; + for_each_link(params->mld_params.valid_links, i) { + if (TEST_FAIL_TAG("link")) + err_info.link_id = i; + } + } + if (ret) { wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: MLME command failed (assoc) ret=%d (%s)", ret, strerror(-ret)); nl80211_dump_scan(drv); + + /* Mark failed link within params */ + if (err_info.link_id >= 0) { + if (err_info.link_id >= MAX_NUM_MLD_LINKS || + !(params->mld_params.valid_links & + BIT(err_info.link_id))) { + wpa_printf(MSG_DEBUG, + "nl80211: Invalid errorred link_id %d", + err_info.link_id); + goto fail; + } + params->mld_params.mld_links[err_info.link_id].error = + ret; + } } else { wpa_printf(MSG_DEBUG, "nl80211: Association request send successfully"); @@ -6949,7 +7442,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (!ret) return 0; @@ -7193,14 +7686,17 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) struct nl_msg *msg; struct nl80211_sta_flag_update upd; int ret; + const u8 *connected_addr = drv->sta_mlo_info.valid_links ? + drv->sta_mlo_info.ap_mld_addr : drv->bssid; - if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) { + if (!drv->associated && is_zero_ether_addr(connected_addr) && + !authorized) { wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated"); return 0; } wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for " - MACSTR_SEC, authorized ? "" : "un", MAC2STR_SEC(drv->bssid)); + MACSTR_SEC, authorized ? "" : "un", MAC2STR_SEC(connected_addr)); os_memset(&upd, 0, sizeof(upd)); upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED); @@ -7208,13 +7704,13 @@ static int wpa_driver_nl80211_set_supp_port(void *priv, int authorized) upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED); if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) || - nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, connected_addr) || nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) { nlmsg_free(msg); return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (!ret) return 0; wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)", @@ -7262,24 +7758,33 @@ static int get_key_handler(struct nl_msg *msg, void *arg) static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr, - int idx, u8 *seq) + int idx, int link_id, u8 *seq) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; + int res; msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0, NL80211_CMD_GET_KEY); if (!msg || (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) || + (link_id != NL80211_DRV_LINK_ID_NA && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) || nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) { nlmsg_free(msg); return -ENOBUFS; } - memset(seq, 0, 6); + os_memset(seq, 0, 6); + res = send_and_recv_resp(drv, msg, get_key_handler, seq); + if (res) { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to get current TX sequence for a key (link_id=%d idx=%d): %d (%s)", + link_id, idx, res, strerror(-res)); + } - return send_and_recv_msgs(drv, msg, get_key_handler, seq, NULL, NULL); + return res; } @@ -7302,7 +7807,7 @@ static int i802_set_rts(void *priv, int rts) return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (!ret) return 0; wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: " @@ -7330,7 +7835,7 @@ static int i802_set_frag(void *priv, int frag) return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (!ret) return 0; wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold " @@ -7339,25 +7844,37 @@ static int i802_set_frag(void *priv, int frag) } -static int i802_flush(void *priv) +static int i802_flush(void *priv, int link_id) { struct i802_bss *bss = priv; struct nl_msg *msg; int res; - wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)", - bss->ifname); + if (link_id == NL80211_DRV_LINK_ID_NA) + wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)", + bss->ifname); + else + wpa_printf(MSG_DEBUG, + "nl80211: flush -> DEL_STATION %s (with link %d)", + bss->ifname, link_id); /* * 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, NULL, NULL); + if (link_id >= 0 && (bss->valid_links & BIT(link_id)) && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) + goto fail; + + res = send_and_recv_cmd(bss->drv, msg); if (res) { wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d " "(%s)", res, strerror(-res)); } return res; +fail: + nlmsg_free(msg); + return -1; } @@ -7401,16 +7918,26 @@ static int get_sta_handler(struct nl_msg *msg, void *arg) [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_RETRIES] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 }, + [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 }, + [NL80211_STA_INFO_CONNECTED_TIME] = { .type = NLA_U32 }, + [NL80211_STA_INFO_BEACON_LOSS] = { .type = NLA_U32 }, [NL80211_STA_INFO_RX_BYTES64] = { .type = NLA_U64 }, [NL80211_STA_INFO_TX_BYTES64] = { .type = NLA_U64 }, - [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, - [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 }, + [NL80211_STA_INFO_EXPECTED_THROUGHPUT] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_DROP_MISC] = { .type = NLA_U64 }, + [NL80211_STA_INFO_BEACON_RX] = { .type = NLA_U64 }, + [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8}, [NL80211_STA_INFO_RX_DURATION] = { .type = NLA_U64 }, + [NL80211_STA_INFO_ACK_SIGNAL] = { .type = NLA_U8 }, + [NL80211_STA_INFO_ACK_SIGNAL_AVG] = { .type = NLA_S8 }, + [NL80211_STA_INFO_RX_MPDUS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_FCS_ERROR_COUNT] = { .type = NLA_U32 }, [NL80211_STA_INFO_TX_DURATION] = { .type = NLA_U64 }, - [NL80211_STA_INFO_CONNECTED_TIME] = { .type = NLA_U32 }, }; struct nlattr *rate[NL80211_RATE_INFO_MAX + 1]; static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { @@ -7420,6 +7947,10 @@ static int get_sta_handler(struct nl_msg *msg, void *arg) [NL80211_RATE_INFO_VHT_MCS] = { .type = NLA_U8 }, [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, [NL80211_RATE_INFO_VHT_NSS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_HE_MCS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_HE_NSS] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_HE_GI] = { .type = NLA_U8 }, + [NL80211_RATE_INFO_HE_DCM] = { .type = NLA_U8 }, }; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), @@ -7462,34 +7993,62 @@ static int get_sta_handler(struct nl_msg *msg, void *arg) nla_get_u64(stats[NL80211_STA_INFO_TX_BYTES64]); data->bytes_64bit = 1; } + if (stats[NL80211_STA_INFO_SIGNAL]) + data->signal = (s8) nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]); if (stats[NL80211_STA_INFO_RX_PACKETS]) data->rx_packets = nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]); if (stats[NL80211_STA_INFO_TX_PACKETS]) data->tx_packets = nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]); - if (stats[NL80211_STA_INFO_RX_DURATION]) - data->rx_airtime = - nla_get_u64(stats[NL80211_STA_INFO_RX_DURATION]); - if (stats[NL80211_STA_INFO_TX_DURATION]) - data->tx_airtime = - nla_get_u64(stats[NL80211_STA_INFO_TX_DURATION]); + if (stats[NL80211_STA_INFO_TX_RETRIES]) + data->tx_retry_count = + nla_get_u32(stats[NL80211_STA_INFO_TX_RETRIES]); if (stats[NL80211_STA_INFO_TX_FAILED]) data->tx_retry_failed = nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]); - if (stats[NL80211_STA_INFO_SIGNAL]) - data->signal = nla_get_u8(stats[NL80211_STA_INFO_SIGNAL]); - if (stats[NL80211_STA_INFO_ACK_SIGNAL]) { - data->last_ack_rssi = - nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]); - data->flags |= STA_DRV_DATA_LAST_ACK_RSSI; - } - + if (stats[NL80211_STA_INFO_SIGNAL_AVG]) + data->avg_signal = + (s8) nla_get_u8(stats[NL80211_STA_INFO_SIGNAL_AVG]); if (stats[NL80211_STA_INFO_CONNECTED_TIME]) { data->connected_sec = nla_get_u32(stats[NL80211_STA_INFO_CONNECTED_TIME]); data->flags |= STA_DRV_DATA_CONN_TIME; } + if (stats[NL80211_STA_INFO_BEACON_LOSS]) + data->beacon_loss_count = + nla_get_u32(stats[NL80211_STA_INFO_BEACON_LOSS]); + if (stats[NL80211_STA_INFO_EXPECTED_THROUGHPUT]) + data->expected_throughput = + nla_get_u32(stats[NL80211_STA_INFO_EXPECTED_THROUGHPUT]); + if (stats[NL80211_STA_INFO_RX_DROP_MISC]) + data->rx_drop_misc = + nla_get_u64(stats[NL80211_STA_INFO_RX_DROP_MISC]); + if (stats[NL80211_STA_INFO_BEACON_RX]) + data->beacons_count = + nla_get_u64(stats[NL80211_STA_INFO_BEACON_RX]); + if (stats[NL80211_STA_INFO_BEACON_SIGNAL_AVG]) + data->avg_beacon_signal = + (s8) nla_get_u8(stats[NL80211_STA_INFO_BEACON_SIGNAL_AVG]); + if (stats[NL80211_STA_INFO_RX_DURATION]) + data->rx_airtime = + nla_get_u64(stats[NL80211_STA_INFO_RX_DURATION]); + if (stats[NL80211_STA_INFO_ACK_SIGNAL]) { + data->last_ack_rssi = + nla_get_u8(stats[NL80211_STA_INFO_ACK_SIGNAL]); + data->flags |= STA_DRV_DATA_LAST_ACK_RSSI; + } + if (stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]) + data->avg_ack_signal = + nla_get_s8(stats[NL80211_STA_INFO_ACK_SIGNAL_AVG]); + if (stats[NL80211_STA_INFO_RX_MPDUS]) + data->rx_mpdus = nla_get_u32(stats[NL80211_STA_INFO_RX_MPDUS]); + if (stats[NL80211_STA_INFO_FCS_ERROR_COUNT]) + data->fcs_error_count = + nla_get_u32(stats[NL80211_STA_INFO_FCS_ERROR_COUNT]); + if (stats[NL80211_STA_INFO_TX_DURATION]) + data->tx_airtime = + nla_get_u64(stats[NL80211_STA_INFO_TX_DURATION]); if (stats[NL80211_STA_INFO_TX_BITRATE] && nla_parse_nested(rate, NL80211_RATE_INFO_MAX, @@ -7502,6 +8061,10 @@ static int get_sta_handler(struct nl_msg *msg, void *arg) data->current_tx_rate = nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]); + /* Convert from 100 kbps to kbps; it's a more convenient unit. + * It's also safe up until ~1Tbps. */ + data->current_tx_rate = data->current_tx_rate * 100; + if (rate[NL80211_RATE_INFO_MCS]) { data->tx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]); data->flags |= STA_DRV_DATA_TX_MCS; @@ -7511,13 +8074,44 @@ static int get_sta_handler(struct nl_msg *msg, void *arg) nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]); data->flags |= STA_DRV_DATA_TX_VHT_MCS; } - if (rate[NL80211_RATE_INFO_SHORT_GI]) + if (rate[NL80211_RATE_INFO_SHORT_GI]) { + data->tx_guard_interval = GUARD_INTERVAL_0_4; data->flags |= STA_DRV_DATA_TX_SHORT_GI; + } if (rate[NL80211_RATE_INFO_VHT_NSS]) { data->tx_vht_nss = nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]); data->flags |= STA_DRV_DATA_TX_VHT_NSS; } + if (rate[NL80211_RATE_INFO_HE_MCS]) { + data->tx_hemcs = + nla_get_u8(rate[NL80211_RATE_INFO_HE_MCS]); + data->flags |= STA_DRV_DATA_TX_HE_MCS; + } + if (rate[NL80211_RATE_INFO_HE_NSS]) { + data->tx_he_nss = + nla_get_u8(rate[NL80211_RATE_INFO_HE_NSS]); + data->flags |= STA_DRV_DATA_TX_HE_NSS; + } + if (rate[NL80211_RATE_INFO_HE_GI]) { + switch (nla_get_u8(rate[NL80211_RATE_INFO_HE_GI])) { + case NL80211_RATE_INFO_HE_GI_0_8: + data->tx_guard_interval = GUARD_INTERVAL_0_8; + break; + case NL80211_RATE_INFO_HE_GI_1_6: + data->tx_guard_interval = GUARD_INTERVAL_1_6; + break; + case NL80211_RATE_INFO_HE_GI_3_2: + data->tx_guard_interval = GUARD_INTERVAL_3_2; + break; + } + data->flags |= STA_DRV_DATA_TX_HE_GI; + } + if (rate[NL80211_RATE_INFO_HE_DCM]) { + data->tx_dcm = + nla_get_u8(rate[NL80211_RATE_INFO_HE_DCM]); + data->flags |= STA_DRV_DATA_TX_HE_DCM; + } } if (stats[NL80211_STA_INFO_RX_BITRATE] && @@ -7531,9 +8125,12 @@ static int get_sta_handler(struct nl_msg *msg, void *arg) data->current_rx_rate = nla_get_u16(rate[NL80211_RATE_INFO_BITRATE]); + /* Convert from 100 kbps to kbps; it's a more convenient unit. + * It's also safe up until ~1Tbps. */ + data->current_rx_rate = data->current_rx_rate * 100; + if (rate[NL80211_RATE_INFO_MCS]) { - data->rx_mcs = - nla_get_u8(rate[NL80211_RATE_INFO_MCS]); + data->rx_mcs = nla_get_u8(rate[NL80211_RATE_INFO_MCS]); data->flags |= STA_DRV_DATA_RX_MCS; } if (rate[NL80211_RATE_INFO_VHT_MCS]) { @@ -7541,21 +8138,72 @@ static int get_sta_handler(struct nl_msg *msg, void *arg) nla_get_u8(rate[NL80211_RATE_INFO_VHT_MCS]); data->flags |= STA_DRV_DATA_RX_VHT_MCS; } - if (rate[NL80211_RATE_INFO_SHORT_GI]) + if (rate[NL80211_RATE_INFO_SHORT_GI]) { + data->rx_guard_interval = GUARD_INTERVAL_0_4; data->flags |= STA_DRV_DATA_RX_SHORT_GI; + } if (rate[NL80211_RATE_INFO_VHT_NSS]) { data->rx_vht_nss = nla_get_u8(rate[NL80211_RATE_INFO_VHT_NSS]); data->flags |= STA_DRV_DATA_RX_VHT_NSS; } + if (rate[NL80211_RATE_INFO_HE_MCS]) { + data->rx_hemcs = + nla_get_u8(rate[NL80211_RATE_INFO_HE_MCS]); + data->flags |= STA_DRV_DATA_RX_HE_MCS; + } + if (rate[NL80211_RATE_INFO_HE_NSS]) { + data->rx_he_nss = + nla_get_u8(rate[NL80211_RATE_INFO_HE_NSS]); + data->flags |= STA_DRV_DATA_RX_HE_NSS; + } + if (rate[NL80211_RATE_INFO_HE_GI]) { + switch (nla_get_u8(rate[NL80211_RATE_INFO_HE_GI])) { + case NL80211_RATE_INFO_HE_GI_0_8: + data->rx_guard_interval = GUARD_INTERVAL_0_8; + break; + case NL80211_RATE_INFO_HE_GI_1_6: + data->rx_guard_interval = GUARD_INTERVAL_1_6; + break; + case NL80211_RATE_INFO_HE_GI_3_2: + data->rx_guard_interval = GUARD_INTERVAL_3_2; + break; + } + data->flags |= STA_DRV_DATA_RX_HE_GI; + } + if (rate[NL80211_RATE_INFO_HE_DCM]) { + data->rx_dcm = + nla_get_u8(rate[NL80211_RATE_INFO_HE_DCM]); + data->flags |= STA_DRV_DATA_RX_HE_DCM; + } } - if (stats[NL80211_STA_INFO_TID_STATS]) - get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]); + if (stats[NL80211_STA_INFO_TID_STATS]) + get_sta_tid_stats(data, stats[NL80211_STA_INFO_TID_STATS]); + + return NL_SKIP; +} + + +int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv, + const u8 *bssid, + struct hostap_sta_driver_data *data) +{ + struct nl_msg *msg; + + data->signal = -WPA_INVALID_NOISE; + data->current_tx_rate = 0; + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) { + nlmsg_free(msg); + return -ENOBUFS; + } - return NL_SKIP; + return send_and_recv_resp(drv, msg, get_sta_handler, data); } + static int i802_read_sta_data(struct i802_bss *bss, struct hostap_sta_driver_data *data, const u8 *addr) @@ -7568,13 +8216,13 @@ static int i802_read_sta_data(struct i802_bss *bss, return -ENOBUFS; } - return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data, - NULL, NULL); + return send_and_recv_resp(bss->drv, msg, get_sta_handler, data); } static int i802_set_tx_queue_params(void *priv, int queue, int aifs, - int cw_min, int cw_max, int burst_time) + int cw_min, int cw_max, int burst_time, + int link_id) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -7626,10 +8274,14 @@ 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, NULL, NULL); + if (link_id != NL80211_DRV_LINK_ID_NA && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) + goto fail; + + res = send_and_recv_cmd(drv, msg); 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); + "nl80211: link=%d: TX queue param set: queue=%d aifs=%d cw_min=%d cw_max=%d burst_time=%d --> res=%d", + link_id, queue, aifs, cw_min, cw_max, burst_time, res); if (res == 0) return 0; msg = NULL; @@ -7640,7 +8292,7 @@ fail: static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr, - const char *ifname, int vlan_id) + const char *ifname, int vlan_id, int link_id) { struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; @@ -7654,12 +8306,14 @@ static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr, nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) && nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) || + (link_id != NL80211_DRV_LINK_ID_NA && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr=" MACSTR_SEC " ifname=%s vlan_id=%d) failed: %d (%s)", @@ -7696,14 +8350,15 @@ static int i802_sta_clear_stats(void *priv, const u8 *addr) static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, - u16 reason) + u16 reason, int link_id) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct ieee80211_mgmt mgmt; u8 channel; + struct i802_link *link = nl80211_get_link(bss, link_id); - if (ieee80211_freq_to_chan(bss->freq, &channel) == + if (ieee80211_freq_to_chan(link->freq, &channel) == HOSTAPD_MODE_IEEE80211AD) { /* Deauthentication is not used in DMG/IEEE 802.11ad; * disassociate the STA instead. */ @@ -7726,7 +8381,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + sizeof(mgmt.u.deauth), 0, 0, 0, 0, - 0, NULL, 0, 0); + 0, NULL, 0, 0, link_id); } @@ -7753,7 +8408,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + sizeof(mgmt.u.disassoc), 0, 0, 0, 0, - 0, NULL, 0, 0); + 0, NULL, 0, 0, -1); } @@ -7911,7 +8566,8 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA " "interface %s up", name); } - return i802_set_sta_vlan(priv, addr, name, 0); + return i802_set_sta_vlan(priv, addr, name, 0, + NL80211_DRV_LINK_ID_NA); } else { if (bridge_ifname && linux_br_del_if(drv->global->ioctl_sock, bridge_ifname, @@ -7920,7 +8576,8 @@ static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val, "nl80211: Failed to remove interface %s from bridge %s: %s", name, bridge_ifname, strerror(errno)); - i802_set_sta_vlan(priv, addr, bss->ifname, 0); + i802_set_sta_vlan(priv, addr, bss->ifname, 0, + NL80211_DRV_LINK_ID_NA); nl80211_remove_iface(drv, if_nametoindex(name)); os_memset(&event, 0, sizeof(event)); event.wds_sta_interface.sta_addr = addr; @@ -8084,7 +8741,6 @@ static void *i802_init(struct hostapd_data *hapd, (params->num_bridge == 0 || !params->bridge[0])) add_ifidx(drv, br_ifindex, drv->ifindex); -#ifdef CONFIG_LIBNL3_ROUTE if (bss->added_if_into_bridge || bss->already_in_bridge) { int err; @@ -8101,7 +8757,6 @@ static void *i802_init(struct hostapd_data *hapd, goto failed; } } -#endif /* CONFIG_LIBNL3_ROUTE */ if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) { wpa_printf(MSG_DEBUG, @@ -8175,7 +8830,7 @@ static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr) struct wpa_driver_nl80211_data *drv; dl_list_for_each(drv, &global->interfaces, struct wpa_driver_nl80211_data, list) { - if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0) + if (ether_addr_equal(addr, drv->first_bss->addr)) return 1; } return 0; @@ -8294,7 +8949,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, if (!addr && (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP || type == WPA_IF_P2P_GO || type == WPA_IF_MESH || - type == WPA_IF_STATION)) { + type == WPA_IF_STATION || type == WPA_IF_AP_BSS)) { /* Enforce unique address */ u8 new_addr[ETH_ALEN]; @@ -8360,14 +9015,11 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, new_bss->ifindex = ifidx; new_bss->drv = drv; new_bss->next = drv->first_bss->next; -#ifdef CONFIG_MLD_PATCH new_bss->flink = &new_bss->links[0]; new_bss->valid_links = 0; os_memcpy(new_bss->flink->addr, new_bss->addr, ETH_ALEN); new_bss->flink->freq = drv->first_bss->flink->freq; -#endif - new_bss->freq = drv->first_bss->freq; new_bss->ctx = bss_ctx; new_bss->added_if = added; drv->first_bss->next = new_bss; @@ -8444,6 +9096,7 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss, tbss->next = bss->next; /* Unsubscribe management frames */ nl80211_teardown_ap(bss); + nl80211_remove_links(bss); nl80211_destroy_bss(bss); if (!bss->added_if) i802_set_iface_flags(bss, 0); @@ -8458,14 +9111,16 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss, } else { wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context"); nl80211_teardown_ap(bss); + nl80211_remove_links(bss); if (!bss->added_if && !drv->first_bss->next) - wpa_driver_nl80211_del_beacon(bss); + wpa_driver_nl80211_del_beacon_all(bss); nl80211_destroy_bss(bss); if (!bss->added_if) i802_set_iface_flags(bss, 0); if (drv->first_bss->next) { drv->first_bss = drv->first_bss->next; drv->ctx = drv->first_bss->ctx; + drv->ifindex = drv->first_bss->ifindex; os_free(bss); } else { wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to"); @@ -8494,7 +9149,7 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss, const u8 *buf, size_t buf_len, int save_cookie, int no_cck, int no_ack, int offchanok, const u16 *csa_offs, - size_t csa_offs_len) + size_t csa_offs_len, int link_id) { struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; @@ -8507,6 +9162,8 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss, wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len); if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) || + ((link_id != NL80211_DRV_LINK_ID_NA) && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) || (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) || (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) || (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) || @@ -8520,7 +9177,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, NULL, NULL); + ret = send_and_recv_resp(drv, msg, cookie_handler, &cookie); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d " @@ -8534,6 +9191,11 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss, if (save_cookie) drv->send_frame_cookie = no_ack ? (u64) -1 : cookie; + if (!wait) { + /* There is no need to store this cookie since there + * is no wait that could be canceled later. */ + goto fail; + } if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) { wpa_printf(MSG_DEBUG, "nl80211: Drop oldest pending send frame cookie 0x%llx", @@ -8569,13 +9231,18 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss, struct ieee80211_hdr *hdr; int offchanok = 1; - if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq && - bss->beacon_set) + if (is_ap_interface(drv->nlmode) && (int) freq == bss->flink->freq && + bss->flink->beacon_set) + offchanok = 0; + + if (!freq && is_sta_interface(drv->nlmode)) offchanok = 0; - wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, " - "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)", - drv->ifindex, freq, wait_time, no_cck, offchanok); + wpa_printf(MSG_DEBUG, + "nl80211: Send Action frame (ifindex=%d, freq=%u MHz wait=%d ms no_cck=%d offchanok=%d dst=" + MACSTR " src=" MACSTR " bssid=" MACSTR ")", + drv->ifindex, freq, wait_time, no_cck, offchanok, + MAC2STR(dst), MAC2STR(src), MAC2STR(bssid)); buf = os_zalloc(24 + data_len); if (buf == NULL) @@ -8588,7 +9255,7 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss, os_memcpy(hdr->addr2, src, ETH_ALEN); os_memcpy(hdr->addr3, bssid, ETH_ALEN); - if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) { + if (!ether_addr_equal(bss->addr, src)) { wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR_SEC, MAC2STR_SEC(src)); os_memcpy(bss->rand_addr, src, ETH_ALEN); @@ -8606,7 +9273,7 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss, 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)) + ieee80211_is_dfs(bss->flink->freq, modes, num_modes)) offchanok = 0; if (modes) { for (i = 0; i < num_modes; i++) { @@ -8620,15 +9287,16 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss, if (is_ap_interface(drv->nlmode) && (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) || - (int) freq == bss->freq || drv->device_ap_sme || + (int) freq == bss->flink->freq || drv->device_ap_sme || !drv->use_monitor)) ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len, 0, freq, no_cck, offchanok, - wait_time, NULL, 0, 0); + wait_time, NULL, 0, 0, -1); else ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf, - 24 + data_len, - 1, no_cck, 0, offchanok, NULL, 0); + 24 + data_len, 1, no_cck, 0, + offchanok, NULL, 0, + NL80211_DRV_LINK_ID_NA); os_free(buf); return ret; @@ -8649,7 +9317,7 @@ static void nl80211_frame_wait_cancel(struct i802_bss *bss, u64 cookie) return; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d " "(%s)", ret, strerror(-ret)); @@ -8664,7 +9332,8 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv) u64 cookie; /* Cancel the last pending TX cookie */ - nl80211_frame_wait_cancel(bss, drv->send_frame_cookie); + if (drv->send_frame_cookie != (u64) -1) + nl80211_frame_wait_cancel(bss, drv->send_frame_cookie); /* * Cancel the other pending TX cookies, if any. This is needed since @@ -8680,6 +9349,43 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv) } +static int nl80211_put_any_link_id(struct nl_msg *msg, + struct driver_sta_mlo_info *mlo, + int freq) +{ + int i; + int link_id = -1; + int any_valid_link_id = -1; + + if (!mlo->valid_links) + return 0; + + /* First try to pick a link that uses the same band */ + for_each_link(mlo->valid_links, i) { + if (any_valid_link_id == -1) + any_valid_link_id = i; + + if (is_same_band(freq, mlo->links[i].freq)) { + link_id = i; + break; + } + } + + /* Use any valid link ID if no band match was found */ + if (link_id == -1) + link_id = any_valid_link_id; + + if (link_id == -1) { + wpa_printf(MSG_INFO, + "nl80211: No valid Link ID found for freq %u", freq); + return 0; + } + + wpa_printf(MSG_DEBUG, "nl80211: Add Link ID %d", link_id); + return nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id); +} + + static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq, unsigned int duration) { @@ -8691,13 +9397,14 @@ static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq, if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || - nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) { + nla_put_u32(msg, NL80211_ATTR_DURATION, duration) || + nl80211_put_any_link_id(msg, &drv->sta_mlo_info, freq)) { nlmsg_free(msg); return -1; } cookie = 0; - ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie, NULL, NULL); + ret = send_and_recv_resp(drv, msg, cookie_handler, &cookie); if (ret == 0) { wpa_printf(MSG_WARNING, "nl80211: Remain-on-channel cookie " "0x%llx for freq=%u MHz duration=%u", @@ -8737,7 +9444,7 @@ static int wpa_driver_nl80211_cancel_remain_on_channel(void *priv) return -1; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret == 0) return 0; wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: " @@ -8834,7 +9541,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d " "(%s)", ret, strerror(-ret)); @@ -8849,14 +9556,96 @@ fail: } +static int nl80211_remove_link(struct i802_bss *bss, int link_id) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; + struct i802_link *link; + struct nl_msg *msg; + size_t i; + int ret; + + wpa_printf(MSG_DEBUG, "nl80211: Remove link (ifindex=%d link_id=%u)", + bss->ifindex, link_id); + + if (!(bss->valid_links & BIT(link_id))) { + wpa_printf(MSG_DEBUG, + "nl80211: MLD: remove link: Link not found"); + return -1; + } + + link = &bss->links[link_id]; + + wpa_driver_nl80211_del_beacon(bss, link_id); + + /* First remove the link locally */ + bss->valid_links &= ~BIT(link_id); + os_memset(link->addr, 0, ETH_ALEN); + + /* Choose new deflink if we are removing that link */ + if (bss->flink == link) { + for_each_link_default(bss->valid_links, i, 0) { + bss->flink = &bss->links[i]; + break; + } + } + + /* If this was the last link, reset default link */ + if (!bss->valid_links) { + /* TODO: Does keeping freq/bandwidth make sense? */ + if (bss->flink != link) + os_memcpy(bss->flink, link, sizeof(*link)); + + os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN); + } + + /* Remove the link from the kernel */ + msg = nl80211_bss_msg(bss, 0, NL80211_CMD_REMOVE_LINK); + if (!msg || + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) { + nlmsg_free(msg); + wpa_printf(MSG_ERROR, + "nl80211: remove link (%d) failed", link_id); + return -1; + } + + ret = send_and_recv_cmd(drv, msg); + if (ret) + wpa_printf(MSG_ERROR, + "nl80211: remove link (%d) failed. ret=%d (%s)", + link_id, ret, strerror(-ret)); + + return ret; +} + + +static void nl80211_remove_links(struct i802_bss *bss) +{ + int ret; + u8 link_id; + + for_each_link(bss->valid_links, link_id) { + ret = nl80211_remove_link(bss, link_id); + if (ret) + break; + } + + if (bss->flink) + os_memcpy(bss->flink->addr, bss->addr, ETH_ALEN); +} + + static int wpa_driver_nl80211_deinit_ap(void *priv) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; + if (!is_ap_interface(drv->nlmode)) return -1; - wpa_driver_nl80211_del_beacon(bss); - bss->beacon_set = 0; + + /* Stop beaconing */ + wpa_driver_nl80211_del_beacon(bss, NL80211_DRV_LINK_ID_NA); + + nl80211_remove_links(bss); /* * If the P2P GO interface was dynamically added, then it is @@ -8869,15 +9658,25 @@ static int wpa_driver_nl80211_deinit_ap(void *priv) } -static int wpa_driver_nl80211_stop_ap(void *priv) +static int wpa_driver_nl80211_stop_ap(void *priv, int link_id) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; + if (!is_ap_interface(drv->nlmode)) return -1; - wpa_driver_nl80211_del_beacon(bss); - bss->beacon_set = 0; - return 0; + + if (link_id == -1) { + wpa_driver_nl80211_del_beacon_all(bss); + return 0; + } + + if (nl80211_link_valid(bss->valid_links, link_id)) { + wpa_driver_nl80211_del_beacon(bss, link_id); + return 0; + } + + return -1; } @@ -8931,7 +9730,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, NULL, NULL); + return send_and_recv_cmd(drv, msg); } @@ -8969,7 +9768,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, NULL, NULL); + return send_and_recv_resp(drv, msg, get_channel_width, sig); } @@ -8980,12 +9779,12 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si) int res; os_memset(si, 0, sizeof(*si)); - res = nl80211_get_link_signal(drv, si); + res = nl80211_get_link_signal(drv, drv->bssid, &si->data); if (res) { if (drv->nlmode != NL80211_IFTYPE_ADHOC && drv->nlmode != NL80211_IFTYPE_MESH_POINT) return res; - si->current_signal = 0; + si->data.signal = 0; } res = nl80211_get_channel_width(drv, si); @@ -8995,7 +9794,7 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si) return nl80211_get_link_noise(drv, si); } -#ifdef CONFIG_MLD_PATCH_EXT + static int get_links_noise(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; @@ -9030,10 +9829,7 @@ static int get_links_noise(struct nl_msg *msg, void *arg) if (!sinfo[NL80211_SURVEY_INFO_NOISE]) return NL_SKIP; - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(mlo_sig->valid_links & BIT(i))) - continue; - + for_each_link(mlo_sig->valid_links, i) { if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) != mlo_sig->links[i].frequency) continue; @@ -9046,14 +9842,14 @@ static int get_links_noise(struct nl_msg *msg, void *arg) return NL_SKIP; } + static int nl80211_get_links_noise(struct wpa_driver_nl80211_data *drv, struct wpa_mlo_signal_info *mlo_sig) { struct nl_msg *msg; msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY); - return send_and_recv_msgs(drv, msg, get_links_noise, mlo_sig, - NULL, NULL); + return send_and_recv_resp(drv, msg, get_links_noise, mlo_sig); } @@ -9107,8 +9903,7 @@ static int nl80211_get_links_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_links_channel_width, mlo_sig, - NULL, NULL); + return send_and_recv_resp(drv, msg, get_links_channel_width, mlo_sig); } @@ -9127,11 +9922,10 @@ static int nl80211_mlo_signal_poll(void *priv, os_memset(mlo_si, 0, sizeof(*mlo_si)); mlo_si->valid_links = drv->sta_mlo_info.valid_links; - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(mlo_si->valid_links & BIT(i))) - continue; - - res = nl80211_get_link_signal(drv, mlo_si); + for_each_link(mlo_si->valid_links, i) { + res = nl80211_get_link_signal(drv, + drv->sta_mlo_info.links[i].bssid, + &mlo_si->links[i].data); if (res != 0) return res; @@ -9148,7 +9942,7 @@ static int nl80211_mlo_signal_poll(void *priv, return nl80211_get_links_noise(drv, mlo_si); } -#endif + static int nl80211_set_param(void *priv, const char *param) { @@ -9214,6 +10008,11 @@ static int nl80211_set_param(void *priv, const char *param) } } + if (os_strstr(param, "secure_ltf=1")) { + drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_STA | + WPA_DRIVER_FLAGS2_SEC_LTF_AP; + } + return 0; } @@ -9222,6 +10021,13 @@ static void * nl80211_global_init(void *ctx) { struct nl80211_global *global; struct netlink_config *cfg; + struct utsname name; + + if (uname(&name) == 0) { + wpa_printf(MSG_DEBUG, "nl80211: Kernel version: %s %s (%s; %s)", + name.sysname, name.release, + name.version, name.machine); + } global = os_zalloc(sizeof(*global)); if (global == NULL) @@ -9299,10 +10105,14 @@ static const char * nl80211_get_radio_name(void *priv) static int nl80211_pmkid(struct i802_bss *bss, int cmd, - struct wpa_pmkid_params *params) + struct wpa_pmkid_params *params, bool skip_pmk) { struct nl_msg *msg; - const size_t PMK_MAX_LEN = 48; /* current cfg80211 limit */ + + if (cmd == NL80211_CMD_SET_PMKSA) + wpa_printf(MSG_DEBUG, + "nl80211: NL80211_CMD_SET_PMKSA with skip_pmk=%s pmk_len=%zu", + skip_pmk ? "true" : "false", params->pmk_len); if (!(msg = nl80211_bss_msg(bss, 0, cmd)) || (params->pmkid && @@ -9321,20 +10131,23 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd, nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD, params->pmk_reauth_threshold)) || (cmd != NL80211_CMD_DEL_PMKSA && - params->pmk_len && params->pmk_len <= PMK_MAX_LEN && + params->pmk_len && !skip_pmk && nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) { nl80211_nlmsg_clear(msg); nlmsg_free(msg); return -ENOBUFS; } - return send_and_recv_msgs(bss->drv, msg, NULL, NULL, NULL, NULL); + return send_and_recv_cmd(bss->drv, msg); } static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params) { struct i802_bss *bss = priv; + const size_t PMK_MAX_LEN = 64; /* current cfg80211 limit */ + const size_t LEGACY_PMK_MAX_LEN = 48; /* old cfg80211 limit */ + bool skip_pmk = params->pmk_len > PMK_MAX_LEN; int ret; if (params->bssid) @@ -9347,7 +10160,15 @@ static int nl80211_add_pmkid(void *priv, struct wpa_pmkid_params *params) anonymize_ssid(wpa_ssid_txt(params->ssid, params->ssid_len))); } - ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params); + ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params, skip_pmk); + /* + * Try again by skipping PMK if the first attempt failed with ERANGE + * error, PMK was not skipped, and PMK length is greater than the + * legacy kernel maximum allowed limit. + */ + if (ret == -ERANGE && !skip_pmk && + params->pmk_len > LEGACY_PMK_MAX_LEN) + ret = nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, params, true); if (ret < 0) { wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_PMKSA failed: %d (%s)", @@ -9373,7 +10194,7 @@ static int nl80211_remove_pmkid(void *priv, struct wpa_pmkid_params *params) anonymize_ssid(wpa_ssid_txt(params->ssid, params->ssid_len))); } - ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params); + ret = nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, params, true); if (ret < 0) { wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_DEL_PMKSA failed: %d (%s)", @@ -9393,7 +10214,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, NULL, NULL); + return send_and_recv_cmd(bss->drv, msg); } @@ -9557,8 +10378,8 @@ 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, NULL, NULL); + err = send_and_recv_resp(drv, msg, survey_handler, + survey_results); } while (err > 0); if (err) @@ -9598,7 +10419,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, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret == -EOPNOTSUPP) { wpa_printf(MSG_DEBUG, "nl80211: Driver does not support rekey offload"); @@ -9640,7 +10461,7 @@ static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr, os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0, - 0, 0, NULL, 0, 0) < 0) + 0, 0, NULL, 0, 0, -1) < 0) wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to " "send poll frame"); } @@ -9665,7 +10486,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, NULL, NULL); + ret = send_and_recv_resp(drv, msg, cookie_handler, &cookie); if (ret < 0) { wpa_printf(MSG_DEBUG, "nl80211: Client probe request for " MACSTR_SEC " failed: ret=%d (%s)", @@ -9691,7 +10512,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, NULL, NULL); + ret = send_and_recv_cmd(bss->drv, msg); if (ret < 0) { wpa_printf(MSG_DEBUG, "nl80211: Setting PS state %s failed: %d (%s)", @@ -9751,7 +10572,7 @@ static int nl80211_start_radar_detection(void *priv, return -1; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret == 0) return 0; wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: " @@ -9783,10 +10604,46 @@ static int nl80211_add_peer_capab(struct nl_msg *msg, } +static int +nl80211_tdls_set_discovery_resp_link(struct wpa_driver_nl80211_data *drv, + int link_id) +{ +#ifdef CONFIG_DRIVER_NL80211_QCA + struct nl_msg *msg; + struct nlattr *params; + + wpa_printf(MSG_DEBUG, "nl80211: TDLS Discovery Response Tx link ID %u", + link_id); + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT) || + !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) || + nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK, + link_id)) { + wpa_printf(MSG_ERROR, + "%s: err in adding vendor_cmd and vendor_data", + __func__); + nlmsg_free(msg); + return -1; + } + nla_nest_end(msg, params); + + return send_and_recv_cmd(drv, msg); +#else /* CONFIG_DRIVER_NL80211_QCA */ + wpa_printf(MSG_ERROR, + "nl80211: Setting TX link for TDLS Discovery Response not supported"); + return -1; +#endif /* CONFIG_DRIVER_NL80211_QCA */ +} + + static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, int initiator, const u8 *buf, - size_t len) + size_t len, int link_id) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -9798,17 +10655,26 @@ static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, if (!dst) return -EINVAL; + if (link_id >= 0 && + nl80211_tdls_set_discovery_resp_link(drv, link_id) < 0) + return -EOPNOTSUPP; + + if (link_id < 0 && drv->sta_mlo_info.valid_links) + link_id = drv->sta_mlo_info.assoc_link_id; + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) || nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) || nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) || nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code) || + (link_id >= 0 && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) || nl80211_add_peer_capab(msg, peer_capab) || (initiator && nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) || nla_put(msg, NL80211_ATTR_IE, len, buf)) goto fail; - return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + return send_and_recv_cmd(drv, msg); fail: nlmsg_free(msg); @@ -9858,7 +10724,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, NULL, NULL); + res = send_and_recv_cmd(drv, msg); wpa_printf(MSG_DEBUG, "nl80211: TDLS_OPER: oper=%d mac=" MACSTR_SEC " --> res=%d (%s)", nl80211_oper, MAC2STR_SEC(peer), res, strerror(-res)); @@ -9892,7 +10758,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, NULL, NULL); + return send_and_recv_cmd(drv, msg); } @@ -9918,7 +10784,7 @@ nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr) return -ENOBUFS; } - return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + return send_and_recv_cmd(drv, msg); } #endif /* CONFIG TDLS */ @@ -9985,16 +10851,84 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type, } +#ifdef CONFIG_IEEE80211BE + +static int driver_nl80211_link_remove(void *priv, enum wpa_driver_if_type type, + const char *ifname, u8 link_id) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + + if (type != WPA_IF_AP_BSS || + !nl80211_link_valid(bss->valid_links, link_id)) + return -1; + + wpa_printf(MSG_DEBUG, + "nl80211: Teardown AP(%s) link %d (type=%d ifname=%s links=0x%x)", + bss->ifname, link_id, type, ifname, bss->valid_links); + + nl80211_remove_link(bss, link_id); + + bss->ctx = bss->flink->ctx; + + if (drv->first_bss == bss && bss->valid_links) + drv->ctx = bss->ctx; + + if (!bss->valid_links) { + wpa_printf(MSG_DEBUG, + "nl80211: No more links remaining, so remove interface"); + return wpa_driver_nl80211_if_remove(bss, type, ifname); + } + + return 0; +} + + +static bool nl80211_is_drv_shared(void *priv, void *bss_ctx) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + unsigned int num_bss = 0; + + /* If any other BSS exist, someone else is using this since at this + * time, we would have removed all BSSs created by this driver and only + * this BSS should be remaining if the driver is not shared by anyone. + */ + for (bss = drv->first_bss; bss; bss = bss->next) { + num_bss++; + if (num_bss > 1) + return true; + } + + /* This is the only BSS present */ + bss = priv; + + /* If only one/no link is there no one is sharing */ + if (bss->valid_links <= 1) + return false; + + /* More than one link means someone is still using. To check if + * only 1 bit is set, power of 2 condition can be checked. */ + if (!(bss->valid_links & (bss->valid_links - 1))) + return false; + + return true; +} + +#endif /* CONFIG_IEEE80211BE */ + + static int driver_nl80211_send_mlme(void *priv, const u8 *data, size_t data_len, int noack, unsigned int freq, const u16 *csa_offs, size_t csa_offs_len, - int no_encrypt, unsigned int wait) + int no_encrypt, unsigned int wait, + int link_id) { struct i802_bss *bss = priv; return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack, freq, 0, 0, wait, csa_offs, - csa_offs_len, no_encrypt); + csa_offs_len, no_encrypt, link_id); } @@ -10006,10 +10940,11 @@ static int driver_nl80211_sta_remove(void *priv, const u8 *addr) static int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr, - const char *ifname, int vlan_id) + const char *ifname, int vlan_id, + int link_id) { struct i802_bss *bss = priv; - return i802_set_sta_vlan(bss, addr, ifname, vlan_id); + return i802_set_sta_vlan(bss, addr, ifname, vlan_id, link_id); } @@ -10061,7 +10996,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed " "err=%d (%s)", ret, strerror(-ret)); @@ -10089,7 +11024,7 @@ static int nl80211_update_dh_ie(void *priv, const u8 *peer_mac, return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: update_dh_ie failed err=%d (%s)", @@ -10160,8 +11095,8 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) bss->ifname, bss->brname, MAC2STR(bss->addr), - bss->freq, - bss->beacon_set ? "beacon_set=1\n" : "", + bss->flink->freq, + bss->flink->beacon_set ? "beacon_set=1\n" : "", bss->added_if_into_bridge ? "added_if_into_bridge=1\n" : "", bss->already_in_bridge ? "already_in_bridge=1\n" : "", @@ -10231,19 +11166,59 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) drv->retry_auth ? "retry_auth=1\n" : "", drv->use_monitor ? "use_monitor=1\n" : "", drv->ignore_next_local_disconnect ? - "ignore_next_local_disconnect=1\n" : "", + "ignore_next_local_disconnect\n" : "", drv->ignore_next_local_deauth ? - "ignore_next_local_deauth=1\n" : ""); + "ignore_next_local_deauth\n" : ""); if (os_snprintf_error(end - pos, res)) return pos - buf; pos += res; + if (drv->sta_mlo_info.valid_links) { + int i; + struct driver_sta_mlo_info *mlo = &drv->sta_mlo_info; + + res = os_snprintf(pos, end - pos, + "ap_mld_addr=" MACSTR "\n" + "default_map=%d\n", + MAC2STR(mlo->ap_mld_addr), + mlo->default_map); + if (os_snprintf_error(end - pos, res)) + return pos - buf; + pos += res; + + for_each_link(mlo->valid_links, i) { + res = os_snprintf(pos, end - pos, + "link_addr[%u]=" MACSTR "\n" + "link_bssid[%u]=" MACSTR "\n" + "link_freq[%u]=%u\n", + i, MAC2STR(mlo->links[i].addr), + i, MAC2STR(mlo->links[i].bssid), + i, mlo->links[i].freq); + if (os_snprintf_error(end - pos, res)) + return pos - buf; + pos += res; + + if (!mlo->default_map) { + res = os_snprintf( + pos, end - pos, + "uplink_map[%u]=%x\n" + "downlink_map[%u]=%x\n", + i, mlo->links[i].t2lmap.uplink, + i, mlo->links[i].t2lmap.downlink); + if (os_snprintf_error(end - pos, res)) + return pos - buf; + pos += res; + } + } + } + if (drv->has_capability) { res = os_snprintf(pos, end - pos, "capa.key_mgmt=0x%x\n" "capa.enc=0x%x\n" "capa.auth=0x%x\n" "capa.flags=0x%llx\n" + "capa.flags2=0x%llx\n" "capa.rrm_flags=0x%x\n" "capa.max_scan_ssids=%d\n" "capa.max_sched_scan_ssids=%d\n" @@ -10261,11 +11236,14 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) "capa.max_conc_chan_5_0=%u\n" "capa.max_sched_scan_plans=%u\n" "capa.max_sched_scan_plan_interval=%u\n" - "capa.max_sched_scan_plan_iterations=%u\n", + "capa.max_sched_scan_plan_iterations=%u\n" + "capa.mbssid_max_interfaces=%u\n" + "capa.ema_max_periodicity=%u\n", drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth, (unsigned long long) drv->capa.flags, + (unsigned long long) drv->capa.flags2, drv->capa.rrm_flags, drv->capa.max_scan_ssids, drv->capa.max_sched_scan_ssids, @@ -10283,7 +11261,9 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) drv->capa.max_conc_chan_5_0, drv->capa.max_sched_scan_plans, drv->capa.max_sched_scan_plan_interval, - drv->capa.max_sched_scan_plan_iterations); + drv->capa.max_sched_scan_plan_iterations, + drv->capa.mbssid_max_interfaces, + drv->capa.ema_max_periodicity); if (os_snprintf_error(end - pos, res)) return pos - buf; pos += res; @@ -10293,8 +11273,8 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) if (msg && 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, NULL, NULL) == 0 && + if (send_and_recv_resp(drv, msg, nl80211_get_country, + alpha2) == 0 && alpha2[0]) { res = os_snprintf(pos, end - pos, "country=%s\n", alpha2); @@ -10347,7 +11327,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) int i; wpa_printf(MSG_DEBUG, - "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d%s%s%s)", + "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d puncturing_bitmap=0x%04x link_id=%d%s%s%s)", settings->cs_count, settings->block_tx, settings->freq_params.freq, settings->freq_params.channel, @@ -10355,6 +11335,8 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) settings->freq_params.bandwidth, settings->freq_params.center_freq1, settings->freq_params.center_freq2, + settings->punct_bitmap, + settings->link_id, settings->freq_params.ht_enabled ? " ht" : "", settings->freq_params.vht_enabled ? " vht" : "", settings->freq_params.he_enabled ? " he" : ""); @@ -10425,7 +11407,12 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) settings->cs_count) || (ret = nl80211_put_freq_params(msg, &settings->freq_params)) || (settings->block_tx && - nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX))) + nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)) || + (settings->punct_bitmap && + nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP, + settings->punct_bitmap)) || + (settings->link_id != NL80211_DRV_LINK_ID_NA && + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->link_id))) goto error; /* beacon_after params */ @@ -10442,30 +11429,139 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) if (ret) goto error; - if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON, - csa_off_len * sizeof(u16), - settings->counter_offset_beacon) || - (settings->beacon_csa.probe_resp && - nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP, - csa_off_len * sizeof(u16), - settings->counter_offset_presp))) - goto fail; + if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON, + csa_off_len * sizeof(u16), + settings->counter_offset_beacon) || + (settings->beacon_csa.probe_resp && + nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP, + csa_off_len * sizeof(u16), + settings->counter_offset_presp))) + goto fail; + + nla_nest_end(msg, beacon_csa); + +#ifdef CONFIG_IEEE80211AX + if (settings->ubpr.unsol_bcast_probe_resp_interval && + nl80211_unsol_bcast_probe_resp(bss, msg, &settings->ubpr) < 0) + goto fail; +#endif /* CONFIG_IEEE80211AX */ + + ret = send_and_recv_cmd(drv, msg); + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)", + ret, strerror(-ret)); + } + return ret; + +fail: + ret = -ENOBUFS; +error: + nlmsg_free(msg); + wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request"); + return ret; +} + + +#ifdef CONFIG_IEEE80211AX +static int nl80211_switch_color(void *priv, struct cca_settings *settings) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nlattr *beacon_cca; + struct nl_msg *msg; + int ret = -ENOBUFS; + + wpa_printf(MSG_DEBUG, + "nl80211: Color change request (cca_count=%u color=%d)", + settings->cca_count, settings->cca_color); + + if (drv->nlmode != NL80211_IFTYPE_AP) + return -EOPNOTSUPP; + + if (!settings->beacon_cca.tail) + return -EINVAL; + + if (settings->beacon_cca.tail_len <= settings->counter_offset_beacon || + settings->beacon_cca.tail[settings->counter_offset_beacon] != + settings->cca_count) + return -EINVAL; + + if (settings->beacon_cca.probe_resp && + (settings->beacon_cca.probe_resp_len <= + settings->counter_offset_presp || + settings->beacon_cca.probe_resp[settings->counter_offset_presp] != + settings->cca_count)) + return -EINVAL; + + msg = nl80211_bss_msg(bss, 0, NL80211_CMD_COLOR_CHANGE_REQUEST); + if (!msg || + nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COUNT, + settings->cca_count) || + nla_put_u8(msg, NL80211_ATTR_COLOR_CHANGE_COLOR, + settings->cca_color)) + goto error; + + /* beacon_after params */ + ret = set_beacon_data(msg, &settings->beacon_after); + if (ret) + goto error; + + /* beacon_csa params */ + beacon_cca = nla_nest_start(msg, NL80211_ATTR_COLOR_CHANGE_ELEMS); + if (!beacon_cca) { + ret = -ENOBUFS; + goto error; + } + + ret = set_beacon_data(msg, &settings->beacon_cca); + if (ret) + goto error; + + if (nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_BEACON, + settings->counter_offset_beacon) || + (settings->beacon_cca.probe_resp && + nla_put_u16(msg, NL80211_ATTR_CNTDWN_OFFS_PRESP, + settings->counter_offset_presp))) { + ret = -ENOBUFS; + goto error; + } + + nla_nest_end(msg, beacon_cca); + + if (settings->ubpr.unsol_bcast_probe_resp_interval && + nl80211_unsol_bcast_probe_resp(bss, msg, &settings->ubpr) < 0) { + ret = -ENOBUFS; + goto error; + } + +#ifdef CONFIG_IEEE80211BE + if (nl80211_link_valid(bss->valid_links, settings->link_id)) { + wpa_printf(MSG_DEBUG, + "nl80211: Color change request on link_id=%d", + settings->link_id); - nla_nest_end(msg, beacon_csa); - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, + settings->link_id)) { + nlmsg_free(msg); + return -1; + } + } +#endif /* CONFIG_IEEE80211BE */ + + ret = send_and_recv_cmd(drv, msg); if (ret) { - wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)", + wpa_printf(MSG_DEBUG, + "nl80211: switch_color failed err=%d (%s)", ret, strerror(-ret)); } return ret; -fail: - ret = -ENOBUFS; error: nlmsg_free(msg); - wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request"); + wpa_printf(MSG_DEBUG, "nl80211: Could not build color switch request"); return ret; } +#endif /* CONFIG_IEEE80211AX */ static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr, @@ -10493,7 +11589,7 @@ static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr, return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)", ret, strerror(-ret)); @@ -10520,7 +11616,7 @@ static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr) return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)", ret, strerror(-ret)); @@ -10622,12 +11718,10 @@ static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id, 0) goto fail; /* This test vendor_cmd can be used with nl80211 commands that - * need the connect nl_sock, so use the owner-setting variant - * of send_and_recv_msgs(). */ - ret = send_and_recv_msgs_owner(drv, msg, - get_connect_handle(bss), 0, - cmd_reply_handler, buf, - NULL, NULL); + * need the connect nl_sock, so use the variant that takes in + * bss->nl_connect as the handle. */ + ret = send_and_recv(drv->global, bss->nl_connect, msg, + cmd_reply_handler, buf, NULL, NULL, NULL); if (ret) wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d", ret); @@ -10651,8 +11745,7 @@ static int nl80211_vendor_cmd(void *priv, unsigned int vendor_id, data_len, data))) goto fail; - ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf, - NULL, NULL); + ret = send_and_recv_resp(drv, msg, vendor_reply_handler, buf); if (ret) wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d", ret); @@ -10675,13 +11768,13 @@ static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set, wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map", qos_map_set, qos_map_set_len); - if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) || + if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_QOS_MAP)) || nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) { nlmsg_free(msg); return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed"); @@ -10716,8 +11809,7 @@ 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, - NULL, NULL); + ret = send_and_recv_resp(drv, msg, get_wowlan_handler, &wowlan_enabled); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed"); return 0; @@ -10764,7 +11856,7 @@ static int nl80211_set_wowlan(void *priv, nla_nest_end(msg, wowlan_triggers); - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed"); @@ -10803,7 +11895,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, NULL, NULL); + return send_and_recv_cmd(drv, msg); } @@ -10831,7 +11923,7 @@ static int nl80211_disable_fils(void *priv, int disable) } nla_nest_end(msg, params); - return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + return send_and_recv_cmd(drv, msg); } @@ -10888,7 +11980,7 @@ static int nl80211_set_bssid_tmp_disallow(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, NULL, NULL); + return send_and_recv_cmd(drv, msg); fail: nlmsg_free(msg); @@ -10926,7 +12018,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, NULL, NULL); + return send_and_recv_cmd(drv, msg); } #endif /* CONFIG_DRIVER_NL80211_QCA */ @@ -10963,6 +12055,7 @@ static int nl80211_set_mac_addr(void *priv, const u8 *addr) wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR_SEC, bss->ifname, MAC2STR_SEC(addr)); drv->addr_changed = new_addr; + os_memcpy(bss->prev_addr, bss->addr, ETH_ALEN); os_memcpy(bss->addr, addr, ETH_ALEN); if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0) @@ -11100,7 +12193,10 @@ static int nl80211_join_mesh(struct i802_bss *bss, if (nl80211_put_mesh_config(msg, ¶ms->conf) < 0) goto fail; - ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1); + if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER)) + return -1; + ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL, + NULL, NULL); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)", @@ -11108,7 +12204,7 @@ static int nl80211_join_mesh(struct i802_bss *bss, goto fail; } ret = 0; - drv->assoc_freq = bss->freq = params->freq.freq; + drv->assoc_freq = bss->flink->freq = params->freq.freq; wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully"); fail: @@ -11157,13 +12253,15 @@ 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_connect_handle(drv, msg, bss, 0); + ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL, + NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)", ret, strerror(-ret)); } else { wpa_printf(MSG_DEBUG, "nl80211: mesh leave request send successfully"); + drv->first_bss->flink->freq = 0; } if (drv->start_mode_sta && @@ -11192,7 +12290,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: mesh link probe to " MACSTR_SEC " failed: ret=%d (%s)", @@ -11212,13 +12310,14 @@ static int wpa_driver_br_add_ip_neigh(void *priv, u8 version, const u8 *ipaddr, int prefixlen, const u8 *addr) { -#ifdef CONFIG_LIBNL3_ROUTE struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - struct rtnl_neigh *rn; - struct nl_addr *nl_ipaddr = NULL; - struct nl_addr *nl_lladdr = NULL; - int family, addrsize; + struct ndmsg nhdr = { + .ndm_state = NUD_PERMANENT, + .ndm_ifindex = bss->br_ifindex, + }; + struct nl_msg *msg; + int addrsize; int res; if (!ipaddr || prefixlen == 0 || !addr) @@ -11237,85 +12336,62 @@ static int wpa_driver_br_add_ip_neigh(void *priv, u8 version, } if (version == 4) { - family = AF_INET; + nhdr.ndm_family = AF_INET; addrsize = 4; } else if (version == 6) { - family = AF_INET6; + nhdr.ndm_family = AF_INET6; addrsize = 16; } else { return -EINVAL; } - rn = rtnl_neigh_alloc(); - if (rn == NULL) + msg = nlmsg_alloc_simple(RTM_NEWNEIGH, NLM_F_CREATE); + if (!msg) return -ENOMEM; - /* set the destination ip address for neigh */ - nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize); - if (nl_ipaddr == NULL) { - wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed"); - res = -ENOMEM; - goto errout; - } - nl_addr_set_prefixlen(nl_ipaddr, prefixlen); - res = rtnl_neigh_set_dst(rn, nl_ipaddr); - if (res) { - wpa_printf(MSG_DEBUG, - "nl80211: neigh set destination addr failed"); + res = -ENOMEM; + if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 || + nla_put(msg, NDA_DST, addrsize, (void *) ipaddr) || + nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *) addr)) goto errout; - } - /* set the corresponding lladdr for neigh */ - nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN); - if (nl_lladdr == NULL) { - wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed"); - res = -ENOMEM; + res = nl_send_auto_complete(drv->rtnl_sk, msg); + if (res < 0) goto errout; - } - rtnl_neigh_set_lladdr(rn, nl_lladdr); - - rtnl_neigh_set_ifindex(rn, bss->br_ifindex); - rtnl_neigh_set_state(rn, NUD_PERMANENT); - res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE); + res = nl_wait_for_ack(drv->rtnl_sk); if (res) { wpa_printf(MSG_DEBUG, "nl80211: Adding bridge ip neigh failed: %s", nl_geterror(res)); } errout: - if (nl_lladdr) - nl_addr_put(nl_lladdr); - if (nl_ipaddr) - nl_addr_put(nl_ipaddr); - if (rn) - rtnl_neigh_put(rn); + nlmsg_free(msg); return res; -#else /* CONFIG_LIBNL3_ROUTE */ - return -1; -#endif /* CONFIG_LIBNL3_ROUTE */ } static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version, const u8 *ipaddr) { -#ifdef CONFIG_LIBNL3_ROUTE struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; - struct rtnl_neigh *rn; - struct nl_addr *nl_ipaddr; - int family, addrsize; + struct ndmsg nhdr = { + .ndm_state = NUD_PERMANENT, + .ndm_ifindex = bss->br_ifindex, + }; + struct nl_msg *msg; + int addrsize; int res; if (!ipaddr) return -EINVAL; if (version == 4) { - family = AF_INET; + nhdr.ndm_family = AF_INET; addrsize = 4; } else if (version == 6) { - family = AF_INET6; + nhdr.ndm_family = AF_INET6; addrsize = 16; } else { return -EINVAL; @@ -11333,41 +12409,28 @@ static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version, return -1; } - rn = rtnl_neigh_alloc(); - if (rn == NULL) + msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE); + if (!msg) return -ENOMEM; - /* set the destination ip address for neigh */ - nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize); - if (nl_ipaddr == NULL) { - wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed"); - res = -ENOMEM; - goto errout; - } - res = rtnl_neigh_set_dst(rn, nl_ipaddr); - if (res) { - wpa_printf(MSG_DEBUG, - "nl80211: neigh set destination addr failed"); + res = -ENOMEM; + if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0 || + nla_put(msg, NDA_DST, addrsize, (void *) ipaddr)) goto errout; - } - rtnl_neigh_set_ifindex(rn, bss->br_ifindex); + res = nl_send_auto_complete(drv->rtnl_sk, msg); + if (res < 0) + goto errout; - res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0); + res = nl_wait_for_ack(drv->rtnl_sk); if (res) { wpa_printf(MSG_DEBUG, "nl80211: Deleting bridge ip neigh failed: %s", nl_geterror(res)); } errout: - if (nl_ipaddr) - nl_addr_put(nl_ipaddr); - if (rn) - rtnl_neigh_put(rn); + nlmsg_free(msg); return res; -#else /* CONFIG_LIBNL3_ROUTE */ - return -1; -#endif /* CONFIG_LIBNL3_ROUTE */ } @@ -11404,6 +12467,8 @@ static const char * drv_br_port_attr_str(enum drv_br_port_attr attr) return "proxyarp_wifi"; case DRV_BR_PORT_ATTR_HAIRPIN_MODE: return "hairpin_mode"; + case DRV_BR_PORT_ATTR_MCAST2UCAST: + return "multicast_to_unicast"; } return NULL; @@ -11588,23 +12653,29 @@ static int nl80211_qca_do_acs(struct wpa_driver_nl80211_data *drv, nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) || (params->vht_enabled && nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) || + (params->eht_enabled && + nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED)) || nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width) || add_acs_ch_list(msg, params->freq_list) || add_acs_freq_list(msg, params->freq_list) || (params->edmg_enabled && - nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) { + nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED)) || + (params->link_id != NL80211_DRV_LINK_ID_NA && + nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_LINK_ID, + params->link_id))) { nlmsg_free(msg); return -ENOBUFS; } nla_nest_end(msg, data); wpa_printf(MSG_DEBUG, - "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d", + "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d EHT: %d BW: %d EDMG: %d, link_id: %d", params->hw_mode, params->ht_enabled, params->ht40_enabled, - params->vht_enabled, params->ch_width, params->edmg_enabled); + params->vht_enabled, params->eht_enabled, params->ch_width, + params->edmg_enabled, params->link_id); - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Failed to invoke driver ACS function: %s", @@ -11662,7 +12733,7 @@ static int nl80211_set_band(void *priv, u32 band_mask) } nla_nest_end(msg, data); - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Driver setband function failed: %s", @@ -11674,9 +12745,33 @@ static int nl80211_set_band(void *priv, u32 band_mask) struct nl80211_pcl { unsigned int num; - unsigned int *freq_list; + struct weighted_pcl *freq_list; }; +static void get_pcl_attr_values(struct weighted_pcl *wpcl, struct nlattr *nl[]) +{ + if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ]) + wpcl->freq = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FREQ]); + if (nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT]) + wpcl->weight = nla_get_u8(nl[QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT]); + if (nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]) { + u32 flags = nla_get_u32(nl[QCA_WLAN_VENDOR_ATTR_PCL_FLAG]); + + wpcl->flag = 0; + if (flags & BIT(0)) + wpcl->flag |= WEIGHTED_PCL_GO; + if (flags & BIT(1)) + wpcl->flag |= WEIGHTED_PCL_CLI; + if (flags & BIT(2)) + wpcl->flag |= WEIGHTED_PCL_MUST_CONSIDER; + if (flags & BIT(3)) + wpcl->flag |= WEIGHTED_PCL_EXCLUDE; + } else { + wpcl->flag = WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI; + } +} + + static int preferred_freq_info_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; @@ -11685,6 +12780,7 @@ static int preferred_freq_info_handler(struct nl_msg *msg, void *arg) struct nlattr *nl_vend, *attr; enum qca_iface_type iface_type; struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + struct nlattr *nl_pcl[QCA_WLAN_VENDOR_ATTR_PCL_MAX + 1]; unsigned int num, max_num; u32 *freqs; @@ -11710,26 +12806,69 @@ static int preferred_freq_info_handler(struct nl_msg *msg, void *arg) wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d", iface_type); - attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]; - if (!attr) { + attr = tb_vendor[ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL]; + if (attr) { + int rem; + struct nlattr *wpcl = attr; + unsigned int i; + + num = 0; + nla_for_each_nested(attr, wpcl, rem) { + if (num == param->num) + break; /* not enough room for all entries */ + if (nla_parse(nl_pcl, QCA_WLAN_VENDOR_ATTR_PCL_MAX, + nla_data(attr), nla_len(attr), NULL)) { + wpa_printf(MSG_ERROR, + "nl80211: Failed to parse PCL info"); + param->num = 0; + return NL_SKIP; + } + get_pcl_attr_values(¶m->freq_list[num], nl_pcl); + num++; + } + param->num = num; + + /* Sort frequencies based on their weight */ + for (i = 0; i < num; i++) { + unsigned int j; + + for (j = i + 1; j < num; j++) { + if (param->freq_list[i].weight < + param->freq_list[j].weight) { + struct weighted_pcl tmp; + + tmp = param->freq_list[i]; + param->freq_list[i] = + param->freq_list[j]; + param->freq_list[j] = tmp; + } + } + } + } else if (tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]) { + wpa_printf(MSG_DEBUG, + "nl80211: Driver does not provide weighted PCL; use the non-weighted variant"); + attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]; + /* + * param->num has the maximum number of entries for which there + * is room in the freq_list provided by the caller. + */ + freqs = nla_data(attr); + max_num = nla_len(attr) / sizeof(u32); + if (max_num > param->num) + max_num = param->num; + for (num = 0; num < max_num; num++) { + param->freq_list[num].freq = freqs[num]; + param->freq_list[num].flag = + WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI; + } + param->num = num; + } else { wpa_printf(MSG_ERROR, "nl80211: preferred_freq_list couldn't be found"); param->num = 0; return NL_SKIP; } - - /* - * param->num has the maximum number of entries for which there - * is room in the freq_list provided by the caller. - */ - freqs = nla_data(attr); - max_num = nla_len(attr) / sizeof(u32); - if (max_num > param->num) - max_num = param->num; - for (num = 0; num < max_num; num++) - param->freq_list[num] = freqs[num]; - param->num = num; - return NL_SKIP; } @@ -11737,7 +12876,7 @@ static int preferred_freq_info_handler(struct nl_msg *msg, void *arg) static int nl80211_get_pref_freq_list(void *priv, enum wpa_driver_if_type if_type, unsigned int *num, - unsigned int *freq_list) + struct weighted_pcl *freq_list) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -11794,20 +12933,22 @@ 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, ¶m, - NULL, NULL); + if (freq_list) + os_memset(freq_list, 0, *num * sizeof(struct weighted_pcl)); + ret = send_and_recv_resp(drv, msg, preferred_freq_info_handler, ¶m); if (ret) { wpa_printf(MSG_ERROR, - "%s: err in send_and_recv_msgs", __func__); + "%s: err in send_and_recv_resp", __func__); return ret; } *num = param.num; for (i = 0; i < *num; i++) { - wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d", - i, freq_list[i]); + wpa_printf(MSG_DEBUG, + "nl80211: preferred_channel_list[%d]=%d[%d]:0x%x", + i, freq_list[i].freq, freq_list[i].weight, + freq_list[i].flag); } return 0; @@ -11848,10 +12989,10 @@ 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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) { - wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs", + wpa_printf(MSG_ERROR, "%s: err in send_and_recv_cmd", __func__); return ret; } @@ -11904,7 +13045,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, @@ -11939,7 +13080,7 @@ static int nl80211_p2p_lo_stop(void *priv) return -1; } - return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + return send_and_recv_cmd(drv, msg); } @@ -11978,7 +13119,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) { wpa_printf(MSG_ERROR, @@ -12169,9 +13310,9 @@ nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params) nla_nest_end(msg, attr1); nla_nest_end(msg, attr); - ret = send_and_recv_msgs(drv, msg, + ret = send_and_recv_resp(drv, msg, nl80211_get_bss_transition_status_handler, - info, NULL, NULL); + info); msg = NULL; if (ret) { wpa_printf(MSG_ERROR, @@ -12224,7 +13365,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) { wpa_printf(MSG_ERROR, @@ -12240,6 +13381,170 @@ fail: #endif /* CONFIG_MBO */ + +#ifdef CONFIG_PASN + +static int nl80211_send_pasn_resp(void *priv, struct pasn_auth *params) +{ + unsigned int i; + struct i802_bss *bss = priv; + struct nl_msg *msg = NULL; + struct nlattr *nlpeers, *attr, *attr1; + struct wpa_driver_nl80211_data *drv = bss->drv; + + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: PASN authentication response for %d entries", + params->num_peers); + 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_PASN)) + goto fail; + + attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); + if (!attr) + goto fail; + + nlpeers = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEERS); + if (!nlpeers) + goto fail; + + for (i = 0; i < params->num_peers; i++) { + attr1 = nla_nest_start(msg, i); + if (!attr1 || + nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR, + ETH_ALEN, params->peer[i].own_addr) || + nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR, + ETH_ALEN, params->peer[i].peer_addr)) + goto fail; + + if (params->peer[i].status == 0 && + nla_put_flag(msg, + QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS)) + goto fail; + + wpa_printf(MSG_DEBUG, + "nl80211: Own address[%u]: " MACSTR_SEC + " Peer address[%u]: " MACSTR_SEC " Status: %s", + i, MAC2STR_SEC(params->peer[i].own_addr), i, + MAC2STR_SEC(params->peer[i].peer_addr), + params->peer[i].status ? "Fail" : "Success"); + nla_nest_end(msg, attr1); + } + + nla_nest_end(msg, nlpeers); + nla_nest_end(msg, attr); + + return send_and_recv_cmd(drv, msg); + +fail: + nlmsg_free(msg); + return -1; +} + + +static u32 wpa_ltf_keyseed_len_to_sha_type(size_t len) +{ + if (len == SHA384_MAC_LEN) + return QCA_WLAN_VENDOR_SHA_384; + if (len == SHA256_MAC_LEN) + return QCA_WLAN_VENDOR_SHA_256; + + wpa_printf(MSG_ERROR, "nl80211: Unexpected LTF keyseed len %zu", len); + return (u32) -1; +} + + +static int nl80211_set_secure_ranging_ctx(void *priv, + struct secure_ranging_params *params) +{ + int ret; + u32 suite; + struct nlattr *attr; + struct nl_msg *msg = NULL; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + + /* Configure secure ranging context only to the drivers that support it. + */ + if (!drv->secure_ranging_ctx_vendor_cmd_avail) + return 0; + + if (!params->peer_addr || !params->own_addr) + return -1; + + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: Secure ranging context for " MACSTR, + MAC2STR(params->peer_addr)); + + 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_SECURE_RANGING_CONTEXT)) + goto fail; + + attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); + if (!attr) + goto fail; + + if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR, + ETH_ALEN, params->peer_addr) || + nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR, + ETH_ALEN, params->own_addr) || + nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION, + params->action)) + goto fail; + + if (params->cipher) { + suite = wpa_cipher_to_cipher_suite(params->cipher); + if (!suite || + nla_put_u32(msg, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER, + suite)) + goto fail; + } + + if (params->tk_len && params->tk) { + if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK, + params->tk_len, params->tk)) + goto fail; + wpa_hexdump_key(MSG_DEBUG, "nl80211: TK", + params->tk, params->tk_len); + } + + if (params->ltf_keyseed_len && params->ltf_keyseed) { + u32 sha_type = wpa_ltf_keyseed_len_to_sha_type( + params->ltf_keyseed_len); + + if (sha_type == (u32) -1 || + nla_put_u32( + msg, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE, + sha_type) || + nla_put(msg, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED, + params->ltf_keyseed_len, params->ltf_keyseed)) + goto fail; + wpa_hexdump_key(MSG_DEBUG, "nl80211: LTF keyseed", + params->ltf_keyseed, params->ltf_keyseed_len); + } + nla_nest_end(msg, attr); + + ret = send_and_recv_cmd(drv, msg); + if (ret) + wpa_printf(MSG_DEBUG, + "nl80211: Set secure ranging context failed: ret=%d (%s)", + ret, strerror(-ret)); + return ret; +fail: + nlmsg_free(msg); + return -1; +} + +#endif /* CONFIG_PASN */ + #endif /* CONFIG_DRIVER_NL80211_QCA */ @@ -12281,7 +13586,7 @@ static int wpa_driver_do_broadcom_acs(struct wpa_driver_nl80211_data *drv, 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); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_ERROR, "nl80211: BRCM Failed to invoke driver ACS function: %s", @@ -12447,11 +13752,42 @@ static int nl80211_get_ext_capab(void *priv, enum wpa_driver_if_type type, *ext_capa_len = drv->extended_capa_len; /* Replace the default value if a per-interface type value exists */ - for (i = 0; i < drv->num_iface_ext_capa; i++) { - if (nlmode == drv->iface_ext_capa[i].iftype) { - *ext_capa = drv->iface_ext_capa[i].ext_capa; - *ext_capa_mask = drv->iface_ext_capa[i].ext_capa_mask; - *ext_capa_len = drv->iface_ext_capa[i].ext_capa_len; + for (i = 0; i < drv->num_iface_capa; i++) { + if (nlmode == drv->iface_capa[i].iftype) { + *ext_capa = drv->iface_capa[i].ext_capa; + *ext_capa_mask = drv->iface_capa[i].ext_capa_mask; + *ext_capa_len = drv->iface_capa[i].ext_capa_len; + break; + } + } + + return 0; +} + + +static int nl80211_get_mld_capab(void *priv, enum wpa_driver_if_type type, + u16 *eml_capa, u16 *mld_capa_and_ops) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + enum nl80211_iftype nlmode; + unsigned int i; + + if (!eml_capa || !mld_capa_and_ops) + return -1; + + nlmode = wpa_driver_nl80211_if_type(type); + + /* By default, set to zero */ + *eml_capa = 0; + *mld_capa_and_ops = 0; + + /* Replace the default value if a per-interface type value exists */ + for (i = 0; i < drv->num_iface_capa; i++) { + if (nlmode == drv->iface_capa[i].iftype) { + *eml_capa = drv->iface_capa[i].eml_capa; + *mld_capa_and_ops = + drv->iface_capa[i].mld_capa_and_ops; break; } } @@ -12505,7 +13841,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) wpa_dbg(drv->ctx, MSG_DEBUG, @@ -12548,7 +13884,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, @@ -12588,7 +13924,7 @@ 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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret && val && nl80211_get_4addr(bss) == 1) { wpa_printf(MSG_DEBUG, @@ -12631,24 +13967,9 @@ static int nl80211_dpp_listen(void *priv, bool enable) } #endif /* CONFIG_DPP */ -#ifdef CONFIG_TESTING_OPTIONS -static int testing_nl80211_register_frame(void *priv, u16 type, - const u8 *match, size_t match_len, - bool multicast) -{ - struct i802_bss *bss = priv; - struct nl_sock *handle; - - if (!bss->nl_mgmt) - return -1; - handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID); - return nl80211_register_frame(bss, handle, type, match, match_len, - multicast); -} -#endif /* CONFIG_TESTING_OPTIONS */ -#ifdef CONFIG_MLD_PATCH -static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr) +static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr, + void *bss_ctx) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -12685,7 +14006,7 @@ static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr) } } - msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ADD_LINK); + msg = nl80211_bss_msg(bss, 0, NL80211_CMD_ADD_LINK); if (!msg || nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id) || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) { @@ -12693,7 +14014,7 @@ static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr) return -ENOBUFS; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: add link failed. ret=%d (%s)", ret, strerror(-ret)); @@ -12707,12 +14028,87 @@ static int nl80211_link_add(void *priv, u8 link_id, const u8 *addr) bss->flink = &bss->links[link_id]; bss->valid_links |= BIT(link_id); + bss->links[link_id].ctx = bss_ctx; wpa_printf(MSG_DEBUG, "nl80211: MLD: valid_links=0x%04x on %s", bss->valid_links, bss->ifname); return 0; } -#endif + + +#ifdef CONFIG_IEEE80211BE +static int wpa_driver_nl80211_link_sta_remove(void *priv, u8 link_id, + const u8 *addr) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + + if (!(bss->valid_links & BIT(link_id))) + return -ENOLINK; + + if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_REMOVE_LINK_STA)) || + nla_put(msg, NL80211_ATTR_MLD_ADDR, ETH_ALEN, addr) || + nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id)) { + nlmsg_free(msg); + return -ENOBUFS; + } + + ret = send_and_recv_cmd(drv, msg); + wpa_printf(MSG_DEBUG, + "nl80211: link_sta_remove -> REMOVE_LINK_STA on link_id %u from MLD STA " + MACSTR ", from %s --> %d (%s)", + link_id, MAC2STR(addr), bss->ifname, ret, strerror(-ret)); + + return ret; +} +#endif /* CONFIG_IEEE80211BE */ + + +#ifdef CONFIG_TESTING_OPTIONS + +static int testing_nl80211_register_frame(void *priv, u16 type, + const u8 *match, size_t match_len, + bool multicast) +{ + struct i802_bss *bss = priv; + struct nl_sock *handle; + + if (!bss->nl_mgmt) + return -1; + handle = (void *) (((intptr_t) bss->nl_mgmt) ^ ELOOP_SOCKET_INVALID); + return nl80211_register_frame(bss, handle, type, match, match_len, + multicast); +} + + +static int testing_nl80211_radio_disable(void *priv, int disabled) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + + /* For now, this is supported only partially in station mode with + * SME-in-wpa_supplicant case where the NL80211_ATTR_LOCAL_STATE_CHANGE + * attribute can be used to avoid sending out the Deauthentication frame + * to the currently associated AP. */ + + if (!disabled) + return 0; + + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) + return -1; + + if (!drv->associated) + return 0; + + return wpa_driver_nl80211_mlme(drv, drv->bssid, + NL80211_CMD_DEAUTHENTICATE, + WLAN_REASON_PREV_AUTH_NOT_VALID, 1, + drv->first_bss); +} + +#endif /* CONFIG_TESTING_OPTIONS */ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", @@ -12723,7 +14119,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .scan2 = driver_nl80211_scan2, .sched_scan = wpa_driver_nl80211_sched_scan, .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan, - .get_scan_results2 = wpa_driver_nl80211_get_scan_results, + .get_scan_results = wpa_driver_nl80211_get_scan_results, .abort_scan = wpa_driver_nl80211_abort_scan, .deauthenticate = driver_nl80211_deauthenticate, .authenticate = driver_nl80211_authenticate, @@ -12775,9 +14171,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .resume = wpa_driver_nl80211_resume, .signal_monitor = nl80211_signal_monitor, .signal_poll = nl80211_signal_poll, -#ifdef CONFIG_MLD_PATCH_EXT .mlo_signal_poll = nl80211_mlo_signal_poll, -#endif .channel_info = nl80211_channel_info, .set_param = nl80211_set_param, .get_radio_name = nl80211_get_radio_name, @@ -12801,6 +14195,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .get_survey = wpa_driver_nl80211_get_survey, .status = wpa_driver_nl80211_status, .switch_channel = nl80211_switch_channel, +#ifdef CONFIG_IEEE80211AX + .switch_color = nl80211_switch_color, +#endif /* CONFIG_IEEE80211AX */ #if defined(ANDROID_P2P) || defined(CONFIG_DRIVER_NL80211_HISI) .set_noa = wpa_driver_set_p2p_noa, .get_noa = wpa_driver_get_p2p_noa, @@ -12845,21 +14242,30 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { #endif /* CONFIG_MBO */ .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow, .add_sta_node = nl80211_add_sta_node, +#ifdef CONFIG_PASN + .send_pasn_resp = nl80211_send_pasn_resp, + .set_secure_ranging_ctx = nl80211_set_secure_ranging_ctx, +#endif /* CONFIG_PASN */ #endif /* CONFIG_DRIVER_NL80211_QCA */ .do_acs = nl80211_do_acs, .configure_data_frame_filters = nl80211_configure_data_frame_filters, .get_ext_capab = nl80211_get_ext_capab, + .get_mld_capab = nl80211_get_mld_capab, .update_connect_params = nl80211_update_connection_params, .send_external_auth_status = nl80211_send_external_auth_status, .set_4addr_mode = nl80211_set_4addr_mode, #ifdef CONFIG_DPP .dpp_listen = nl80211_dpp_listen, #endif /* CONFIG_DPP */ -#ifdef CONFIG_MLD_PATCH - .get_sta_mlo_info = nl80211_get_sta_mlo_info, - .link_add = nl80211_link_add, -#endif + .get_sta_mlo_info = nl80211_get_sta_mlo_info, + .link_add = nl80211_link_add, +#ifdef CONFIG_IEEE80211BE + .link_remove = driver_nl80211_link_remove, + .is_drv_shared = nl80211_is_drv_shared, + .link_sta_remove = wpa_driver_nl80211_link_sta_remove, +#endif /* CONFIG_IEEE80211BE */ #ifdef CONFIG_TESTING_OPTIONS .register_frame = testing_nl80211_register_frame, + .radio_disable = testing_nl80211_radio_disable, #endif /* CONFIG_TESTING_OPTIONS */ }; diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211.h b/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211.h index f3f74d77c69f22c379c8430ea6e79d7cea5d14a5..9511b0f85b7406e7fced394de7ddfd49cf575e70 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211.h +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211.h @@ -32,6 +32,7 @@ struct nl80211_global { struct nl_cb *nl_cb; struct nl_sock *nl; int nl80211_id; + unsigned int nl80211_maxattr; int nlctrl_id; int ioctl_sock; /* socket for ioctl() use */ @@ -48,33 +49,31 @@ struct nl80211_wiphy_data { int wiphy_idx; }; -#ifdef CONFIG_MLD_PATCH + #define NL80211_DRV_LINK_ID_NA (-1) struct i802_link { unsigned int beacon_set:1; - s8 link_id; int freq; int bandwidth; u8 addr[ETH_ALEN]; void *ctx; }; -#endif + struct i802_bss { struct wpa_driver_nl80211_data *drv; struct i802_bss *next; -#ifdef CONFIG_MLD_PATCH + u16 valid_links; struct i802_link links[MAX_NUM_MLD_LINKS]; struct i802_link *flink; -#endif + int ifindex; int br_ifindex; u64 wdev_id; char ifname[IFNAMSIZ + 1]; char brname[IFNAMSIZ]; - unsigned int beacon_set:1; unsigned int added_if_into_bridge:1; unsigned int already_in_bridge:1; unsigned int added_bridge:1; @@ -82,15 +81,13 @@ struct i802_bss { unsigned int wdev_id_set:1; unsigned int added_if:1; unsigned int static_ap:1; - unsigned int use_nl_connect:1; #ifdef CONFIG_VENDOR_EXT unsigned int p2p_enhance_iface:1; /* vendor extension */ #endif u8 addr[ETH_ALEN]; + u8 prev_addr[ETH_ALEN]; - int freq; - int bandwidth; int if_dynamic; void *ctx; @@ -124,12 +121,14 @@ struct wpa_driver_nl80211_data { struct wpa_driver_capa capa; u8 *extended_capa, *extended_capa_mask; unsigned int extended_capa_len; - struct drv_nl80211_ext_capa { + struct drv_nl80211_iface_capa { enum nl80211_iftype iftype; u8 *ext_capa, *ext_capa_mask; unsigned int ext_capa_len; - } iface_ext_capa[NL80211_IFTYPE_MAX]; - unsigned int num_iface_ext_capa; + u16 eml_capa; + u16 mld_capa_and_ops; + } iface_capa[NL80211_IFTYPE_MAX]; + unsigned int num_iface_capa; int has_capability; int has_driver_key_mgmt; @@ -148,9 +147,7 @@ struct wpa_driver_nl80211_data { u8 bssid[ETH_ALEN]; u8 prev_bssid[ETH_ALEN]; int associated; -#ifdef CONFIG_MLD_PATCH struct driver_sta_mlo_info sta_mlo_info; -#endif u8 ssid[SSID_MAX_LEN]; size_t ssid_len; enum nl80211_iftype nlmode; @@ -170,8 +167,6 @@ struct wpa_driver_nl80211_data { unsigned int scan_for_auth:1; unsigned int retry_auth:1; unsigned int use_monitor:1; - unsigned int ignore_next_local_disconnect:1; - unsigned int ignore_next_local_deauth:1; unsigned int hostapd:1; unsigned int start_mode_sta:1; unsigned int start_iface_up:1; @@ -203,14 +198,24 @@ struct wpa_driver_nl80211_data { unsigned int unsol_bcast_probe_resp:1; unsigned int qca_do_acs:1; unsigned int brcm_do_acs:1; + unsigned int uses_6ghz:1; + unsigned int uses_s1g:1; + unsigned int secure_ranging_ctx_vendor_cmd_avail:1; + unsigned int puncturing:1; + unsigned int qca_ap_allowed_freqs:1; + + u32 ignore_next_local_disconnect; + u32 ignore_next_local_deauth; u64 vendor_scan_cookie; u64 remain_on_chan_cookie; u64 send_frame_cookie; + int send_frame_link_id; #define MAX_SEND_FRAME_COOKIES 20 u64 send_frame_cookies[MAX_SEND_FRAME_COOKIES]; unsigned int num_send_frame_cookies; u64 eapol_tx_cookie; + int eapol_tx_link_id; unsigned int last_mgmt_freq; @@ -244,11 +249,10 @@ struct wpa_driver_nl80211_data { int auth_wep_tx_keyidx; int auth_local_state_change; int auth_p2p; -#ifdef CONFIG_MLD_PATCH bool auth_mld; u8 auth_mld_link_id; u8 auth_ap_mld_addr[ETH_ALEN]; -#endif + /* * Tells whether the last scan issued from wpa_supplicant was a normal * scan (NL80211_CMD_TRIGGER_SCAN) or a vendor scan @@ -259,24 +263,52 @@ struct wpa_driver_nl80211_data { bool roam_indication_done; u8 *pending_roam_data; size_t pending_roam_data_len; - struct os_reltime pending_roam_ind_time; + u8 *pending_t2lm_data; + size_t pending_t2lm_data_len; + u8 *pending_link_reconfig_data; + size_t pending_link_reconfig_data_len; #endif /* CONFIG_DRIVER_NL80211_QCA */ }; struct nl_msg; +struct nl80211_err_info { + int link_id; +}; + void * nl80211_cmd(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg, int flags, uint8_t cmd); struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd); struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags, uint8_t cmd); 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, - int (*ack_handler_custom)(struct nl_msg *, void *), - void *ack_data); -struct nl_sock * get_connect_handle(struct i802_bss *bss); + +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, + int (*ack_handler_custom)(struct nl_msg *, void *), + void *ack_data, + struct nl80211_err_info *err_info); + +static inline int +send_and_recv_cmd(struct wpa_driver_nl80211_data *drv, + struct nl_msg *msg) +{ + return send_and_recv(drv->global, drv->global->nl, msg, + NULL, NULL, NULL, NULL, NULL); +} + +static inline int +send_and_recv_resp(struct wpa_driver_nl80211_data *drv, + struct nl_msg *msg, + int (*valid_handler)(struct nl_msg *, void *), + void *valid_data) +{ + return send_and_recv(drv->global, drv->global->nl, msg, + valid_handler, valid_data, NULL, NULL, NULL); +} + int nl80211_create_iface(struct wpa_driver_nl80211_data *drv, const char *ifname, enum nl80211_iftype iftype, const u8 *addr, int wds, @@ -293,7 +325,8 @@ int is_ap_interface(enum nl80211_iftype nlmode); int is_sta_interface(enum nl80211_iftype nlmode); int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv); int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv, - struct wpa_signal_info *sig); + const u8 *bssid, + struct hostap_sta_driver_data *data); int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv, struct wpa_signal_info *sig_change); int nl80211_get_wiphy_index(struct i802_bss *bss); @@ -303,6 +336,7 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, const u8 *addr, int cmd, u16 reason_code, int local_state_change, struct i802_bss *bss); + int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv); void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv); int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv, @@ -320,7 +354,8 @@ int process_bss_event(struct nl_msg *msg, void *arg); const char * nl80211_iftype_str(enum nl80211_iftype mode); void nl80211_restore_ap_mode(struct i802_bss *bss); -#ifdef CONFIG_MLD_PATCH +struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id); + static inline bool nl80211_link_valid(u16 links, s8 link_id) { if (link_id < 0 || link_id >= MAX_NUM_MLD_LINKS) @@ -331,7 +366,13 @@ static inline bool nl80211_link_valid(u16 links, s8 link_id) return false; } -#endif + + +static inline bool +nl80211_attr_supported(struct wpa_driver_nl80211_data *drv, unsigned int attr) +{ + return attr <= drv->global->nl80211_maxattr; +} #if defined(ANDROID) || defined(CONFIG_DRIVER_NL80211_HISI) int android_nl_socket_set_nonblocking(struct nl_sock *handle); @@ -363,7 +404,8 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss, int wpa_driver_nl80211_sched_scan(void *priv, struct wpa_driver_scan_params *params); int wpa_driver_nl80211_stop_sched_scan(void *priv); -struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv); +struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv, + const u8 *bssid); void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv); int wpa_driver_nl80211_abort_scan(void *priv, u64 scan_cookie); int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss, diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_capa.c b/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_capa.c index 18bc9d38b0ff708233b7ddec9b8aebf01130a9be..9365ab2fa0768d79d3697983009da36905d3fb4e 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_capa.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_capa.c @@ -50,8 +50,7 @@ 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, - NULL, NULL) == 0) + if (send_and_recv_resp(drv, msg, protocol_feature_handler, &feat) == 0) return feat; return 0; @@ -295,6 +294,9 @@ static unsigned int get_akm_suites_info(struct nlattr *tb) case RSN_AUTH_KEY_MGMT_FT_SAE: key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE; break; + case RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY: + key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE_EXT_KEY; + break; case RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384: key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384; break; @@ -597,6 +599,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X)) capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X; + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_SAE_OFFLOAD)) + capa->flags2 |= WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA; + if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_MFP_OPTIONAL)) capa->flags |= WPA_DRIVER_FLAGS_MFP_OPTIONAL; @@ -661,6 +667,9 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP)) info->drv->unsol_bcast_probe_resp = 1; + if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_PUNCT)) + info->drv->puncturing = 1; + if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT)) capa->flags2 |= WPA_DRIVER_FLAGS2_BEACON_PROTECTION_CLIENT; @@ -668,6 +677,49 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info, if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION)) capa->flags2 |= WPA_DRIVER_FLAGS2_OCV; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_RADAR_BACKGROUND)) + capa->flags2 |= WPA_DRIVER_FLAGS2_RADAR_BACKGROUND; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_SECURE_LTF)) { + capa->flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_STA; + capa->flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_AP; + } + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_SECURE_RTT)) { + capa->flags2 |= WPA_DRIVER_FLAGS2_SEC_RTT_STA; + capa->flags2 |= WPA_DRIVER_FLAGS2_SEC_RTT_AP; + } + + if (ext_feature_isset( + ext_features, len, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE)) { + capa->flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA; + capa->flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP; + } + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT)) + capa->flags2 |= WPA_DRIVER_FLAGS2_SCAN_MIN_PREQ; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK)) + capa->flags2 |= WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_OWE_OFFLOAD)) + capa->flags2 |= WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_OWE_OFFLOAD_AP)) + capa->flags2 |= WPA_DRIVER_FLAGS2_OWE_OFFLOAD_AP; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_SAE_OFFLOAD_AP)) + capa->flags2 |= WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP; } @@ -788,12 +840,12 @@ static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv, int rem = 0, i; struct nlattr *tb1[NL80211_ATTR_MAX + 1], *attr; - if (!tb || drv->num_iface_ext_capa == NL80211_IFTYPE_MAX) + if (!tb || drv->num_iface_capa == NL80211_IFTYPE_MAX) return; nla_for_each_nested(attr, tb, rem) { unsigned int len; - struct drv_nl80211_ext_capa *capa; + struct drv_nl80211_iface_capa *capa; nla_parse(tb1, NL80211_ATTR_MAX, nla_data(attr), nla_len(attr), NULL); @@ -803,7 +855,7 @@ static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv, !tb1[NL80211_ATTR_EXT_CAPA_MASK]) continue; - capa = &drv->iface_ext_capa[drv->num_iface_ext_capa]; + capa = &drv->iface_capa[drv->num_iface_capa]; capa->iftype = nla_get_u32(tb1[NL80211_ATTR_IFTYPE]); wpa_printf(MSG_DEBUG, "nl80211: Driver-advertised extended capabilities for interface type %s", @@ -829,8 +881,20 @@ static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv, wpa_hexdump(MSG_DEBUG, "nl80211: Extended capabilities mask", capa->ext_capa_mask, capa->ext_capa_len); - drv->num_iface_ext_capa++; - if (drv->num_iface_ext_capa == NL80211_IFTYPE_MAX) + if (tb1[NL80211_ATTR_EML_CAPABILITY] && + tb1[NL80211_ATTR_MLD_CAPA_AND_OPS]) { + capa->eml_capa = + nla_get_u16(tb1[NL80211_ATTR_EML_CAPABILITY]); + capa->mld_capa_and_ops = + nla_get_u16(tb1[NL80211_ATTR_MLD_CAPA_AND_OPS]); + } + + wpa_printf(MSG_DEBUG, + "nl80211: EML Capability: 0x%x MLD Capability: 0x%x", + capa->eml_capa, capa->mld_capa_and_ops); + + drv->num_iface_capa++; + if (drv->num_iface_capa == NL80211_IFTYPE_MAX) break; } @@ -839,13 +903,37 @@ static void wiphy_info_extended_capab(struct wpa_driver_nl80211_data *drv, err: /* Cleanup allocated memory on error */ for (i = 0; i < NL80211_IFTYPE_MAX; i++) { - os_free(drv->iface_ext_capa[i].ext_capa); - drv->iface_ext_capa[i].ext_capa = NULL; - os_free(drv->iface_ext_capa[i].ext_capa_mask); - drv->iface_ext_capa[i].ext_capa_mask = NULL; - drv->iface_ext_capa[i].ext_capa_len = 0; + os_free(drv->iface_capa[i].ext_capa); + drv->iface_capa[i].ext_capa = NULL; + os_free(drv->iface_capa[i].ext_capa_mask); + drv->iface_capa[i].ext_capa_mask = NULL; + drv->iface_capa[i].ext_capa_len = 0; } - drv->num_iface_ext_capa = 0; + drv->num_iface_capa = 0; +} + + +static void wiphy_info_mbssid(struct wpa_driver_capa *cap, struct nlattr *attr) +{ + struct nlattr *config[NL80211_MBSSID_CONFIG_ATTR_MAX + 1]; + + if (nla_parse_nested(config, NL80211_MBSSID_CONFIG_ATTR_MAX, attr, + NULL)) + return; + + if (!config[NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES]) + return; + + cap->mbssid_max_interfaces = + nla_get_u8(config[NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES]); + + if (config[NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY]) + cap->ema_max_periodicity = + nla_get_u8(config[NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY]); + + wpa_printf(MSG_DEBUG, + "mbssid: max interfaces %u, max profile periodicity %u", + cap->mbssid_max_interfaces, cap->ema_max_periodicity); } @@ -928,8 +1016,15 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT], tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]); - if (tb[NL80211_ATTR_DEVICE_AP_SME]) + if (tb[NL80211_ATTR_DEVICE_AP_SME]) { + u32 ap_sme_features_flags = + nla_get_u32(tb[NL80211_ATTR_DEVICE_AP_SME]); + + if (ap_sme_features_flags & NL80211_AP_SME_SA_QUERY_OFFLOAD) + capa->flags2 |= WPA_DRIVER_FLAGS2_SA_QUERY_OFFLOAD_AP; + info->device_ap_sme = 1; + } wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]); wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]); @@ -1027,6 +1122,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) case QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO: drv->get_sta_info_vendor_cmd_avail = 1; break; + case QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT: + drv->secure_ranging_ctx_vendor_cmd_avail = 1; + break; #endif /* CONFIG_DRIVER_NL80211_QCA */ } #ifdef CONFIG_DRIVER_NL80211_BRCM @@ -1078,6 +1176,16 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) if (tb[NL80211_ATTR_WIPHY_SELF_MANAGED_REG]) capa->flags |= WPA_DRIVER_FLAGS_SELF_MANAGED_REGULATORY; + if (tb[NL80211_ATTR_MAX_NUM_AKM_SUITES]) + capa->max_num_akms = + nla_get_u16(tb[NL80211_ATTR_MAX_NUM_AKM_SUITES]); + + if (tb[NL80211_ATTR_MBSSID_CONFIG]) + wiphy_info_mbssid(capa, tb[NL80211_ATTR_MBSSID_CONFIG]); + + if (tb[NL80211_ATTR_MLO_SUPPORT]) + capa->flags2 |= WPA_DRIVER_FLAGS2_MLO; + return NL_SKIP; } @@ -1102,7 +1210,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, NULL, NULL)) + if (send_and_recv_resp(drv, msg, wiphy_info_handler, info)) return -1; if (info->auth_supported) @@ -1160,6 +1268,9 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, if (info->update_ft_ies_supported) drv->capa.flags |= WPA_DRIVER_FLAGS_UPDATE_FT_IES; + if (!drv->capa.max_num_akms) + drv->capa.max_num_akms = NL80211_MAX_NR_AKM_SUITES; + return 0; } @@ -1212,8 +1323,7 @@ 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, - NULL, NULL); + ret = send_and_recv_resp(drv, msg, dfs_info_handler, &dfs_capability); if (!ret && dfs_capability) drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD; } @@ -1300,8 +1410,7 @@ 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, - NULL, NULL); + ret = send_and_recv_resp(drv, msg, features_info_handler, &info); if (ret || !info.flags) return; @@ -1322,6 +1431,27 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv) drv->capa.flags |= WPA_DRIVER_FLAGS_OCE_AP; if (check_feature(QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON, &info)) drv->capa.flags |= WPA_DRIVER_FLAGS_OCE_STA_CFON; + if (check_feature(QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_STA, &info)) + drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_STA; + if (check_feature(QCA_WLAN_VENDOR_FEATURE_SECURE_LTF_AP, &info)) + drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_LTF_AP; + if (check_feature(QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_STA, &info)) + drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_RTT_STA; + if (check_feature(QCA_WLAN_VENDOR_FEATURE_SECURE_RTT_AP, &info)) + drv->capa.flags2 |= WPA_DRIVER_FLAGS2_SEC_RTT_AP; + if (check_feature( + QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_STA, + &info)) + drv->capa.flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA; + if (check_feature( + QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP, + &info)) + drv->capa.flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP; + if (check_feature(QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST, + &info)) + drv->qca_ap_allowed_freqs = 1; + if (check_feature(QCA_WLAN_VENDOR_FEATURE_HT_VHT_TWT_RESPONDER, &info)) + drv->capa.flags2 |= WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER; os_free(info.flags); } @@ -1342,7 +1472,7 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) drv->has_capability = 1; drv->has_driver_key_mgmt = info.has_key_mgmt | info.has_key_mgmt_iftype; - /* Fallback to hardcoded defaults if the driver does nott advertize any + /* Fallback to hardcoded defaults if the driver does not advertise any * AKM capabilities. */ if (!drv->has_driver_key_mgmt) { drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | @@ -1468,9 +1598,10 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) #endif /* CONFIG_DRIVER_NL80211_QCA */ wpa_printf(MSG_DEBUG, - "nl80211: key_mgmt=0x%x enc=0x%x auth=0x%x flags=0x%llx rrm_flags=0x%x probe_resp_offloads=0x%x max_stations=%u max_remain_on_chan=%u max_scan_ssids=%d", + "nl80211: key_mgmt=0x%x enc=0x%x auth=0x%x flags=0x%llx flags2=0x%llx rrm_flags=0x%x probe_resp_offloads=0x%x max_stations=%u max_remain_on_chan=%u max_scan_ssids=%d", drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth, - (unsigned long long) drv->capa.flags, drv->capa.rrm_flags, + (unsigned long long) drv->capa.flags, + (unsigned long long) drv->capa.flags2, drv->capa.rrm_flags, drv->capa.probe_resp_offloads, drv->capa.max_stations, drv->capa.max_remain_on_chan, drv->capa.max_scan_ssids); return 0; @@ -1782,12 +1913,14 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb) } -static void phy_info_iftype_copy(struct he_capabilities *he_capab, +static void phy_info_iftype_copy(struct hostapd_hw_modes *mode, enum ieee80211_op_mode opmode, struct nlattr **tb, struct nlattr **tb_flags) { enum nl80211_iftype iftype; size_t len; + struct he_capabilities *he_capab = &mode->he_capab[opmode]; + struct eht_capabilities *eht_capab = &mode->eht_capab[opmode]; switch (opmode) { case IEEE80211_MODE_INFRA: @@ -1857,6 +1990,47 @@ static void phy_info_iftype_copy(struct he_capabilities *he_capab, capa = nla_get_u16(tb[NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA]); he_capab->he_6ghz_capa = le_to_host16(capa); } + + if (!tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC] || + !tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]) + return; + + eht_capab->eht_supported = true; + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC] && + nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]) >= 2) { + const u8 *pos; + + pos = nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC]); + eht_capab->mac_cap = WPA_GET_LE16(pos); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]); + if (len > sizeof(eht_capab->phy_cap)) + len = sizeof(eht_capab->phy_cap); + os_memcpy(eht_capab->phy_cap, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY]), + len); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]); + if (len > sizeof(eht_capab->mcs)) + len = sizeof(eht_capab->mcs); + os_memcpy(eht_capab->mcs, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET]), + len); + } + + if (tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]) { + len = nla_len(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]); + if (len > sizeof(eht_capab->ppet)) + len = sizeof(eht_capab->ppet); + os_memcpy(&eht_capab->ppet, + nla_data(tb[NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE]), + len); + } } @@ -1878,7 +2052,7 @@ static int phy_info_iftype(struct hostapd_hw_modes *mode, return NL_STOP; for (i = 0; i < IEEE80211_MODE_NUM; i++) - phy_info_iftype_copy(&mode->he_capab[i], i, tb, tb_flags); + phy_info_iftype_copy(mode, i, tb, tb_flags); return NL_OK; } @@ -1904,7 +2078,8 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band) os_memset(mode, 0, sizeof(*mode)); mode->mode = NUM_HOSTAPD_MODES; mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN | - HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN; + HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN | + HOSTAPD_MODE_FLAG_HE_INFO_KNOWN; /* * Unsupported VHT MCS stream is defined as value 3, so the VHT @@ -1999,6 +2174,9 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes, for (m = 0; m < *num_modes; m++) { if (!modes[m].num_channels) continue; + + modes[m].is_6ghz = false; + if (modes[m].channels[0].freq < 2000) { modes[m].num_channels = 0; continue; @@ -2010,10 +2188,14 @@ wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes, break; } } - } else if (modes[m].channels[0].freq > 50000) + } else if (modes[m].channels[0].freq > 50000) { modes[m].mode = HOSTAPD_MODE_IEEE80211AD; - else + } else if (is_6ghz_freq(modes[m].channels[0].freq)) { + modes[m].mode = HOSTAPD_MODE_IEEE80211A; + modes[m].is_6ghz = true; + } else { modes[m].mode = HOSTAPD_MODE_IEEE80211A; + } } /* Remove unsupported bands */ @@ -2197,43 +2379,15 @@ static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start, for (c = 0; c < mode->num_channels; c++) { struct hostapd_channel_data *chan = &mode->channels[c]; - if (chan->freq - 10 >= start && chan->freq + 70 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_10_70; - - if (chan->freq - 30 >= start && chan->freq + 50 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_30_50; - - if (chan->freq - 50 >= start && chan->freq + 30 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_50_30; - - if (chan->freq - 70 >= start && chan->freq + 10 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_70_10; - - if (max_bw >= 160) { - if (chan->freq - 10 >= start && chan->freq + 150 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_10_150; - - if (chan->freq - 30 >= start && chan->freq + 130 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_30_130; - - if (chan->freq - 50 >= start && chan->freq + 110 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_50_110; - if (chan->freq - 70 >= start && chan->freq + 90 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_70_90; - - if (chan->freq - 90 >= start && chan->freq + 70 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_90_70; - - if (chan->freq - 110 >= start && chan->freq + 50 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_110_50; + if (chan->freq - 10 < start || chan->freq + 10 > end) + continue; - if (chan->freq - 130 >= start && chan->freq + 30 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_130_30; + if (max_bw >= 80) + chan->flag |= HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL; - if (chan->freq - 150 >= start && chan->freq + 10 <= end) - chan->flag |= HOSTAPD_CHAN_VHT_150_10; - } + if (max_bw >= 160) + chan->flag |= HOSTAPD_CHAN_VHT_160MHZ_SUBCHANNEL; } } @@ -2269,6 +2423,57 @@ static void nl80211_reg_rule_vht(struct nlattr *tb[], } +static void nl80211_set_6ghz_mode(struct hostapd_hw_modes *mode, int start, + int end, int max_bw) +{ + int c; + + for (c = 0; c < mode->num_channels; c++) { + struct hostapd_channel_data *chan = &mode->channels[c]; + + if (chan->freq - 10 < start || chan->freq + 10 > end) + continue; + + if (max_bw >= 80) + chan->flag |= HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL; + + if (max_bw >= 160) + chan->flag |= HOSTAPD_CHAN_VHT_160MHZ_SUBCHANNEL; + + if (max_bw >= 320) + chan->flag |= HOSTAPD_CHAN_EHT_320MHZ_SUBCHANNEL; + } +} + + +static void nl80211_reg_rule_6ghz(struct nlattr *tb[], + struct phy_info_arg *results) +{ + u32 start, end, max_bw; + u16 m; + + if (!tb[NL80211_ATTR_FREQ_RANGE_START] || + !tb[NL80211_ATTR_FREQ_RANGE_END] || + !tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) + return; + + start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000; + end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000; + max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000; + + if (max_bw < 80) + return; + + for (m = 0; m < *results->num_modes; m++) { + if (results->modes[m].num_channels == 0 || + !is_6ghz_freq(results->modes[m].channels[0].freq)) + continue; + + nl80211_set_6ghz_mode(&results->modes[m], start, end, max_bw); + } +} + + static void nl80211_set_dfs_domain(enum nl80211_dfs_regions region, u8 *dfs_domain) { @@ -2387,6 +2592,13 @@ static int nl80211_get_reg(struct nl_msg *msg, void *arg) nl80211_reg_rule_vht(tb_rule, results); } + nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule) + { + nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX, + nla_data(nl_rule), nla_len(nl_rule), reg_policy); + nl80211_reg_rule_6ghz(tb_rule, results); + } + return NL_SKIP; } @@ -2408,8 +2620,7 @@ static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv, } } - return send_and_recv_msgs(drv, msg, nl80211_get_reg, results, - NULL, NULL); + return send_and_recv_resp(drv, msg, nl80211_get_reg, results); } @@ -2430,7 +2641,8 @@ static const char * modestr(enum hostapd_hw_mode mode) } -static void nl80211_dump_chan_list(struct hostapd_hw_modes *modes, +static void nl80211_dump_chan_list(struct wpa_driver_nl80211_data *drv, + struct hostapd_hw_modes *modes, u16 num_modes) { int i; @@ -2440,7 +2652,7 @@ static void nl80211_dump_chan_list(struct hostapd_hw_modes *modes, for (i = 0; i < num_modes; i++) { struct hostapd_hw_modes *mode = &modes[i]; - char str[200]; + char str[1000]; char *pos = str; char *end = pos + sizeof(str); int j, res; @@ -2448,6 +2660,10 @@ static void nl80211_dump_chan_list(struct hostapd_hw_modes *modes, for (j = 0; j < mode->num_channels; j++) { struct hostapd_channel_data *chan = &mode->channels[j]; + if (is_6ghz_freq(chan->freq)) + drv->uses_6ghz = true; + if (chan->freq >= 900 && chan->freq < 1000) + drv->uses_s1g = true; res = os_snprintf(pos, end - pos, " %d%s%s%s", chan->freq, (chan->flag & HOSTAPD_CHAN_DISABLED) ? @@ -2501,8 +2717,7 @@ 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, - NULL, NULL) == 0) { + if (send_and_recv_resp(drv, msg, phy_info_handler, &result) == 0) { struct hostapd_hw_modes *modes; nl80211_set_regulatory_flags(drv, &result); @@ -2522,7 +2737,7 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags, modes = wpa_driver_nl80211_postprocess_modes(result.modes, num_modes); - nl80211_dump_chan_list(modes, *num_modes); + nl80211_dump_chan_list(drv, modes, *num_modes); return modes; } diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_event.c b/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_event.c index cac7d01eb28c97691e067891ba24675d3460eca3..8b6fd35e41a878dccd67972030338b67f6215473 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_event.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_event.c @@ -32,7 +32,7 @@ #endif static void -nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv, +nl80211_control_port_frame_tx_status(struct i802_bss *bss, const u8 *frame, size_t len, struct nlattr *ack, struct nlattr *cookie); @@ -182,8 +182,6 @@ const char * nl80211_command_to_string(enum nl80211_commands cmd) C2S(NL80211_CMD_UNPROT_BEACON) C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS) C2S(NL80211_CMD_SET_SAR_SPECS) - C2S(__NL80211_CMD_AFTER_LAST) -#ifdef CONFIG_MLD_PATCH C2S(NL80211_CMD_OBSS_COLOR_COLLISION) C2S(NL80211_CMD_COLOR_CHANGE_REQUEST) C2S(NL80211_CMD_COLOR_CHANGE_STARTED) @@ -197,9 +195,12 @@ const char * nl80211_command_to_string(enum nl80211_commands cmd) C2S(NL80211_CMD_MODIFY_LINK_STA) C2S(NL80211_CMD_REMOVE_LINK_STA) C2S(NL80211_CMD_SET_HW_TIMESTAMP) + C2S(NL80211_CMD_LINKS_REMOVED) +#ifdef CONFIG_MLD_PATCH C2S(NL80211_CMD_LINK_SWITCH_EVENT) #endif C2S(NL80211_CMD_MLO_WORK_STATE_EVENT) + C2S(__NL80211_CMD_AFTER_LAST) } #undef C2S @@ -342,7 +343,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, } event.assoc_info.freq = drv->assoc_freq; - drv->first_bss->freq = drv->assoc_freq; + drv->first_bss->flink->freq = drv->assoc_freq; nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params); @@ -399,9 +400,9 @@ drv_get_connect_fail_reason_code(struct wpa_driver_nl80211_data *drv) return 0; } - ret = send_and_recv_msgs(drv, msg, + ret = send_and_recv_resp(drv, msg, qca_drv_connect_fail_reason_code_handler, - &reason_code, NULL, NULL); + &reason_code); if (ret) wpa_printf(MSG_DEBUG, "nl80211: Get connect fail reason_code failed: ret=%d (%s)", @@ -435,9 +436,116 @@ convert_connect_fail_reason_codes(enum qca_sta_connect_fail_reason_codes } } + +static void qca_nl80211_link_reconfig_event(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX + 1]; + u16 removed_links; + u8 *ap_mld; + int i; + + if (!data) + return; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR]) + return; + + ap_mld = nla_data(tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR]); + wpa_printf(MSG_DEBUG, "nl80211: AP MLD address " MACSTR + " received in link reconfig event", MAC2STR(ap_mld)); + if (!drv->sta_mlo_info.valid_links || + !ether_addr_equal(drv->sta_mlo_info.ap_mld_addr, ap_mld)) { + if (drv->pending_link_reconfig_data == data) { + wpa_printf(MSG_DEBUG, + "nl80211: Drop pending link reconfig event since AP MLD not matched even after new connect/roam event"); + os_free(drv->pending_link_reconfig_data); + drv->pending_link_reconfig_data = NULL; + return; + } + + wpa_printf(MSG_DEBUG, + "nl80211: Cache new link reconfig event till next connect/roam event"); + if (drv->pending_link_reconfig_data) { + wpa_printf(MSG_DEBUG, "nl80211: Override old link reconfig event data"); + os_free(drv->pending_link_reconfig_data); + } + drv->pending_link_reconfig_data = os_memdup(data, len); + if (!drv->pending_link_reconfig_data) + return; + drv->pending_link_reconfig_data_len = len; + return; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS]) + return; + removed_links = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS]); + + drv->sta_mlo_info.valid_links &= ~removed_links; + + /* + * Set default BSSID to the BSSID of the lowest link ID of remaining + * links when the link used for (re)association is removed. + */ + if (removed_links & BIT(drv->sta_mlo_info.assoc_link_id)) { + for_each_link(drv->sta_mlo_info.valid_links, i) { + os_memcpy(drv->bssid, drv->sta_mlo_info.links[i].bssid, + ETH_ALEN); + drv->sta_mlo_info.assoc_link_id = i; + break; + } + } + + wpa_printf(MSG_DEBUG, "nl80211: Removed MLO links bitmap: 0x%x", + removed_links); + + wpa_supplicant_event(drv->ctx, EVENT_LINK_RECONFIG, NULL); +} + + +static void +nl80211_parse_qca_vendor_mlo_link_info(struct driver_sta_mlo_info *mlo, + struct nlattr *mlo_links) +{ + struct nlattr *link; + int rem_links; + + nla_for_each_nested(link, mlo_links, rem_links) { + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAX + 1]; + int link_id; + + nla_parse(tb,QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAX, nla_data(link), + nla_len(link), NULL); + + if (!tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_ID] || + !tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAC_ADDR] || + !tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_BSSID]) + continue; + + link_id = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_ID]); + if (link_id >= MAX_NUM_MLD_LINKS) + continue; + + mlo->valid_links |= BIT(link_id); + os_memcpy(mlo->links[link_id].addr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAC_ADDR]), + ETH_ALEN); + os_memcpy(mlo->links[link_id].bssid, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_BSSID]), + ETH_ALEN); + wpa_printf(MSG_DEBUG, "nl80211: MLO link[%u] addr " MACSTR + " bssid " MACSTR, + link_id, MAC2STR(mlo->links[link_id].addr), + MAC2STR(mlo->links[link_id].bssid)); + } +} + #endif /* CONFIG_DRIVER_NL80211_QCA */ -#ifdef CONFIG_MLD_PATCH + static void nl80211_parse_mlo_link_info(struct driver_sta_mlo_info *mlo, struct nlattr *mlo_links) { @@ -563,7 +671,8 @@ static int nl80211_update_rejected_links_info(struct driver_sta_mlo_info *mlo, return -1; } - mle = ieee802_11_defrag_mle(&req_elems, MULTI_LINK_CONTROL_TYPE_BASIC); + mle = ieee802_11_defrag(req_elems.basic_mle, req_elems.basic_mle_len, + true); if (!mle) { wpa_printf(MSG_INFO, "nl80211: MLO: Basic Multi-Link element not found in Association Request"); @@ -574,7 +683,8 @@ static int nl80211_update_rejected_links_info(struct driver_sta_mlo_info *mlo, &req_info); wpabuf_free(mle); - mle = ieee802_11_defrag_mle(&resp_elems, MULTI_LINK_CONTROL_TYPE_BASIC); + mle = ieee802_11_defrag(resp_elems.basic_mle, resp_elems.basic_mle_len, + true); if (!mle) { wpa_printf(MSG_ERROR, "nl80211: MLO: Basic Multi-Link element not found in Association Response"); @@ -603,10 +713,7 @@ static int nl80211_update_rejected_links_info(struct driver_sta_mlo_info *mlo, } /* Get MLO links info for rejected links */ - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!((mlo->req_links & ~mlo->valid_links) & BIT(i))) - continue; - + for_each_link((mlo->req_links & ~mlo->valid_links), i) { os_memcpy(mlo->links[i].bssid, resp_info.addr[i], ETH_ALEN); os_memcpy(mlo->links[i].addr, req_info.addr[i], ETH_ALEN); } @@ -614,6 +721,7 @@ static int nl80211_update_rejected_links_info(struct driver_sta_mlo_info *mlo, return 0; } + static int nl80211_get_assoc_link_id(const u8 *data, u8 len) { u16 control; @@ -635,7 +743,9 @@ static int nl80211_get_assoc_link_id(const u8 *data, u8 len) return data[BASIC_ML_IE_COMMON_INFO_LINK_ID_IDX] & 0x0F; } + static void nl80211_parse_mlo_info(struct wpa_driver_nl80211_data *drv, + bool qca_roam_auth, struct nlattr *addr, struct nlattr *mlo_links, struct nlattr *req_ie, @@ -666,10 +776,16 @@ static void nl80211_parse_mlo_info(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: AP MLD MAC Address " MACSTR_SEC, MAC2STR_SEC(mlo->ap_mld_addr)); - nl80211_parse_mlo_link_info(mlo, mlo_links); + if (!qca_roam_auth) + nl80211_parse_mlo_link_info(mlo, mlo_links); +#ifdef CONFIG_DRIVER_NL80211_QCA + if (qca_roam_auth) + nl80211_parse_qca_vendor_mlo_link_info(mlo, mlo_links); +#endif /* CONFIG_DRIVER_NL80211_QCA */ + if (!(mlo->valid_links & BIT(mlo->assoc_link_id)) || (!mlo->req_links && - nl80211_update_rejected_links_info(mlo, req_ie, resp_ie))) { + nl80211_update_rejected_links_info(mlo, req_ie, resp_ie))) { wpa_printf(MSG_INFO, "nl80211: Invalid MLO connection info"); mlo->valid_links = 0; return; @@ -679,9 +795,129 @@ static void nl80211_parse_mlo_info(struct wpa_driver_nl80211_data *drv, ETH_ALEN); os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN); } -#endif + + +#ifdef CONFIG_DRIVER_NL80211_QCA +static void +qca_nl80211_tid_to_link_map_event(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX + 1]; + struct nlattr *tids; + union wpa_event_data event; + u8 *ap_mld; + int i, rem, tidnum = 0; + + os_memset(&event, 0, sizeof(event)); + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR]) + return; + + ap_mld = nla_data(tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR]); + + wpa_printf(MSG_DEBUG, "nl80211: AP MLD address " MACSTR + " received in TID to link mapping event", MAC2STR(ap_mld)); + if (!drv->sta_mlo_info.valid_links || + !ether_addr_equal(drv->sta_mlo_info.ap_mld_addr, ap_mld)) { + if (drv->pending_t2lm_data == data) { + wpa_printf(MSG_DEBUG, + "nl80211: Drop pending TID-to-link mapping event since AP MLD not matched even after new connect/roam event"); + os_free(drv->pending_t2lm_data); + drv->pending_t2lm_data = NULL; + return; + } + wpa_printf(MSG_DEBUG, + "nl80211: Cache new TID-to-link map event until the next connect/roam event"); + if (drv->pending_t2lm_data) { + wpa_printf(MSG_DEBUG, + "nl80211: Override old TID-to-link map event data"); + os_free(drv->pending_t2lm_data); + } + drv->pending_t2lm_data = os_memdup(data, len); + if (!drv->pending_t2lm_data) + return; + drv->pending_t2lm_data_len = len; + return; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS]) { + wpa_printf(MSG_DEBUG, "nl80211: Default TID-to-link map"); + event.t2l_map_info.default_map = true; + goto out; + } + + event.t2l_map_info.default_map = false; + + nla_for_each_nested(tids, + tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS], + rem) { + u16 uplink, downlink; + struct nlattr *tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX + 1]; + + if (nla_parse_nested( + tid, QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX, + tids, NULL)) { + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: nla_parse_nested() failed"); + return; + } + + if (!tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK]) { + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: uplink not present for tid: %d", + tidnum); + return; + } + uplink = nla_get_u16(tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK]); + + if (!tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK]) { + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: downlink not present for tid: %d", + tidnum); + return; + } + downlink = nla_get_u16(tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK]); + + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: Received uplink %x downlink %x", + uplink, downlink); + for_each_link(drv->sta_mlo_info.valid_links, i) { + if (uplink & BIT(i)) + event.t2l_map_info.t2lmap[i].uplink |= + BIT(tidnum); + if (downlink & BIT(i)) + event.t2l_map_info.t2lmap[i].downlink |= + BIT(tidnum); + } + + tidnum++; + } + +out: + drv->sta_mlo_info.default_map = event.t2l_map_info.default_map; + + event.t2l_map_info.valid_links = drv->sta_mlo_info.valid_links; + for (i = 0; i < MAX_NUM_MLD_LINKS && !drv->sta_mlo_info.default_map; + i++) { + if (!(drv->sta_mlo_info.valid_links & BIT(i))) + continue; + + drv->sta_mlo_info.links[i].t2lmap.uplink = + event.t2l_map_info.t2lmap[i].uplink; + drv->sta_mlo_info.links[i].t2lmap.downlink = + event.t2l_map_info.t2lmap[i].downlink; + } + + wpa_supplicant_event(drv->ctx, EVENT_TID_LINK_MAP, &event); +} +#endif /* CONFIG_DRIVER_NL80211_QCA */ + + static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, - enum nl80211_commands cmd, struct nlattr *status, + enum nl80211_commands cmd, bool qca_roam_auth, + struct nlattr *status, struct nlattr *addr, struct nlattr *req_ie, struct nlattr *resp_ie, struct nlattr *timed_out, @@ -693,12 +929,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, struct nlattr *subnet_status, struct nlattr *fils_erp_next_seq_num, struct nlattr *fils_pmk, -#ifdef CONFIG_MLD_PATCH - struct nlattr *fils_pmkid, - struct nlattr *mlo_links) -#else - struct nlattr *fils_pmkid) -#endif + struct nlattr *fils_pmkid, + struct nlattr *mlo_links) { union wpa_event_data event; const u8 *ssid = NULL; @@ -734,9 +966,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, if (drv->ignore_next_local_disconnect) { drv->ignore_next_local_disconnect = 0; if (!event.assoc_reject.bssid || - (os_memcmp(event.assoc_reject.bssid, - drv->auth_attempt_bssid, - ETH_ALEN) != 0)) { + !ether_addr_equal(event.assoc_reject.bssid, + drv->auth_attempt_bssid)) { /* * Ignore the event that came without a BSSID or * for the old connection since this is likely @@ -790,14 +1021,10 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, } drv->associated = 1; -#ifdef CONFIG_MLD_PATCH os_memset(&drv->sta_mlo_info, 0, sizeof(drv->sta_mlo_info)); - nl80211_parse_mlo_info(drv, addr, mlo_links, req_ie, + nl80211_parse_mlo_info(drv, qca_roam_auth, addr, mlo_links, req_ie, resp_ie); if (!drv->sta_mlo_info.valid_links && addr) { -#else - if (addr) { -#endif os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN); os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN); } @@ -826,7 +1053,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, } event.assoc_info.freq = nl80211_get_assoc_freq(drv); - drv->first_bss->freq = drv->assoc_freq; + drv->first_bss->flink->freq = drv->assoc_freq; if ((!ssid || ssid[1] == 0 || ssid[1] > 32) && (ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid)) > 0) { @@ -886,6 +1113,19 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, * operation that happened in parallel with the disconnection request. */ drv->ignore_next_local_disconnect = 0; + +#ifdef CONFIG_DRIVER_NL80211_QCA + if (drv->pending_t2lm_data) + qca_nl80211_tid_to_link_map_event(drv, drv->pending_t2lm_data, + drv->pending_t2lm_data_len); + else + drv->sta_mlo_info.default_map = true; + + if (drv->pending_link_reconfig_data) + qca_nl80211_link_reconfig_event( + drv, drv->pending_link_reconfig_data, + drv->pending_link_reconfig_data_len); +#endif /* CONFIG_DRIVER_NL80211_QCA */ } @@ -953,6 +1193,9 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2) case CHAN_WIDTH_80P80: freq1 = cf1 - 30; break; + case CHAN_WIDTH_320: + freq1 = cf1 - 150; + break; case CHAN_WIDTH_UNKNOWN: case CHAN_WIDTH_2160: case CHAN_WIDTH_4320: @@ -967,17 +1210,11 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2) static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, -#ifdef CONFIG_MLD_PATCH struct nlattr *ifindex, struct nlattr *link, struct nlattr *freq, struct nlattr *type, struct nlattr *bw, struct nlattr *cf1, struct nlattr *cf2, struct nlattr *punct_bitmap, -#else - struct nlattr *ifindex, struct nlattr *freq, - struct nlattr *type, struct nlattr *bw, - struct nlattr *cf1, struct nlattr *cf2, -#endif int finished) { struct i802_bss *bss; @@ -1033,10 +1270,8 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, data.ch_switch.freq = nla_get_u32(freq); data.ch_switch.ht_enabled = ht_enabled; data.ch_switch.ch_offset = chan_offset; -#ifdef CONFIG_MLD_PATCH if (punct_bitmap) data.ch_switch.punct_bitmap = (u16) nla_get_u32(punct_bitmap); -#endif if (bw) data.ch_switch.ch_width = convert2width(nla_get_u32(bw)); if (cf1) @@ -1044,16 +1279,34 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, if (cf2) data.ch_switch.cf2 = nla_get_u32(cf2); -#ifdef CONFIG_MLD_PATCH - if (finished) - bss->flink->freq = data.ch_switch.freq; + if (link) + data.ch_switch.link_id = nla_get_u8(link); + else + data.ch_switch.link_id = NL80211_DRV_LINK_ID_NA; + + if (finished) { + if (data.ch_switch.link_id != NL80211_DRV_LINK_ID_NA) { + struct i802_link *mld_link; + + mld_link = nl80211_get_link(bss, + data.ch_switch.link_id); + mld_link->freq = data.ch_switch.freq; + if (bw) + mld_link->bandwidth = channel_width_to_int( + data.ch_switch.ch_width); + } else { + bss->flink->freq = data.ch_switch.freq; + if (bw) + bss->flink->bandwidth = channel_width_to_int( + data.ch_switch.ch_width); + } + } - if (link) { - u8 link_id = nla_get_u8(link); + if (link && is_sta_interface(drv->nlmode)) { + u8 link_id = data.ch_switch.link_id; if (link_id < MAX_NUM_MLD_LINKS && drv->sta_mlo_info.valid_links & BIT(link_id)) { - data.ch_switch.link_id = link_id; drv->sta_mlo_info.links[link_id].freq = data.ch_switch.freq; wpa_supplicant_event( @@ -1065,9 +1318,7 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, if (link_id != drv->sta_mlo_info.assoc_link_id) return; } -#endif - if (finished) - bss->freq = data.ch_switch.freq; + drv->assoc_freq = data.ch_switch.freq; wpa_supplicant_event(bss->ctx, finished ? @@ -1102,11 +1353,8 @@ static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv, static void mlme_event_mgmt(struct i802_bss *bss, struct nlattr *freq, struct nlattr *sig, -#ifdef CONFIG_MLD_PATCH - const u8 *frame, size_t len, int link_id) -#else - const u8 *frame, size_t len) -#endif + const u8 *frame, size_t len, + int link_id) { struct wpa_driver_nl80211_data *drv = bss->drv; const struct ieee80211_mgmt *mgmt; @@ -1144,19 +1392,20 @@ static void mlme_event_mgmt(struct i802_bss *bss, event.rx_mgmt.frame_len = len; event.rx_mgmt.ssi_signal = ssi_signal; event.rx_mgmt.drv_priv = bss; -#ifdef CONFIG_MLD_PATCH + event.rx_mgmt.ctx = bss->ctx; event.rx_mgmt.link_id = link_id; -#endif + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); } -static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv, +static void mlme_event_mgmt_tx_status(struct i802_bss *bss, struct nlattr *cookie, const u8 *frame, size_t len, struct nlattr *ack) { union wpa_event_data event; const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame; + struct wpa_driver_nl80211_data *drv = bss->drv; u16 fc = le_to_host16(hdr->frame_control); u64 cookie_val = 0; @@ -1175,7 +1424,7 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv, 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, + nl80211_control_port_frame_tx_status(bss, frame, len, ack, cookie); return; } @@ -1209,7 +1458,9 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv, event.tx_status.data = frame; event.tx_status.data_len = len; event.tx_status.ack = ack != NULL; - wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); + event.tx_status.link_id = cookie_val == drv->send_frame_cookie ? + drv->send_frame_link_id : NL80211_DRV_LINK_ID_NA; + wpa_supplicant_event(bss->ctx, EVENT_TX_STATUS, &event); } @@ -1233,9 +1484,9 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) && !drv->associated && - os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 && - os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 && - os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) { + !ether_addr_equal(bssid, drv->auth_bssid) && + !ether_addr_equal(bssid, drv->auth_attempt_bssid) && + ether_addr_equal(bssid, drv->prev_bssid)) { /* * Avoid issues with some roaming cases where * disconnection event for the old AP may show up after @@ -1244,8 +1495,10 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, * ignore_next_local_deauth as well, to avoid next local * deauth event be wrongly ignored. */ - if (!os_memcmp(mgmt->sa, drv->first_bss->addr, - ETH_ALEN)) { + if (ether_addr_equal(mgmt->sa, drv->first_bss->addr) || + (!is_zero_ether_addr(drv->first_bss->prev_addr) && + ether_addr_equal(mgmt->sa, + drv->first_bss->prev_addr))) { wpa_printf(MSG_DEBUG, "nl80211: Received a locally generated deauth event. Clear ignore_next_local_deauth flag"); drv->ignore_next_local_deauth = 0; @@ -1261,8 +1514,8 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) && drv->connect_reassoc && drv->associated && - os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0 && - os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0) { + ether_addr_equal(bssid, drv->prev_bssid) && + !ether_addr_equal(bssid, drv->auth_attempt_bssid)) { /* * Avoid issues with some roaming cases where * disconnection event for the old AP may show up after @@ -1278,8 +1531,8 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, } if (drv->associated != 0 && - os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 && - os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) { + !ether_addr_equal(bssid, drv->bssid) && + !ether_addr_equal(bssid, drv->auth_bssid)) { /* * We have presumably received this deauth as a * response to a clear_state_mismatch() outgoing @@ -1301,7 +1554,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, if (type == EVENT_DISASSOC) { event.disassoc_info.locally_generated = - !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN); + ether_addr_equal(mgmt->sa, drv->first_bss->addr); event.disassoc_info.addr = bssid; event.disassoc_info.reason_code = reason_code; if (frame + len > mgmt->u.disassoc.variable) { @@ -1311,7 +1564,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, } } else { event.deauth_info.locally_generated = - !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN); + ether_addr_equal(mgmt->sa, drv->first_bss->addr); if (drv->ignore_deauth_event) { wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth"); drv->ignore_deauth_event = 0; @@ -1393,7 +1646,7 @@ static void mlme_event_unprot_beacon(struct wpa_driver_nl80211_data *drv, wpa_supplicant_event(drv->ctx, EVENT_UNPROT_BEACON, &event); } -#ifdef CONFIG_MLD_PATCH + static s8 nl80211_get_link_id_by_freq(struct i802_bss *bss, unsigned int freq) { @@ -1406,26 +1659,22 @@ nl80211_get_link_id_by_freq(struct i802_bss *bss, unsigned int freq) return NL80211_DRV_LINK_ID_NA; } -#endif + static void mlme_event(struct i802_bss *bss, enum nl80211_commands cmd, struct nlattr *frame, struct nlattr *addr, struct nlattr *timed_out, struct nlattr *freq, struct nlattr *ack, struct nlattr *cookie, struct nlattr *sig, -#ifdef CONFIG_MLD_PATCH struct nlattr *wmm, struct nlattr *req_ie, struct nlattr *link) -#else - struct nlattr *wmm, struct nlattr *req_ie) -#endif { struct wpa_driver_nl80211_data *drv = bss->drv; + u16 stype = 0, auth_type = 0; const u8 *data; size_t len; -#ifdef CONFIG_MLD_PATCH int link_id = -1; -#endif + struct i802_link *mld_link = NULL; if (timed_out && addr) { mlme_timeout_event(drv, cmd, addr); @@ -1438,14 +1687,17 @@ static void mlme_event(struct i802_bss *bss, cmd, nl80211_command_to_string(cmd)); return; } -#ifdef CONFIG_MLD_PATCH + /* Determine the MLD link either by an explicitly provided link id or * finding a match based on the frequency. */ if (link) link_id = nla_get_u8(link); else if (freq) link_id = nl80211_get_link_id_by_freq(bss, nla_get_u32(freq)); -#endif + + if (nl80211_link_valid(bss->valid_links, link_id)) + mld_link = nl80211_get_link(bss, link_id); + data = nla_data(frame); len = nla_len(frame); if (len < 4 + 2 * ETH_ALEN) { @@ -1455,24 +1707,40 @@ static void mlme_event(struct i802_bss *bss, MAC2STR_SEC(bss->addr)); return; } -#ifdef CONFIG_MLD_PATCH wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR ") A1=" MACSTR " A2=" MACSTR " on link_id=%d", cmd, nl80211_command_to_string(cmd), bss->ifname, MAC2STR(bss->addr), MAC2STR(data + 4), MAC2STR(data + 4 + ETH_ALEN), link_id); -#else - wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR_SEC - ") A1=" MACSTR_SEC " A2=" MACSTR_SEC, cmd, - nl80211_command_to_string(cmd), bss->ifname, - MAC2STR_SEC(bss->addr), MAC2STR_SEC(data + 4), - MAC2STR_SEC(data + 4 + ETH_ALEN)); -#endif - if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) && - os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 && - (is_zero_ether_addr(bss->rand_addr) || - os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) && - os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) { + + /* PASN Authentication frame can be received with a different source MAC + * address. Allow NL80211_CMD_FRAME event with foreign addresses also. + */ + if (cmd == NL80211_CMD_FRAME && len >= 24) { + const struct ieee80211_mgmt *mgmt; + u16 fc; + + mgmt = (const struct ieee80211_mgmt *) data; + fc = le_to_host16(mgmt->frame_control); + stype = WLAN_FC_GET_STYPE(fc); + auth_type = le_to_host16(mgmt->u.auth.auth_alg); + } + + if (cmd == NL80211_CMD_FRAME && stype == WLAN_FC_STYPE_AUTH && + auth_type == host_to_le16(WLAN_AUTH_PASN)) { + wpa_printf(MSG_DEBUG, + "nl80211: %s: Allow PASN frame for foreign address", + bss->ifname); + } else if (cmd != NL80211_CMD_FRAME_TX_STATUS && + !(data[4] & 0x01) && + !ether_addr_equal(bss->addr, data + 4) && + (is_zero_ether_addr(bss->rand_addr) || + !ether_addr_equal(bss->rand_addr, data + 4)) && + !ether_addr_equal(bss->addr, data + 4 + ETH_ALEN) && + (is_zero_ether_addr(drv->first_bss->prev_addr) || + !ether_addr_equal(bss->prev_addr, data + 4 + ETH_ALEN)) && + (!mld_link || + !ether_addr_equal(mld_link->addr, data + 4))) { wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event " "for foreign address", bss->ifname); return; @@ -1498,14 +1766,10 @@ static void mlme_event(struct i802_bss *bss, break; case NL80211_CMD_FRAME: mlme_event_mgmt(bss, freq, sig, nla_data(frame), -#ifdef CONFIG_MLD_PATCH nla_len(frame), link_id); -#else - nla_len(frame)); -#endif break; case NL80211_CMD_FRAME_TX_STATUS: - mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame), + mlme_event_mgmt_tx_status(bss, cookie, nla_data(frame), nla_len(frame), ack); break; case NL80211_CMD_UNPROT_DEAUTHENTICATE: @@ -1582,7 +1846,7 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, if (freq) { wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz", freq); - drv->first_bss->freq = freq; + drv->first_bss->flink->freq = freq; } os_memset(&event, 0, sizeof(event)); @@ -1673,6 +1937,8 @@ static void mlme_event_dh_event(struct wpa_driver_nl80211_data *drv, struct nlattr *tb[]) { union wpa_event_data data; + u8 *addr, *link_addr = NULL; + int assoc_link_id = -1; if (!is_ap_interface(drv->nlmode)) return; @@ -1680,9 +1946,37 @@ static void mlme_event_dh_event(struct wpa_driver_nl80211_data *drv, return; os_memset(&data, 0, sizeof(data)); - data.update_dh.peer = nla_data(tb[NL80211_ATTR_MAC]); + addr = nla_data(tb[NL80211_ATTR_MAC]); + + if (!bss->valid_links && + (tb[NL80211_ATTR_MLO_LINK_ID] || + tb[NL80211_ATTR_MLD_ADDR])) { + wpa_printf(MSG_ERROR, + "nl80211: Link info not expected for DH event for non-MLD AP"); + return; + } + + if (tb[NL80211_ATTR_MLO_LINK_ID]) { + assoc_link_id = nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]); + wpa_printf(MSG_DEBUG, + "nl80211: STA assoc link ID %d in UPDATE_OWE_INFO event", + assoc_link_id); + + if (assoc_link_id != NL80211_DRV_LINK_ID_NA && + tb[NL80211_ATTR_MLD_ADDR]) { + link_addr = addr; + addr = nla_data(tb[NL80211_ATTR_MLD_ADDR]); + wpa_printf(MSG_DEBUG, + "nl80211: STA assoc link addr " MACSTR, + MAC2STR(link_addr)); + } + } + + data.update_dh.peer = addr; data.update_dh.ie = nla_data(tb[NL80211_ATTR_IE]); data.update_dh.ie_len = nla_len(tb[NL80211_ATTR_IE]); + data.update_dh.assoc_link_id = assoc_link_id; + data.update_dh.link_addr = link_addr; wpa_printf(MSG_DEBUG, "nl80211: DH event - peer " MACSTR_SEC, MAC2STR_SEC(data.update_dh.peer)); @@ -1698,7 +1992,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, struct nlattr *nl; int rem; struct scan_info *info; -#define MAX_REPORT_FREQS 100 +#define MAX_REPORT_FREQS 110 int freqs[MAX_REPORT_FREQS]; int num_freqs = 0; @@ -1730,7 +2024,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, } } if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { - char msg[500], *pos, *end; + char msg[MAX_REPORT_FREQS * 5 + 1], *pos, *end; int res; pos = msg; @@ -1745,11 +2039,12 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, if (!os_snprintf_error(end - pos, res)) pos += res; num_freqs++; - if (num_freqs == MAX_REPORT_FREQS - 1) + if (num_freqs == MAX_REPORT_FREQS) break; } info->freqs = freqs; info->num_freqs = num_freqs; + msg[sizeof(msg) - 1] = '\0'; wpa_printf(MSG_WARNING, "nl80211: Scan included frequencies:%s", msg); } @@ -1853,11 +2148,11 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv, * 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); + res = nl80211_get_link_signal(drv, drv->bssid, &ed.signal_change.data); if (res == 0) { - wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d", - ed.signal_change.current_signal, - ed.signal_change.current_txrate); + wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %lu", + ed.signal_change.data.signal, + ed.signal_change.data.current_tx_rate); } else { wpa_printf(MSG_DEBUG, "nl80211: Querying the driver for signal info failed"); @@ -1902,28 +2197,60 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, struct i802_bss *bss, struct nlattr **tb) { - u8 *addr; + u8 *peer_addr; union wpa_event_data data; if (tb[NL80211_ATTR_MAC] == NULL) return; - addr = nla_data(tb[NL80211_ATTR_MAC]); - long select_start_time = get_select_start_time(); - long select_end_time = get_select_end_time(); - long end_time = get_realtime_microsecond(); - wpa_printf(MSG_INFO, "nl80211: New station start - end time used %ld end - now time used %ld", - select_end_time - select_start_time, end_time - select_end_time); - wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR_SEC, MAC2STR_SEC(addr)); + peer_addr = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR_SEC, + MAC2STR_SEC(peer_addr)); if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { - u8 *ies = NULL; - size_t ies_len = 0; + u8 *link_addr = NULL; + int assoc_link_id = -1; + u8 *req_ies = NULL, *resp_ies = NULL; + size_t req_ies_len = 0, resp_ies_len = 0; + + if (!bss->valid_links && + (tb[NL80211_ATTR_MLO_LINK_ID] || + tb[NL80211_ATTR_MLD_ADDR])) { + wpa_printf(MSG_ERROR, + "nl80211: MLO info not expected for new station event for non-MLD AP"); + return; + } + + if (tb[NL80211_ATTR_MLO_LINK_ID]) { + assoc_link_id = + nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]); + wpa_printf(MSG_DEBUG, "nl80211: STA assoc link ID %d", + assoc_link_id); + if (tb[NL80211_ATTR_MLD_ADDR]) { + peer_addr = nla_data(tb[NL80211_ATTR_MLD_ADDR]); + link_addr = nla_data(tb[NL80211_ATTR_MAC]); + wpa_printf(MSG_DEBUG, + "nl80211: STA MLD address " MACSTR_SEC, + MAC2STR_SEC(peer_addr)); + } + } + if (tb[NL80211_ATTR_IE]) { - ies = nla_data(tb[NL80211_ATTR_IE]); - ies_len = nla_len(tb[NL80211_ATTR_IE]); + req_ies = nla_data(tb[NL80211_ATTR_IE]); + req_ies_len = nla_len(tb[NL80211_ATTR_IE]); + wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", + req_ies, req_ies_len); + } + + if (tb[NL80211_ATTR_RESP_IE]) { + resp_ies = nla_data(tb[NL80211_ATTR_RESP_IE]); + resp_ies_len = nla_len(tb[NL80211_ATTR_RESP_IE]); + wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Resp IEs", + resp_ies, resp_ies_len); } - wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len); - drv_event_assoc(bss->ctx, addr, ies, ies_len, 0); + + drv_event_assoc(bss->ctx, peer_addr, req_ies, req_ies_len, + resp_ies, resp_ies_len, link_addr, + assoc_link_id, 0); return; } @@ -1931,7 +2258,7 @@ static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv, return; os_memset(&data, 0, sizeof(data)); - os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN); + os_memcpy(data.ibss_rsn_start.peer, peer_addr, ETH_ALEN); wpa_supplicant_event(bss->ctx, EVENT_IBSS_RSN_START, &data); } @@ -2170,9 +2497,19 @@ static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv, return; os_memset(&data, 0, sizeof(data)); + data.dfs_event.link_id = NL80211_DRV_LINK_ID_NA; data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]); + if (tb[NL80211_ATTR_MLO_LINK_ID]) { + data.dfs_event.link_id = + nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]); + } else if (data.dfs_event.freq) { + data.dfs_event.link_id = + nl80211_get_link_id_by_freq(drv->first_bss, + data.dfs_event.freq); + } + /* Check HT params */ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { data.dfs_event.ht_enabled = 1; @@ -2203,10 +2540,12 @@ static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv, if (tb[NL80211_ATTR_CENTER_FREQ2]) data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]); - wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz", + wpa_printf(MSG_DEBUG, + "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz, link_id=%d", data.dfs_event.freq, data.dfs_event.ht_enabled, data.dfs_event.chan_offset, data.dfs_event.chan_width, - data.dfs_event.cf1, data.dfs_event.cf2); + data.dfs_event.cf1, data.dfs_event.cf2, + data.dfs_event.link_id); switch (event_type) { case NL80211_RADAR_DETECTED: @@ -2436,15 +2775,26 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv, if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]) event.acs_selected_channels.ch_width = nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]); + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP]) + event.acs_selected_channels.puncture_bitmap = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP]); + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_LINK_ID]) + event.acs_selected_channels.link_id = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_LINK_ID]); + else + event.acs_selected_channels.link_id = -1; + wpa_printf(MSG_INFO, - "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d EDMGCH: %d", + "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d EDMGCH: %d PUNCBITMAP: 0x%x, LinkId: %d", event.acs_selected_channels.pri_freq, event.acs_selected_channels.sec_freq, event.acs_selected_channels.ch_width, event.acs_selected_channels.vht_seg0_center_ch, event.acs_selected_channels.vht_seg1_center_ch, event.acs_selected_channels.hw_mode, - event.acs_selected_channels.edmg_channel); + event.acs_selected_channels.edmg_channel, + event.acs_selected_channels.puncture_bitmap, + event.acs_selected_channels.link_id); /* Ignore ACS channel list check for backwards compatibility */ @@ -2473,7 +2823,7 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]); wpa_printf(MSG_DEBUG, " * roam BSSID " MACSTR_SEC, MAC2STR_SEC(bssid)); - mlme_event_connect(drv, NL80211_CMD_ROAM, NULL, + mlme_event_connect(drv, NL80211_CMD_ROAM, true, NULL, tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID], tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE], tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE], @@ -2485,7 +2835,16 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS], tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM], tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMK], - tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID]); + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MLO_LINKS]); + +#ifdef ANDROID +#ifdef ANDROID_LIB_EVENT + wpa_driver_nl80211_driver_event( + drv, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH, + data, len); +#endif /* ANDROID_LIB_EVENT */ +#endif /* ANDROID */ } @@ -2496,7 +2855,6 @@ qca_nl80211_key_mgmt_auth_handler(struct wpa_driver_nl80211_data *drv, 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); @@ -2531,9 +2889,19 @@ static void qca_nl80211_dfs_offload_radar_event( os_memset(&data, 0, sizeof(data)); data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); + data.dfs_event.link_id = NL80211_DRV_LINK_ID_NA; + + if (tb[NL80211_ATTR_MLO_LINK_ID]) { + data.dfs_event.link_id = + nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]); + } else if (data.dfs_event.freq) { + data.dfs_event.link_id = + nl80211_get_link_id_by_freq(drv->first_bss, + data.dfs_event.freq); + } - wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz", - data.dfs_event.freq); + wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, link=%d", + data.dfs_event.freq, data.dfs_event.link_id); /* Check HT params */ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { @@ -2641,6 +3009,7 @@ static void send_vendor_scan_event(struct wpa_driver_nl80211_data *drv, info = &event.scan_info; info->aborted = aborted; info->external_scan = external_scan; + info->scan_cookie = nla_get_u64(tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]); if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) { nla_for_each_nested(nl, @@ -2681,7 +3050,7 @@ static void send_vendor_scan_event(struct wpa_driver_nl80211_data *drv, info->freqs = freqs; info->num_freqs = num_freqs; - wpa_printf(MSG_WARNING, "nl80211: Scan included frequencies:%s", + wpa_printf(MSG_EXCESSIVE, "nl80211: Scan included frequencies:%s", msg); } wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event); @@ -2752,6 +3121,82 @@ static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv, wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event); } + +#ifdef CONFIG_PASN + +static void qca_nl80211_pasn_auth(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + int ret = -EINVAL; + struct nlattr *attr; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + struct nlattr *cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX + 1]; + unsigned int n_peers = 0, idx = 0; + int rem_conf; + enum qca_wlan_vendor_pasn_action action; + union wpa_event_data event; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PASN_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS] || + !tb[QCA_WLAN_VENDOR_ATTR_PASN_ACTION]) { + return; + } + + os_memset(&event, 0, sizeof(event)); + action = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_PASN_ACTION]); + switch (action) { + case QCA_WLAN_VENDOR_PASN_ACTION_AUTH: + event.pasn_auth.action = PASN_ACTION_AUTH; + break; + case QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT: + event.pasn_auth.action = + PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT; + break; + default: + return; + } + + nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS], rem_conf) + n_peers++; + + if (n_peers > WPAS_MAX_PASN_PEERS) { + wpa_printf(MSG_DEBUG, "nl80211: PASN auth: too many peers (%d)", + n_peers); + return; + } + + nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS], + rem_conf) { + struct nlattr *nl_src, *nl_peer; + + ret = nla_parse_nested(cfg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX, + attr, NULL); + if (ret) + return; + nl_src = cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR]; + nl_peer = cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR]; + if (nl_src) + os_memcpy(event.pasn_auth.peer[idx].own_addr, + nla_data(nl_src), ETH_ALEN); + if (nl_peer) + os_memcpy(event.pasn_auth.peer[idx].peer_addr, + nla_data(nl_peer), ETH_ALEN); + if (cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED]) + event.pasn_auth.peer[idx].ltf_keyseed_required = true; + idx++; + } + event.pasn_auth.num_peers = n_peers; + + wpa_printf(MSG_DEBUG, + "nl80211: PASN auth action: %u, num_bssids: %d", + event.pasn_auth.action, + event.pasn_auth.num_peers); + wpa_supplicant_event(drv->ctx, EVENT_PASN_AUTH, &event); +} + +#endif /* CONFIG_PASN */ + #endif /* CONFIG_DRIVER_NL80211_QCA */ @@ -2788,6 +3233,17 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: qca_nl80211_p2p_lo_stop_event(drv, data, len); break; +#ifdef CONFIG_PASN + case QCA_NL80211_VENDOR_SUBCMD_PASN: + qca_nl80211_pasn_auth(drv, data, len); + break; +#endif /* CONFIG_PASN */ + case QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP: + qca_nl80211_tid_to_link_map_event(drv, data, len); + break; + case QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG: + qca_nl80211_link_reconfig_event(drv, data, len); + break; #endif /* CONFIG_DRIVER_NL80211_QCA */ default: wpa_printf(MSG_DEBUG, @@ -2915,7 +3371,13 @@ static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, #ifdef ANDROID #ifdef ANDROID_LIB_EVENT - wpa_driver_nl80211_driver_event(drv, vendor_id, subcmd, data, len); + /* Postpone QCA roam+auth event indication to the point when both that + * and the NL80211_CMD_ROAM event have been received (see calls to + * qca_nl80211_key_mgmt_auth() and drv->pending_roam_data). */ + if (!(vendor_id == OUI_QCA && + subcmd == QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH)) + wpa_driver_nl80211_driver_event(drv, vendor_id, subcmd, data, + len); #endif /* ANDROID_LIB_EVENT */ #endif /* ANDROID */ @@ -3002,7 +3464,8 @@ static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv, } -static void nl80211_dump_freq(const char *title, struct nlattr *nl_freq) +static void nl80211_parse_freq_attrs(const char *title, struct nlattr *nl_freq, + struct frequency_attrs *attrs) { static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, @@ -3029,6 +3492,15 @@ static void nl80211_dump_freq(const char *title, struct nlattr *nl_freq) tb[NL80211_FREQUENCY_ATTR_DISABLED] ? " disabled" : "", tb[NL80211_FREQUENCY_ATTR_NO_IR] ? " no-IR" : "", tb[NL80211_FREQUENCY_ATTR_RADAR] ? " radar" : ""); + + attrs->freq = freq; + attrs->max_tx_power = max_tx_power; + if (tb[NL80211_FREQUENCY_ATTR_DISABLED]) + attrs->disabled = true; + if (tb[NL80211_FREQUENCY_ATTR_NO_IR]) + attrs->no_ir = true; + if (tb[NL80211_FREQUENCY_ATTR_RADAR]) + attrs->radar = true; } @@ -3042,9 +3514,13 @@ static void nl80211_reg_beacon_hint_event(struct wpa_driver_nl80211_data *drv, data.channel_list_changed.initiator = REGDOM_BEACON_HINT; if (tb[NL80211_ATTR_FREQ_BEFORE]) - nl80211_dump_freq("before", tb[NL80211_ATTR_FREQ_BEFORE]); + nl80211_parse_freq_attrs( + "before", tb[NL80211_ATTR_FREQ_BEFORE], + &data.channel_list_changed.beacon_hint_before); if (tb[NL80211_ATTR_FREQ_AFTER]) - nl80211_dump_freq("after", tb[NL80211_ATTR_FREQ_AFTER]); + nl80211_parse_freq_attrs( + "after", tb[NL80211_ATTR_FREQ_AFTER], + &data.channel_list_changed.beacon_hint_after); wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data); } @@ -3055,9 +3531,7 @@ static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv, { union wpa_event_data event; enum nl80211_external_auth_action act; -#ifdef CONFIG_MLD_PATCH char mld_addr[50]; -#endif if (!tb[NL80211_ATTR_AKM_SUITES] || !tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION] || @@ -3087,7 +3561,7 @@ static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv, event.external_auth.ssid = nla_data(tb[NL80211_ATTR_SSID]); event.external_auth.bssid = nla_data(tb[NL80211_ATTR_BSSID]); -#ifdef CONFIG_MLD_PATCH + mld_addr[0] = '\0'; if (tb[NL80211_ATTR_MLD_ADDR]) { event.external_auth.mld_addr = @@ -3100,14 +3574,9 @@ static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv, "nl80211: External auth action: %u, AKM: 0x%x, SSID: %s, BSSID: " MACSTR_SEC "%s", event.external_auth.action, event.external_auth.key_mgmt_suite, - wpa_ssid_txt(event.external_auth.ssid, - event.external_auth.ssid_len), + anonymize_ssid(wpa_ssid_txt(event.external_auth.ssid, + event.external_auth.ssid_len)), MAC2STR_SEC(event.external_auth.bssid), mld_addr); -#endif - wpa_printf(MSG_DEBUG, - "nl80211: External auth action: %u, AKM: 0x%x", - event.external_auth.action, - event.external_auth.key_mgmt_suite); wpa_supplicant_event(drv->ctx, EVENT_EXTERNAL_AUTH, &event); } @@ -3116,6 +3585,9 @@ static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv, struct nlattr **tb) { const u8 *addr; + union wpa_event_data event; + + os_memset(&event, 0, sizeof(event)); if (!tb[NL80211_ATTR_MAC] || nla_len(tb[NL80211_ATTR_MAC]) != ETH_ALEN) { @@ -3125,15 +3597,35 @@ static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv, } addr = nla_data(tb[NL80211_ATTR_MAC]); - if (os_memcmp(addr, drv->bssid, ETH_ALEN) != 0) { + if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { + event.port_authorized.sta_addr = addr; wpa_printf(MSG_DEBUG, - "nl80211: Ignore port authorized event for " MACSTR_SEC - " (not the currently connected BSSID " MACSTR_SEC ")", - MAC2STR_SEC(addr), MAC2STR_SEC(drv->bssid)); - return; + "nl80211: Port authorized for STA addr " MACSTR, + MAC2STR(addr)); + } else if (is_sta_interface(drv->nlmode)) { + const u8 *connected_addr; + + connected_addr = drv->sta_mlo_info.valid_links ? + drv->sta_mlo_info.ap_mld_addr : drv->bssid; + if (!ether_addr_equal(addr, connected_addr)) { + wpa_printf(MSG_DEBUG, + "nl80211: Ignore port authorized event for " + MACSTR_SEC " (not the currently connected BSSID " + MACSTR_SEC ")", + MAC2STR_SEC(addr), MAC2STR_SEC(connected_addr)); + return; + } } - wpa_supplicant_event(drv->ctx, EVENT_PORT_AUTHORIZED, NULL); + if (tb[NL80211_ATTR_TD_BITMAP]) { + event.port_authorized.td_bitmap_len = + nla_len(tb[NL80211_ATTR_TD_BITMAP]); + if (event.port_authorized.td_bitmap_len > 0) + event.port_authorized.td_bitmap = + nla_data(tb[NL80211_ATTR_TD_BITMAP]); + } + + wpa_supplicant_event(drv->ctx, EVENT_PORT_AUTHORIZED, &event); } @@ -3193,6 +3685,9 @@ static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv, case NL80211_CHAN_WIDTH_160: ed.sta_opmode.chan_width = CHAN_WIDTH_160; break; + case NL80211_CHAN_WIDTH_320: + ed.sta_opmode.chan_width = CHAN_WIDTH_320; + break; default: ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN; break; @@ -3207,11 +3702,12 @@ static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv, } -static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) +static void nl80211_control_port_frame(struct i802_bss *bss, struct nlattr **tb) { u8 *src_addr; u16 ethertype; + enum frame_encryption encrypted; + int link_id; if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_FRAME] || @@ -3220,6 +3716,13 @@ static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv, src_addr = nla_data(tb[NL80211_ATTR_MAC]); ethertype = nla_get_u16(tb[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]); + encrypted = nla_get_flag(tb[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]) ? + FRAME_NOT_ENCRYPTED : FRAME_ENCRYPTED; + + if (tb[NL80211_ATTR_MLO_LINK_ID]) + link_id = nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]); + else + link_id = -1; switch (ethertype) { case ETH_P_RSN_PREAUTH: @@ -3228,12 +3731,14 @@ static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv, MAC2STR_SEC(src_addr)); break; case ETH_P_PAE: - drv_event_eapol_rx(drv->ctx, src_addr, - nla_data(tb[NL80211_ATTR_FRAME]), - nla_len(tb[NL80211_ATTR_FRAME])); + drv_event_eapol_rx2(bss->ctx, src_addr, + nla_data(tb[NL80211_ATTR_FRAME]), + nla_len(tb[NL80211_ATTR_FRAME]), + encrypted, link_id); break; default: - wpa_printf(MSG_INFO, "nl80211: Unxpected ethertype 0x%04x from " + wpa_printf(MSG_INFO, + "nl80211: Unexpected ethertype 0x%04x from " MACSTR_SEC " over control port", ethertype, MAC2STR_SEC(src_addr)); break; @@ -3242,10 +3747,11 @@ 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, +nl80211_control_port_frame_tx_status(struct i802_bss *bss, const u8 *frame, size_t len, struct nlattr *ack, struct nlattr *cookie) { + struct wpa_driver_nl80211_data *drv = bss->drv; union wpa_event_data event; if (!cookie || len < ETH_HLEN) @@ -3260,7 +3766,11 @@ nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv, 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); + event.eapol_tx_status.link_id = + nla_get_u64(cookie) == drv->eapol_tx_cookie ? + drv->eapol_tx_link_id : NL80211_DRV_LINK_ID_NA; + + wpa_supplicant_event(bss->ctx, EVENT_EAPOL_TX_STATUS, &event); } #ifdef CONFIG_MLD_PATCH @@ -3282,6 +3792,121 @@ static void nl80211_mlo_link_switch_event(struct wpa_driver_nl80211_data *drv, s } #endif + +static void nl80211_frame_wait_cancel(struct wpa_driver_nl80211_data *drv, + struct nlattr *cookie_attr) +{ + unsigned int i; + u64 cookie; + bool match = false; + + if (!cookie_attr) + return; + cookie = nla_get_u64(cookie_attr); + + for (i = 0; i < drv->num_send_frame_cookies; i++) { + if (cookie == drv->send_frame_cookies[i]) { + match = true; + break; + } + } + wpa_printf(MSG_DEBUG, + "nl80211: TX frame wait expired for cookie 0x%llx%s%s", + (long long unsigned int) cookie, + match ? " (match)" : "", + drv->send_frame_cookie == cookie ? " (match-saved)" : ""); + if (drv->send_frame_cookie == cookie) { + drv->send_frame_cookie = (u64) -1; + if (!match) + goto send_event; + } + if (!match) + return; + + if (i < drv->num_send_frame_cookies - 1) + os_memmove(&drv->send_frame_cookies[i], + &drv->send_frame_cookies[i + 1], + (drv->num_send_frame_cookies - i - 1) * sizeof(u64)); + drv->num_send_frame_cookies--; + +send_event: + wpa_supplicant_event(drv->ctx, EVENT_TX_WAIT_EXPIRE, NULL); +} + + +static void nl80211_assoc_comeback(struct wpa_driver_nl80211_data *drv, + struct nlattr *mac, struct nlattr *timeout) +{ + if (!mac || !timeout) + return; + wpa_printf(MSG_DEBUG, "nl80211: Association comeback requested by " + MACSTR " (timeout: %u ms)", + MAC2STR((u8 *) nla_data(mac)), nla_get_u32(timeout)); +} + + +#ifdef CONFIG_IEEE80211AX + +static void nl80211_obss_color_event(struct i802_bss *bss, + enum nl80211_commands cmd, + struct nlattr *tb[]) +{ + union wpa_event_data data; + enum wpa_event_type event_type; + + os_memset(&data, 0, sizeof(data)); + data.bss_color_collision.link_id = NL80211_DRV_LINK_ID_NA; + + switch (cmd) { + case NL80211_CMD_OBSS_COLOR_COLLISION: + event_type = EVENT_BSS_COLOR_COLLISION; + if (!tb[NL80211_ATTR_OBSS_COLOR_BITMAP]) + return; + data.bss_color_collision.bitmap = + nla_get_u64(tb[NL80211_ATTR_OBSS_COLOR_BITMAP]); + wpa_printf(MSG_DEBUG, + "nl80211: BSS color collision - bitmap %08llx", + (long long unsigned int) + data.bss_color_collision.bitmap); + break; + case NL80211_CMD_COLOR_CHANGE_STARTED: + event_type = EVENT_CCA_STARTED_NOTIFY; + wpa_printf(MSG_DEBUG, "nl80211: CCA started"); + break; + case NL80211_CMD_COLOR_CHANGE_ABORTED: + event_type = EVENT_CCA_ABORTED_NOTIFY; + wpa_printf(MSG_DEBUG, "nl80211: CCA aborted"); + break; + case NL80211_CMD_COLOR_CHANGE_COMPLETED: + event_type = EVENT_CCA_NOTIFY; + wpa_printf(MSG_DEBUG, "nl80211: CCA completed"); + break; + default: + wpa_printf(MSG_DEBUG, "nl80211: Unknown CCA command %d", cmd); + return; + } + + if (tb[NL80211_ATTR_MLO_LINK_ID]) { + data.bss_color_collision.link_id = + nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]); + + if (!nl80211_link_valid(bss->valid_links, + data.bss_color_collision.link_id)) { + wpa_printf(MSG_DEBUG, + "nl80211: Invalid BSS color event link ID %d", + data.bss_color_collision.link_id); + return; + } + + wpa_printf(MSG_DEBUG, "nl80211: BSS color event - Link ID %d", + data.bss_color_collision.link_id); + } + + wpa_supplicant_event(bss->ctx, event_type, &data); +} + +#endif /* CONFIG_IEEE80211AX */ + static void nl80211_mlo_working_state_event(struct wpa_driver_nl80211_data *drv, struct nlattr **tb) { union wpa_event_data event; @@ -3317,17 +3942,10 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, 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); - } + 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; @@ -3360,7 +3978,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, * upper layer implementation could get confused about * scanning state. */ - wpa_printf(MSG_INFO, "nl80211: Do not indicate scan-start event due to internal scan_for_auth"); + wpa_printf(MSG_EXCESSIVE, "nl80211: Do not indicate scan-start event due to internal scan_for_auth"); break; } wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL); @@ -3416,6 +4034,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_ASSOCIATE: case NL80211_CMD_DEAUTHENTICATE: case NL80211_CMD_DISASSOCIATE: + case NL80211_CMD_FRAME: case NL80211_CMD_FRAME_TX_STATUS: case NL80211_CMD_UNPROT_DEAUTHENTICATE: case NL80211_CMD_UNPROT_DISASSOCIATE: @@ -3425,12 +4044,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, tb[NL80211_ATTR_COOKIE], tb[NL80211_ATTR_RX_SIGNAL_DBM], tb[NL80211_ATTR_STA_WME], -#ifdef CONFIG_MLD_PATCH tb[NL80211_ATTR_REQ_IE], tb[NL80211_ATTR_MLO_LINK_ID]); -#else - tb[NL80211_ATTR_REQ_IE]); -#endif break; case NL80211_CMD_CONNECT: case NL80211_CMD_ROAM: @@ -3439,7 +4054,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, break; } #endif - mlme_event_connect(drv, cmd, + mlme_event_connect(drv, cmd, false, tb[NL80211_ATTR_STATUS_CODE], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_REQ_IE], @@ -3451,43 +4066,31 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, NULL, tb[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM], tb[NL80211_ATTR_PMK], -#ifdef CONFIG_MLD_PATCH tb[NL80211_ATTR_PMKID], tb[NL80211_ATTR_MLO_LINKS]); -#else - tb[NL80211_ATTR_PMKID]); -#endif break; case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: mlme_event_ch_switch(drv, tb[NL80211_ATTR_IFINDEX], -#ifdef CONFIG_MLD_PATCH tb[NL80211_ATTR_MLO_LINK_ID], -#endif tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], tb[NL80211_ATTR_CHANNEL_WIDTH], tb[NL80211_ATTR_CENTER_FREQ1], tb[NL80211_ATTR_CENTER_FREQ2], -#ifdef CONFIG_MLD_PATCH tb[NL80211_ATTR_PUNCT_BITMAP], -#endif 0); break; case NL80211_CMD_CH_SWITCH_NOTIFY: mlme_event_ch_switch(drv, tb[NL80211_ATTR_IFINDEX], -#ifdef CONFIG_MLD_PATCH tb[NL80211_ATTR_MLO_LINK_ID], -#endif tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], tb[NL80211_ATTR_CHANNEL_WIDTH], tb[NL80211_ATTR_CENTER_FREQ1], tb[NL80211_ATTR_CENTER_FREQ2], -#ifdef CONFIG_MLD_PATCH tb[NL80211_ATTR_PUNCT_BITMAP], -#endif 1); break; case NL80211_CMD_DISCONNECT: @@ -3574,12 +4177,30 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: if (!frame) break; - nl80211_control_port_frame_tx_status(drv, + nl80211_control_port_frame_tx_status(bss, nla_data(frame), nla_len(frame), tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE]); break; + case NL80211_CMD_FRAME_WAIT_CANCEL: + nl80211_frame_wait_cancel(drv, tb[NL80211_ATTR_COOKIE]); + break; + case NL80211_CMD_ASSOC_COMEBACK: + nl80211_assoc_comeback(drv, tb[NL80211_ATTR_MAC], + tb[NL80211_ATTR_TIMEOUT]); + break; +#ifdef CONFIG_IEEE80211AX + case NL80211_CMD_OBSS_COLOR_COLLISION: + case NL80211_CMD_COLOR_CHANGE_STARTED: + case NL80211_CMD_COLOR_CHANGE_ABORTED: + case NL80211_CMD_COLOR_CHANGE_COMPLETED: + nl80211_obss_color_event(bss, cmd, tb); + break; +#endif /* CONFIG_IEEE80211AX */ + case NL80211_CMD_LINKS_REMOVED: + wpa_supplicant_event(drv->ctx, EVENT_LINK_RECONFIG, NULL); + break; #ifdef CONFIG_MLD_PATCH case NL80211_CMD_LINK_SWITCH_EVENT: nl80211_mlo_link_switch_event(drv, tb); @@ -3596,6 +4217,21 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, } +static bool nl80211_drv_in_list(struct nl80211_global *global, + struct wpa_driver_nl80211_data *drv) +{ + struct wpa_driver_nl80211_data *tmp; + + dl_list_for_each(tmp, &global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (drv == tmp) + return true; + } + + return false; +} + + int process_global_event(struct nl_msg *msg, void *arg) { struct nl80211_global *global = arg; @@ -3607,6 +4243,31 @@ int process_global_event(struct nl_msg *msg, void *arg) u64 wdev_id = 0; int wdev_id_set = 0; int wiphy_idx_set = 0; + bool processed = false; + + /* Event marker, all prior events have been processed */ + if (gnlh->cmd == NL80211_CMD_GET_PROTOCOL_FEATURES) { + u32 seq = nlmsg_hdr(msg)->nlmsg_seq; + + dl_list_for_each_safe(drv, tmp, &global->interfaces, + struct wpa_driver_nl80211_data, list) { + if (drv->ignore_next_local_deauth > 0 && + drv->ignore_next_local_deauth <= seq) { + wpa_printf(MSG_DEBUG, + "nl80211: No DEAUTHENTICATE event was ignored"); + drv->ignore_next_local_deauth = 0; + } + + if (drv->ignore_next_local_disconnect > 0 && + drv->ignore_next_local_disconnect <= seq) { + wpa_printf(MSG_DEBUG, + "nl80211: No DISCONNECT event was ignored"); + drv->ignore_next_local_disconnect = 0; + } + } + + return NL_SKIP; + } nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); @@ -3632,22 +4293,42 @@ int process_global_event(struct nl_msg *msg, void *arg) (wdev_id_set && bss->wdev_id_set && wdev_id == bss->wdev_id)) { #ifdef CONFIG_VENDOR_EXT - if (wpa_vendor_ext_nl80211_is_match_iface(bss, gnlh->cmd, tb)) { + if (wpa_vendor_ext_nl80211_is_match_iface(bss, gnlh->cmd, tb)) { + processed = true; do_process_drv_event(bss, gnlh->cmd, tb); - return NL_SKIP; + if (!wiphy_idx_set) + return NL_SKIP; + /* The driver instance could have been removed, + * e.g., due to NL80211_CMD_RADAR_DETECT event, + * so need to stop the loop if that has + * happened. */ + if (!nl80211_drv_in_list(global, drv)) + break; } #else + processed = true; do_process_drv_event(bss, gnlh->cmd, tb); - return NL_SKIP; + if (!wiphy_idx_set) + return NL_SKIP; + /* The driver instance could have been removed, + * e.g., due to NL80211_CMD_RADAR_DETECT event, + * so need to stop the loop if that has + * happened. */ + if (!nl80211_drv_in_list(global, drv)) + break; #endif } } - wpa_printf(MSG_EXCESSIVE, - "nl80211: Ignored event %d (%s) for foreign interface (ifindex %d wdev 0x%llx)", - gnlh->cmd, nl80211_command_to_string(gnlh->cmd), - ifidx, (long long unsigned int) wdev_id); } + if (processed) + return NL_SKIP; + + wpa_printf(MSG_EXCESSIVE, + "nl80211: Ignored event %d (%s) for foreign interface (ifindex %d wdev 0x%llx wiphy %d)", + gnlh->cmd, nl80211_command_to_string(gnlh->cmd), + ifidx, (long long unsigned int) wdev_id, wiphy_idx_rx); + return NL_SKIP; } @@ -3677,12 +4358,8 @@ int process_bss_event(struct nl_msg *msg, void *arg) tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE], tb[NL80211_ATTR_RX_SIGNAL_DBM], -#ifdef CONFIG_MLD_PATCH tb[NL80211_ATTR_STA_WME], NULL, tb[NL80211_ATTR_MLO_LINK_ID]); -#else - tb[NL80211_ATTR_STA_WME], NULL); -#endif break; case NL80211_CMD_UNEXPECTED_FRAME: nl80211_spurious_frame(bss, tb, 0); @@ -3694,7 +4371,7 @@ int process_bss_event(struct nl_msg *msg, void *arg) nl80211_external_auth(bss->drv, tb); break; case NL80211_CMD_CONTROL_PORT_FRAME: - nl80211_control_port_frame(bss->drv, tb); + nl80211_control_port_frame(bss, tb); break; default: wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event " diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_scan.c b/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_scan.c index a9bef5b9b047e3e5126a8365337f4a1d77f454ce..92aa6b98389d48492c1ef25e0293d242c7605ee5 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_scan.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_nl80211_scan.c @@ -24,7 +24,7 @@ #include "p2p_onehop_scan_opt.h" #endif -#define MAX_NL80211_NOISE_FREQS 50 +#define MAX_NL80211_NOISE_FREQS 100 struct nl80211_noise_info { u32 freq[MAX_NL80211_NOISE_FREQS]; @@ -44,7 +44,7 @@ static int get_noise_for_scan_results(struct nl_msg *msg, void *arg) struct nl80211_noise_info *info = arg; if (info->count >= MAX_NL80211_NOISE_FREQS) - return NL_STOP; + return NL_SKIP; nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); @@ -85,8 +85,7 @@ 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, - NULL, NULL); + return send_and_recv_resp(drv, msg, get_noise_for_scan_results, info); } @@ -98,7 +97,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Abort scan failed: ret=%d (%s)", ret, strerror(-ret)); @@ -129,7 +128,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) { wpa_printf(MSG_INFO, @@ -206,6 +205,21 @@ nl80211_scan_common(struct i802_bss *bss, u8 cmd, goto fail; } nla_nest_end(msg, ssids); + + /* + * If allowed, scan for 6 GHz APs that are reported by other + * APs. Note that if the flag is not set and 6 GHz channels are + * to be scanned, it is highly likely that non-PSC channels + * would be scanned passively (due to the Probe Request frame + * transmission restrictions mandated in IEEE Std 802.11ax-2021, + * 26.17.2.3 (Scanning in the 6 GHz band). Passive scanning of + * all non-PSC channels would take a significant amount of time. + */ + if (!params->non_coloc_6ghz) { + wpa_printf(MSG_DEBUG, + "nl80211: Scan co-located APs on 6 GHz"); + scan_flags |= NL80211_SCAN_FLAG_COLOCATED_6GHZ; + } } else { wpa_printf(MSG_EXCESSIVE, "nl80211: Passive scan requested"); } @@ -303,6 +317,14 @@ nl80211_scan_common(struct i802_bss *bss, u8 cmd, NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION; } + if (params->min_probe_req_content) { + if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SCAN_MIN_PREQ) + scan_flags |= NL80211_SCAN_FLAG_MIN_PREQ_CONTENT; + else + wpa_printf(MSG_DEBUG, + "nl80211: NL80211_SCAN_FLAG_MIN_PREQ_CONTENT not supported"); + } + #ifdef OPEN_HARMONY_P2P_ONEHOP_FIND p2p_set_onehop_scan_param(&scan_flags, bss); #endif @@ -369,33 +391,36 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss, if (params->bssid) { wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: " MACSTR_SEC, MAC2STR_SEC(params->bssid)); - if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) + if (nla_put(msg, NL80211_ATTR_BSSID, ETH_ALEN, params->bssid)) + goto fail; + /* NL80211_ATTR_MAC was used for this purpose initially and the + * NL80211_ATTR_BSSID was added in 2016 when MAC address + * randomization was added. For compatibility with older kernel + * versions, add the NL80211_ATTR_MAC attribute as well when + * the conflicting functionality is not in use. */ + if (!params->mac_addr_rand && + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid)) goto fail; } - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) { wpa_printf(MSG_INFO, "nl80211: Scan trigger failed: ret=%d " "(%s)", ret, strerror(-ret)); if (drv->hostapd && is_ap_interface(drv->nlmode)) { - enum nl80211_iftype old_mode = drv->nlmode; - /* * mac80211 does not allow scan requests in AP mode, so * try to do this in station mode. */ + drv->ap_scan_as_station = drv->nlmode; if (wpa_driver_nl80211_set_mode( - bss, NL80211_IFTYPE_STATION)) - goto fail; - - if (wpa_driver_nl80211_scan(bss, params)) { - wpa_driver_nl80211_set_mode(bss, old_mode); + bss, NL80211_IFTYPE_STATION) || + wpa_driver_nl80211_scan(bss, params)) { + nl80211_restore_ap_mode(bss); goto fail; } - /* Restore AP mode when processing scan results */ - drv->ap_scan_as_station = old_mode; ret = 0; } else goto fail; @@ -404,7 +429,9 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss, drv->scan_state = SCAN_REQUESTED; /* Not all drivers generate "scan completed" wireless event, so try to * read results after a timeout. */ - timeout = 10; + timeout = drv->uses_6ghz ? 20 : 10; + if (drv->uses_s1g) + timeout += 5; if (drv->scan_complete_events) { /* * The driver seems to deliver events to notify when scan is @@ -413,7 +440,7 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss, */ timeout = 30; } - wpa_printf(MSG_EXCESSIVE, "Scan requested (ret=%d) - scan timeout %d " + wpa_printf(MSG_INFO, "Scan requested (ret=%d) - scan timeout %d " "seconds", ret, timeout); eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout, @@ -626,7 +653,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); /* TODO: if we get an error here, we should fall back to normal scan */ @@ -663,7 +690,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: ret=%d (%s)", @@ -703,7 +730,7 @@ static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv, static struct wpa_scan_res * nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, - struct nl_msg *msg) + struct nl_msg *msg, const u8 *bssid) { struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); @@ -720,6 +747,7 @@ nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, [NL80211_BSS_STATUS] = { .type = NLA_U32 }, [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 }, [NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC }, + [NL80211_BSS_BEACON_TSF] = { .type = NLA_U64 }, [NL80211_BSS_PARENT_TSF] = { .type = NLA_U64 }, [NL80211_BSS_PARENT_BSSID] = { .type = NLA_UNSPEC }, [NL80211_BSS_LAST_SEEN_BOOTTIME] = { .type = NLA_U64 }, @@ -736,6 +764,9 @@ nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) return NULL; + if (bssid && bss[NL80211_BSS_BSSID] && + !ether_addr_equal(bssid, nla_data(bss[NL80211_BSS_BSSID]))) + return NULL; if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]); ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]); @@ -781,8 +812,10 @@ nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); if (bss[NL80211_BSS_BEACON_TSF]) { u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]); - if (tsf > r->tsf) + if (tsf > r->tsf) { r->tsf = tsf; + r->beacon_newer = true; + } } if (bss[NL80211_BSS_SEEN_MS_AGO]) r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); @@ -838,6 +871,7 @@ nl80211_parse_bss_info(struct wpa_driver_nl80211_data *drv, struct nl80211_bss_info_arg { struct wpa_driver_nl80211_data *drv; struct wpa_scan_results *res; + const u8 *bssid; }; static int bss_info_handler(struct nl_msg *msg, void *arg) @@ -847,7 +881,7 @@ static int bss_info_handler(struct nl_msg *msg, void *arg) struct wpa_scan_res **tmp; struct wpa_scan_res *r; - r = nl80211_parse_bss_info(_arg->drv, msg); + r = nl80211_parse_bss_info(_arg->drv, msg, _arg->bssid); if (!r) return NL_SKIP; @@ -895,14 +929,14 @@ static void nl80211_check_bss_status(struct wpa_driver_nl80211_data *drv, "nl80211: Local state (not associated) does not match with BSS state"); clear_state_mismatch(drv, r->bssid); } else if (is_sta_interface(drv->nlmode) && - os_memcmp(drv->bssid, r->bssid, ETH_ALEN) != 0) { + !ether_addr_equal(drv->bssid, r->bssid)) { wpa_printf(MSG_DEBUG, "nl80211: Local state (associated with " MACSTR_SEC ") does not match with BSS state", MAC2STR_SEC(drv->bssid)); -#ifdef CONFIG_MLD_PATCH - if (os_memcmp(drv->sta_mlo_info.ap_mld_addr, - drv->bssid, ETH_ALEN) != 0) { + + if (!ether_addr_equal(drv->sta_mlo_info.ap_mld_addr, + drv->bssid)) { clear_state_mismatch(drv, r->bssid); if (!is_zero_ether_addr(drv->sta_mlo_info.ap_mld_addr)) @@ -915,10 +949,6 @@ static void nl80211_check_bss_status(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: BSSID is the MLD address"); } -#else - clear_state_mismatch(drv, r->bssid); - clear_state_mismatch(drv, drv->bssid); -#endif } } @@ -949,7 +979,7 @@ static void nl80211_update_scan_res_noise(struct wpa_scan_res *res, static struct wpa_scan_results * -nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) +nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv, const u8 *bssid) { struct nl_msg *msg; struct wpa_scan_results *res; @@ -969,7 +999,8 @@ try_again: arg.drv = drv; arg.res = res; - ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg, NULL, NULL); + arg.bssid = bssid; + ret = send_and_recv_resp(drv, msg, bss_info_handler, &arg); if (ret == -EAGAIN) { count++; if (count >= 10) { @@ -1005,16 +1036,18 @@ try_again: /** * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results - * @priv: Pointer to private wext data from wpa_driver_nl80211_init() + * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init() + * @bssid: Return results only for the specified BSSID, %NULL for all * Returns: Scan results on success, -1 on failure */ -struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv) +struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv, + const u8 *bssid) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct wpa_scan_results *res; - res = nl80211_get_scan_results(drv); + res = nl80211_get_scan_results(drv, bssid); if (res) wpa_driver_nl80211_check_bss_status(drv, res); return res; @@ -1031,7 +1064,7 @@ static int nl80211_dump_scan_handler(struct nl_msg *msg, void *arg) struct nl80211_dump_scan_ctx *ctx = arg; struct wpa_scan_res *r; - r = nl80211_parse_bss_info(ctx->drv, msg); + r = nl80211_parse_bss_info(ctx->drv, msg, NULL); if (!r) return NL_SKIP; wpa_printf(MSG_DEBUG, "nl80211: %d " MACSTR_SEC " %d%s", @@ -1053,8 +1086,7 @@ 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, - NULL, NULL); + send_and_recv_resp(drv, msg, nl80211_dump_scan_handler, &ctx); } @@ -1245,10 +1277,14 @@ int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss, goto fail; } + if (is_ap_interface(drv->nlmode) && + params->link_id != NL80211_DRV_LINK_ID_NA && + nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_SCAN_LINK_ID, params->link_id)) + goto fail; + nla_nest_end(msg, attr); - ret = send_and_recv_msgs(drv, msg, scan_cookie_handler, &cookie, - NULL, NULL); + ret = send_and_recv_resp(drv, msg, scan_cookie_handler, &cookie); msg = NULL; if (ret) { wpa_printf(MSG_DEBUG, @@ -1311,7 +1347,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, NULL, NULL); + ret = send_and_recv_cmd(drv, msg); msg = NULL; if (ret) { wpa_printf(MSG_ERROR, diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_roboswitch.c b/wpa_supplicant-2.9_standard/src/drivers/driver_roboswitch.c index 9beb6c46d367cbcb8053089be43582b61b5cb900..23c7086b2a97648079ff1acf72218283961e0d6f 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_roboswitch.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_roboswitch.c @@ -175,7 +175,7 @@ static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr, struct wpa_driver_roboswitch_data *drv = priv; if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL && - os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0) + ether_addr_equal(buf, drv->own_addr)) drv_event_eapol_rx(drv->ctx, src_addr, buf + 14, len - 14); } diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_wext.c b/wpa_supplicant-2.9_standard/src/drivers/driver_wext.c index 77a04c412d13cafafceaaffa5e4a12bceceb3fbb..e594c8556bd1e2502a6a43af69ae408f08f6c963 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_wext.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_wext.c @@ -452,9 +452,10 @@ static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv, MAC2STR_SEC((u8 *) iwe->u.ap_addr.sa_data)); if (is_zero_ether_addr( (const u8 *) iwe->u.ap_addr.sa_data) || - os_memcmp(iwe->u.ap_addr.sa_data, - "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == - 0) { + ether_addr_equal((const u8 *) + iwe->u.ap_addr.sa_data, + (const u8 *) + "\x44\x44\x44\x44\x44\x44")) { os_free(drv->assoc_req_ies); drv->assoc_req_ies = NULL; os_free(drv->assoc_resp_ies); @@ -2424,7 +2425,7 @@ static int wpa_driver_wext_signal_poll(void *priv, struct wpa_signal_info *si) struct iwreq iwr; os_memset(si, 0, sizeof(*si)); - si->current_signal = -WPA_INVALID_NOISE; + si->data.signal = -WPA_INVALID_NOISE; si->current_noise = WPA_INVALID_NOISE; si->chanwidth = CHAN_WIDTH_UNKNOWN; @@ -2440,7 +2441,7 @@ static int wpa_driver_wext_signal_poll(void *priv, struct wpa_signal_info *si) return -1; } - si->current_signal = stats.qual.level - + si->data.signal = stats.qual.level - ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0); si->current_noise = stats.qual.noise - ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0); diff --git a/wpa_supplicant-2.9_standard/src/drivers/driver_wired.c b/wpa_supplicant-2.9_standard/src/drivers/driver_wired.c index e9df9f9d237947689ea14558de2524efd54cd211..9f3532c23672bd73ac33cb62c816527b7b33540f 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/driver_wired.c +++ b/wpa_supplicant-2.9_standard/src/drivers/driver_wired.c @@ -285,7 +285,7 @@ static int wired_init_sockets(struct wpa_driver_wired_data *drv, u8 *own_addr) static int wired_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, int encrypt, - const u8 *own_addr, u32 flags) + const u8 *own_addr, u32 flags, int link_id) { struct wpa_driver_wired_data *drv = priv; struct ieee8023_hdr *hdr; diff --git a/wpa_supplicant-2.9_standard/src/drivers/drivers.mak b/wpa_supplicant-2.9_standard/src/drivers/drivers.mak index 6489d5063353743b02c3b92d79f7f945c30de503..45d896f36c599c9a125c5db611113282dcb71d71 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/drivers.mak +++ b/wpa_supplicant-2.9_standard/src/drivers/drivers.mak @@ -87,7 +87,6 @@ DRV_OBJS += ../src/drivers/wpa_hal_event.o DRV_OBJS += ../src/drivers/wpa_hal.o endif - ##### PURE AP DRIVERS ifdef CONFIG_DRIVER_HOSTAP diff --git a/wpa_supplicant-2.9_standard/src/drivers/linux_ioctl.c b/wpa_supplicant-2.9_standard/src/drivers/linux_ioctl.c index 7edb9df2edd49a3bfafec49ef1b0307ebc99cb6e..29abc0c59e8383ec17240b57a6852869982238ba 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/linux_ioctl.c +++ b/wpa_supplicant-2.9_standard/src/drivers/linux_ioctl.c @@ -161,11 +161,20 @@ int linux_br_add_if(int sock, const char *brname, const char *ifname) ifr.ifr_ifindex = ifindex; if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) { int saved_errno = errno; + char in_br[IFNAMSIZ]; wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge " "%s: %s", ifname, brname, strerror(errno)); errno = saved_errno; - return -1; + + /* If ioctl() returns EBUSY when adding an interface into the + * bridge, the interface might have already been added by an + * external operation, so check whether the interface is + * currently on the right bridge and ignore the error if it is. + */ + if (errno != EBUSY || linux_br_get(in_br, ifname) != 0 || + os_strcmp(in_br, brname) != 0) + return -1; } return 0; diff --git a/wpa_supplicant-2.9_standard/src/drivers/ndis_events.c b/wpa_supplicant-2.9_standard/src/drivers/ndis_events.c index 93673a36320cf4db2933448a5d81323ee4ade1fd..4d4ec81d9f7813e5ba1bccb067d0522f918cdb37 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/ndis_events.c +++ b/wpa_supplicant-2.9_standard/src/drivers/ndis_events.c @@ -372,8 +372,9 @@ ndis_events_indicate(IWbemObjectSink *this, long lObjectCount, L"MSNdis_NotifyAdapterRemoval") == 0) { ndis_events_adapter_removal(events); } else { - wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: " - "'%S'", vtClass.bstrVal); + wpa_printf(MSG_DEBUG, + "Unexpected event - __CLASS: '%S'", + vtClass.bstrVal); } VariantClear(&vtClass); diff --git a/wpa_supplicant-2.9_standard/src/drivers/netlink.c b/wpa_supplicant-2.9_standard/src/drivers/netlink.c index 826c7a5e85d90f346433cb39a208b3dd80c446b3..9ddfecfe9ebca0b92d68719aa8c40326d737c86e 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/netlink.c +++ b/wpa_supplicant-2.9_standard/src/drivers/netlink.c @@ -147,8 +147,9 @@ static const char * linkmode_str(int mode) return "kernel-control"; case 1: return "userspace-control"; + default: + return "?"; } - return "?"; } @@ -161,8 +162,9 @@ static const char * operstate_str(int state) return "IF_OPER_DORMANT"; case IF_OPER_UP: return "IF_OPER_UP"; + default: + return "?"; } - return "?"; } diff --git a/wpa_supplicant-2.9_standard/src/drivers/nl80211_copy.h b/wpa_supplicant-2.9_standard/src/drivers/nl80211_copy.h index bf1c1dd7964e6b543d10476a6dcfc165ce117df1..ced83b46bd42334258c34408714ba78271b41cf0 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/nl80211_copy.h +++ b/wpa_supplicant-2.9_standard/src/drivers/nl80211_copy.h @@ -11,7 +11,7 @@ * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -167,7 +167,7 @@ * following events occur. * a) Expiration of hardware timer whose expiration time is set to maximum * coalescing delay of matching coalesce rule. - * b) Coalescing buffer in hardware reaches it's limit. + * b) Coalescing buffer in hardware reaches its limit. * c) Packet doesn't match any of the configured coalesce rules. * * User needs to configure following parameters for creating a coalesce @@ -300,6 +300,49 @@ * the interface goes down. */ +/** + * DOC: FILS shared key crypto offload + * + * This feature is applicable to drivers running in AP mode. + * + * FILS shared key crypto offload can be advertised by drivers by setting + * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD flag. The drivers that support + * FILS shared key crypto offload should be able to encrypt and decrypt + * association frames for FILS shared key authentication as per IEEE 802.11ai. + * With this capability, for FILS key derivation, drivers depend on userspace. + * + * After FILS key derivation, userspace shares the FILS AAD details with the + * driver and the driver stores the same to use in decryption of association + * request and in encryption of association response. The below parameters + * should be given to the driver in %NL80211_CMD_SET_FILS_AAD. + * %NL80211_ATTR_MAC - STA MAC address, used for storing FILS AAD per STA + * %NL80211_ATTR_FILS_KEK - Used for encryption or decryption + * %NL80211_ATTR_FILS_NONCES - Used for encryption or decryption + * (STA Nonce 16 bytes followed by AP Nonce 16 bytes) + * + * Once the association is done, the driver cleans the FILS AAD data. + */ + +/** + * DOC: Multi-Link Operation + * + * In Multi-Link Operation, a connection between two MLDs utilizes multiple + * links. To use this in nl80211, various commands and responses now need + * to or will include the new %NL80211_ATTR_MLO_LINKS attribute. + * Additionally, various commands that need to operate on a specific link + * now need to be given the %NL80211_ATTR_MLO_LINK_ID attribute, e.g. to + * use %NL80211_CMD_START_AP or similar functions. + */ + +/** + * DOC: OWE DH IE handling offload + * + * By setting @NL80211_EXT_FEATURE_OWE_OFFLOAD flag, drivers can indicate + * kernel/application space to avoid DH IE handling. When this flag is + * advertised, the driver/device will take care of DH IE inclusion and + * processing of peer DH IE to generate PMK. + */ + /** * enum nl80211_commands - supported nl80211 commands * @@ -337,17 +380,28 @@ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from * userspace to request deletion of a virtual interface, then requires - * attribute %NL80211_ATTR_IFINDEX. + * attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are + * enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS, + * and if this command is used for the transmitting interface, then all + * the non-transmitting interfaces are deleted as well. * * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified - * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. + * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. %NL80211_ATTR_MAC + * represents peer's MLD address for MLO pairwise key. For MLO group key, + * the link is identified by %NL80211_ATTR_MLO_LINK_ID. * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT, * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD. + * For MLO connection, the link to set default key is identified by + * %NL80211_ATTR_MLO_LINK_ID. * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER, - * and %NL80211_ATTR_KEY_SEQ attributes. + * and %NL80211_ATTR_KEY_SEQ attributes. %NL80211_ATTR_MAC represents + * peer's MLD address for MLO pairwise key. The link to add MLO + * group key is identified by %NL80211_ATTR_MLO_LINK_ID. * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX - * or %NL80211_ATTR_MAC. + * or %NL80211_ATTR_MAC. %NL80211_ATTR_MAC represents peer's MLD address + * for MLO pairwise key. The link to delete group key is identified by + * %NL80211_ATTR_MLO_LINK_ID. * * @NL80211_CMD_GET_BEACON: (not used) * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface @@ -379,7 +433,8 @@ * 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 + * by %NL80211_ATTR_IFINDEX. For MLD station, MLD address is used in + * %NL80211_ATTR_MAC. %NL80211_ATTR_MGMT_SUBTYPE and * %NL80211_ATTR_REASON_CODE can optionally be used to specify which type * of disconnection indication should be sent to the station * (Deauthentication or Disassociation frame and reason code for that @@ -727,6 +782,13 @@ * %NL80211_ATTR_CSA_C_OFFSETS_TX is an array of offsets to CSA * counters which will be updated to the current value. This attribute * is used during CSA period. + * For TX on an MLD, the frequency can be omitted and the link ID be + * specified, or if transmitting to a known peer MLD (with MLD addresses + * in the frame) both can be omitted and the link will be selected by + * lower layers. + * For RX notification, %NL80211_ATTR_RX_HW_TIMESTAMP may be included to + * indicate the frame RX timestamp and %NL80211_ATTR_TX_HW_TIMESTAMP may + * be included to indicate the ack TX timestamp. * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this * command may be used with the corresponding cookie to cancel the wait * time if it is known that it is no longer necessary. This command is @@ -737,7 +799,9 @@ * transmitted with %NL80211_CMD_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. + * the frame. %NL80211_ATTR_TX_HW_TIMESTAMP may be included to indicate the + * tx timestamp and %NL80211_ATTR_RX_HW_TIMESTAMP may be included to + * indicate the ack RX timestamp. * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for * backward compatibility. * @@ -1082,6 +1146,12 @@ * has been received. %NL80211_ATTR_FRAME is used to specify the * frame contents. The frame is the raw EAPoL data, without ethernet or * 802.11 headers. + * For an MLD transmitter, the %NL80211_ATTR_MLO_LINK_ID may be given and + * its effect will depend on the destination: If the destination is known + * to be an MLD, this will be used as a hint to select the link to transmit + * the frame on. If the destination is not an MLD, this will select both + * the link to transmit on and the source address will be set to the link + * address of that link. * When used as an event indication %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT and %NL80211_ATTR_MAC are added * indicating the protocol type of the received frame; whether the frame @@ -1106,6 +1176,23 @@ * %NL80211_ATTR_STATUS_CODE attribute in %NL80211_CMD_EXTERNAL_AUTH * command interface. * + * Host driver sends MLD address of the AP with %NL80211_ATTR_MLD_ADDR in + * %NL80211_CMD_EXTERNAL_AUTH event to indicate user space to enable MLO + * during the authentication offload in STA mode while connecting to MLD + * APs. Host driver should check %NL80211_ATTR_MLO_SUPPORT flag capability + * in %NL80211_CMD_CONNECT to know whether the user space supports enabling + * MLO during the authentication offload or not. + * User space should enable MLO during the authentication only when it + * receives the AP MLD address in authentication offload request. User + * space shouldn't enable MLO when the authentication offload request + * doesn't indicate the AP MLD address even if the AP is MLO capable. + * User space should use %NL80211_ATTR_MLD_ADDR as peer's MLD address and + * interface address identified by %NL80211_ATTR_IFINDEX as self MLD + * address. User space and host driver to use MLD addresses in RA, TA and + * BSSID fields of the frames between them, and host driver translates the + * MLD addresses to/from link addresses based on the link chosen for the + * authentication. + * * Host driver reports this status on an authentication failure to the * user space through the connect result as the user space would have * initiated the connection through the connect request. @@ -1185,6 +1272,57 @@ * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to * specify the wiphy index to be applied to. * + * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever + * mac80211/drv detects a bss color collision. + * + * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that + * userspace wants to change the BSS color. + * + * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has + * started + * + * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has + * been aborted + * + * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change + * has completed + * + * @NL80211_CMD_SET_FILS_AAD: Set FILS AAD data to the driver using - + * &NL80211_ATTR_MAC - for STA MAC address + * &NL80211_ATTR_FILS_KEK - for KEK + * &NL80211_ATTR_FILS_NONCES - for FILS Nonces + * (STA Nonce 16 bytes followed by AP Nonce 16 bytes) + * + * @NL80211_CMD_ASSOC_COMEBACK: notification about an association + * temporal rejection with comeback. The event includes %NL80211_ATTR_MAC + * to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to + * specify the timeout value. + * + * @NL80211_CMD_ADD_LINK: Add a new link to an interface. The + * %NL80211_ATTR_MLO_LINK_ID attribute is used for the new link. + * @NL80211_CMD_REMOVE_LINK: Remove a link from an interface. This may come + * without %NL80211_ATTR_MLO_LINK_ID as an easy way to remove all links + * in preparation for e.g. roaming to a regular (non-MLO) AP. + * + * @NL80211_CMD_ADD_LINK_STA: Add a link to an MLD station + * @NL80211_CMD_MODIFY_LINK_STA: Modify a link of an MLD station + * @NL80211_CMD_REMOVE_LINK_STA: Remove a link of an MLD station + * + * @NL80211_CMD_SET_HW_TIMESTAMP: Enable/disable HW timestamping of Timing + * measurement and Fine timing measurement frames. If %NL80211_ATTR_MAC + * is included, enable/disable HW timestamping only for frames to/from the + * specified MAC address. Otherwise enable/disable HW timestamping for + * all TM/FTM frames (including ones that were enabled with specific MAC + * address). If %NL80211_ATTR_HW_TIMESTAMP_ENABLED is not included, disable + * HW timestamping. + * The number of peers that HW timestamping can be enabled for concurrently + * is indicated by %NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS. + * + * @NL80211_CMD_LINKS_REMOVED: Notify userspace about the removal of STA MLD + * setup links due to AP MLD removing the corresponding affiliated APs with + * Multi-Link reconfiguration. %NL80211_ATTR_MLO_LINKS is used to provide + * information about the removed STA MLD setup links. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1416,7 +1554,7 @@ enum nl80211_commands { NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, NL80211_CMD_SET_SAR_SPECS, -#ifdef CONFIG_MLD_PATCH + NL80211_CMD_OBSS_COLOR_COLLISION, NL80211_CMD_COLOR_CHANGE_REQUEST, @@ -1437,10 +1575,12 @@ enum nl80211_commands { NL80211_CMD_REMOVE_LINK_STA, NL80211_CMD_SET_HW_TIMESTAMP, + + NL80211_CMD_LINKS_REMOVED, +#ifdef CONFIG_MLD_PATCH NL80211_CMD_LINK_SWITCH_EVENT, #endif NL80211_CMD_MLO_WORK_STATE_EVENT, - /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2300,8 +2440,10 @@ enum nl80211_commands { * * @NL80211_ATTR_IFTYPE_EXT_CAPA: Nested attribute of the following attributes: * %NL80211_ATTR_IFTYPE, %NL80211_ATTR_EXT_CAPA, - * %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per - * interface type. + * %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities and + * other interface-type specific capabilities per interface type. For MLO, + * %NL80211_ATTR_EML_CAPABILITY and %NL80211_ATTR_MLD_CAPA_AND_OPS are + * present. * * @NL80211_ATTR_MU_MIMO_GROUP_DATA: array of 24 bytes that defines a MU-MIMO * groupID for monitor mode. @@ -2437,7 +2579,9 @@ enum nl80211_commands { * space supports external authentication. This attribute shall be used * with %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP request. The driver * may offload authentication processing to user space if this capability - * is indicated in the respective requests from the user space. + * is indicated in the respective requests from the user space. (This flag + * attribute deprecated for %NL80211_CMD_START_AP, use + * %NL80211_ATTR_AP_SETTINGS_FLAGS) * * @NL80211_ATTR_NSS: Station's New/updated RX_NSS value notified using this * u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED. @@ -2558,11 +2702,13 @@ enum nl80211_commands { * * @NL80211_ATTR_FILS_DISCOVERY: Optional parameter to configure FILS * discovery. It is a nested attribute, see - * &enum nl80211_fils_discovery_attributes. + * &enum nl80211_fils_discovery_attributes. Userspace should pass an empty + * nested attribute to disable this feature and delete the templates. * * @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. + * &enum nl80211_unsol_bcast_probe_resp_attributes. Userspace should pass an empty + * nested attribute to disable this feature and delete the templates. * * @NL80211_ATTR_S1G_CAPABILITY: S1G Capability information element (from * association request when used with NL80211_CMD_NEW_STATION) @@ -2584,6 +2730,105 @@ enum nl80211_commands { * disassoc events to indicate that an immediate reconnect to the AP * is desired. * + * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the + * %NL80211_CMD_OBSS_COLOR_COLLISION event. + * + * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's + * until the color switch event. + * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are + * switching to + * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE + * information for the time while performing a color switch. + * + * @NL80211_ATTR_MBSSID_CONFIG: Nested attribute for multiple BSSID + * advertisements (MBSSID) parameters in AP mode. + * Kernel uses this attribute to indicate the driver's support for MBSSID + * and enhanced multi-BSSID advertisements (EMA AP) to the userspace. + * Userspace should use this attribute to configure per interface MBSSID + * parameters. + * See &enum nl80211_mbssid_config_attributes for details. + * + * @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements. + * Mandatory parameter for the transmitting interface to enable MBSSID. + * Optional for the non-transmitting interfaces. + * + * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain + * available for radar/CAC detection on some hw. This chain can't be used + * to transmit or receive frames and it is bounded to a running wdev. + * Background radar/CAC detection allows to avoid the CAC downtime + * switching on a different channel during CAC detection on the selected + * radar channel. + * + * @NL80211_ATTR_AP_SETTINGS_FLAGS: u32 attribute contains ap settings flags, + * enumerated in &enum nl80211_ap_settings_flags. This attribute shall be + * used with %NL80211_CMD_START_AP request. + * + * @NL80211_ATTR_EHT_CAPABILITY: EHT Capability information element (from + * association request when used with NL80211_CMD_NEW_STATION). Can be set + * only if %NL80211_STA_FLAG_WME is set. + * + * @NL80211_ATTR_MLO_LINK_ID: A (u8) link ID for use with MLO, to be used with + * various commands that need a link ID to operate. + * @NL80211_ATTR_MLO_LINKS: A nested array of links, each containing some + * per-link information and a link ID. + * @NL80211_ATTR_MLD_ADDR: An MLD address, used with various commands such as + * authenticate/associate. + * + * @NL80211_ATTR_MLO_SUPPORT: Flag attribute to indicate user space supports MLO + * connection. Used with %NL80211_CMD_CONNECT. If this attribute is not + * included in NL80211_CMD_CONNECT drivers must not perform MLO connection. + * + * @NL80211_ATTR_MAX_NUM_AKM_SUITES: U16 attribute. Indicates maximum number of + * AKM suites allowed for %NL80211_CMD_CONNECT, %NL80211_CMD_ASSOCIATE and + * %NL80211_CMD_START_AP in %NL80211_CMD_GET_WIPHY response. If this + * attribute is not present userspace shall consider maximum number of AKM + * suites allowed as %NL80211_MAX_NR_AKM_SUITES which is the legacy maximum + * number prior to the introduction of this attribute. + * + * @NL80211_ATTR_EML_CAPABILITY: EML Capability information (u16) + * @NL80211_ATTR_MLD_CAPA_AND_OPS: MLD Capabilities and Operations (u16) + * + * @NL80211_ATTR_TX_HW_TIMESTAMP: Hardware timestamp for TX operation in + * nanoseconds (u64). This is the device clock timestamp so it will + * probably reset when the device is stopped or the firmware is reset. + * When used with %NL80211_CMD_FRAME_TX_STATUS, indicates the frame TX + * timestamp. When used with %NL80211_CMD_FRAME RX notification, indicates + * the ack TX timestamp. + * @NL80211_ATTR_RX_HW_TIMESTAMP: Hardware timestamp for RX operation in + * nanoseconds (u64). This is the device clock timestamp so it will + * probably reset when the device is stopped or the firmware is reset. + * When used with %NL80211_CMD_FRAME_TX_STATUS, indicates the ack RX + * timestamp. When used with %NL80211_CMD_FRAME RX notification, indicates + * the incoming frame RX timestamp. + * @NL80211_ATTR_TD_BITMAP: Transition Disable bitmap, for subsequent + * (re)associations. + * + * @NL80211_ATTR_PUNCT_BITMAP: (u32) Preamble puncturing bitmap, lowest + * bit corresponds to the lowest 20 MHz channel. Each bit set to 1 + * indicates that the sub-channel is punctured. Higher 16 bits are + * reserved. + * + * @NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS: Maximum number of peers that HW + * timestamping can be enabled for concurrently (u16), a wiphy attribute. + * A value of 0xffff indicates setting for all peers (i.e. not specifying + * an address with %NL80211_CMD_SET_HW_TIMESTAMP) is supported. + * @NL80211_ATTR_HW_TIMESTAMP_ENABLED: Indicates whether HW timestamping should + * be enabled or not (flag attribute). + * + * @NL80211_ATTR_EMA_RNR_ELEMS: Optional nested attribute for + * reduced neighbor report (RNR) elements. This attribute can be used + * only when NL80211_MBSSID_CONFIG_ATTR_EMA is enabled. + * Userspace is responsible for splitting the RNR into multiple + * elements such that each element excludes the non-transmitting + * profiles already included in the MBSSID element + * (%NL80211_ATTR_MBSSID_ELEMS) at the same index. Each EMA beacon + * will be generated by adding MBSSID and RNR elements at the same + * index. If the userspace includes more RNR elements than number of + * MBSSID elements then these will be added in every EMA beacon. + * + * @NL80211_ATTR_MLO_LINK_DISABLED: Flag attribute indicating that the link is + * disabled. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3080,7 +3325,7 @@ enum nl80211_attrs { NL80211_ATTR_SAR_SPEC, NL80211_ATTR_DISABLE_HE, -#ifdef CONFIG_MLD_PATCH + NL80211_ATTR_OBSS_COLOR_BITMAP, NL80211_ATTR_COLOR_CHANGE_COUNT, @@ -3117,8 +3362,11 @@ enum nl80211_attrs { NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS, NL80211_ATTR_HW_TIMESTAMP_ENABLED, + NL80211_ATTR_EMA_RNR_ELEMS, + NL80211_ATTR_MLO_LINK_DISABLED, +#ifdef CONFIG_MLD_PATCH NL80211_ATTR_MLO_LINK_SWITCH_LINK_ID, NL80211_ATTR_MLO_LINK_SWITCH_WORK_BSSID, #endif @@ -3183,7 +3431,14 @@ enum nl80211_attrs { #define NL80211_HE_MIN_CAPABILITY_LEN 16 #define NL80211_HE_MAX_CAPABILITY_LEN 54 #define NL80211_MAX_NR_CIPHER_SUITES 5 + +/* + * NL80211_MAX_NR_AKM_SUITES is obsolete when %NL80211_ATTR_MAX_NUM_AKM_SUITES + * present in %NL80211_CMD_GET_WIPHY response. + */ #define NL80211_MAX_NR_AKM_SUITES 2 +#define NL80211_EHT_MIN_CAPABILITY_LEN 13 +#define NL80211_EHT_MAX_CAPABILITY_LEN 51 #define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10 @@ -3211,7 +3466,7 @@ enum nl80211_attrs { * and therefore can't be created in the normal ways, use the * %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE * commands to create and destroy one - * @NL80211_IF_TYPE_OCB: Outside Context of a BSS + * @NL80211_IFTYPE_OCB: Outside Context of a BSS * This mode corresponds to the MIB variable dot11OCBActivated=true * @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev) * @NL80211_IFTYPE_MAX: highest interface type number currently defined @@ -3352,6 +3607,56 @@ enum nl80211_he_ru_alloc { NL80211_RATE_INFO_HE_RU_ALLOC_2x996, }; +/** + * enum nl80211_eht_gi - EHT guard interval + * @NL80211_RATE_INFO_EHT_GI_0_8: 0.8 usec + * @NL80211_RATE_INFO_EHT_GI_1_6: 1.6 usec + * @NL80211_RATE_INFO_EHT_GI_3_2: 3.2 usec + */ +enum nl80211_eht_gi { + NL80211_RATE_INFO_EHT_GI_0_8, + NL80211_RATE_INFO_EHT_GI_1_6, + NL80211_RATE_INFO_EHT_GI_3_2, +}; + +/** + * enum nl80211_eht_ru_alloc - EHT RU allocation values + * @NL80211_RATE_INFO_EHT_RU_ALLOC_26: 26-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_52: 52-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_52P26: 52+26-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_106: 106-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_106P26: 106+26 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_242: 242-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_484: 484-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_484P242: 484+242 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_996: 996-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484: 996+484 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242: 996+484+242 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996: 2x996-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484: 2x996+484 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996: 3x996-tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484: 3x996+484 tone RU allocation + * @NL80211_RATE_INFO_EHT_RU_ALLOC_4x996: 4x996-tone RU allocation + */ +enum nl80211_eht_ru_alloc { + NL80211_RATE_INFO_EHT_RU_ALLOC_26, + NL80211_RATE_INFO_EHT_RU_ALLOC_52, + NL80211_RATE_INFO_EHT_RU_ALLOC_52P26, + NL80211_RATE_INFO_EHT_RU_ALLOC_106, + NL80211_RATE_INFO_EHT_RU_ALLOC_106P26, + NL80211_RATE_INFO_EHT_RU_ALLOC_242, + NL80211_RATE_INFO_EHT_RU_ALLOC_484, + NL80211_RATE_INFO_EHT_RU_ALLOC_484P242, + NL80211_RATE_INFO_EHT_RU_ALLOC_996, + NL80211_RATE_INFO_EHT_RU_ALLOC_996P484, + NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242, + NL80211_RATE_INFO_EHT_RU_ALLOC_2x996, + NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484, + NL80211_RATE_INFO_EHT_RU_ALLOC_3x996, + NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484, + NL80211_RATE_INFO_EHT_RU_ALLOC_4x996, +}; + /** * enum nl80211_rate_info - bitrate information * @@ -3391,6 +3696,20 @@ enum nl80211_he_ru_alloc { * @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1) * @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then * non-OFDMA was used (u8, see &enum nl80211_he_ru_alloc) + * @NL80211_RATE_INFO_320_MHZ_WIDTH: 320 MHz bitrate + * @NL80211_RATE_INFO_EHT_MCS: EHT MCS index (u8, 0-15) + * @NL80211_RATE_INFO_EHT_NSS: EHT NSS value (u8, 1-8) + * @NL80211_RATE_INFO_EHT_GI: EHT guard interval identifier + * (u8, see &enum nl80211_eht_gi) + * @NL80211_RATE_INFO_EHT_RU_ALLOC: EHT RU allocation, if not present then + * non-OFDMA was used (u8, see &enum nl80211_eht_ru_alloc) + * @NL80211_RATE_INFO_S1G_MCS: S1G MCS index (u8, 0-10) + * @NL80211_RATE_INFO_S1G_NSS: S1G NSS value (u8, 1-4) + * @NL80211_RATE_INFO_1_MHZ_WIDTH: 1 MHz S1G rate + * @NL80211_RATE_INFO_2_MHZ_WIDTH: 2 MHz S1G rate + * @NL80211_RATE_INFO_4_MHZ_WIDTH: 4 MHz S1G rate + * @NL80211_RATE_INFO_8_MHZ_WIDTH: 8 MHz S1G rate + * @NL80211_RATE_INFO_16_MHZ_WIDTH: 16 MHz S1G rate * @__NL80211_RATE_INFO_AFTER_LAST: internal use */ enum nl80211_rate_info { @@ -3412,6 +3731,18 @@ enum nl80211_rate_info { NL80211_RATE_INFO_HE_GI, NL80211_RATE_INFO_HE_DCM, NL80211_RATE_INFO_HE_RU_ALLOC, + NL80211_RATE_INFO_320_MHZ_WIDTH, + NL80211_RATE_INFO_EHT_MCS, + NL80211_RATE_INFO_EHT_NSS, + NL80211_RATE_INFO_EHT_GI, + NL80211_RATE_INFO_EHT_RU_ALLOC, + NL80211_RATE_INFO_S1G_MCS, + NL80211_RATE_INFO_S1G_NSS, + NL80211_RATE_INFO_1_MHZ_WIDTH, + NL80211_RATE_INFO_2_MHZ_WIDTH, + NL80211_RATE_INFO_4_MHZ_WIDTH, + NL80211_RATE_INFO_8_MHZ_WIDTH, + NL80211_RATE_INFO_16_MHZ_WIDTH, /* keep last */ __NL80211_RATE_INFO_AFTER_LAST, @@ -3722,11 +4053,20 @@ enum nl80211_mpath_info { * capabilities IE * @NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE: HE PPE thresholds information as * 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_VENDOR_ELEMS: vendor element capabilities that are + * advertised on this band/for this iftype (binary) + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC: EHT MAC capabilities as in EHT + * capabilities element + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY: EHT PHY capabilities as in EHT + * capabilities element + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET: EHT supported NSS/MCS as in EHT + * capabilities element + * @NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE: EHT PPE thresholds information as + * defined in EHT capabilities element * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use + * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band attribute currently defined */ enum nl80211_band_iftype_attr { __NL80211_BAND_IFTYPE_ATTR_INVALID, @@ -3737,6 +4077,11 @@ enum nl80211_band_iftype_attr { NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, + NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET, + NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE, /* keep last */ __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST, @@ -3766,6 +4111,10 @@ enum nl80211_band_iftype_attr { * @NL80211_BAND_ATTR_EDMG_BW_CONFIG: Channel BW Configuration subfield encodes * the allowed channel bandwidth configurations. * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13. + * @NL80211_BAND_ATTR_S1G_MCS_NSS_SET: S1G capabilities, supported S1G-MCS and NSS + * set subfield, as in the S1G information IE, 5 bytes + * @NL80211_BAND_ATTR_S1G_CAPA: S1G capabilities information subfield as in the + * S1G information IE, 10 bytes * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined * @__NL80211_BAND_ATTR_AFTER_LAST: internal use */ @@ -3786,6 +4135,9 @@ enum nl80211_band_attr { NL80211_BAND_ATTR_EDMG_CHANNELS, NL80211_BAND_ATTR_EDMG_BW_CONFIG, + NL80211_BAND_ATTR_S1G_MCS_NSS_SET, + NL80211_BAND_ATTR_S1G_CAPA, + /* keep last */ __NL80211_BAND_ATTR_AFTER_LAST, NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 @@ -3881,6 +4233,12 @@ enum nl80211_wmm_rule { * 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_NO_320MHZ: any 320 MHz channel using this channel + * as the primary or any of the secondary channels isn't possible + * @NL80211_FREQUENCY_ATTR_NO_EHT: EHT operation is not allowed on this channel + * in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_PSD: Power spectral density (in dBm) that + * 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 @@ -3917,6 +4275,9 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_4MHZ, NL80211_FREQUENCY_ATTR_8MHZ, NL80211_FREQUENCY_ATTR_16MHZ, + NL80211_FREQUENCY_ATTR_NO_320MHZ, + NL80211_FREQUENCY_ATTR_NO_EHT, + NL80211_FREQUENCY_ATTR_PSD, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, @@ -4017,6 +4378,8 @@ enum nl80211_reg_type { * a given frequency range. The value is in mBm (100 * dBm). * @NL80211_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds. * If not present or 0 default CAC time will be used. + * @NL80211_ATTR_POWER_RULE_PSD: power spectral density (in dBm). + * This could be negative. * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number * currently defined * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use @@ -4034,6 +4397,8 @@ enum nl80211_reg_rule_attr { NL80211_ATTR_DFS_CAC_TIME, + NL80211_ATTR_POWER_RULE_PSD, + /* keep last */ __NL80211_REG_RULE_ATTR_AFTER_LAST, NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 @@ -4115,6 +4480,9 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed * @NL80211_RRF_NO_HE: HE operation not allowed + * @NL80211_RRF_NO_320MHZ: 320MHz operation not allowed + * @NL80211_RRF_NO_EHT: EHT operation not allowed + * @NL80211_RRF_PSD: Ruleset has power spectral density value */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -4133,6 +4501,9 @@ enum nl80211_reg_rule_flags { NL80211_RRF_NO_80MHZ = 1<<15, NL80211_RRF_NO_160MHZ = 1<<16, NL80211_RRF_NO_HE = 1<<17, + NL80211_RRF_NO_320MHZ = 1<<18, + NL80211_RRF_NO_EHT = 1<<19, + NL80211_RRF_PSD = 1<<20, }; #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR @@ -4630,6 +5001,8 @@ enum nl80211_key_mode { * @NL80211_CHAN_WIDTH_4: 4 MHz OFDM channel * @NL80211_CHAN_WIDTH_8: 8 MHz OFDM channel * @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel + * @NL80211_CHAN_WIDTH_320: 320 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 + * attribute must be provided as well */ enum nl80211_chan_width { NL80211_CHAN_WIDTH_20_NOHT, @@ -4645,6 +5018,7 @@ enum nl80211_chan_width { NL80211_CHAN_WIDTH_4, NL80211_CHAN_WIDTH_8, NL80211_CHAN_WIDTH_16, + NL80211_CHAN_WIDTH_320, }; /** @@ -4697,7 +5071,7 @@ enum nl80211_bss_scan_width { * elements from a Beacon frame (bin); not present if no Beacon frame has * yet been received * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel - * (u32, enum nl80211_bss_scan_width) + * (u32, enum nl80211_bss_scan_width) - No longer used! * @NL80211_BSS_BEACON_TSF: TSF of the last received beacon (u64) * (not present if no beacon frame has been received yet) * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and @@ -4743,10 +5117,9 @@ enum nl80211_bss { NL80211_BSS_PARENT_BSSID, NL80211_BSS_CHAIN_SIGNAL, NL80211_BSS_FREQUENCY_OFFSET, -#ifdef CONFIG_MLD_PATCH NL80211_BSS_MLO_LINK_ID, NL80211_BSS_MLD_ADDR, -#endif + /* keep last */ __NL80211_BSS_AFTER_LAST, NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1 @@ -4964,6 +5337,7 @@ enum nl80211_txrate_gi { * @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 + * @NL80211_BAND_LC: light communication band (placeholder) * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace * since newer kernel versions may support more bands */ @@ -4973,6 +5347,7 @@ enum nl80211_band { NL80211_BAND_60GHZ, NL80211_BAND_6GHZ, NL80211_BAND_S1GHZ, + NL80211_BAND_LC, NUM_NL80211_BANDS, }; @@ -5539,7 +5914,7 @@ enum nl80211_iface_limit_attrs { * => allows 8 of AP/GO that can have BI gcd >= min gcd * * numbers = [ #{STA} <= 2 ], channels = 2, max = 2 - * => allows two STAs on different channels + * => allows two STAs on the same or on different channels * * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4 * => allows a STA plus three P2P interfaces @@ -5584,7 +5959,7 @@ enum nl80211_if_combination_attrs { * @NL80211_PLINK_ESTAB: mesh peer link is established * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh - * plink are discarded + * plink are discarded, except for authentication frames * @NUM_NL80211_PLINK_STATES: number of peer link states * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states */ @@ -5623,6 +5998,7 @@ enum plink_actions { #define NL80211_KEK_LEN 16 #define NL80211_KCK_EXT_LEN 24 #define NL80211_KEK_EXT_LEN 32 +#define NL80211_KCK_EXT_LEN_32 32 #define NL80211_REPLAY_CTR_LEN 8 /** @@ -5721,13 +6097,15 @@ enum nl80211_tdls_operation { NL80211_TDLS_DISABLE_LINK, }; -/* +/** * enum nl80211_ap_sme_features - device-integrated AP features - * Reserved for future use, no bits are defined in - * NL80211_ATTR_DEVICE_AP_SME yet. + * @NL80211_AP_SME_SA_QUERY_OFFLOAD: SA Query procedures offloaded to driver + * when user space indicates support for SA Query procedures offload during + * "start ap" with %NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT. + */ enum nl80211_ap_sme_features { + NL80211_AP_SME_SA_QUERY_OFFLOAD = 1 << 0, }; - */ /** * enum nl80211_feature_flags - device/driver features @@ -5738,7 +6116,7 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up * the connected inactive stations in AP mode. * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested - * to work properly to suppport receiving regulatory hints from + * to work properly to support receiving regulatory hints from * cellular base stations. * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: (no longer available, only * here to reserve the value for API/ABI compatibility) @@ -6027,6 +6405,40 @@ enum nl80211_feature_flags { * frame protection for all management frames exchanged during the * negotiation and range measurement procedure. * + * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision + * detection and change announcemnts. + * + * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD: Driver running in AP mode supports + * FILS encryption and decryption for (Re)Association Request and Response + * frames. Userspace has to share FILS AAD details to the driver by using + * @NL80211_CMD_SET_FILS_AAD. + * + * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC + * detection. + * + * @NL80211_EXT_FEATURE_POWERED_ADDR_CHANGE: Device can perform a MAC address + * change without having to bring the underlying network device down + * first. For example, in station mode this can be used to vary the + * origin MAC address prior to a connection to a new AP for privacy + * or other reasons. Note that certain driver specific restrictions + * might apply, e.g. no scans in progress, no offchannel operations + * in progress, and no active connections. + * + * @NL80211_EXT_FEATURE_PUNCT: Driver supports preamble puncturing in AP mode. + * + * @NL80211_EXT_FEATURE_SECURE_NAN: Device supports NAN Pairing which enables + * authentication, data encryption and message integrity. + * + * @NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA: Device supports randomized TA + * in authentication and deauthentication frames sent to unassociated peer + * using @NL80211_CMD_FRAME. + * + * @NL80211_EXT_FEATURE_OWE_OFFLOAD: Driver/Device wants to do OWE DH IE + * handling in station mode. + * + * @NL80211_EXT_FEATURE_OWE_OFFLOAD_AP: Driver/Device wants to do OWE DH IE + * handling in AP mode. + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -6091,6 +6503,15 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_SECURE_LTF, NL80211_EXT_FEATURE_SECURE_RTT, NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, + NL80211_EXT_FEATURE_BSS_COLOR, + NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD, + NL80211_EXT_FEATURE_RADAR_BACKGROUND, + NL80211_EXT_FEATURE_POWERED_ADDR_CHANGE, + NL80211_EXT_FEATURE_PUNCT, + NL80211_EXT_FEATURE_SECURE_NAN, + NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA, + NL80211_EXT_FEATURE_OWE_OFFLOAD, + NL80211_EXT_FEATURE_OWE_OFFLOAD_AP, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -6205,8 +6626,16 @@ enum nl80211_timeout_reason { * @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 + * @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for collocated APs reported by + * 2.4/5 GHz APs. When the flag is set, the scan logic will use the + * information from the RNR element found in beacons/probe responses + * received on the 2.4/5 GHz channels to actively scan only the 6GHz + * channels on which APs are expected to be found. Note that when not set, + * the scan logic would scan all 6GHz channels, but since transmission of + * probe requests on non PSC channels is limited, it is highly likely that + * these channels would passively be scanned. Also note that when the flag + * is set, in addition to the colocated APs, PSC channels would also be + * scanned if the user space has asked for it. */ enum nl80211_scan_flags { NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, @@ -6989,6 +7418,9 @@ enum nl80211_peer_measurement_ftm_capa { * @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only * valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set. + * @NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR: optional. The BSS color of the + * responder. Only valid if %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED + * or %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED is set. * * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number @@ -7008,6 +7440,7 @@ enum nl80211_peer_measurement_ftm_req { NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK, + NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR, /* keep last */ NUM_NL80211_PMSR_FTM_REQ_ATTR, @@ -7214,7 +7647,7 @@ enum nl80211_iftype_akm_attributes { * @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) + * Allowed range: 0..10000 (TU = Time Unit). If set to 0, the feature is disabled. * @NL80211_FILS_DISCOVERY_ATTR_TMPL: Template data for FILS discovery action * frame including the headers. * @@ -7247,7 +7680,8 @@ enum nl80211_fils_discovery_attributes { * * @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). + * 26.17.2.3.2 (AP behavior for fast passive scanning). If set to 0, the feature is + * disabled. * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL: Unsolicited broadcast probe response * frame template (binary). * @@ -7376,4 +7810,76 @@ enum nl80211_sar_specs_attrs { NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1, }; +/** + * enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced + * multi-BSSID advertisements (EMA) in AP mode. + * Kernel uses some of these attributes to advertise driver's support for + * MBSSID and EMA. + * Remaining attributes should be used by the userspace to configure the + * features. + * + * @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid + * + * @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise + * the maximum number of MBSSID interfaces supported by the driver. + * Driver should indicate MBSSID support by setting + * wiphy->mbssid_max_interfaces to a value more than or equal to 2. + * + * @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel + * to advertise the maximum profile periodicity supported by the driver + * if EMA is enabled. Driver should indicate EMA support to the userspace + * by setting wiphy->ema_max_profile_periodicity to + * a non-zero value. + * + * @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of + * this BSS (u8) in the multiple BSSID set. + * Value must be set to 0 for the transmitting interface and non-zero for + * all non-transmitting interfaces. The userspace will be responsible + * for using unique indices for the interfaces. + * Range: 0 to wiphy->mbssid_max_interfaces-1. + * + * @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for + * a non-transmitted profile which provides the interface index (u32) of + * the transmitted profile. The value must match one of the interface + * indices advertised by the kernel. Optional if the interface being set up + * is the transmitting one, however, if provided then the value must match + * the interface index of the same. + * + * @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature. + * Setting this flag is permitted only if the driver advertises EMA support + * by setting wiphy->ema_max_profile_periodicity to non-zero. + * + * @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal + * @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute + */ +enum nl80211_mbssid_config_attributes { + __NL80211_MBSSID_CONFIG_ATTR_INVALID, + + NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, + NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, + NL80211_MBSSID_CONFIG_ATTR_INDEX, + NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX, + NL80211_MBSSID_CONFIG_ATTR_EMA, + + /* keep last */ + __NL80211_MBSSID_CONFIG_ATTR_LAST, + NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1, +}; + +/** + * enum nl80211_ap_settings_flags - AP settings flags + * + * @NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT: AP supports external + * authentication. + * @NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT: Userspace supports SA Query + * procedures offload to driver. If driver advertises + * %NL80211_AP_SME_SA_QUERY_OFFLOAD in AP SME features, userspace shall + * ignore SA Query procedures and validations when this flag is set by + * userspace. + */ +enum nl80211_ap_settings_flags { + NL80211_AP_SETTINGS_EXTERNAL_AUTH_SUPPORT = 1 << 0, + NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT = 1 << 1, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/wpa_supplicant-2.9_standard/src/drivers/wpa_hal.c b/wpa_supplicant-2.9_standard/src/drivers/wpa_hal.c index 1d43af70a7b3d28969a33ce44539b4880d16d7c2..1c697327fa7c12f0a7a9562f49c32ab1752c1194 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/wpa_hal.c +++ b/wpa_supplicant-2.9_standard/src/drivers/wpa_hal.c @@ -1,2174 +1,2174 @@ -/* - * Driver interaction with hdf wifi - * Copyright (c) 2020 Huawei Device Co., Ltd. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "wpa_hal.h" -#include "includes.h" -#include "utils/common.h" -#include "driver.h" -#include "ap/hostapd.h" -#include "l2_packet/l2_packet.h" -#include "eloop.h" -#include "securec.h" -#include - -#ifdef __cplusplus -#if __cplusplus -extern "C" { -#endif -#endif - -WifiDriverData *g_wifiDriverData = NULL; -enum WifiIfType g_wifiDriverType = WIFI_IFTYPE_UNSPECIFIED; -#define WAIT_LOAD_NETDEVICE 2500 -#ifdef CONFIG_OHOS_P2P -uint8_t g_msgInit = true; -#endif - -WifiDriverData *GetDrvData() -{ - return g_wifiDriverData; -} - -#ifdef CONFIG_OHOS_P2P -#define WPA_MAX_WIFI_DEV_NUM 3 - -WifiDev* g_wifiDev[WPA_MAX_WIFI_DEV_NUM] = {NULL}; - -WifiDev* GetWifiDevByName(const char *ifName) -{ - int32_t i; - if (ifName == NULL) { - return NULL; - } - for (i = 0; i < WPA_MAX_WIFI_DEV_NUM; i++) { - if ((g_wifiDev[i] != NULL) && (strncmp(g_wifiDev[i]->ifName, ifName, strlen(ifName)) == 0)) { - g_wifiDev[i]->networkId = i; - return g_wifiDev[i]; - } - } - return NULL; -} - -int32_t SetWifiDev(WifiDev *wifiDev) -{ - int32_t i; - if (wifiDev == NULL) { - return -EFAIL; - } - for (i = 0; i < WPA_MAX_WIFI_DEV_NUM; i++) { - if ((g_wifiDev[i] != NULL) && (strncmp(g_wifiDev[i]->ifName, wifiDev->ifName, strlen(wifiDev->ifName)) == 0)) { - g_wifiDev[i] = wifiDev; - return SUCC; - } else if (g_wifiDev[i] == NULL) { - g_wifiDev[i] = wifiDev; - g_wifiDev[i]->networkId = i; - return SUCC; - } - } - return -EFAIL; -} - -void FreeWifiDev(WifiDev *wifiDev) -{ - int32_t i; - if (wifiDev == NULL) { - return; - } - for (i = 0; i < WPA_MAX_WIFI_DEV_NUM; i++) { - if (g_wifiDev[i] == wifiDev) { - g_wifiDev[i] = NULL; - break; - } - } - os_free(wifiDev); - wifiDev = NULL; -} - -int32_t CountWifiDevInUse() -{ - int32_t i; - int32_t count = 0; - for (i = 0; i < WPA_MAX_WIFI_DEV_NUM; i++) { - if (g_wifiDev[i] != NULL) { - count++; - } - } - return count; -} -#endif // CONFIG_OHOS_P2P - -static int OnWpaWiFiEvents(uint32_t event, void *data, const char *ifName) -{ - WifiDriverData *drv = NULL; -#ifndef CONFIG_OHOS_P2P - drv = GetDrvData(); -#else - WifiDev *wifiDev = NULL; - wifiDev = GetWifiDevByName(ifName); - if (wifiDev == NULL) { - wpa_printf(MSG_ERROR, "OnWpaWiFiEvents wifiDev is null\n"); - return -EFAIL; - } - drv = wifiDev->priv; -#endif - (void)ifName; - wpa_printf(MSG_INFO, "OnWpaWiFiEvents event=%d", event); - if (drv == NULL || data == NULL) { - return -EFAIL; - } - switch (event) { - case WIFI_EVENT_NEW_STA: - WifiWpaNewStaProcess(drv, (WifiNewStaInfo *)data); - break; - case WIFI_EVENT_DEL_STA: - WifiWpaDelStaProcess(drv, (uint8_t *)data); - break; - case WIFI_EVENT_RX_MGMT: - WifiWpaRxMgmtProcess(drv, (WifiRxMgmt *)data); - break; - case WIFI_EVENT_TX_STATUS: - WifiWpaTxStatusProcess(drv, (WifiTxStatus *)data); - break; - case WIFI_EVENT_SCAN_DONE: - WifiWpaScanDoneProcess(drv, (uint32_t *)data); - break; - case WIFI_EVENT_SCAN_RESULT: - WifiWpaScanResultProcess(drv, (WifiScanResult *)data); - break; - case WIFI_EVENT_CONNECT_RESULT: - WifiWpaConnectResultProcess(drv, (WifiConnectResult *)data); - break; - case WIFI_EVENT_DISCONNECT: - WifiWpaDisconnectProcess(drv, (WifiDisconnect *)data); - break; - case WIFI_EVENT_EAPOL_RECV: - WifiWpaDriverEapolRecvProcess(drv, data); - break; - case WIFI_EVENT_REMAIN_ON_CHANNEL: - WifiWpaRemainOnChannelProcess(drv, (WifiOnChannel *)data); - break; - case WIFI_EVENT_CANCEL_REMAIN_ON_CHANNEL: - WifiWpaCancelRemainOnChannelProcess(drv, (WifiOnChannel *)data); - break; - default: - break; - } - - return SUCC; -} - -static int32_t WifiClientInit(const char *ifName) -{ - int32_t ret; - - wpa_printf(MSG_INFO, "WifiClientInit enter."); - ret = WifiDriverClientInit(); - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "WifiWpa init msg service failed"); - return ret; - } - ret = WifiRegisterEventCallback(OnWpaWiFiEvents, WIFI_KERNEL_TO_WPA_CLIENT, ifName); - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "WifiWpa register event listener faild"); - } - return ret; -} - -void WifiClientDeinit(const char *ifName) -{ - WifiUnregisterEventCallback(OnWpaWiFiEvents, WIFI_KERNEL_TO_WPA_CLIENT, ifName); - WifiDriverClientDeinit(); -} - -static int32_t WifiWpaGetBssid(void *priv, uint8_t *bssid) -{ - WifiDriverData *drv = priv; - errno_t rc; - if ((priv == NULL) || (bssid == NULL)) { - return -EFAIL; - } - if (drv->associated == WIFI_DISCONNECT) { - wpa_printf(MSG_ERROR, "%s associated status error", __func__); - return -EFAIL; - } - - rc = memcpy_s(bssid, ETH_ADDR_LEN, drv->bssid, ETH_ADDR_LEN); - if (rc != EOK) { - return -EFAIL; - } - return SUCC; -} - -static int32_t WifiWpaGetSsid(void *priv, uint8_t *ssid) -{ - WifiDriverData *drv = priv; - errno_t rc; - if ((priv == NULL) || (ssid == NULL)) { - return -EFAIL; - } - if (drv->associated == WIFI_DISCONNECT) { - wpa_printf(MSG_ERROR, "%s associated status error", __func__); - return -EFAIL; - } - rc = memcpy_s(ssid, MAX_SSID_LEN, drv->ssid, drv->ssidLen); - if (rc != EOK) { - return -EFAIL; - } - return drv->ssidLen; -} - -static uint32_t WifiAlgToCipherSuite(enum wpa_alg alg, size_t keyLen) -{ - switch (alg) { - case WPA_ALG_WEP: - if (keyLen == WPA_WEP40_KEY_LEN) { - return RSN_CIPHER_SUITE_WEP40; - } - return RSN_CIPHER_SUITE_WEP104; - case WPA_ALG_TKIP: - return RSN_CIPHER_SUITE_TKIP; - case WPA_ALG_CCMP: - return RSN_CIPHER_SUITE_CCMP; - case WPA_ALG_GCMP: - return RSN_CIPHER_SUITE_GCMP; - case WPA_ALG_CCMP_256: - return RSN_CIPHER_SUITE_CCMP_256; - case WPA_ALG_GCMP_256: - return RSN_CIPHER_SUITE_GCMP_256; - case WPA_ALG_BIP_CMAC_128: - return RSN_CIPHER_SUITE_AES_128_CMAC; - case WPA_ALG_BIP_GMAC_128: - return RSN_CIPHER_SUITE_BIP_GMAC_128; - case WPA_ALG_BIP_GMAC_256: - return RSN_CIPHER_SUITE_BIP_GMAC_256; - case WPA_ALG_BIP_CMAC_256: - return RSN_CIPHER_SUITE_BIP_CMAC_256; - case WPA_ALG_SMS4: - return RSN_CIPHER_SUITE_SMS4; - case WPA_ALG_KRK: - return RSN_CIPHER_SUITE_KRK; - case WPA_ALG_NONE: - return 0; - default: - return 0; - } -} - -static inline int IsBroadcastAddr(const uint8_t *addr) -{ - // 0 1 2 3 4 5 are mac index - return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff; -} - -static void WifiWpaInitAlg(WifiKeyExt *keyExt, enum wpa_alg alg, size_t keyLen) -{ - keyExt->cipher = WifiAlgToCipherSuite(alg, keyLen); - if ((alg == WPA_ALG_BIP_CMAC_128) || (alg == WPA_ALG_BIP_GMAC_128) || - (alg == WPA_ALG_BIP_GMAC_256) || (alg == WPA_ALG_BIP_CMAC_256)) { - keyExt->defMgmt = true; - } else { - keyExt->def = true; - } -} - -static int32_t WifiWpaInitAddr(WifiKeyExt *keyExt, const uint8_t *addr, const enum wpa_alg alg, const int32_t keyIdx, - const int32_t setTx) -{ - keyExt->type = WIFI_KEYTYPE_BUTT; - keyExt->defaultTypes = WIFI_KEY_DEFAULT_TYPE_INVALID; - if (addr != NULL) { - if (!IsBroadcastAddr(addr)) { - keyExt->addr = (uint8_t *)os_zalloc(ETH_ADDR_LEN); - if ((keyExt->addr == NULL) || (memcpy_s(keyExt->addr, ETH_ADDR_LEN, addr, ETH_ADDR_LEN) != EOK)) { - return -EFAIL; - } - if ((alg != WPA_ALG_WEP) && (keyIdx != 0) && (setTx == 0)) { - keyExt->type = WIFI_KEYTYPE_GROUP; - } - keyExt->defaultTypes = WIFI_KEY_DEFAULT_TYPE_UNICAST; - } else { - keyExt->addr = NULL; - keyExt->defaultTypes = WIFI_KEY_DEFAULT_TYPE_MULTICAST; - } - } - if (keyExt->type == WIFI_KEYTYPE_BUTT) { - keyExt->type = (keyExt->addr != NULL) ? WIFI_KEYTYPE_PAIRWISE : WIFI_KEYTYPE_GROUP; - } - return SUCC; -} - -static int32_t WifiWpaInitSeq(WifiKeyExt *keyExt, const uint8_t *seq, const size_t seqLen) -{ - keyExt->seqLen = seqLen; - if ((seq != NULL) && (seqLen != 0)) { - keyExt->seq = (uint8_t *)os_zalloc(seqLen); - if ((keyExt->seq == NULL) || (memcpy_s(keyExt->seq, seqLen, seq, seqLen) != EOK)) { - return -EFAIL; - } - } - return SUCC; -} - -static int32_t WifiWpaInitKey(WifiKeyExt *keyExt, const uint8_t *key, const size_t keyLen, const int32_t keyIdx, - const enum wpa_alg alg) -{ - keyExt->keyLen = keyLen; - keyExt->keyIdx = keyIdx; - if ((alg != WPA_ALG_NONE) && (key != NULL) && (keyLen != 0)) { - keyExt->key = (uint8_t *)os_zalloc(keyLen); - if ((keyExt->key == NULL) || (memcpy_s(keyExt->key, keyLen, key, keyLen) != EOK)) { - return -EFAIL; - } - } - return SUCC; -} - -static void WifiKeyExtFree(WifiKeyExt **key) -{ - if (key == NULL || *key == NULL) { - return; - } - - if ((*key)->addr != NULL) { - os_free((*key)->addr); - (*key)->addr = NULL; - } - if ((*key)->seq != NULL) { - os_free((*key)->seq); - (*key)->seq = NULL; - } - if ((*key)->key != NULL) { - os_free((*key)->key); - (*key)->key = NULL; - } - - os_free(*key); - *key = NULL; -} - -static inline int32_t IsApInterface(int32_t mode) -{ - return ((mode) == WIFI_IFTYPE_AP || (mode) == WIFI_IFTYPE_P2P_GO); -} - -static int32_t WifiWpaSetKey(void *priv, - struct wpa_driver_set_key_params *params) { - int32_t ret; - WifiKeyExt *keyExt = NULL; - WifiDriverData *drv = priv; - - if ((priv == NULL) || (params->ifname == NULL) || (priv == NULL)) { - return -EFAIL; - } - if (drv->mode == WIFI_IFTYPE_P2P_DEVICE) { - return SUCC; - } - - keyExt = os_zalloc(sizeof(WifiKeyExt)); - if (keyExt == NULL) { - return -EFAIL; - } - - WifiWpaInitAlg(keyExt, params->alg, params->key_len); - if (WifiWpaInitAddr(keyExt, params->addr, params->alg, params->key_idx, - params->set_tx) != SUCC || - WifiWpaInitSeq(keyExt, params->seq, params->seq_len) != SUCC || - WifiWpaInitKey(keyExt, params->key, params->key_len, params->key_idx, - params->alg) != SUCC) { - WifiKeyExtFree(&keyExt); - wpa_printf(MSG_ERROR, "WifiWpaInitKey failed"); - return -EFAIL; - } - - if (params->alg == WPA_ALG_NONE) { - ret = WifiCmdDelKey(params->ifname, keyExt); - } else { - ret = WifiCmdNewKey(params->ifname, keyExt); - if ((ret != SUCC) || (params->set_tx == 0) || - (params->alg == WPA_ALG_NONE)) { - WifiKeyExtFree(&keyExt); - return ret; - } - - if ((IsApInterface(drv->mode)) && (keyExt->addr != NULL) && - (!IsBroadcastAddr(keyExt->addr))) { - WifiKeyExtFree(&keyExt); - return ret; - } - ret = WifiCmdSetKey(params->ifname, keyExt); - } - - WifiKeyExtFree(&keyExt); - return ret; -} - -static void WifiWpaReceiveEapol(void *ctx, const uint8_t *srcAddr, const uint8_t *buf, size_t len) -{ - WifiDriverData *drv = ctx; - - if ((ctx == NULL) || (srcAddr == NULL) || (buf == NULL) || (len < sizeof(struct l2_ethhdr))) { - return; - } - - drv_event_eapol_rx(drv->ctx, srcAddr, buf + sizeof(struct l2_ethhdr), len - sizeof(struct l2_ethhdr)); - wpa_printf(MSG_INFO, "WifiWpaReceiveEapol done"); -} - -static void WifiWpaPreInit(const WifiDriverData *drv) -{ - WifiSetMode setMode; - WifiSetNewDev info; - - if (drv == NULL) { - return; - } - - (void)memset_s(&setMode, sizeof(WifiSetMode), 0, sizeof(WifiSetMode)); - (void)memset_s(&info, sizeof(WifiSetNewDev), 0, sizeof(WifiSetNewDev)); - - if (strncmp(drv->iface, "p2p-p2p0-", 9) == 0) { - info.ifType = WIFI_IFTYPE_P2P_CLIENT; - setMode.iftype = WIFI_IFTYPE_P2P_CLIENT; - } else if (strncmp(drv->iface, "p2p0", 4) == 0) { - info.ifType = WIFI_IFTYPE_P2P_DEVICE; - setMode.iftype = WIFI_IFTYPE_P2P_DEVICE; - } else { - setMode.iftype = WIFI_IFTYPE_STATION; - info.status = false; - info.ifType = WIFI_IFTYPE_STATION; - info.mode = WIFI_PHY_MODE_11N; - if (WifiCmdSetNetdev(drv->iface, &info) != SUCC) { - wpa_printf(MSG_ERROR, "%s set netdev failed", __func__); - } - if (WifiCmdSetMode((char *)drv->iface, &setMode) != SUCC) { - wpa_printf(MSG_ERROR, "%s set mode failed", __func__); - } - } -} - -#ifdef CONFIG_OPEN_HARMONY_PATCH -static void CheckWifiIface(const char *ifName) -{ - DIR *dir; - struct dirent *dent; - while (true) { - dir = opendir("/sys/class/net"); - if (dir == 0) { - return; - } - while ((dent = readdir(dir))) { - if (dent->d_name[0] == '.') { - continue; - } - if (strcmp(dent->d_name, ifName) == 0) { - goto out; - } - usleep(WAIT_LOAD_NETDEVICE); - } - } -out: - closedir(dir); -} -#endif - -static void WifiWpaDeinit(void *priv) -{ - WifiDriverData *drv = NULL; - WifiSetNewDev info; - - if (priv == NULL) { - return; - } - - drv = (WifiDriverData *)priv; - info.status = false; - info.ifType = WIFI_IFTYPE_STATION; - info.mode = WIFI_PHY_MODE_11N; -#ifdef CONFIG_OHOS_P2P - if (strncmp(drv->iface, "p2p-p2p0-", 9) == 0) { - info.ifType = WIFI_IFTYPE_P2P_CLIENT; - } else if (strncmp(drv->iface, "p2p0", 4) == 0) { - info.ifType = WIFI_IFTYPE_P2P_DEVICE; - } - WifiDev *wifiDev = NULL; - wifiDev = GetWifiDevByName(drv->iface); - if (wifiDev == NULL) { - wpa_printf(MSG_ERROR, "%s: GetWifiDevByName failed.\r\n.", __FUNCTION__); - } - FreeWifiDev(wifiDev); -#endif // CONFIG_OHOS_P2P - eloop_cancel_timeout(WifiWpaScanTimeout, drv, drv->ctx); - WifiCmdSetNetdev(drv->iface, &info); - - if (drv->eapolSock != NULL) { - l2_packet_deinit(drv->eapolSock); - } - -#ifdef CONFIG_OHOS_P2P - WifiUnregisterEventCallback(OnWpaWiFiEvents, WIFI_KERNEL_TO_WPA_CLIENT, drv->iface); - if (CountWifiDevInUse() == 0) { - g_msgInit = true; - os_free(g_wifiDriverData); - g_wifiDriverData = NULL; - (void)WifiClientDeinit(drv->iface); - } -#else - os_free(g_wifiDriverData); - g_wifiDriverData = NULL; - (void)WifiClientDeinit(drv->iface); -#endif //CONFIG_OHOS_P2P - - wpa_printf(MSG_INFO, "WifiWpaDeinit done"); -} - -static void *WifiWpaInit(void *ctx, const char *ifName) -{ - int32_t ret; - WifiSetNewDev info; -#ifdef CONFIG_OHOS_P2P - WifiDev *wifiDev = NULL; - errno_t rc; -#endif - - if ((ctx == NULL) || (ifName == NULL)) { - return NULL; - } - - wpa_printf(MSG_INFO, "%s enter, interface name:%s.", __FUNCTION__, ifName); - (void)memset_s(&info, sizeof(WifiSetNewDev), 0, sizeof(WifiSetNewDev)); - WifiDriverData *drv = os_zalloc(sizeof(WifiDriverData)); - if (drv == NULL) { - goto failed; - } - - drv->ctx = ctx; - if (memcpy_s(drv->iface, sizeof(drv->iface), ifName, sizeof(drv->iface)) != EOK) { - goto failed; - } -#ifdef CONFIG_OHOS_P2P - if (g_msgInit && (strncmp(drv->iface, "p2p0", 4) == 0)) { - if (WifiClientInit(drv->iface) != SUCC) { - goto failed; - } - g_msgInit = false; - } -#endif // CONFIG_OHOS_P2P - if (strncmp(drv->iface, "wlan0", 5) == 0) { - if (WifiClientInit(drv->iface) != SUCC) { - goto failed; - } - } -#ifdef CONFIG_OPEN_HARMONY_PATCH - CheckWifiIface(ifName); -#endif - WifiWpaPreInit(drv); - - info.status = true; - info.ifType = WIFI_IFTYPE_STATION; - info.mode = WIFI_PHY_MODE_11N; -#ifdef CONFIG_OHOS_P2P - if (strncmp(drv->iface, "p2p-p2p0-", 9) == 0) { - info.ifType = WIFI_IFTYPE_P2P_CLIENT; - } else if (strncmp(drv->iface, "p2p0", 4) == 0) { - info.ifType = WIFI_IFTYPE_P2P_DEVICE; - } -#endif // CONFIG_OHOS_P2P - ret = WifiCmdSetNetdev(drv->iface, &info); - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "WifiWpaInit set netdev faild"); - goto failed; - } - drv->eapolSock = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, WifiWpaReceiveEapol, drv, 1); - if (drv->eapolSock == NULL) { - wpa_printf(MSG_ERROR, "WifiWpaInit l2_packet_init faild"); - goto failed; - } - - if (l2_packet_get_own_addr(drv->eapolSock, drv->ownAddr)) { - wpa_printf(MSG_ERROR, "l2_packet_get_own_addr faild"); - goto failed; - } - - g_wifiDriverType = WIFI_IFTYPE_STATION; -#ifdef CONFIG_OHOS_P2P - wifiDev = (WifiDev *)os_zalloc(sizeof(WifiDev)); - if (wifiDev == NULL) { - wpa_printf(MSG_ERROR, "%s wifiDev malloc failed.", __FUNCTION__); - goto failed; - } - wifiDev->priv = drv; - wifiDev->ifNameLen = sizeof(ifName); - rc = memcpy_s(wifiDev->ifName, sizeof(wifiDev->ifName), drv->iface, sizeof(drv->iface)); - if (rc != EOK) { - wpa_printf(MSG_ERROR, "%s could not copy wifi device name.", __FUNCTION__); - goto failed; - } - wpa_printf(MSG_ERROR, "%s init done, ifName:%s.", __FUNCTION__, wifiDev->ifName); - SetWifiDev(wifiDev); -#endif // CONFIG_OHOS_P2P - g_wifiDriverData = drv; - return drv; - -failed: -#ifdef CONFIG_OHOS_P2P - FreeWifiDev(wifiDev); -#endif // CONFIG_OHOS_P2P - WifiWpaDeinit(drv); - return NULL; -} - -static int32_t WifiWpaDeauthenticate(void *priv, const uint8_t *addr, uint16_t reasonCode) -{ - int32_t ret; - WifiDriverData *drv = priv; - - (void)addr; - if (priv == NULL) { - return -EFAIL; - } - - wpa_printf(MSG_INFO, "WifiWpaDeauthenticate reasonCode = %d", reasonCode); - ret = WifiCmdDisconnet(drv->iface, reasonCode); - if (ret == SUCC) { - drv->associated = WIFI_DISCONNECT; - } - return ret; -} - -static int32_t WifiWpaDriverAp(WifiDriverData *drv, struct wpa_driver_associate_params *params) -{ - int32_t ret; - WifiSetMode setMode; - errno_t rc; - - if ((drv == NULL) || (params == NULL)) { - wpa_printf(MSG_ERROR, "%s input NULL ptr.", __FUNCTION__); - return -EFAIL; - } - rc = memset_s(&setMode, sizeof(WifiSetMode), 0, sizeof(WifiSetMode)); - if (rc != EOK) { - wpa_printf(MSG_ERROR, "%s: memset failed.", __FUNCTION__); - return -EFAIL; - } - if (params->p2p) { - wpa_printf(MSG_INFO, "%s: Setup AP operations for P2P group.(GO).", __FUNCTION__); - setMode.iftype = WIFI_IFTYPE_P2P_GO; - } else { - setMode.iftype = WIFI_IFTYPE_AP; - } - rc = memcpy_s(setMode.bssid, ETH_ADDR_LEN, drv->ownAddr, ETH_ADDR_LEN); - if (rc != EOK) { - wpa_printf(MSG_ERROR, "%s memcpy failed.", __FUNCTION__); - return -EFAIL; - } - ret = WifiCmdSetMode(drv->iface, &setMode); - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "%s: set mode failed.", __FUNCTION__); - return -EFAIL; - } - return SUCC; -} - -static int32_t WifiWpaAssocParamsSet(WifiDriverData *drv, struct wpa_driver_associate_params *params, - WifiAssociateParams *assocParams) -{ - if (params->bssid != NULL) { - assocParams->bssid = (uint8_t *)os_zalloc(ETH_ADDR_LEN); - if (assocParams->bssid == NULL) { - return -EFAIL; - } - if (memcpy_s(assocParams->bssid, ETH_ADDR_LEN, params->bssid, ETH_ADDR_LEN) != EOK) { - return -EFAIL; - } - } - - if (params->freq.freq != 0) { - assocParams->freq = params->freq.freq; - } - if (params->ssid_len > MAX_SSID_LEN) { - params->ssid_len = MAX_SSID_LEN; - } - if ((params->ssid != NULL) && (params->ssid_len != 0)) { - assocParams->ssid = (uint8_t *)os_zalloc(params->ssid_len); - if (assocParams->ssid == NULL) { - return -EFAIL; - } - assocParams->ssidLen = params->ssid_len; - if (memcpy_s(assocParams->ssid, assocParams->ssidLen, params->ssid, params->ssid_len) != EOK) { - return -EFAIL; - } - if (memset_s(drv->ssid, MAX_SSID_LEN, 0, MAX_SSID_LEN) != EOK) { - return -EFAIL; - } - if (memcpy_s(drv->ssid, MAX_SSID_LEN, params->ssid, params->ssid_len) != EOK) { - return -EFAIL; - } - drv->ssidLen = params->ssid_len; - } - - if ((params->wpa_ie != NULL) && (params->wpa_ie_len != 0)) { - assocParams->ie = (uint8_t *)os_zalloc(params->wpa_ie_len); - if (assocParams->ie == NULL) { - return -EFAIL; - } - assocParams->ieLen = params->wpa_ie_len; - if (memcpy_s(assocParams->ie, assocParams->ieLen, params->wpa_ie, params->wpa_ie_len) != EOK) { - return -EFAIL; - } - } - - return SUCC; -} - -static uint32_t WifiCipherToCipherSuite(uint32_t cipher) -{ - switch (cipher) { - case WPA_CIPHER_CCMP_256: - return RSN_CIPHER_SUITE_CCMP_256; - case WPA_CIPHER_GCMP_256: - return RSN_CIPHER_SUITE_GCMP_256; - case WPA_CIPHER_CCMP: - return RSN_CIPHER_SUITE_CCMP; - case WPA_CIPHER_GCMP: - return RSN_CIPHER_SUITE_GCMP; - case WPA_CIPHER_TKIP: - return RSN_CIPHER_SUITE_TKIP; - case WPA_CIPHER_WEP104: - return RSN_CIPHER_SUITE_WEP104; - case WPA_CIPHER_WEP40: - return RSN_CIPHER_SUITE_WEP40; - case WPA_CIPHER_GTK_NOT_USED: - return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; - default: - return 0; - } -} - -static int32_t WifiWpaAssocParamCryptoSet(const struct wpa_driver_associate_params *params, - WifiAssociateParams *assocParams) -{ - uint32_t ver = 0; - uint32_t akm_suites_num = 0; - uint32_t ciphers_pairwise_num = 0; - int32_t mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; - - assocParams->crypto = (WifiCryptoSetting *)os_zalloc(sizeof(WifiCryptoSetting)); - if (assocParams->crypto == NULL) { - return -EFAIL; - } - - if (params->wpa_proto != 0) { - if (params->wpa_proto & WPA_PROTO_WPA) { - ver |= WPA_VERSION_1; - } - if (params->wpa_proto & WPA_PROTO_RSN) { - ver |= WPA_VERSION_2; - } - assocParams->crypto->wpaVersions = ver; - } - - if (params->pairwise_suite != WPA_CIPHER_NONE) { - assocParams->crypto->ciphersPairwise[ciphers_pairwise_num++] = WifiCipherToCipherSuite(params->pairwise_suite); - assocParams->crypto->nCiphersPairwise = ciphers_pairwise_num; - } - - if (params->group_suite != WPA_CIPHER_NONE) { - assocParams->crypto->cipherGroup = WifiCipherToCipherSuite(params->group_suite); - } - - if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK || params->key_mgmt_suite == WPA_KEY_MGMT_SAE || - params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) { - switch (params->key_mgmt_suite) { - case WPA_KEY_MGMT_PSK_SHA256: - mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256; - break; - case WPA_KEY_MGMT_SAE: - mgmt = RSN_AUTH_KEY_MGMT_SAE; - break; - case WPA_KEY_MGMT_PSK: /* fall through */ - default: - mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; - break; - } - assocParams->crypto->akmSuites[akm_suites_num++] = mgmt; - assocParams->crypto->nAkmSuites = akm_suites_num; - } - - return SUCC; -} - -static void WifiWpaSetConnKeys(const struct wpa_driver_associate_params *wpa_params, WifiAssociateParams *params) -{ - int32_t loop; - uint8_t privacy; - errno_t rc; - - if ((wpa_params == NULL) || (params == NULL)) { - return; - } - - privacy = 0; - for (loop = 0; loop < WEP_KEY_NUM; loop++) { - if (wpa_params->wep_key[loop] == NULL) { - continue; - } - privacy = 1; - break; - } - - if ((wpa_params->wps == WPS_MODE_PRIVACY) || - ((wpa_params->pairwise_suite != 0) && (wpa_params->pairwise_suite != WPA_CIPHER_NONE))) { - privacy = 1; - } - if (privacy == 0) { - return; - } - params->privacy = privacy; - for (loop = 0; loop < WEP_KEY_NUM; loop++) { - if (wpa_params->wep_key[loop] == NULL) { - continue; - } - params->keyLen = wpa_params->wep_key_len[loop]; - params->key = (uint8_t *)os_zalloc(params->keyLen); - if (params->key == NULL) { - return; - } - - rc = memcpy_s(params->key, params->keyLen, wpa_params->wep_key[loop], params->keyLen); - if (rc != EOK) { - os_free(params->key); - params->key = NULL; - return; - } - params->keyIdx = wpa_params->wep_tx_keyidx; - break; - } - - return; -} - -static void WifiWpaConnectFree(WifiAssociateParams **params) -{ - if (params == NULL || *params == NULL) { - return; - } - - if ((*params)->ie != NULL) { - os_free((*params)->ie); - (*params)->ie = NULL; - } - if ((*params)->crypto != NULL) { - os_free((*params)->crypto); - (*params)->crypto = NULL; - } - if ((*params)->ssid != NULL) { - os_free((*params)->ssid); - (*params)->ssid = NULL; - } - if ((*params)->bssid != NULL) { - os_free((*params)->bssid); - (*params)->bssid = NULL; - } - if ((*params)->key != NULL) { - os_free((*params)->key); - (*params)->key = NULL; - } - - os_free(*params); - *params = NULL; -} - -static WifiAuthType WifiGetStaAuthType(const struct wpa_driver_associate_params *params) -{ - WifiAuthType type = WIFI_AUTHTYPE_BUTT; - uint32_t algs = 0; - - if ((uint32_t)(params->auth_alg) & WPA_AUTH_ALG_OPEN) { - type = WIFI_AUTHTYPE_OPEN_SYSTEM; - algs++; - } - if ((uint32_t)(params->auth_alg) & WPA_AUTH_ALG_SHARED) { - type = WIFI_AUTHTYPE_SHARED_KEY; - algs++; - } - if ((uint32_t)(params->auth_alg) & WPA_AUTH_ALG_LEAP) { - type = WIFI_AUTHTYPE_EAP; - algs++; - } - - if (algs > 1) { - return WIFI_AUTHTYPE_AUTOMATIC; - } else if (algs == 1) { - return type; - } - - if ((uint32_t)params->auth_alg & WPA_AUTH_ALG_FT) { - type = WIFI_AUTHTYPE_FT; - } - return type; -} - -static int32_t WifiWpaTryConnect(WifiDriverData *drv, struct wpa_driver_associate_params *params) -{ - WifiAssociateParams *assocParams = NULL; - int32_t ret = -EFAIL; - - if ((drv == NULL) || (params == NULL)) { - return -EFAIL; - } - - assocParams = (WifiAssociateParams *)os_zalloc(sizeof(WifiAssociateParams)); - if (assocParams == NULL) { - return ret; - } - if (WifiWpaAssocParamsSet(drv, params, assocParams) != SUCC) { - wpa_printf(MSG_ERROR, "WifiWpaTryConnect set assoc params faild"); - goto skip_auth_type; - } - if (WifiWpaAssocParamCryptoSet(params, assocParams) != SUCC) { - wpa_printf(MSG_ERROR, "WifiWpaTryConnect set assoc crypto faild"); - goto skip_auth_type; - } - assocParams->mfp = params->mgmt_frame_protection; - assocParams->authType = WifiGetStaAuthType(params); - - WifiWpaSetConnKeys(params, assocParams); - ret = WifiCmdAssoc(drv->iface, assocParams); - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "WifiWpaTryConnect assoc faild"); - } - -skip_auth_type: - WifiWpaConnectFree(&assocParams); - return ret; -} - -static int32_t WifiWpaDisconnet(WifiDriverData *drv, uint16_t reasonCode) -{ - int32_t ret; - - if (drv == NULL) { - return -EFAIL; - } - ret = WifiCmdDisconnet(drv->iface, reasonCode); - if (ret == SUCC) { - drv->associated = WIFI_DISCONNECT; - } - wpa_printf(MSG_INFO, "WifiWpaDisconnet done ret=%d", ret); - return ret; -} -static int WifiWpaAssociate(void *priv, struct wpa_driver_associate_params *params) -{ - int ret; - WifiDriverData *drv = priv; - - if ((drv == NULL) || (params == NULL)) { - return -EFAIL; - } -#ifdef CONFIG_OHOS_P2P - if (params->mode == IEEE80211_MODE_AP) { - return WifiWpaDriverAp(drv, params); - } -#endif - ret = WifiWpaTryConnect(drv, params); - if (ret != SUCC) { - if (WifiWpaDisconnet(drv, WLAN_REASON_PREV_AUTH_NOT_VALID)) { - return -EFAIL; - } - ret = WifiWpaTryConnect(drv, params); - } - wpa_printf(MSG_INFO, "WifiWpaAssociate done ret=%d", ret); - return ret; -} - -static const uint8_t *WifiWpaGetMacAddr(void *priv) -{ - WifiDriverData *drv = priv; - - if (priv == NULL) { - return NULL; - } - return drv->ownAddr; -} - -int32_t WifiWpaWpaSendEapol(void *priv, const uint8_t *dest, uint16_t proto, const uint8_t *data, size_t dataLen) -{ - WifiDriverData *drv = priv; - int32_t ret; - uint32_t frameLen; - uint8_t *frame = NULL; - uint8_t *payload = NULL; - struct l2_ethhdr *l2_ethhdr = NULL; - errno_t rc; - - if ((priv == NULL) || (data == NULL) || (dest == NULL)) { - return -EFAIL; - } - - frameLen = dataLen + sizeof(struct l2_ethhdr); - frame = os_zalloc(frameLen); - if (frame == NULL) { - return -EFAIL; - } - - l2_ethhdr = (struct l2_ethhdr *)frame; - rc = memcpy_s(l2_ethhdr->h_dest, ETH_ADDR_LEN, dest, ETH_ADDR_LEN); - if (rc != EOK) { - os_free(frame); - frame = NULL; - return -EFAIL; - } - rc = memcpy_s(l2_ethhdr->h_source, ETH_ADDR_LEN, drv->ownAddr, ETH_ADDR_LEN); - if (rc != EOK) { - os_free(frame); - frame = NULL; - return -EFAIL; - } - l2_ethhdr->h_proto = host_to_be16(proto); - - payload = (uint8_t *)(l2_ethhdr + 1); - rc = memcpy_s(payload, dataLen, data, dataLen); - if (rc != EOK) { - os_free(frame); - frame = NULL; - return -EFAIL; - } - ret = l2_packet_send(drv->eapolSock, dest, host_to_be16(proto), frame, frameLen); - os_free(frame); - frame = NULL; - wpa_printf(MSG_INFO, "WifiWpaWpaSendEapol done ret=%d", ret); - return ret; -} - -static void WifiWpaHwFeatureDataFree(struct hostapd_hw_modes **modes, uint16_t num) -{ - uint16_t loop; - - if (modes == NULL || *modes == NULL) { - return; - } - for (loop = 0; loop < num; ++loop) { - if ((*modes)[loop].channels != NULL) { - os_free((*modes)[loop].channels); - (*modes)[loop].channels = NULL; - } - if ((*modes)[loop].rates != NULL) { - os_free((*modes)[loop].rates); - (*modes)[loop].rates = NULL; - } - } - os_free(*modes); - *modes = NULL; -} - -static struct hostapd_hw_modes *WifiWpaGetHwFeatureData(void *priv, uint16_t *numModes, uint16_t *flags, uint8_t *dfs) -{ - WifiModes modesData[] = {{IEEE80211G_RATES_NUM, HOSTAPD_MODE_IEEE80211G}, - {IEEE80211B_RATES_NUM, HOSTAPD_MODE_IEEE80211B}, {IEEE80211A_RATES_NUM, HOSTAPD_MODE_IEEE80211A}}; - size_t loop; - uint32_t index; - uint32_t iee80211band; - WifiHwFeatureData hwFeatureData; - WifiDriverData *drv = (WifiDriverData *)priv; - (void)dfs; - if ((priv == NULL) || (numModes == NULL) || (flags == NULL)) { - return NULL; - } - (void)memset_s(&hwFeatureData, sizeof(WifiHwFeatureData), 0, sizeof(WifiHwFeatureData)); - *numModes = DEFAULT_NUM_MODES; - *flags = 0; - - if (WifiCmdGetHwFeature(drv->iface, &hwFeatureData) != SUCC) { - return NULL; - } - if (hwFeatureData.bands[IEEE80211_BAND_5GHZ].channelNum != 0) { - *numModes = sizeof(modesData) / sizeof(WifiModes); - } - struct hostapd_hw_modes *modes = os_calloc(*numModes, sizeof(struct hostapd_hw_modes)); - if (modes == NULL) { - return NULL; - } - - for (loop = 0; loop < *numModes; ++loop) { - modes[loop].channels = NULL; - modes[loop].rates = NULL; - } - - modes[0].ht_capab = hwFeatureData.htCapab; - iee80211band = IEEE80211_BAND_2GHZ; - for (index = 0; index < *numModes; index++) { - if (index >= DEFAULT_NUM_MODES) { - iee80211band = IEEE80211_BAND_5GHZ; - } - modes[index].mode = modesData[index].mode; - modes[index].num_channels = hwFeatureData.bands[iee80211band].channelNum; - modes[index].num_rates = modesData[index].numRates; - modes[index].channels = os_calloc(hwFeatureData.bands[iee80211band].channelNum, sizeof(struct hostapd_channel_data)); - modes[index].rates = os_calloc(modes[index].num_rates, sizeof(uint32_t)); - if ((modes[index].channels == NULL) || (modes[index].rates == NULL)) { - WifiWpaHwFeatureDataFree(&modes, *numModes); - return NULL; - } - - for (loop = 0; loop < (size_t)hwFeatureData.bands[iee80211band].channelNum; loop++) { - modes[index].channels[loop].chan = hwFeatureData.bands[iee80211band].iee80211Channel[loop].channel; - modes[index].channels[loop].freq = hwFeatureData.bands[iee80211band].iee80211Channel[loop].freq; - modes[index].channels[loop].flag = hwFeatureData.bands[iee80211band].iee80211Channel[loop].flags; - modes[index].channels[loop].allowed_bw = HOSTAPD_CHAN_WIDTH_20 | HOSTAPD_CHAN_WIDTH_10; - } - - for (loop = 0; loop < (size_t)modes[index].num_rates; loop++) { - if (index < DEFAULT_NUM_MODES) { - modes[index].rates[loop] = hwFeatureData.bitrate[loop]; - } else { - modes[index].rates[loop] = hwFeatureData.bitrate[loop + IEEE80211B_RATES_NUM]; - } - } - } - - wpa_printf(MSG_INFO, "WifiWpaGetHwFeatureData done"); - return modes; -} - -static int32_t WifiWpaSendMlme(void *priv, const uint8_t *data, size_t dataLen, int32_t noack, uint32_t freq, - const uint16_t *csaOffs, size_t csaOffsLen, int no_encrypt, unsigned int wait) -{ - int32_t ret; - WifiDriverData *drv = priv; - WifiMlmeData *mlme = NULL; - errno_t rc; - - (void)freq; - (void)csaOffs; - (void)csaOffsLen; - (void)noack; - (void)no_encrypt; - (void)wait; - if ((priv == NULL) || (data == NULL)) { - return -EFAIL; - } - mlme = os_zalloc(sizeof(WifiMlmeData)); - if (mlme == NULL) { - return -EFAIL; - } - mlme->data = NULL; - mlme->dataLen = dataLen; - mlme->cookie = &(drv->actionCookie); - if ((data != NULL) && (dataLen != 0)) { - mlme->data = (uint8_t *)os_zalloc(dataLen); - if (mlme->data == NULL) { - os_free(mlme); - mlme = NULL; - return -EFAIL; - } - rc = memcpy_s(mlme->data, dataLen, data, dataLen); - if (rc != EOK) { - os_free(mlme->data); - mlme->data = NULL; - os_free(mlme); - return -EFAIL; - } - } - ret = WifiCmdSendMlme(drv->iface, mlme); - os_free(mlme->data); - mlme->data = NULL; - os_free(mlme); - if (ret != SUCC) { - ret = -EFAIL; - } - wpa_printf(MSG_INFO, "WifiWpaSendMlme done ret=%d", ret); - return ret; -} - -static struct wpa_scan_results *WifiWpaGetScanResults2(void *priv) -{ - struct wpa_scan_results *results = NULL; - WifiDriverData *drv = priv; - uint32_t loop; - errno_t rc; - - if (priv == NULL) { - return NULL; - } - - results = (struct wpa_scan_results *)os_zalloc(sizeof(struct wpa_scan_results)); - if (results == NULL) { - return NULL; - } - - results->num = drv->scanNum; - if (results->num == 0) { - return results; - } - results->res = (struct wpa_scan_res **)os_zalloc(results->num * sizeof(struct wpa_scan_res *)); - if (results->res == NULL) { - os_free(results); - results = NULL; - return NULL; - } - rc = memcpy_s(results->res, results->num * sizeof(struct wpa_scan_res *), drv->scanRes, - results->num * sizeof(struct wpa_scan_res *)); - if (rc != EOK) { - os_free(results->res); - os_free(results); - results = NULL; - return NULL; - } - drv->scanNum = 0; - for (loop = 0; loop < SCAN_AP_LIMIT; loop++) { - drv->scanRes[loop] = NULL; - } - wpa_printf(MSG_INFO, "WifiWpaGetScanResults2 done"); - return results; -} - -static void *WifiWpaInit2(void *ctx, const char *ifname, void *globalPriv) -{ - (void)globalPriv; - return WifiWpaInit(ctx, ifname); -} - -static int32_t WifiWpaScanProcessSsid(struct wpa_driver_scan_params *params, WifiScan *scan) -{ - errno_t rc; - size_t loop; - if (params->num_ssids == 0) { - return SUCC; - } - - scan->numSsids = params->num_ssids; - scan->ssids = (WifiDriverScanSsid *)os_zalloc(sizeof(WifiDriverScanSsid) * params->num_ssids); - if (scan->ssids == NULL) { - return -EFAIL; - } - - for (loop = 0; (loop < params->num_ssids) && (loop < WPAS_MAX_SCAN_SSIDS); loop++) { - wpa_printf(MSG_INFO, "WIFI: Scan : %s SSID : %zu\n", anonymize_ssid(params->ssids[loop].ssid), - params->ssids[loop].ssid_len); - - if (params->ssids[loop].ssid_len > MAX_SSID_LEN) { - params->ssids[loop].ssid_len = MAX_SSID_LEN; - } - if (params->ssids[loop].ssid_len) { - rc = memcpy_s(scan->ssids[loop].ssid, MAX_SSID_LEN, params->ssids[loop].ssid, params->ssids[loop].ssid_len); - if (rc != EOK) { - return -EFAIL; - } - } - scan->ssids[loop].ssidLen = params->ssids[loop].ssid_len; - } - - return SUCC; -} - -static int32_t WifiWpaScanProcessBssid(const struct wpa_driver_scan_params *params, WifiScan *scan) -{ - errno_t rc; - if (params->bssid != NULL) { - scan->bssid = (uint8_t *)os_zalloc(ETH_ADDR_LEN); - if (scan->bssid == NULL) { - return -EFAIL; - } - rc = memcpy_s(scan->bssid, ETH_ADDR_LEN, params->bssid, ETH_ADDR_LEN); - if (rc != EOK) { - return -EFAIL; - } - } - return SUCC; -} - -static int32_t WifiWpaScanProcessExtraIes(const struct wpa_driver_scan_params *params, WifiScan *scan) -{ - errno_t rc; - if ((params->extra_ies != NULL) && (params->extra_ies_len != 0)) { - scan->extraIes = (uint8_t *)os_zalloc(params->extra_ies_len); - if (scan->extraIes == NULL) { - return -EFAIL; - } - - rc = memcpy_s(scan->extraIes, params->extra_ies_len, params->extra_ies, params->extra_ies_len); - if (rc != EOK) { - return -EFAIL; - } - scan->extraIesLen = params->extra_ies_len; - } - return SUCC; -} - -static int32_t WifiWpaScanProcessFreq(const struct wpa_driver_scan_params *params, WifiScan *scan) -{ - uint32_t numFreqs; - int32_t *freqs = NULL; - errno_t rc; - - if (params->freqs != NULL) { - numFreqs = 0; - for (freqs = params->freqs; *freqs != 0; freqs++) { - numFreqs++; - if (numFreqs > 14) { // 14 is 2.4G channel num - return -EFAIL; - } - } - - scan->numFreqs = numFreqs; - scan->freqs = (int32_t *)os_zalloc(numFreqs * (sizeof(int32_t))); - if (scan->freqs == NULL) { - return -EFAIL; - } - rc = memcpy_s(scan->freqs, numFreqs * (sizeof(int32_t)), params->freqs, numFreqs * (sizeof(int32_t))); - if (rc != EOK) { - return -EFAIL; - } - } - return SUCC; -} - -static void WifiWpaScanFree(WifiScan **scan) -{ - if (scan == NULL || *scan == NULL) { - return; - } - - if ((*scan)->ssids != NULL) { - os_free((*scan)->ssids); - (*scan)->ssids = NULL; - } - if ((*scan)->bssid != NULL) { - os_free((*scan)->bssid); - (*scan)->bssid = NULL; - } - - if ((*scan)->extraIes != NULL) { - os_free((*scan)->extraIes); - (*scan)->extraIes = NULL; - } - - if ((*scan)->freqs != NULL) { - os_free((*scan)->freqs); - (*scan)->freqs = NULL; - } - - os_free(*scan); - *scan = NULL; -} - -void WifiWpaScanTimeout(void *eloop, void *ctx) -{ - (void)eloop; - if (ctx == NULL) { - return; - } - wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); -} - -static int32_t WifiWpaScan2(void *priv, struct wpa_driver_scan_params *params) -{ - WifiScan *scan = NULL; - WifiDriverData *drv = NULL; - int32_t timeout; - int32_t ret; - - if ((priv == NULL) || (params == NULL) || (params->num_ssids > WPAS_MAX_SCAN_SSIDS)) { - return -EFAIL; - } - drv = (WifiDriverData *)priv; - scan = (WifiScan *)os_zalloc(sizeof(WifiScan)); - if (scan == NULL) { - return -EFAIL; - } - if ((WifiWpaScanProcessSsid(params, scan) != SUCC) || (WifiWpaScanProcessBssid(params, scan) != SUCC) || - (WifiWpaScanProcessExtraIes(params, scan) != SUCC) || (WifiWpaScanProcessFreq(params, scan) != SUCC)) { - WifiWpaScanFree(&scan); - return -EFAIL; - } - - scan->fastConnectFlag = WPA_FLAG_OFF; - scan->prefixSsidScanFlag = WPA_FLAG_OFF; - ret = WifiCmdScan(drv->iface, scan); - WifiWpaScanFree(&scan); - - timeout = SCAN_TIME_OUT; - eloop_cancel_timeout(WifiWpaScanTimeout, drv, drv->ctx); - eloop_register_timeout(timeout, 0, WifiWpaScanTimeout, drv, drv->ctx); - - return ret; -} - -static void WifiSetApFreq(WifiApSetting *apsettings, const struct wpa_driver_ap_params *params) -{ - if (params->freq != NULL) { - apsettings->freqParams.mode = params->freq->mode; - apsettings->freqParams.freq = params->freq->freq; - apsettings->freqParams.channel = params->freq->channel; - apsettings->freqParams.htEnabled = params->freq->ht_enabled; - apsettings->freqParams.secChannelOffset = params->freq->sec_channel_offset; - apsettings->freqParams.centerFreq1 = params->freq->center_freq1; - apsettings->freqParams.bandwidth = params->freq->bandwidth; - if (params->freq->bandwidth == WPA_BANDWIDTH_20) { - apsettings->freqParams.bandwidth = WIFI_CHAN_WIDTH_20; - } else { - apsettings->freqParams.bandwidth = WIFI_CHAN_WIDTH_40; - } - } -} - -static void WifiSetApBand(WifiApSetting *apsettings, struct hostapd_data *hapd) -{ - if ((apsettings!= NULL) && (hapd!= NULL)) { - switch (hapd->conf->wps_rf_bands) { - case WPS_RF_24GHZ: - apsettings->freqParams.band = IEEE80211_BAND_2GHZ; - break; - case WPS_RF_50GHZ: - apsettings->freqParams.band = IEEE80211_BAND_5GHZ; - break; - default: - apsettings->freqParams.band = IEEE80211_BAND_2GHZ; - break; - } - } -} - -static int WifiSetApBeaconData(WifiApSetting *apsettings, const struct wpa_driver_ap_params *params) -{ - if ((params->head != NULL) && (params->head_len != 0)) { - apsettings->beaconData.headLen = params->head_len; - apsettings->beaconData.head = (uint8_t *)os_zalloc(apsettings->beaconData.headLen); - if (apsettings->beaconData.head == NULL) { - return -EFAIL; - } - if (memcpy_s(apsettings->beaconData.head, apsettings->beaconData.headLen, params->head, params->head_len) != - EOK) { - return -EFAIL; - } - } - - if ((params->tail != NULL) && (params->tail_len != 0)) { - apsettings->beaconData.tailLen = params->tail_len; - apsettings->beaconData.tail = (uint8_t *)os_zalloc(apsettings->beaconData.tailLen); - if (apsettings->beaconData.tail == NULL) { - return -EFAIL; - } - if (memcpy_s(apsettings->beaconData.tail, apsettings->beaconData.tailLen, params->tail, params->tail_len) != - EOK) { - return -EFAIL; - } - } - return SUCC; -} - -static void WifiApSettingsFree(WifiApSetting **apsettings) -{ - if (apsettings == NULL || *apsettings == NULL) { - return; - } - - if ((*apsettings)->meshSsid != NULL) { - os_free((*apsettings)->meshSsid); - (*apsettings)->meshSsid = NULL; - } - - if ((*apsettings)->ssid != NULL) { - os_free((*apsettings)->ssid); - (*apsettings)->ssid = NULL; - } - - if ((*apsettings)->beaconData.head != NULL) { - os_free((*apsettings)->beaconData.head); - (*apsettings)->beaconData.head = NULL; - } - - if ((*apsettings)->beaconData.tail != NULL) { - os_free((*apsettings)->beaconData.tail); - (*apsettings)->beaconData.tail = NULL; - } - - os_free(*apsettings); - *apsettings = NULL; -} - -static WifiAuthType WifiGetApAuthType(const struct wpa_driver_ap_params *params) -{ - WifiAuthType type; - - if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) == (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) { - type = WIFI_AUTHTYPE_AUTOMATIC; - } else if ((params->auth_algs & WPA_AUTH_ALG_SHARED) == WPA_AUTH_ALG_SHARED) { - type = WIFI_AUTHTYPE_SHARED_KEY; - } else { - type = WIFI_AUTHTYPE_OPEN_SYSTEM; - } - return type; -} - -static int32_t WifiWpaSetAp(void *priv, struct wpa_driver_ap_params *params) -{ - int32_t ret; - WifiApSetting *apsettings = NULL; - WifiDriverData *drv = (WifiDriverData *)priv; - if ((priv == NULL) || (params == NULL) || (params->freq == NULL)) { - return -EFAIL; - } - if ((params->freq->bandwidth != WPA_BANDWIDTH_20) && (params->freq->bandwidth != WPA_BANDWIDTH_40)) { - return -EFAIL; - } - - apsettings = os_zalloc(sizeof(WifiApSetting)); - if (apsettings == NULL) { - return -EFAIL; - } - apsettings->beaconInterval = params->beacon_int; - apsettings->dtimPeriod = params->dtim_period; - apsettings->hiddenSsid = params->hide_ssid; - apsettings->authType = WifiGetApAuthType(params); - - if ((params->ssid != NULL) && (params->ssid_len != 0)) { - apsettings->ssidLen = params->ssid_len; - apsettings->ssid = (uint8_t *)os_zalloc(apsettings->ssidLen); - if ((apsettings->ssid == NULL) || - (memcpy_s(apsettings->ssid, apsettings->ssidLen, params->ssid, params->ssid_len) != EOK)) { - goto failed; - } - } - WifiSetApFreq(apsettings, params); - WifiSetApBand(apsettings, drv->hapd); - if (WifiSetApBeaconData(apsettings, params) != SUCC) { - goto failed; - } - if (drv->beaconSet == true) { - ret = WifiCmdChangeBeacon(drv->iface, apsettings); - } else { - ret = WifiCmdSetAp(drv->iface, apsettings); - } - if (ret == SUCC) { - drv->beaconSet = true; - } - WifiApSettingsFree(&apsettings); - wpa_printf(MSG_INFO, "WifiWpaGetScanResults2 done ret=%d", ret); - return ret; - -failed: - WifiApSettingsFree(&apsettings); - return -EFAIL; -} - -static void WifiHapdPreInit(const WifiDriverData *drv) -{ - WifiSetNewDev info; - - if (drv == NULL) { - return; - } - info.status = false; - info.ifType = WIFI_IFTYPE_STATION; - info.mode = WIFI_PHY_MODE_11N; - int ret = WifiCmdSetNetdev(drv->iface, &info); - - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "%s set netdev failed ret = %d.", __func__, ret); - } -} - -static WifiDriverData *WifiDrvInit(void *ctx, const struct wpa_init_params *params) -{ - WifiDriverData *drv = NULL; - errno_t rc; - WifiSetNewDev info; - WifiSetMode setMode; - int32_t ret; -#ifdef CONFIG_OHOS_P2P - WifiDev *wifiDev = NULL; -#endif - if ((ctx == NULL) || (params == NULL)) { - return NULL; - } - drv = os_zalloc(sizeof(WifiDriverData)); - if (drv == NULL) { - goto failed; - } - - drv->ctx = ctx; - rc = memcpy_s(drv->iface, sizeof(drv->iface), params->ifname, sizeof(drv->iface)); - if (rc != EOK) { - os_free(drv); - drv = NULL; - goto failed; - } -#ifdef CONFIG_OHOS_P2P - wifiDev = (WifiDev *)os_zalloc(sizeof(WifiDev)); - if (wifiDev == NULL) - { - wpa_printf(MSG_ERROR, "%s wifiDev malloc failed.", __FUNCTION__); - goto failed; - } - wifiDev->priv = drv; - wifiDev->ifNameLen = sizeof(params->ifname); - rc = memcpy_s(wifiDev->ifName, sizeof(wifiDev->ifName), drv->iface, sizeof(drv->iface)); - if (rc != EOK) { - wpa_printf(MSG_ERROR, "%s wifiDev could not copy interface name.", __FUNCTION__); - goto failed; - } - wpa_printf(MSG_INFO, "%s init, interface name:%s.", __FUNCTION__, wifiDev->ifName); - SetWifiDev(wifiDev); -#endif // CONFIG_OHOS_P2P - WifiHapdPreInit(drv); - - setMode.iftype = WIFI_IFTYPE_AP; - ret = WifiCmdSetMode(drv->iface, &setMode); - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "WifiWpaHapdInit set mode failed, iface = %s, ret = %d.", drv->iface, ret); - goto failed; - } - info.status = true; - info.ifType = WIFI_IFTYPE_AP; - info.mode = WIFI_PHY_MODE_11N; - ret = WifiCmdSetNetdev(drv->iface, &info); - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "WifiDrvInit set netdev failed"); - goto failed; - } - wpa_printf(MSG_INFO, "WifiDrvInit done"); - return drv; - -failed: - if (drv != NULL) { - info.status = false; - info.ifType = WIFI_IFTYPE_STATION; - info.mode = WIFI_PHY_MODE_11N; - WifiCmdSetNetdev(drv->iface, &info); - os_free(drv); - drv = NULL; - } -#ifdef CONFIG_OHOS_P2P - FreeWifiDev(wifiDev); -#endif // CONFIG_OHOS_P2P - return NULL; -} - -static int32_t WifiWpaInitl2(struct wpa_init_params *params, WifiDriverData *drv) -{ - int32_t ret; - uint8_t addrTmp[ETH_ADDR_LEN] = {0}; - - drv->eapolSock = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, WifiWpaReceiveEapol, drv, 1); - if (drv->eapolSock == NULL) { - wpa_printf(MSG_ERROR, "WifiDrvInit l2 packet init failed"); - return -EFAIL; - } - if (l2_packet_get_own_addr(drv->eapolSock, addrTmp)) { - return -EFAIL; - } - ret = memcpy_s(params->own_addr, ETH_ADDR_LEN, addrTmp, ETH_ADDR_LEN); - if (ret != EOK) { - return -EFAIL; - } - ret = memcpy_s(drv->ownAddr, ETH_ADDR_LEN, addrTmp, ETH_ADDR_LEN); - if (ret != EOK) { - return -EFAIL; - } - return SUCC; -} - -static void *WifiWpaHapdInit(struct hostapd_data *hapd, struct wpa_init_params *params) -{ - WifiDriverData *drv = NULL; - - int32_t ret; - - if ((hapd == NULL) || (params == NULL) || (hapd->conf == NULL)) { - return NULL; - } - - if (WifiClientInit(params->ifname) != SUCC) { - wpa_printf(MSG_ERROR, "Wifi client init failed"); - return NULL; - } - drv = WifiDrvInit(hapd, params); - if (drv == NULL) { - wpa_printf(MSG_ERROR, "WifiWpaHapdInit drv init failed"); - goto failed; - } - drv->hapd = hapd; - - ret = WifiWpaInitl2(params, drv); - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "WifiWpaInitI2 failed"); - goto failed; - } - - g_wifiDriverData = drv; - g_wifiDriverType = WIFI_IFTYPE_AP; - wpa_printf(MSG_INFO, "WifiWpaHapdInit done"); - return (void *)drv; - -failed: - if (drv != NULL && drv->eapolSock != NULL) { - l2_packet_deinit(drv->eapolSock); - } - WifiWpaDeinit(drv); - return NULL; -} - -static void WifiWpaHapdDeinit(void *priv) -{ - int32_t ret; - WifiDriverData *drv = NULL; - WifiSetMode setMode; - WifiSetNewDev info; - - if (priv == NULL) { - return; - } - - (void)memset_s(&setMode, sizeof(WifiSetMode), 0, sizeof(WifiSetMode)); - drv = (WifiDriverData *)priv; - setMode.iftype = WIFI_IFTYPE_STATION; - info.status = false; - info.ifType = WIFI_IFTYPE_AP; - info.mode = WIFI_PHY_MODE_11N; - - WifiCmdSetNetdev(drv->iface, &info); - ret = WifiCmdSetMode((char *)drv->iface, &setMode); - if (ret != SUCC) { - return; - } - - if (drv->eapolSock != NULL) { - l2_packet_deinit(drv->eapolSock); - } - os_free(g_wifiDriverData); - g_wifiDriverData = NULL; - WifiClientDeinit(drv->iface); - - wpa_printf(MSG_INFO, "WifiWpaHapdDeinit done"); -} - -static int32_t WifiWpaHapdSendEapol(void *priv, const uint8_t *addr, const uint8_t *data, size_t dataLen, int encrypt, - const uint8_t *ownAddr, uint32_t flags) -{ - WifiDriverData *drv = priv; - int32_t ret; - uint32_t frameLen; - uint8_t *frameBuf = NULL; - uint8_t *payload = NULL; - struct l2_ethhdr *ethhdr = NULL; - - (void)encrypt; - (void)flags; - if ((priv == NULL) || (addr == NULL) || (data == NULL) || (ownAddr == NULL)) { - return -EFAIL; - } - - frameLen = dataLen + sizeof(struct l2_ethhdr); - frameBuf = os_zalloc(frameLen); - if (frameBuf == NULL) { - return -EFAIL; - } - - ethhdr = (struct l2_ethhdr *)frameBuf; - if (memcpy_s(ethhdr->h_dest, ETH_ADDR_LEN, addr, ETH_ADDR_LEN) != EOK) { - os_free(frameBuf); - frameBuf = NULL; - return -EFAIL; - } - if (memcpy_s(ethhdr->h_source, ETH_ADDR_LEN, ownAddr, ETH_ADDR_LEN) != EOK) { - os_free(frameBuf); - frameBuf = NULL; - return -EFAIL; - } - ethhdr->h_proto = host_to_be16(ETH_P_PAE); - payload = (uint8_t *)(ethhdr + 1); - if (memcpy_s(payload, dataLen, data, dataLen) != EOK) { - os_free(frameBuf); - frameBuf = NULL; - return -EFAIL; - } - ret = l2_packet_send(drv->eapolSock, addr, ETH_P_EAPOL, frameBuf, frameLen); - os_free(frameBuf); - frameBuf = NULL; - wpa_printf(MSG_INFO, "WifiWpaHapdSendEapol done, ret=%d", ret); - return ret; -} - -static int32_t WifiWpaStaRemove(void *priv, const uint8_t *addr) -{ - WifiDriverData *drv = NULL; - int32_t ret; - - if ((priv == NULL) || (addr == NULL)) { - return -EFAIL; - } - drv = (WifiDriverData *)priv; - ret = WifiCmdStaRemove(drv->iface, addr, ETH_ADDR_LEN); - if (ret != SUCC) { - return -EFAIL; - } - wpa_printf(MSG_INFO, "WifiWpaStaRemove done, ret=%d", ret); - return ret; -} - -static uint8_t *WifiDuplicateStr(const uint8_t *src, size_t len) -{ - uint8_t *res = NULL; - - if (src == NULL) { - return NULL; - } - res = os_malloc(len + 1); - if (res == NULL) { - return NULL; - } - if (memcpy_s(res, len, src, len) != EOK) { - os_free(res); - return NULL; - } - res[len] = '\0'; - - return res; -} - -static void WifiActionDataBufFree(WifiActionData *actionData) -{ - if (actionData == NULL) { - return; - } - if (actionData->data != NULL) { - os_free(actionData->data); - actionData->data = NULL; - } -} - -static int32_t WifiWpaSendAction(void *priv, uint32_t freq, uint32_t wait, const uint8_t *dst, const uint8_t *src, - const uint8_t *bssid, const uint8_t *data, size_t dataLen, int32_t noCck) -{ - WifiActionData actionData = { - .dst = {0}, - .src = {0}, - .bssid = {0}, - .data = NULL, - .dataLen = 0, - .freq = 0, - .wait = 0, - .noCck = 0, - }; - WifiDriverData *drv = NULL; - int32_t ret; - - if ((priv == NULL) || (data == NULL) || (dst == NULL) || (src == NULL) || (bssid == NULL)) { - return -EFAIL; - } - drv = (WifiDriverData *)priv; - - if (memcpy_s(actionData.dst, ETH_ADDR_LEN, dst, ETH_ADDR_LEN) != EOK) { - return -EFAIL; - } - if (memcpy_s(actionData.src, ETH_ADDR_LEN, src, ETH_ADDR_LEN) != EOK) { - return -EFAIL; - } - if (memcpy_s(actionData.bssid, ETH_ADDR_LEN, bssid, ETH_ADDR_LEN) != EOK) { - return -EFAIL; - } - - actionData.dataLen = dataLen; - actionData.freq = freq; - actionData.wait = wait; - actionData.noCck = noCck; - actionData.data = WifiDuplicateStr(data, dataLen); - if (actionData.data == NULL) { - return -EFAIL; - } - ret = WifiCmdSendAction(drv->iface, &actionData); - WifiActionDataBufFree(&actionData); - wpa_printf(MSG_INFO, "WifiWpaSendAction done, ret=%d", ret); - return ret; -} - -__attribute__ ((visibility ("default"))) void DeinitWifiService() -{ - if (g_wifiDriverType == WIFI_IFTYPE_STATION) { - WifiWpaDeinit(g_wifiDriverData); - } else if (g_wifiDriverType == WIFI_IFTYPE_AP) { - WifiWpaHapdDeinit(g_wifiDriverData); - } else { - printf("no need to cleanup \n"); - } -} - -#ifdef CONFIG_OHOS_P2P -static int32_t WifiProbeReqReport(void *priv, int32_t report) -{ - WifiDriverData *drv = NULL; - wpa_printf(MSG_INFO, "%s enter.", __FUNCTION__); - if (priv == NULL) { - wpa_printf(MSG_ERROR, "%s input invalid.", __FUNCTION__); - return -EFAIL; - } - drv = (WifiDriverData *)priv; - return WifiCmdProbeReqReport(drv->iface, &report); -} - -static int32_t WifiRemainOnChannel(void *priv, uint32_t freq, uint32_t duration) -{ - int32_t ret; - WifiDriverData *drv = priv; - WifiOnChannel *onChannel = NULL; - if (priv == NULL) { - wpa_printf(MSG_ERROR, "%s input invalid.", __FUNCTION__); - return -EFAIL; - } - onChannel = (WifiOnChannel *)os_zalloc(sizeof(WifiOnChannel)); - if (onChannel == NULL) - { - wpa_printf(MSG_ERROR, "%s failed to alloc channel.", __FUNCTION__); - return -EFAIL; - } - onChannel->freq = freq; - onChannel->duration = duration; - - ret = WifiCmdRemainOnChannel(drv->iface, onChannel); - - os_free(onChannel); - onChannel = NULL; - - return ret; -} - -static int32_t WifiCancelRemainOnChannel(void *priv) -{ - WifiDriverData *drv = priv; - if (drv == NULL) { - wpa_printf(MSG_ERROR, "%s input invalid.", __FUNCTION__); - return -EFAIL; - } - - return WifiCmdCancelRemainOnChannel(drv->iface); -} - -static int32_t WifiAddIf(void *priv, enum wpa_driver_if_type type, const char *ifName, const uint8_t *addr, void *bss_ctx, - void **drv_priv, char *force_ifname, uint8_t *if_addr, const char *bridge, int32_t use_existing, int32_t setup_ap) -{ - WifiDriverData *drv = priv; - WifiIfAdd *ifAdd = NULL; - int32_t ret; - WifiDev *wifiDev = NULL; - if (priv == NULL) { - wpa_printf(MSG_ERROR, "%s input invalid.", __FUNCTION__); - return -EFAIL; - } - ifAdd = (WifiIfAdd *)os_zalloc(sizeof(WifiIfAdd)); - if (ifAdd == NULL) { - wpa_printf(MSG_ERROR, "%s failed to alloc ifAdd.", __FUNCTION__); - return -EFAIL; - } - switch (type) { - case WPA_IF_STATION: - ifAdd->type = WIFI_IFTYPE_STATION; - break; - case WPA_IF_P2P_GROUP: - case WPA_IF_P2P_CLIENT: - ifAdd->type = WIFI_IFTYPE_P2P_CLIENT; - break; - case WPA_IF_AP_VLAN: - ifAdd->type = WIFI_IFTYPE_AP_VLAN; - break; - case WPA_IF_AP_BSS: - ifAdd->type = WIFI_IFTYPE_AP; - break; - case WPA_IF_P2P_GO: - ifAdd->type = WIFI_IFTYPE_P2P_GO; - break; - case WPA_IF_P2P_DEVICE: - ifAdd->type = WIFI_IFTYPE_P2P_DEVICE; - break; - case WPA_IF_MESH: - ifAdd->type = WIFI_IFTYPE_MESH_POINT; - break; - default: - wpa_printf(MSG_ERROR, "%s unsuportted interface type %d.", __FUNCTION__, type); - } - - ret = WifiRegisterEventCallback(OnWpaWiFiEvents, WIFI_KERNEL_TO_WPA_CLIENT, ifName); - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "WifiWpa register event listener faild"); - } - ret = memcpy_s(ifAdd->ifName, IFNAMSIZ, ifName, IFNAMSIZ); - if (ret != SUCC) { - wpa_printf(MSG_ERROR, "%s memcpy_s ifName faild", __FUNCTION__); - return -EFAIL; - } - - ret = WifiCmdAddIf(drv->iface, ifAdd); - if (ret == SUCC) { - wifiDev = (WifiDev *)os_zalloc(sizeof(WifiDev)); - if (wifiDev == NULL) { - wpa_printf(MSG_ERROR, "%s failed to malloc wifiDev.", __FUNCTION__); - return -EFAIL; - } - wifiDev->priv = drv; - wifiDev->ifNameLen = sizeof(ifName); - errno_t rc = memcpy_s(wifiDev->ifName, sizeof(wifiDev->ifName), ifName, sizeof(drv->iface)); - if (rc != EOK) { - wpa_printf(MSG_ERROR, "Could not copy wifi device name."); - FreeWifiDev(wifiDev); - return ret; - } - wpa_printf(MSG_INFO, "%s ifName:%s, type:%d", __FUNCTION__, wifiDev->ifName, ifAdd->type); - SetWifiDev(wifiDev); - } - os_free(ifAdd); - ifAdd = NULL; - return ret; -} - -static int32_t WifiRemoveIf(void *priv, enum wpa_driver_if_type type, const char *ifName) -{ - WifiDriverData *drv = priv; - WifiIfRemove ifRemove = {0}; - int32_t ret; - errno_t rc; - WifiDev *wifiDev = NULL; - if (priv == NULL || ifName == NULL) { - wpa_printf(MSG_ERROR, "%s input invalid.", __FUNCTION__); - return -EFAIL; - } - if (os_strlen(ifName) > IFNAMSIZ) { - wpa_printf(MSG_ERROR, "%s ifName invalid:%s.", __FUNCTION__, ifName); - return -EFAIL; - } - rc = memcpy_s(ifRemove.ifName, IFNAMSIZ, ifName, IFNAMSIZ); - if (rc != EOK) { - wpa_printf(MSG_ERROR, "%s can not copy interface name.", __FUNCTION__); - return -EFAIL; - } - - ret = WifiCmdRemoveIf(drv->iface, &ifRemove); - wifiDev = GetWifiDevByName(ifName); - if (wifiDev == NULL) { - wpa_printf(MSG_INFO, "%s: GetWifiDevByName is null, already free.", __FUNCTION__); - return SUCC; - } - FreeWifiDev(wifiDev); - return SUCC; -} - -int32_t WifiSetApWpsP2pIe(void *priv, const struct wpabuf *beacon, const struct wpabuf *probresp, const struct wpabuf *assocresp) -{ - int32_t loops; - int32_t ret = SUCC; - WifiAppIe *appIe = NULL; - struct wpabuf *wpabufTmp = NULL; - WifiDriverData *drv = (WifiDriverData *)priv; - WifiCmd cmdAddr[4] = {{0x1, beacon}, {0x2, probresp}, {0x4, assocresp}, {-1, NULL}}; - errno_t rc; - appIe = (WifiAppIe *)os_zalloc(sizeof(WifiAppIe)); - if (appIe == NULL) { - wpa_printf(MSG_ERROR, "%s:failed to malloc WifiAppIe.", __FUNCTION__); - return -EFAIL; - } - for (loops = 0; cmdAddr[loops].cmd != -1; loops++) { - wpabufTmp = (struct wpabuf *)cmdAddr[loops].src; - if (wpabufTmp != NULL) { - appIe->appIeType = cmdAddr[loops].cmd; - appIe->ieLen = wpabuf_len(wpabufTmp); - if ((wpabufTmp->buf != NULL) && (appIe->ieLen != 0)) { - appIe->ie = os_zalloc(appIe->ieLen); - if (appIe->ie == NULL) { - wpa_printf(MSG_ERROR, "%s appIe->ie malloc failed.", __FUNCTION__); - os_free(appIe); - return -EFAIL; - } - rc = memcpy_s(appIe->ie, appIe->ieLen, wpabuf_head(wpabufTmp), wpabuf_len(wpabufTmp)); - if (rc != EOK) { - wpa_printf(MSG_ERROR, "%s: ", __FUNCTION__); - os_free(appIe->ie); - os_free(appIe); - return -EFAIL; - } - } - wpa_printf(MSG_INFO, "%s type %d, ie_len %d.", __FUNCTION__, appIe->appIeType, appIe->ieLen); - - ret = WifiCmdSetApWpsP2pIe(drv->iface, appIe); - os_free(appIe->ie); - appIe->ie = NULL; - if (ret < 0) { - break; - } - } - } - os_free(appIe); - appIe = NULL; - return ret; -} - -int32_t WifiWpaGetDrvFlags(void *priv, uint64_t *drvFlags) -{ - WifiDriverData *drv = NULL; - WifiGetDrvFlags *params = NULL; - int32_t ret; - if (priv == NULL || drvFlags == NULL) - { - return -EFAIL; - } - drv = (WifiDriverData *)priv; - params = (WifiGetDrvFlags *)os_zalloc(sizeof(WifiGetDrvFlags)); - if (params == NULL) - { - return -EFAIL; - } - params->drvFlags = 0; - ret = WifiCmdGetDrvFlags(drv->iface, params); - if (ret != SUCC) - { - wpa_printf(MSG_ERROR, "%s WifiCmdGetDrvFlags failed, ret is %d.", __FUNCTION__, ret); - os_free(params); - return -EFAIL; - } - *drvFlags = params->drvFlags; - wpa_printf(MSG_INFO, "%s Get drvFlags done.", __FUNCTION__); - os_free(params); - return ret; -} -#endif // CONFIG_OHOS_P2P - -const struct wpa_driver_ops g_wifiDriverOps = { - .name = "hdf wifi", - .desc = "wpa hdf adaptor layer", - .get_bssid = WifiWpaGetBssid, - .get_ssid = WifiWpaGetSsid, - .set_key = WifiWpaSetKey, - .scan2 = WifiWpaScan2, - .get_scan_results2 = WifiWpaGetScanResults2, - .deauthenticate = WifiWpaDeauthenticate, - .associate = WifiWpaAssociate, - .send_eapol = WifiWpaWpaSendEapol, - .init2 = WifiWpaInit2, - .deinit = WifiWpaDeinit, - .set_ap = WifiWpaSetAp, - .send_mlme = WifiWpaSendMlme, - .get_hw_feature_data = WifiWpaGetHwFeatureData, - .sta_remove = WifiWpaStaRemove, - .hapd_init = WifiWpaHapdInit, - .hapd_deinit = WifiWpaHapdDeinit, - .hapd_send_eapol = WifiWpaHapdSendEapol, - .send_action = WifiWpaSendAction, - .get_mac_addr = WifiWpaGetMacAddr, -#ifdef CONFIG_OHOS_P2P - .remain_on_channel = WifiRemainOnChannel, - .cancel_remain_on_channel = WifiCancelRemainOnChannel, - .probe_req_report = WifiProbeReqReport, - .if_add = WifiAddIf, - .if_remove = WifiRemoveIf, - .set_ap_wps_ie = WifiSetApWpsP2pIe, -#endif // CONFIG_OHOS_P2P -}; - -#ifdef __cplusplus -#if __cplusplus -} -#endif -#endif +/* + * Driver interaction with hdf wifi + * Copyright (c) 2020 Huawei Device Co., Ltd. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "wpa_hal.h" +#include "includes.h" +#include "utils/common.h" +#include "driver.h" +#include "ap/hostapd.h" +#include "l2_packet/l2_packet.h" +#include "eloop.h" +#include "securec.h" +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +WifiDriverData *g_wifiDriverData = NULL; +enum WifiIfType g_wifiDriverType = WIFI_IFTYPE_UNSPECIFIED; +#define WAIT_LOAD_NETDEVICE 2500 +#ifdef CONFIG_OHOS_P2P +uint8_t g_msgInit = true; +#endif + +WifiDriverData *GetDrvData() +{ + return g_wifiDriverData; +} + +#ifdef CONFIG_OHOS_P2P +#define WPA_MAX_WIFI_DEV_NUM 3 + +WifiDev* g_wifiDev[WPA_MAX_WIFI_DEV_NUM] = {NULL}; + +WifiDev* GetWifiDevByName(const char *ifName) +{ + int32_t i; + if (ifName == NULL) { + return NULL; + } + for (i = 0; i < WPA_MAX_WIFI_DEV_NUM; i++) { + if ((g_wifiDev[i] != NULL) && (strncmp(g_wifiDev[i]->ifName, ifName, strlen(ifName)) == 0)) { + g_wifiDev[i]->networkId = i; + return g_wifiDev[i]; + } + } + return NULL; +} + +int32_t SetWifiDev(WifiDev *wifiDev) +{ + int32_t i; + if (wifiDev == NULL) { + return -EFAIL; + } + for (i = 0; i < WPA_MAX_WIFI_DEV_NUM; i++) { + if ((g_wifiDev[i] != NULL) && (strncmp(g_wifiDev[i]->ifName, wifiDev->ifName, strlen(wifiDev->ifName)) == 0)) { + g_wifiDev[i] = wifiDev; + return SUCC; + } else if (g_wifiDev[i] == NULL) { + g_wifiDev[i] = wifiDev; + g_wifiDev[i]->networkId = i; + return SUCC; + } + } + return -EFAIL; +} + +void FreeWifiDev(WifiDev *wifiDev) +{ + int32_t i; + if (wifiDev == NULL) { + return; + } + for (i = 0; i < WPA_MAX_WIFI_DEV_NUM; i++) { + if (g_wifiDev[i] == wifiDev) { + g_wifiDev[i] = NULL; + break; + } + } + os_free(wifiDev); + wifiDev = NULL; +} + +int32_t CountWifiDevInUse() +{ + int32_t i; + int32_t count = 0; + for (i = 0; i < WPA_MAX_WIFI_DEV_NUM; i++) { + if (g_wifiDev[i] != NULL) { + count++; + } + } + return count; +} +#endif // CONFIG_OHOS_P2P + +static int OnWpaWiFiEvents(uint32_t event, void *data, const char *ifName) +{ + WifiDriverData *drv = NULL; +#ifndef CONFIG_OHOS_P2P + drv = GetDrvData(); +#else + WifiDev *wifiDev = NULL; + wifiDev = GetWifiDevByName(ifName); + if (wifiDev == NULL) { + wpa_printf(MSG_ERROR, "OnWpaWiFiEvents wifiDev is null\n"); + return -EFAIL; + } + drv = wifiDev->priv; +#endif + (void)ifName; + wpa_printf(MSG_INFO, "OnWpaWiFiEvents event=%d", event); + if (drv == NULL || data == NULL) { + return -EFAIL; + } + switch (event) { + case WIFI_EVENT_NEW_STA: + WifiWpaNewStaProcess(drv, (WifiNewStaInfo *)data); + break; + case WIFI_EVENT_DEL_STA: + WifiWpaDelStaProcess(drv, (uint8_t *)data); + break; + case WIFI_EVENT_RX_MGMT: + WifiWpaRxMgmtProcess(drv, (WifiRxMgmt *)data); + break; + case WIFI_EVENT_TX_STATUS: + WifiWpaTxStatusProcess(drv, (WifiTxStatus *)data); + break; + case WIFI_EVENT_SCAN_DONE: + WifiWpaScanDoneProcess(drv, (uint32_t *)data); + break; + case WIFI_EVENT_SCAN_RESULT: + WifiWpaScanResultProcess(drv, (WifiScanResult *)data); + break; + case WIFI_EVENT_CONNECT_RESULT: + WifiWpaConnectResultProcess(drv, (WifiConnectResult *)data); + break; + case WIFI_EVENT_DISCONNECT: + WifiWpaDisconnectProcess(drv, (WifiDisconnect *)data); + break; + case WIFI_EVENT_EAPOL_RECV: + WifiWpaDriverEapolRecvProcess(drv, data); + break; + case WIFI_EVENT_REMAIN_ON_CHANNEL: + WifiWpaRemainOnChannelProcess(drv, (WifiOnChannel *)data); + break; + case WIFI_EVENT_CANCEL_REMAIN_ON_CHANNEL: + WifiWpaCancelRemainOnChannelProcess(drv, (WifiOnChannel *)data); + break; + default: + break; + } + + return SUCC; +} + +static int32_t WifiClientInit(const char *ifName) +{ + int32_t ret; + + wpa_printf(MSG_INFO, "WifiClientInit enter."); + ret = WifiDriverClientInit(); + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "WifiWpa init msg service failed"); + return ret; + } + ret = WifiRegisterEventCallback(OnWpaWiFiEvents, WIFI_KERNEL_TO_WPA_CLIENT, ifName); + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "WifiWpa register event listener faild"); + } + return ret; +} + +void WifiClientDeinit(const char *ifName) +{ + WifiUnregisterEventCallback(OnWpaWiFiEvents, WIFI_KERNEL_TO_WPA_CLIENT, ifName); + WifiDriverClientDeinit(); +} + +static int32_t WifiWpaGetBssid(void *priv, uint8_t *bssid) +{ + WifiDriverData *drv = priv; + errno_t rc; + if ((priv == NULL) || (bssid == NULL)) { + return -EFAIL; + } + if (drv->associated == WIFI_DISCONNECT) { + wpa_printf(MSG_ERROR, "%s associated status error", __func__); + return -EFAIL; + } + + rc = memcpy_s(bssid, ETH_ADDR_LEN, drv->bssid, ETH_ADDR_LEN); + if (rc != EOK) { + return -EFAIL; + } + return SUCC; +} + +static int32_t WifiWpaGetSsid(void *priv, uint8_t *ssid) +{ + WifiDriverData *drv = priv; + errno_t rc; + if ((priv == NULL) || (ssid == NULL)) { + return -EFAIL; + } + if (drv->associated == WIFI_DISCONNECT) { + wpa_printf(MSG_ERROR, "%s associated status error", __func__); + return -EFAIL; + } + rc = memcpy_s(ssid, MAX_SSID_LEN, drv->ssid, drv->ssidLen); + if (rc != EOK) { + return -EFAIL; + } + return drv->ssidLen; +} + +static uint32_t WifiAlgToCipherSuite(enum wpa_alg alg, size_t keyLen) +{ + switch (alg) { + case WPA_ALG_WEP: + if (keyLen == WPA_WEP40_KEY_LEN) { + return RSN_CIPHER_SUITE_WEP40; + } + return RSN_CIPHER_SUITE_WEP104; + case WPA_ALG_TKIP: + return RSN_CIPHER_SUITE_TKIP; + case WPA_ALG_CCMP: + return RSN_CIPHER_SUITE_CCMP; + case WPA_ALG_GCMP: + return RSN_CIPHER_SUITE_GCMP; + case WPA_ALG_CCMP_256: + return RSN_CIPHER_SUITE_CCMP_256; + case WPA_ALG_GCMP_256: + return RSN_CIPHER_SUITE_GCMP_256; + case WPA_ALG_BIP_CMAC_128: + return RSN_CIPHER_SUITE_AES_128_CMAC; + case WPA_ALG_BIP_GMAC_128: + return RSN_CIPHER_SUITE_BIP_GMAC_128; + case WPA_ALG_BIP_GMAC_256: + return RSN_CIPHER_SUITE_BIP_GMAC_256; + case WPA_ALG_BIP_CMAC_256: + return RSN_CIPHER_SUITE_BIP_CMAC_256; + case WPA_ALG_SMS4: + return RSN_CIPHER_SUITE_SMS4; + case WPA_ALG_KRK: + return RSN_CIPHER_SUITE_KRK; + case WPA_ALG_NONE: + return 0; + default: + return 0; + } +} + +static inline int IsBroadcastAddr(const uint8_t *addr) +{ + // 0 1 2 3 4 5 are mac index + return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff; +} + +static void WifiWpaInitAlg(WifiKeyExt *keyExt, enum wpa_alg alg, size_t keyLen) +{ + keyExt->cipher = WifiAlgToCipherSuite(alg, keyLen); + if ((alg == WPA_ALG_BIP_CMAC_128) || (alg == WPA_ALG_BIP_GMAC_128) || + (alg == WPA_ALG_BIP_GMAC_256) || (alg == WPA_ALG_BIP_CMAC_256)) { + keyExt->defMgmt = true; + } else { + keyExt->def = true; + } +} + +static int32_t WifiWpaInitAddr(WifiKeyExt *keyExt, const uint8_t *addr, const enum wpa_alg alg, const int32_t keyIdx, + const int32_t setTx) +{ + keyExt->type = WIFI_KEYTYPE_BUTT; + keyExt->defaultTypes = WIFI_KEY_DEFAULT_TYPE_INVALID; + if (addr != NULL) { + if (!IsBroadcastAddr(addr)) { + keyExt->addr = (uint8_t *)os_zalloc(ETH_ADDR_LEN); + if ((keyExt->addr == NULL) || (memcpy_s(keyExt->addr, ETH_ADDR_LEN, addr, ETH_ADDR_LEN) != EOK)) { + return -EFAIL; + } + if ((alg != WPA_ALG_WEP) && (keyIdx != 0) && (setTx == 0)) { + keyExt->type = WIFI_KEYTYPE_GROUP; + } + keyExt->defaultTypes = WIFI_KEY_DEFAULT_TYPE_UNICAST; + } else { + keyExt->addr = NULL; + keyExt->defaultTypes = WIFI_KEY_DEFAULT_TYPE_MULTICAST; + } + } + if (keyExt->type == WIFI_KEYTYPE_BUTT) { + keyExt->type = (keyExt->addr != NULL) ? WIFI_KEYTYPE_PAIRWISE : WIFI_KEYTYPE_GROUP; + } + return SUCC; +} + +static int32_t WifiWpaInitSeq(WifiKeyExt *keyExt, const uint8_t *seq, const size_t seqLen) +{ + keyExt->seqLen = seqLen; + if ((seq != NULL) && (seqLen != 0)) { + keyExt->seq = (uint8_t *)os_zalloc(seqLen); + if ((keyExt->seq == NULL) || (memcpy_s(keyExt->seq, seqLen, seq, seqLen) != EOK)) { + return -EFAIL; + } + } + return SUCC; +} + +static int32_t WifiWpaInitKey(WifiKeyExt *keyExt, const uint8_t *key, const size_t keyLen, const int32_t keyIdx, + const enum wpa_alg alg) +{ + keyExt->keyLen = keyLen; + keyExt->keyIdx = keyIdx; + if ((alg != WPA_ALG_NONE) && (key != NULL) && (keyLen != 0)) { + keyExt->key = (uint8_t *)os_zalloc(keyLen); + if ((keyExt->key == NULL) || (memcpy_s(keyExt->key, keyLen, key, keyLen) != EOK)) { + return -EFAIL; + } + } + return SUCC; +} + +static void WifiKeyExtFree(WifiKeyExt **key) +{ + if (key == NULL || *key == NULL) { + return; + } + + if ((*key)->addr != NULL) { + os_free((*key)->addr); + (*key)->addr = NULL; + } + if ((*key)->seq != NULL) { + os_free((*key)->seq); + (*key)->seq = NULL; + } + if ((*key)->key != NULL) { + os_free((*key)->key); + (*key)->key = NULL; + } + + os_free(*key); + *key = NULL; +} + +static inline int32_t IsApInterface(int32_t mode) +{ + return ((mode) == WIFI_IFTYPE_AP || (mode) == WIFI_IFTYPE_P2P_GO); +} + +static int32_t WifiWpaSetKey(void *priv, + struct wpa_driver_set_key_params *params) { + int32_t ret; + WifiKeyExt *keyExt = NULL; + WifiDriverData *drv = priv; + + if ((priv == NULL) || (params->ifname == NULL) || (priv == NULL)) { + return -EFAIL; + } + if (drv->mode == WIFI_IFTYPE_P2P_DEVICE) { + return SUCC; + } + + keyExt = os_zalloc(sizeof(WifiKeyExt)); + if (keyExt == NULL) { + return -EFAIL; + } + + WifiWpaInitAlg(keyExt, params->alg, params->key_len); + if (WifiWpaInitAddr(keyExt, params->addr, params->alg, params->key_idx, + params->set_tx) != SUCC || + WifiWpaInitSeq(keyExt, params->seq, params->seq_len) != SUCC || + WifiWpaInitKey(keyExt, params->key, params->key_len, params->key_idx, + params->alg) != SUCC) { + WifiKeyExtFree(&keyExt); + wpa_printf(MSG_ERROR, "WifiWpaInitKey failed"); + return -EFAIL; + } + + if (params->alg == WPA_ALG_NONE) { + ret = WifiCmdDelKey(params->ifname, keyExt); + } else { + ret = WifiCmdNewKey(params->ifname, keyExt); + if ((ret != SUCC) || (params->set_tx == 0) || + (params->alg == WPA_ALG_NONE)) { + WifiKeyExtFree(&keyExt); + return ret; + } + + if ((IsApInterface(drv->mode)) && (keyExt->addr != NULL) && + (!IsBroadcastAddr(keyExt->addr))) { + WifiKeyExtFree(&keyExt); + return ret; + } + ret = WifiCmdSetKey(params->ifname, keyExt); + } + + WifiKeyExtFree(&keyExt); + return ret; +} + +static void WifiWpaReceiveEapol(void *ctx, const uint8_t *srcAddr, const uint8_t *buf, size_t len) +{ + WifiDriverData *drv = ctx; + + if ((ctx == NULL) || (srcAddr == NULL) || (buf == NULL) || (len < sizeof(struct l2_ethhdr))) { + return; + } + + drv_event_eapol_rx(drv->ctx, srcAddr, buf + sizeof(struct l2_ethhdr), len - sizeof(struct l2_ethhdr)); + wpa_printf(MSG_INFO, "WifiWpaReceiveEapol done"); +} + +static void WifiWpaPreInit(const WifiDriverData *drv) +{ + WifiSetMode setMode; + WifiSetNewDev info; + + if (drv == NULL) { + return; + } + + (void)memset_s(&setMode, sizeof(WifiSetMode), 0, sizeof(WifiSetMode)); + (void)memset_s(&info, sizeof(WifiSetNewDev), 0, sizeof(WifiSetNewDev)); + + if (strncmp(drv->iface, "p2p-p2p0-", 9) == 0) { + info.ifType = WIFI_IFTYPE_P2P_CLIENT; + setMode.iftype = WIFI_IFTYPE_P2P_CLIENT; + } else if (strncmp(drv->iface, "p2p0", 4) == 0) { + info.ifType = WIFI_IFTYPE_P2P_DEVICE; + setMode.iftype = WIFI_IFTYPE_P2P_DEVICE; + } else { + setMode.iftype = WIFI_IFTYPE_STATION; + info.status = false; + info.ifType = WIFI_IFTYPE_STATION; + info.mode = WIFI_PHY_MODE_11N; + if (WifiCmdSetNetdev(drv->iface, &info) != SUCC) { + wpa_printf(MSG_ERROR, "%s set netdev failed", __func__); + } + if (WifiCmdSetMode((char *)drv->iface, &setMode) != SUCC) { + wpa_printf(MSG_ERROR, "%s set mode failed", __func__); + } + } +} + +#ifdef CONFIG_OPEN_HARMONY_PATCH +static void CheckWifiIface(const char *ifName) +{ + DIR *dir; + struct dirent *dent; + while (true) { + dir = opendir("/sys/class/net"); + if (dir == 0) { + return; + } + while ((dent = readdir(dir))) { + if (dent->d_name[0] == '.') { + continue; + } + if (strcmp(dent->d_name, ifName) == 0) { + goto out; + } + usleep(WAIT_LOAD_NETDEVICE); + } + } +out: + closedir(dir); +} +#endif + +static void WifiWpaDeinit(void *priv) +{ + WifiDriverData *drv = NULL; + WifiSetNewDev info; + + if (priv == NULL) { + return; + } + + drv = (WifiDriverData *)priv; + info.status = false; + info.ifType = WIFI_IFTYPE_STATION; + info.mode = WIFI_PHY_MODE_11N; +#ifdef CONFIG_OHOS_P2P + if (strncmp(drv->iface, "p2p-p2p0-", 9) == 0) { + info.ifType = WIFI_IFTYPE_P2P_CLIENT; + } else if (strncmp(drv->iface, "p2p0", 4) == 0) { + info.ifType = WIFI_IFTYPE_P2P_DEVICE; + } + WifiDev *wifiDev = NULL; + wifiDev = GetWifiDevByName(drv->iface); + if (wifiDev == NULL) { + wpa_printf(MSG_ERROR, "%s: GetWifiDevByName failed.\r\n.", __FUNCTION__); + } + FreeWifiDev(wifiDev); +#endif // CONFIG_OHOS_P2P + eloop_cancel_timeout(WifiWpaScanTimeout, drv, drv->ctx); + WifiCmdSetNetdev(drv->iface, &info); + + if (drv->eapolSock != NULL) { + l2_packet_deinit(drv->eapolSock); + } + +#ifdef CONFIG_OHOS_P2P + WifiUnregisterEventCallback(OnWpaWiFiEvents, WIFI_KERNEL_TO_WPA_CLIENT, drv->iface); + if (CountWifiDevInUse() == 0) { + g_msgInit = true; + os_free(g_wifiDriverData); + g_wifiDriverData = NULL; + (void)WifiClientDeinit(drv->iface); + } +#else + os_free(g_wifiDriverData); + g_wifiDriverData = NULL; + (void)WifiClientDeinit(drv->iface); +#endif //CONFIG_OHOS_P2P + + wpa_printf(MSG_INFO, "WifiWpaDeinit done"); +} + +static void *WifiWpaInit(void *ctx, const char *ifName) +{ + int32_t ret; + WifiSetNewDev info; +#ifdef CONFIG_OHOS_P2P + WifiDev *wifiDev = NULL; + errno_t rc; +#endif + + if ((ctx == NULL) || (ifName == NULL)) { + return NULL; + } + + wpa_printf(MSG_INFO, "%s enter, interface name:%s.", __FUNCTION__, ifName); + (void)memset_s(&info, sizeof(WifiSetNewDev), 0, sizeof(WifiSetNewDev)); + WifiDriverData *drv = os_zalloc(sizeof(WifiDriverData)); + if (drv == NULL) { + goto failed; + } + + drv->ctx = ctx; + if (memcpy_s(drv->iface, sizeof(drv->iface), ifName, sizeof(drv->iface)) != EOK) { + goto failed; + } +#ifdef CONFIG_OHOS_P2P + if (g_msgInit && (strncmp(drv->iface, "p2p0", 4) == 0)) { + if (WifiClientInit(drv->iface) != SUCC) { + goto failed; + } + g_msgInit = false; + } +#endif // CONFIG_OHOS_P2P + if (strncmp(drv->iface, "wlan0", 5) == 0) { + if (WifiClientInit(drv->iface) != SUCC) { + goto failed; + } + } +#ifdef CONFIG_OPEN_HARMONY_PATCH + CheckWifiIface(ifName); +#endif + WifiWpaPreInit(drv); + + info.status = true; + info.ifType = WIFI_IFTYPE_STATION; + info.mode = WIFI_PHY_MODE_11N; +#ifdef CONFIG_OHOS_P2P + if (strncmp(drv->iface, "p2p-p2p0-", 9) == 0) { + info.ifType = WIFI_IFTYPE_P2P_CLIENT; + } else if (strncmp(drv->iface, "p2p0", 4) == 0) { + info.ifType = WIFI_IFTYPE_P2P_DEVICE; + } +#endif // CONFIG_OHOS_P2P + ret = WifiCmdSetNetdev(drv->iface, &info); + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "WifiWpaInit set netdev faild"); + goto failed; + } + drv->eapolSock = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, WifiWpaReceiveEapol, drv, 1); + if (drv->eapolSock == NULL) { + wpa_printf(MSG_ERROR, "WifiWpaInit l2_packet_init faild"); + goto failed; + } + + if (l2_packet_get_own_addr(drv->eapolSock, drv->ownAddr)) { + wpa_printf(MSG_ERROR, "l2_packet_get_own_addr faild"); + goto failed; + } + + g_wifiDriverType = WIFI_IFTYPE_STATION; +#ifdef CONFIG_OHOS_P2P + wifiDev = (WifiDev *)os_zalloc(sizeof(WifiDev)); + if (wifiDev == NULL) { + wpa_printf(MSG_ERROR, "%s wifiDev malloc failed.", __FUNCTION__); + goto failed; + } + wifiDev->priv = drv; + wifiDev->ifNameLen = sizeof(ifName); + rc = memcpy_s(wifiDev->ifName, sizeof(wifiDev->ifName), drv->iface, sizeof(drv->iface)); + if (rc != EOK) { + wpa_printf(MSG_ERROR, "%s could not copy wifi device name.", __FUNCTION__); + goto failed; + } + wpa_printf(MSG_ERROR, "%s init done, ifName:%s.", __FUNCTION__, wifiDev->ifName); + SetWifiDev(wifiDev); +#endif // CONFIG_OHOS_P2P + g_wifiDriverData = drv; + return drv; + +failed: +#ifdef CONFIG_OHOS_P2P + FreeWifiDev(wifiDev); +#endif // CONFIG_OHOS_P2P + WifiWpaDeinit(drv); + return NULL; +} + +static int32_t WifiWpaDeauthenticate(void *priv, const uint8_t *addr, uint16_t reasonCode) +{ + int32_t ret; + WifiDriverData *drv = priv; + + (void)addr; + if (priv == NULL) { + return -EFAIL; + } + + wpa_printf(MSG_INFO, "WifiWpaDeauthenticate reasonCode = %d", reasonCode); + ret = WifiCmdDisconnet(drv->iface, reasonCode); + if (ret == SUCC) { + drv->associated = WIFI_DISCONNECT; + } + return ret; +} + +static int32_t WifiWpaDriverAp(WifiDriverData *drv, struct wpa_driver_associate_params *params) +{ + int32_t ret; + WifiSetMode setMode; + errno_t rc; + + if ((drv == NULL) || (params == NULL)) { + wpa_printf(MSG_ERROR, "%s input NULL ptr.", __FUNCTION__); + return -EFAIL; + } + rc = memset_s(&setMode, sizeof(WifiSetMode), 0, sizeof(WifiSetMode)); + if (rc != EOK) { + wpa_printf(MSG_ERROR, "%s: memset failed.", __FUNCTION__); + return -EFAIL; + } + if (params->p2p) { + wpa_printf(MSG_INFO, "%s: Setup AP operations for P2P group.(GO).", __FUNCTION__); + setMode.iftype = WIFI_IFTYPE_P2P_GO; + } else { + setMode.iftype = WIFI_IFTYPE_AP; + } + rc = memcpy_s(setMode.bssid, ETH_ADDR_LEN, drv->ownAddr, ETH_ADDR_LEN); + if (rc != EOK) { + wpa_printf(MSG_ERROR, "%s memcpy failed.", __FUNCTION__); + return -EFAIL; + } + ret = WifiCmdSetMode(drv->iface, &setMode); + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "%s: set mode failed.", __FUNCTION__); + return -EFAIL; + } + return SUCC; +} + +static int32_t WifiWpaAssocParamsSet(WifiDriverData *drv, struct wpa_driver_associate_params *params, + WifiAssociateParams *assocParams) +{ + if (params->bssid != NULL) { + assocParams->bssid = (uint8_t *)os_zalloc(ETH_ADDR_LEN); + if (assocParams->bssid == NULL) { + return -EFAIL; + } + if (memcpy_s(assocParams->bssid, ETH_ADDR_LEN, params->bssid, ETH_ADDR_LEN) != EOK) { + return -EFAIL; + } + } + + if (params->freq.freq != 0) { + assocParams->freq = params->freq.freq; + } + if (params->ssid_len > MAX_SSID_LEN) { + params->ssid_len = MAX_SSID_LEN; + } + if ((params->ssid != NULL) && (params->ssid_len != 0)) { + assocParams->ssid = (uint8_t *)os_zalloc(params->ssid_len); + if (assocParams->ssid == NULL) { + return -EFAIL; + } + assocParams->ssidLen = params->ssid_len; + if (memcpy_s(assocParams->ssid, assocParams->ssidLen, params->ssid, params->ssid_len) != EOK) { + return -EFAIL; + } + if (memset_s(drv->ssid, MAX_SSID_LEN, 0, MAX_SSID_LEN) != EOK) { + return -EFAIL; + } + if (memcpy_s(drv->ssid, MAX_SSID_LEN, params->ssid, params->ssid_len) != EOK) { + return -EFAIL; + } + drv->ssidLen = params->ssid_len; + } + + if ((params->wpa_ie != NULL) && (params->wpa_ie_len != 0)) { + assocParams->ie = (uint8_t *)os_zalloc(params->wpa_ie_len); + if (assocParams->ie == NULL) { + return -EFAIL; + } + assocParams->ieLen = params->wpa_ie_len; + if (memcpy_s(assocParams->ie, assocParams->ieLen, params->wpa_ie, params->wpa_ie_len) != EOK) { + return -EFAIL; + } + } + + return SUCC; +} + +static uint32_t WifiCipherToCipherSuite(uint32_t cipher) +{ + switch (cipher) { + case WPA_CIPHER_CCMP_256: + return RSN_CIPHER_SUITE_CCMP_256; + case WPA_CIPHER_GCMP_256: + return RSN_CIPHER_SUITE_GCMP_256; + case WPA_CIPHER_CCMP: + return RSN_CIPHER_SUITE_CCMP; + case WPA_CIPHER_GCMP: + return RSN_CIPHER_SUITE_GCMP; + case WPA_CIPHER_TKIP: + return RSN_CIPHER_SUITE_TKIP; + case WPA_CIPHER_WEP104: + return RSN_CIPHER_SUITE_WEP104; + case WPA_CIPHER_WEP40: + return RSN_CIPHER_SUITE_WEP40; + case WPA_CIPHER_GTK_NOT_USED: + return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; + default: + return 0; + } +} + +static int32_t WifiWpaAssocParamCryptoSet(const struct wpa_driver_associate_params *params, + WifiAssociateParams *assocParams) +{ + uint32_t ver = 0; + uint32_t akm_suites_num = 0; + uint32_t ciphers_pairwise_num = 0; + int32_t mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; + + assocParams->crypto = (WifiCryptoSetting *)os_zalloc(sizeof(WifiCryptoSetting)); + if (assocParams->crypto == NULL) { + return -EFAIL; + } + + if (params->wpa_proto != 0) { + if (params->wpa_proto & WPA_PROTO_WPA) { + ver |= WPA_VERSION_1; + } + if (params->wpa_proto & WPA_PROTO_RSN) { + ver |= WPA_VERSION_2; + } + assocParams->crypto->wpaVersions = ver; + } + + if (params->pairwise_suite != WPA_CIPHER_NONE) { + assocParams->crypto->ciphersPairwise[ciphers_pairwise_num++] = WifiCipherToCipherSuite(params->pairwise_suite); + assocParams->crypto->nCiphersPairwise = ciphers_pairwise_num; + } + + if (params->group_suite != WPA_CIPHER_NONE) { + assocParams->crypto->cipherGroup = WifiCipherToCipherSuite(params->group_suite); + } + + if (params->key_mgmt_suite == WPA_KEY_MGMT_PSK || params->key_mgmt_suite == WPA_KEY_MGMT_SAE || + params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) { + switch (params->key_mgmt_suite) { + case WPA_KEY_MGMT_PSK_SHA256: + mgmt = RSN_AUTH_KEY_MGMT_PSK_SHA256; + break; + case WPA_KEY_MGMT_SAE: + mgmt = RSN_AUTH_KEY_MGMT_SAE; + break; + case WPA_KEY_MGMT_PSK: __attribute__((fallthrough)); + default: + mgmt = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; + break; + } + assocParams->crypto->akmSuites[akm_suites_num++] = mgmt; + assocParams->crypto->nAkmSuites = akm_suites_num; + } + + return SUCC; +} + +static void WifiWpaSetConnKeys(const struct wpa_driver_associate_params *wpa_params, WifiAssociateParams *params) +{ + int32_t loop; + uint8_t privacy; + errno_t rc; + + if ((wpa_params == NULL) || (params == NULL)) { + return; + } + + privacy = 0; + for (loop = 0; loop < WEP_KEY_NUM; loop++) { + if (wpa_params->wep_key[loop] == NULL) { + continue; + } + privacy = 1; + break; + } + + if ((wpa_params->wps == WPS_MODE_PRIVACY) || + ((wpa_params->pairwise_suite != 0) && (wpa_params->pairwise_suite != WPA_CIPHER_NONE))) { + privacy = 1; + } + if (privacy == 0) { + return; + } + params->privacy = privacy; + for (loop = 0; loop < WEP_KEY_NUM; loop++) { + if (wpa_params->wep_key[loop] == NULL) { + continue; + } + params->keyLen = wpa_params->wep_key_len[loop]; + params->key = (uint8_t *)os_zalloc(params->keyLen); + if (params->key == NULL) { + return; + } + + rc = memcpy_s(params->key, params->keyLen, wpa_params->wep_key[loop], params->keyLen); + if (rc != EOK) { + os_free(params->key); + params->key = NULL; + return; + } + params->keyIdx = wpa_params->wep_tx_keyidx; + break; + } + + return; +} + +static void WifiWpaConnectFree(WifiAssociateParams **params) +{ + if (params == NULL || *params == NULL) { + return; + } + + if ((*params)->ie != NULL) { + os_free((*params)->ie); + (*params)->ie = NULL; + } + if ((*params)->crypto != NULL) { + os_free((*params)->crypto); + (*params)->crypto = NULL; + } + if ((*params)->ssid != NULL) { + os_free((*params)->ssid); + (*params)->ssid = NULL; + } + if ((*params)->bssid != NULL) { + os_free((*params)->bssid); + (*params)->bssid = NULL; + } + if ((*params)->key != NULL) { + os_free((*params)->key); + (*params)->key = NULL; + } + + os_free(*params); + *params = NULL; +} + +static WifiAuthType WifiGetStaAuthType(const struct wpa_driver_associate_params *params) +{ + WifiAuthType type = WIFI_AUTHTYPE_BUTT; + uint32_t algs = 0; + + if ((uint32_t)(params->auth_alg) & WPA_AUTH_ALG_OPEN) { + type = WIFI_AUTHTYPE_OPEN_SYSTEM; + algs++; + } + if ((uint32_t)(params->auth_alg) & WPA_AUTH_ALG_SHARED) { + type = WIFI_AUTHTYPE_SHARED_KEY; + algs++; + } + if ((uint32_t)(params->auth_alg) & WPA_AUTH_ALG_LEAP) { + type = WIFI_AUTHTYPE_EAP; + algs++; + } + + if (algs > 1) { + return WIFI_AUTHTYPE_AUTOMATIC; + } else if (algs == 1) { + return type; + } + + if ((uint32_t)params->auth_alg & WPA_AUTH_ALG_FT) { + type = WIFI_AUTHTYPE_FT; + } + return type; +} + +static int32_t WifiWpaTryConnect(WifiDriverData *drv, struct wpa_driver_associate_params *params) +{ + WifiAssociateParams *assocParams = NULL; + int32_t ret = -EFAIL; + + if ((drv == NULL) || (params == NULL)) { + return -EFAIL; + } + + assocParams = (WifiAssociateParams *)os_zalloc(sizeof(WifiAssociateParams)); + if (assocParams == NULL) { + return ret; + } + if (WifiWpaAssocParamsSet(drv, params, assocParams) != SUCC) { + wpa_printf(MSG_ERROR, "WifiWpaTryConnect set assoc params faild"); + goto skip_auth_type; + } + if (WifiWpaAssocParamCryptoSet(params, assocParams) != SUCC) { + wpa_printf(MSG_ERROR, "WifiWpaTryConnect set assoc crypto faild"); + goto skip_auth_type; + } + assocParams->mfp = params->mgmt_frame_protection; + assocParams->authType = WifiGetStaAuthType(params); + + WifiWpaSetConnKeys(params, assocParams); + ret = WifiCmdAssoc(drv->iface, assocParams); + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "WifiWpaTryConnect assoc faild"); + } + +skip_auth_type: + WifiWpaConnectFree(&assocParams); + return ret; +} + +static int32_t WifiWpaDisconnet(WifiDriverData *drv, uint16_t reasonCode) +{ + int32_t ret; + + if (drv == NULL) { + return -EFAIL; + } + ret = WifiCmdDisconnet(drv->iface, reasonCode); + if (ret == SUCC) { + drv->associated = WIFI_DISCONNECT; + } + wpa_printf(MSG_INFO, "WifiWpaDisconnet done ret=%d", ret); + return ret; +} +static int WifiWpaAssociate(void *priv, struct wpa_driver_associate_params *params) +{ + int ret; + WifiDriverData *drv = priv; + + if ((drv == NULL) || (params == NULL)) { + return -EFAIL; + } +#ifdef CONFIG_OHOS_P2P + if (params->mode == IEEE80211_MODE_AP) { + return WifiWpaDriverAp(drv, params); + } +#endif + ret = WifiWpaTryConnect(drv, params); + if (ret != SUCC) { + if (WifiWpaDisconnet(drv, WLAN_REASON_PREV_AUTH_NOT_VALID)) { + return -EFAIL; + } + ret = WifiWpaTryConnect(drv, params); + } + wpa_printf(MSG_INFO, "WifiWpaAssociate done ret=%d", ret); + return ret; +} + +static const uint8_t *WifiWpaGetMacAddr(void *priv) +{ + WifiDriverData *drv = priv; + + if (priv == NULL) { + return NULL; + } + return drv->ownAddr; +} + +int32_t WifiWpaWpaSendEapol(void *priv, const uint8_t *dest, uint16_t proto, const uint8_t *data, size_t dataLen) +{ + WifiDriverData *drv = priv; + int32_t ret; + uint32_t frameLen; + uint8_t *frame = NULL; + uint8_t *payload = NULL; + struct l2_ethhdr *l2_ethhdr = NULL; + errno_t rc; + + if ((priv == NULL) || (data == NULL) || (dest == NULL)) { + return -EFAIL; + } + + frameLen = dataLen + sizeof(struct l2_ethhdr); + frame = os_zalloc(frameLen); + if (frame == NULL) { + return -EFAIL; + } + + l2_ethhdr = (struct l2_ethhdr *)frame; + rc = memcpy_s(l2_ethhdr->h_dest, ETH_ADDR_LEN, dest, ETH_ADDR_LEN); + if (rc != EOK) { + os_free(frame); + frame = NULL; + return -EFAIL; + } + rc = memcpy_s(l2_ethhdr->h_source, ETH_ADDR_LEN, drv->ownAddr, ETH_ADDR_LEN); + if (rc != EOK) { + os_free(frame); + frame = NULL; + return -EFAIL; + } + l2_ethhdr->h_proto = host_to_be16(proto); + + payload = (uint8_t *)(l2_ethhdr + 1); + rc = memcpy_s(payload, dataLen, data, dataLen); + if (rc != EOK) { + os_free(frame); + frame = NULL; + return -EFAIL; + } + ret = l2_packet_send(drv->eapolSock, dest, host_to_be16(proto), frame, frameLen); + os_free(frame); + frame = NULL; + wpa_printf(MSG_INFO, "WifiWpaWpaSendEapol done ret=%d", ret); + return ret; +} + +static void WifiWpaHwFeatureDataFree(struct hostapd_hw_modes **modes, uint16_t num) +{ + uint16_t loop; + + if (modes == NULL || *modes == NULL) { + return; + } + for (loop = 0; loop < num; ++loop) { + if ((*modes)[loop].channels != NULL) { + os_free((*modes)[loop].channels); + (*modes)[loop].channels = NULL; + } + if ((*modes)[loop].rates != NULL) { + os_free((*modes)[loop].rates); + (*modes)[loop].rates = NULL; + } + } + os_free(*modes); + *modes = NULL; +} + +static struct hostapd_hw_modes *WifiWpaGetHwFeatureData(void *priv, uint16_t *numModes, uint16_t *flags, uint8_t *dfs) +{ + WifiModes modesData[] = {{IEEE80211G_RATES_NUM, HOSTAPD_MODE_IEEE80211G}, + {IEEE80211B_RATES_NUM, HOSTAPD_MODE_IEEE80211B}, {IEEE80211A_RATES_NUM, HOSTAPD_MODE_IEEE80211A}}; + size_t loop; + uint32_t index; + uint32_t iee80211band; + WifiHwFeatureData hwFeatureData; + WifiDriverData *drv = (WifiDriverData *)priv; + (void)dfs; + if ((priv == NULL) || (numModes == NULL) || (flags == NULL)) { + return NULL; + } + (void)memset_s(&hwFeatureData, sizeof(WifiHwFeatureData), 0, sizeof(WifiHwFeatureData)); + *numModes = DEFAULT_NUM_MODES; + *flags = 0; + + if (WifiCmdGetHwFeature(drv->iface, &hwFeatureData) != SUCC) { + return NULL; + } + if (hwFeatureData.bands[IEEE80211_BAND_5GHZ].channelNum != 0) { + *numModes = sizeof(modesData) / sizeof(WifiModes); + } + struct hostapd_hw_modes *modes = os_calloc(*numModes, sizeof(struct hostapd_hw_modes)); + if (modes == NULL) { + return NULL; + } + + for (loop = 0; loop < *numModes; ++loop) { + modes[loop].channels = NULL; + modes[loop].rates = NULL; + } + + modes[0].ht_capab = hwFeatureData.htCapab; + iee80211band = IEEE80211_BAND_2GHZ; + for (index = 0; index < *numModes; index++) { + if (index >= DEFAULT_NUM_MODES) { + iee80211band = IEEE80211_BAND_5GHZ; + } + modes[index].mode = modesData[index].mode; + modes[index].num_channels = hwFeatureData.bands[iee80211band].channelNum; + modes[index].num_rates = modesData[index].numRates; + modes[index].channels = os_calloc(hwFeatureData.bands[iee80211band].channelNum, sizeof(struct hostapd_channel_data)); + modes[index].rates = os_calloc(modes[index].num_rates, sizeof(uint32_t)); + if ((modes[index].channels == NULL) || (modes[index].rates == NULL)) { + WifiWpaHwFeatureDataFree(&modes, *numModes); + return NULL; + } + + for (loop = 0; loop < (size_t)hwFeatureData.bands[iee80211band].channelNum; loop++) { + modes[index].channels[loop].chan = hwFeatureData.bands[iee80211band].iee80211Channel[loop].channel; + modes[index].channels[loop].freq = hwFeatureData.bands[iee80211band].iee80211Channel[loop].freq; + modes[index].channels[loop].flag = hwFeatureData.bands[iee80211band].iee80211Channel[loop].flags; + modes[index].channels[loop].allowed_bw = HOSTAPD_CHAN_WIDTH_20 | HOSTAPD_CHAN_WIDTH_10; + } + + for (loop = 0; loop < (size_t)modes[index].num_rates; loop++) { + if (index < DEFAULT_NUM_MODES) { + modes[index].rates[loop] = hwFeatureData.bitrate[loop]; + } else { + modes[index].rates[loop] = hwFeatureData.bitrate[loop + IEEE80211B_RATES_NUM]; + } + } + } + + wpa_printf(MSG_INFO, "WifiWpaGetHwFeatureData done"); + return modes; +} + +static int32_t WifiWpaSendMlme(void *priv, const uint8_t *data, size_t dataLen, int32_t noack, uint32_t freq, + const uint16_t *csaOffs, size_t csaOffsLen, int no_encrypt, unsigned int wait) +{ + int32_t ret; + WifiDriverData *drv = priv; + WifiMlmeData *mlme = NULL; + errno_t rc; + + (void)freq; + (void)csaOffs; + (void)csaOffsLen; + (void)noack; + (void)no_encrypt; + (void)wait; + if ((priv == NULL) || (data == NULL)) { + return -EFAIL; + } + mlme = os_zalloc(sizeof(WifiMlmeData)); + if (mlme == NULL) { + return -EFAIL; + } + mlme->data = NULL; + mlme->dataLen = dataLen; + mlme->cookie = &(drv->actionCookie); + if ((data != NULL) && (dataLen != 0)) { + mlme->data = (uint8_t *)os_zalloc(dataLen); + if (mlme->data == NULL) { + os_free(mlme); + mlme = NULL; + return -EFAIL; + } + rc = memcpy_s(mlme->data, dataLen, data, dataLen); + if (rc != EOK) { + os_free(mlme->data); + mlme->data = NULL; + os_free(mlme); + return -EFAIL; + } + } + ret = WifiCmdSendMlme(drv->iface, mlme); + os_free(mlme->data); + mlme->data = NULL; + os_free(mlme); + if (ret != SUCC) { + ret = -EFAIL; + } + wpa_printf(MSG_INFO, "WifiWpaSendMlme done ret=%d", ret); + return ret; +} + +static struct wpa_scan_results *WifiWpaGetScanResults2(void *priv) +{ + struct wpa_scan_results *results = NULL; + WifiDriverData *drv = priv; + uint32_t loop; + errno_t rc; + + if (priv == NULL) { + return NULL; + } + + results = (struct wpa_scan_results *)os_zalloc(sizeof(struct wpa_scan_results)); + if (results == NULL) { + return NULL; + } + + results->num = drv->scanNum; + if (results->num == 0) { + return results; + } + results->res = (struct wpa_scan_res **)os_zalloc(results->num * sizeof(struct wpa_scan_res *)); + if (results->res == NULL) { + os_free(results); + results = NULL; + return NULL; + } + rc = memcpy_s(results->res, results->num * sizeof(struct wpa_scan_res *), drv->scanRes, + results->num * sizeof(struct wpa_scan_res *)); + if (rc != EOK) { + os_free(results->res); + os_free(results); + results = NULL; + return NULL; + } + drv->scanNum = 0; + for (loop = 0; loop < SCAN_AP_LIMIT; loop++) { + drv->scanRes[loop] = NULL; + } + wpa_printf(MSG_INFO, "WifiWpaGetScanResults2 done"); + return results; +} + +static void *WifiWpaInit2(void *ctx, const char *ifname, void *globalPriv) +{ + (void)globalPriv; + return WifiWpaInit(ctx, ifname); +} + +static int32_t WifiWpaScanProcessSsid(struct wpa_driver_scan_params *params, WifiScan *scan) +{ + errno_t rc; + size_t loop; + if (params->num_ssids == 0) { + return SUCC; + } + + scan->numSsids = params->num_ssids; + scan->ssids = (WifiDriverScanSsid *)os_zalloc(sizeof(WifiDriverScanSsid) * params->num_ssids); + if (scan->ssids == NULL) { + return -EFAIL; + } + + for (loop = 0; (loop < params->num_ssids) && (loop < WPAS_MAX_SCAN_SSIDS); loop++) { + wpa_printf(MSG_INFO, "WIFI: Scan : %s SSID : %zu\n", anonymize_ssid(params->ssids[loop].ssid), + params->ssids[loop].ssid_len); + + if (params->ssids[loop].ssid_len > MAX_SSID_LEN) { + params->ssids[loop].ssid_len = MAX_SSID_LEN; + } + if (params->ssids[loop].ssid_len) { + rc = memcpy_s(scan->ssids[loop].ssid, MAX_SSID_LEN, params->ssids[loop].ssid, params->ssids[loop].ssid_len); + if (rc != EOK) { + return -EFAIL; + } + } + scan->ssids[loop].ssidLen = params->ssids[loop].ssid_len; + } + + return SUCC; +} + +static int32_t WifiWpaScanProcessBssid(const struct wpa_driver_scan_params *params, WifiScan *scan) +{ + errno_t rc; + if (params->bssid != NULL) { + scan->bssid = (uint8_t *)os_zalloc(ETH_ADDR_LEN); + if (scan->bssid == NULL) { + return -EFAIL; + } + rc = memcpy_s(scan->bssid, ETH_ADDR_LEN, params->bssid, ETH_ADDR_LEN); + if (rc != EOK) { + return -EFAIL; + } + } + return SUCC; +} + +static int32_t WifiWpaScanProcessExtraIes(const struct wpa_driver_scan_params *params, WifiScan *scan) +{ + errno_t rc; + if ((params->extra_ies != NULL) && (params->extra_ies_len != 0)) { + scan->extraIes = (uint8_t *)os_zalloc(params->extra_ies_len); + if (scan->extraIes == NULL) { + return -EFAIL; + } + + rc = memcpy_s(scan->extraIes, params->extra_ies_len, params->extra_ies, params->extra_ies_len); + if (rc != EOK) { + return -EFAIL; + } + scan->extraIesLen = params->extra_ies_len; + } + return SUCC; +} + +static int32_t WifiWpaScanProcessFreq(const struct wpa_driver_scan_params *params, WifiScan *scan) +{ + uint32_t numFreqs; + int32_t *freqs = NULL; + errno_t rc; + + if (params->freqs != NULL) { + numFreqs = 0; + for (freqs = params->freqs; *freqs != 0; freqs++) { + numFreqs++; + if (numFreqs > 14) { // 14 is 2.4G channel num + return -EFAIL; + } + } + + scan->numFreqs = numFreqs; + scan->freqs = (int32_t *)os_zalloc(numFreqs * (sizeof(int32_t))); + if (scan->freqs == NULL) { + return -EFAIL; + } + rc = memcpy_s(scan->freqs, numFreqs * (sizeof(int32_t)), params->freqs, numFreqs * (sizeof(int32_t))); + if (rc != EOK) { + return -EFAIL; + } + } + return SUCC; +} + +static void WifiWpaScanFree(WifiScan **scan) +{ + if (scan == NULL || *scan == NULL) { + return; + } + + if ((*scan)->ssids != NULL) { + os_free((*scan)->ssids); + (*scan)->ssids = NULL; + } + if ((*scan)->bssid != NULL) { + os_free((*scan)->bssid); + (*scan)->bssid = NULL; + } + + if ((*scan)->extraIes != NULL) { + os_free((*scan)->extraIes); + (*scan)->extraIes = NULL; + } + + if ((*scan)->freqs != NULL) { + os_free((*scan)->freqs); + (*scan)->freqs = NULL; + } + + os_free(*scan); + *scan = NULL; +} + +void WifiWpaScanTimeout(void *eloop, void *ctx) +{ + (void)eloop; + if (ctx == NULL) { + return; + } + wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); +} + +static int32_t WifiWpaScan2(void *priv, struct wpa_driver_scan_params *params) +{ + WifiScan *scan = NULL; + WifiDriverData *drv = NULL; + int32_t timeout; + int32_t ret; + + if ((priv == NULL) || (params == NULL) || (params->num_ssids > WPAS_MAX_SCAN_SSIDS)) { + return -EFAIL; + } + drv = (WifiDriverData *)priv; + scan = (WifiScan *)os_zalloc(sizeof(WifiScan)); + if (scan == NULL) { + return -EFAIL; + } + if ((WifiWpaScanProcessSsid(params, scan) != SUCC) || (WifiWpaScanProcessBssid(params, scan) != SUCC) || + (WifiWpaScanProcessExtraIes(params, scan) != SUCC) || (WifiWpaScanProcessFreq(params, scan) != SUCC)) { + WifiWpaScanFree(&scan); + return -EFAIL; + } + + scan->fastConnectFlag = WPA_FLAG_OFF; + scan->prefixSsidScanFlag = WPA_FLAG_OFF; + ret = WifiCmdScan(drv->iface, scan); + WifiWpaScanFree(&scan); + + timeout = SCAN_TIME_OUT; + eloop_cancel_timeout(WifiWpaScanTimeout, drv, drv->ctx); + eloop_register_timeout(timeout, 0, WifiWpaScanTimeout, drv, drv->ctx); + + return ret; +} + +static void WifiSetApFreq(WifiApSetting *apsettings, const struct wpa_driver_ap_params *params) +{ + if (params->freq != NULL) { + apsettings->freqParams.mode = params->freq->mode; + apsettings->freqParams.freq = params->freq->freq; + apsettings->freqParams.channel = params->freq->channel; + apsettings->freqParams.htEnabled = params->freq->ht_enabled; + apsettings->freqParams.secChannelOffset = params->freq->sec_channel_offset; + apsettings->freqParams.centerFreq1 = params->freq->center_freq1; + apsettings->freqParams.bandwidth = params->freq->bandwidth; + if (params->freq->bandwidth == WPA_BANDWIDTH_20) { + apsettings->freqParams.bandwidth = WIFI_CHAN_WIDTH_20; + } else { + apsettings->freqParams.bandwidth = WIFI_CHAN_WIDTH_40; + } + } +} + +static void WifiSetApBand(WifiApSetting *apsettings, struct hostapd_data *hapd) +{ + if ((apsettings!= NULL) && (hapd!= NULL)) { + switch (hapd->conf->wps_rf_bands) { + case WPS_RF_24GHZ: + apsettings->freqParams.band = IEEE80211_BAND_2GHZ; + break; + case WPS_RF_50GHZ: + apsettings->freqParams.band = IEEE80211_BAND_5GHZ; + break; + default: + apsettings->freqParams.band = IEEE80211_BAND_2GHZ; + break; + } + } +} + +static int WifiSetApBeaconData(WifiApSetting *apsettings, const struct wpa_driver_ap_params *params) +{ + if ((params->head != NULL) && (params->head_len != 0)) { + apsettings->beaconData.headLen = params->head_len; + apsettings->beaconData.head = (uint8_t *)os_zalloc(apsettings->beaconData.headLen); + if (apsettings->beaconData.head == NULL) { + return -EFAIL; + } + if (memcpy_s(apsettings->beaconData.head, apsettings->beaconData.headLen, params->head, params->head_len) != + EOK) { + return -EFAIL; + } + } + + if ((params->tail != NULL) && (params->tail_len != 0)) { + apsettings->beaconData.tailLen = params->tail_len; + apsettings->beaconData.tail = (uint8_t *)os_zalloc(apsettings->beaconData.tailLen); + if (apsettings->beaconData.tail == NULL) { + return -EFAIL; + } + if (memcpy_s(apsettings->beaconData.tail, apsettings->beaconData.tailLen, params->tail, params->tail_len) != + EOK) { + return -EFAIL; + } + } + return SUCC; +} + +static void WifiApSettingsFree(WifiApSetting **apsettings) +{ + if (apsettings == NULL || *apsettings == NULL) { + return; + } + + if ((*apsettings)->meshSsid != NULL) { + os_free((*apsettings)->meshSsid); + (*apsettings)->meshSsid = NULL; + } + + if ((*apsettings)->ssid != NULL) { + os_free((*apsettings)->ssid); + (*apsettings)->ssid = NULL; + } + + if ((*apsettings)->beaconData.head != NULL) { + os_free((*apsettings)->beaconData.head); + (*apsettings)->beaconData.head = NULL; + } + + if ((*apsettings)->beaconData.tail != NULL) { + os_free((*apsettings)->beaconData.tail); + (*apsettings)->beaconData.tail = NULL; + } + + os_free(*apsettings); + *apsettings = NULL; +} + +static WifiAuthType WifiGetApAuthType(const struct wpa_driver_ap_params *params) +{ + WifiAuthType type; + + if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) == (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) { + type = WIFI_AUTHTYPE_AUTOMATIC; + } else if ((params->auth_algs & WPA_AUTH_ALG_SHARED) == WPA_AUTH_ALG_SHARED) { + type = WIFI_AUTHTYPE_SHARED_KEY; + } else { + type = WIFI_AUTHTYPE_OPEN_SYSTEM; + } + return type; +} + +static int32_t WifiWpaSetAp(void *priv, struct wpa_driver_ap_params *params) +{ + int32_t ret; + WifiApSetting *apsettings = NULL; + WifiDriverData *drv = (WifiDriverData *)priv; + if ((priv == NULL) || (params == NULL) || (params->freq == NULL)) { + return -EFAIL; + } + if ((params->freq->bandwidth != WPA_BANDWIDTH_20) && (params->freq->bandwidth != WPA_BANDWIDTH_40)) { + return -EFAIL; + } + + apsettings = os_zalloc(sizeof(WifiApSetting)); + if (apsettings == NULL) { + return -EFAIL; + } + apsettings->beaconInterval = params->beacon_int; + apsettings->dtimPeriod = params->dtim_period; + apsettings->hiddenSsid = params->hide_ssid; + apsettings->authType = WifiGetApAuthType(params); + + if ((params->ssid != NULL) && (params->ssid_len != 0)) { + apsettings->ssidLen = params->ssid_len; + apsettings->ssid = (uint8_t *)os_zalloc(apsettings->ssidLen); + if ((apsettings->ssid == NULL) || + (memcpy_s(apsettings->ssid, apsettings->ssidLen, params->ssid, params->ssid_len) != EOK)) { + goto failed; + } + } + WifiSetApFreq(apsettings, params); + WifiSetApBand(apsettings, drv->hapd); + if (WifiSetApBeaconData(apsettings, params) != SUCC) { + goto failed; + } + if (drv->beaconSet == true) { + ret = WifiCmdChangeBeacon(drv->iface, apsettings); + } else { + ret = WifiCmdSetAp(drv->iface, apsettings); + } + if (ret == SUCC) { + drv->beaconSet = true; + } + WifiApSettingsFree(&apsettings); + wpa_printf(MSG_INFO, "WifiWpaGetScanResults2 done ret=%d", ret); + return ret; + +failed: + WifiApSettingsFree(&apsettings); + return -EFAIL; +} + +static void WifiHapdPreInit(const WifiDriverData *drv) +{ + WifiSetNewDev info; + + if (drv == NULL) { + return; + } + info.status = false; + info.ifType = WIFI_IFTYPE_STATION; + info.mode = WIFI_PHY_MODE_11N; + int ret = WifiCmdSetNetdev(drv->iface, &info); + + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "%s set netdev failed ret = %d.", __func__, ret); + } +} + +static WifiDriverData *WifiDrvInit(void *ctx, const struct wpa_init_params *params) +{ + WifiDriverData *drv = NULL; + errno_t rc; + WifiSetNewDev info; + WifiSetMode setMode; + int32_t ret; +#ifdef CONFIG_OHOS_P2P + WifiDev *wifiDev = NULL; +#endif + if ((ctx == NULL) || (params == NULL)) { + return NULL; + } + drv = os_zalloc(sizeof(WifiDriverData)); + if (drv == NULL) { + goto failed; + } + + drv->ctx = ctx; + rc = memcpy_s(drv->iface, sizeof(drv->iface), params->ifname, sizeof(drv->iface)); + if (rc != EOK) { + os_free(drv); + drv = NULL; + goto failed; + } +#ifdef CONFIG_OHOS_P2P + wifiDev = (WifiDev *)os_zalloc(sizeof(WifiDev)); + if (wifiDev == NULL) + { + wpa_printf(MSG_ERROR, "%s wifiDev malloc failed.", __FUNCTION__); + goto failed; + } + wifiDev->priv = drv; + wifiDev->ifNameLen = sizeof(params->ifname); + rc = memcpy_s(wifiDev->ifName, sizeof(wifiDev->ifName), drv->iface, sizeof(drv->iface)); + if (rc != EOK) { + wpa_printf(MSG_ERROR, "%s wifiDev could not copy interface name.", __FUNCTION__); + goto failed; + } + wpa_printf(MSG_INFO, "%s init, interface name:%s.", __FUNCTION__, wifiDev->ifName); + SetWifiDev(wifiDev); +#endif // CONFIG_OHOS_P2P + WifiHapdPreInit(drv); + + setMode.iftype = WIFI_IFTYPE_AP; + ret = WifiCmdSetMode(drv->iface, &setMode); + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "WifiWpaHapdInit set mode failed, iface = %s, ret = %d.", drv->iface, ret); + goto failed; + } + info.status = true; + info.ifType = WIFI_IFTYPE_AP; + info.mode = WIFI_PHY_MODE_11N; + ret = WifiCmdSetNetdev(drv->iface, &info); + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "WifiDrvInit set netdev failed"); + goto failed; + } + wpa_printf(MSG_INFO, "WifiDrvInit done"); + return drv; + +failed: + if (drv != NULL) { + info.status = false; + info.ifType = WIFI_IFTYPE_STATION; + info.mode = WIFI_PHY_MODE_11N; + WifiCmdSetNetdev(drv->iface, &info); + os_free(drv); + drv = NULL; + } +#ifdef CONFIG_OHOS_P2P + FreeWifiDev(wifiDev); +#endif // CONFIG_OHOS_P2P + return NULL; +} + +static int32_t WifiWpaInitl2(struct wpa_init_params *params, WifiDriverData *drv) +{ + int32_t ret; + uint8_t addrTmp[ETH_ADDR_LEN] = {0}; + + drv->eapolSock = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL, WifiWpaReceiveEapol, drv, 1); + if (drv->eapolSock == NULL) { + wpa_printf(MSG_ERROR, "WifiDrvInit l2 packet init failed"); + return -EFAIL; + } + if (l2_packet_get_own_addr(drv->eapolSock, addrTmp)) { + return -EFAIL; + } + ret = memcpy_s(params->own_addr, ETH_ADDR_LEN, addrTmp, ETH_ADDR_LEN); + if (ret != EOK) { + return -EFAIL; + } + ret = memcpy_s(drv->ownAddr, ETH_ADDR_LEN, addrTmp, ETH_ADDR_LEN); + if (ret != EOK) { + return -EFAIL; + } + return SUCC; +} + +static void *WifiWpaHapdInit(struct hostapd_data *hapd, struct wpa_init_params *params) +{ + WifiDriverData *drv = NULL; + + int32_t ret; + + if ((hapd == NULL) || (params == NULL) || (hapd->conf == NULL)) { + return NULL; + } + + if (WifiClientInit(params->ifname) != SUCC) { + wpa_printf(MSG_ERROR, "Wifi client init failed"); + return NULL; + } + drv = WifiDrvInit(hapd, params); + if (drv == NULL) { + wpa_printf(MSG_ERROR, "WifiWpaHapdInit drv init failed"); + goto failed; + } + drv->hapd = hapd; + + ret = WifiWpaInitl2(params, drv); + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "WifiWpaInitI2 failed"); + goto failed; + } + + g_wifiDriverData = drv; + g_wifiDriverType = WIFI_IFTYPE_AP; + wpa_printf(MSG_INFO, "WifiWpaHapdInit done"); + return (void *)drv; + +failed: + if (drv != NULL && drv->eapolSock != NULL) { + l2_packet_deinit(drv->eapolSock); + } + WifiWpaDeinit(drv); + return NULL; +} + +static void WifiWpaHapdDeinit(void *priv) +{ + int32_t ret; + WifiDriverData *drv = NULL; + WifiSetMode setMode; + WifiSetNewDev info; + + if (priv == NULL) { + return; + } + + (void)memset_s(&setMode, sizeof(WifiSetMode), 0, sizeof(WifiSetMode)); + drv = (WifiDriverData *)priv; + setMode.iftype = WIFI_IFTYPE_STATION; + info.status = false; + info.ifType = WIFI_IFTYPE_AP; + info.mode = WIFI_PHY_MODE_11N; + + WifiCmdSetNetdev(drv->iface, &info); + ret = WifiCmdSetMode((char *)drv->iface, &setMode); + if (ret != SUCC) { + return; + } + + if (drv->eapolSock != NULL) { + l2_packet_deinit(drv->eapolSock); + } + os_free(g_wifiDriverData); + g_wifiDriverData = NULL; + WifiClientDeinit(drv->iface); + + wpa_printf(MSG_INFO, "WifiWpaHapdDeinit done"); +} + +static int32_t WifiWpaHapdSendEapol(void *priv, const uint8_t *addr, const uint8_t *data, size_t dataLen, int encrypt, + const uint8_t *ownAddr, uint32_t flags) +{ + WifiDriverData *drv = priv; + int32_t ret; + uint32_t frameLen; + uint8_t *frameBuf = NULL; + uint8_t *payload = NULL; + struct l2_ethhdr *ethhdr = NULL; + + (void)encrypt; + (void)flags; + if ((priv == NULL) || (addr == NULL) || (data == NULL) || (ownAddr == NULL)) { + return -EFAIL; + } + + frameLen = dataLen + sizeof(struct l2_ethhdr); + frameBuf = os_zalloc(frameLen); + if (frameBuf == NULL) { + return -EFAIL; + } + + ethhdr = (struct l2_ethhdr *)frameBuf; + if (memcpy_s(ethhdr->h_dest, ETH_ADDR_LEN, addr, ETH_ADDR_LEN) != EOK) { + os_free(frameBuf); + frameBuf = NULL; + return -EFAIL; + } + if (memcpy_s(ethhdr->h_source, ETH_ADDR_LEN, ownAddr, ETH_ADDR_LEN) != EOK) { + os_free(frameBuf); + frameBuf = NULL; + return -EFAIL; + } + ethhdr->h_proto = host_to_be16(ETH_P_PAE); + payload = (uint8_t *)(ethhdr + 1); + if (memcpy_s(payload, dataLen, data, dataLen) != EOK) { + os_free(frameBuf); + frameBuf = NULL; + return -EFAIL; + } + ret = l2_packet_send(drv->eapolSock, addr, ETH_P_EAPOL, frameBuf, frameLen); + os_free(frameBuf); + frameBuf = NULL; + wpa_printf(MSG_INFO, "WifiWpaHapdSendEapol done, ret=%d", ret); + return ret; +} + +static int32_t WifiWpaStaRemove(void *priv, const uint8_t *addr) +{ + WifiDriverData *drv = NULL; + int32_t ret; + + if ((priv == NULL) || (addr == NULL)) { + return -EFAIL; + } + drv = (WifiDriverData *)priv; + ret = WifiCmdStaRemove(drv->iface, addr, ETH_ADDR_LEN); + if (ret != SUCC) { + return -EFAIL; + } + wpa_printf(MSG_INFO, "WifiWpaStaRemove done, ret=%d", ret); + return ret; +} + +static uint8_t *WifiDuplicateStr(const uint8_t *src, size_t len) +{ + uint8_t *res = NULL; + + if (src == NULL) { + return NULL; + } + res = os_malloc(len + 1); + if (res == NULL) { + return NULL; + } + if (memcpy_s(res, len, src, len) != EOK) { + os_free(res); + return NULL; + } + res[len] = '\0'; + + return res; +} + +static void WifiActionDataBufFree(WifiActionData *actionData) +{ + if (actionData == NULL) { + return; + } + if (actionData->data != NULL) { + os_free(actionData->data); + actionData->data = NULL; + } +} + +static int32_t WifiWpaSendAction(void *priv, uint32_t freq, uint32_t wait, const uint8_t *dst, const uint8_t *src, + const uint8_t *bssid, const uint8_t *data, size_t dataLen, int32_t noCck) +{ + WifiActionData actionData = { + .dst = {0}, + .src = {0}, + .bssid = {0}, + .data = NULL, + .dataLen = 0, + .freq = 0, + .wait = 0, + .noCck = 0, + }; + WifiDriverData *drv = NULL; + int32_t ret; + + if ((priv == NULL) || (data == NULL) || (dst == NULL) || (src == NULL) || (bssid == NULL)) { + return -EFAIL; + } + drv = (WifiDriverData *)priv; + + if (memcpy_s(actionData.dst, ETH_ADDR_LEN, dst, ETH_ADDR_LEN) != EOK) { + return -EFAIL; + } + if (memcpy_s(actionData.src, ETH_ADDR_LEN, src, ETH_ADDR_LEN) != EOK) { + return -EFAIL; + } + if (memcpy_s(actionData.bssid, ETH_ADDR_LEN, bssid, ETH_ADDR_LEN) != EOK) { + return -EFAIL; + } + + actionData.dataLen = dataLen; + actionData.freq = freq; + actionData.wait = wait; + actionData.noCck = noCck; + actionData.data = WifiDuplicateStr(data, dataLen); + if (actionData.data == NULL) { + return -EFAIL; + } + ret = WifiCmdSendAction(drv->iface, &actionData); + WifiActionDataBufFree(&actionData); + wpa_printf(MSG_INFO, "WifiWpaSendAction done, ret=%d", ret); + return ret; +} + +__attribute__ ((visibility ("default"))) void DeinitWifiService() +{ + if (g_wifiDriverType == WIFI_IFTYPE_STATION) { + WifiWpaDeinit(g_wifiDriverData); + } else if (g_wifiDriverType == WIFI_IFTYPE_AP) { + WifiWpaHapdDeinit(g_wifiDriverData); + } else { + printf("no need to cleanup \n"); + } +} + +#ifdef CONFIG_OHOS_P2P +static int32_t WifiProbeReqReport(void *priv, int32_t report) +{ + WifiDriverData *drv = NULL; + wpa_printf(MSG_INFO, "%s enter.", __FUNCTION__); + if (priv == NULL) { + wpa_printf(MSG_ERROR, "%s input invalid.", __FUNCTION__); + return -EFAIL; + } + drv = (WifiDriverData *)priv; + return WifiCmdProbeReqReport(drv->iface, &report); +} + +static int32_t WifiRemainOnChannel(void *priv, uint32_t freq, uint32_t duration) +{ + int32_t ret; + WifiDriverData *drv = priv; + WifiOnChannel *onChannel = NULL; + if (priv == NULL) { + wpa_printf(MSG_ERROR, "%s input invalid.", __FUNCTION__); + return -EFAIL; + } + onChannel = (WifiOnChannel *)os_zalloc(sizeof(WifiOnChannel)); + if (onChannel == NULL) + { + wpa_printf(MSG_ERROR, "%s failed to alloc channel.", __FUNCTION__); + return -EFAIL; + } + onChannel->freq = freq; + onChannel->duration = duration; + + ret = WifiCmdRemainOnChannel(drv->iface, onChannel); + + os_free(onChannel); + onChannel = NULL; + + return ret; +} + +static int32_t WifiCancelRemainOnChannel(void *priv) +{ + WifiDriverData *drv = priv; + if (drv == NULL) { + wpa_printf(MSG_ERROR, "%s input invalid.", __FUNCTION__); + return -EFAIL; + } + + return WifiCmdCancelRemainOnChannel(drv->iface); +} + +static int32_t WifiAddIf(void *priv, enum wpa_driver_if_type type, const char *ifName, const uint8_t *addr, void *bss_ctx, + void **drv_priv, char *force_ifname, uint8_t *if_addr, const char *bridge, int32_t use_existing, int32_t setup_ap) +{ + WifiDriverData *drv = priv; + WifiIfAdd *ifAdd = NULL; + int32_t ret; + WifiDev *wifiDev = NULL; + if (priv == NULL) { + wpa_printf(MSG_ERROR, "%s input invalid.", __FUNCTION__); + return -EFAIL; + } + ifAdd = (WifiIfAdd *)os_zalloc(sizeof(WifiIfAdd)); + if (ifAdd == NULL) { + wpa_printf(MSG_ERROR, "%s failed to alloc ifAdd.", __FUNCTION__); + return -EFAIL; + } + switch (type) { + case WPA_IF_STATION: + ifAdd->type = WIFI_IFTYPE_STATION; + break; + case WPA_IF_P2P_GROUP: + case WPA_IF_P2P_CLIENT: + ifAdd->type = WIFI_IFTYPE_P2P_CLIENT; + break; + case WPA_IF_AP_VLAN: + ifAdd->type = WIFI_IFTYPE_AP_VLAN; + break; + case WPA_IF_AP_BSS: + ifAdd->type = WIFI_IFTYPE_AP; + break; + case WPA_IF_P2P_GO: + ifAdd->type = WIFI_IFTYPE_P2P_GO; + break; + case WPA_IF_P2P_DEVICE: + ifAdd->type = WIFI_IFTYPE_P2P_DEVICE; + break; + case WPA_IF_MESH: + ifAdd->type = WIFI_IFTYPE_MESH_POINT; + break; + default: + wpa_printf(MSG_ERROR, "%s unsuportted interface type %d.", __FUNCTION__, type); + } + + ret = WifiRegisterEventCallback(OnWpaWiFiEvents, WIFI_KERNEL_TO_WPA_CLIENT, ifName); + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "WifiWpa register event listener faild"); + } + ret = memcpy_s(ifAdd->ifName, IFNAMSIZ, ifName, IFNAMSIZ); + if (ret != SUCC) { + wpa_printf(MSG_ERROR, "%s memcpy_s ifName faild", __FUNCTION__); + return -EFAIL; + } + + ret = WifiCmdAddIf(drv->iface, ifAdd); + if (ret == SUCC) { + wifiDev = (WifiDev *)os_zalloc(sizeof(WifiDev)); + if (wifiDev == NULL) { + wpa_printf(MSG_ERROR, "%s failed to malloc wifiDev.", __FUNCTION__); + return -EFAIL; + } + wifiDev->priv = drv; + wifiDev->ifNameLen = sizeof(ifName); + errno_t rc = memcpy_s(wifiDev->ifName, sizeof(wifiDev->ifName), ifName, sizeof(drv->iface)); + if (rc != EOK) { + wpa_printf(MSG_ERROR, "Could not copy wifi device name."); + FreeWifiDev(wifiDev); + return ret; + } + wpa_printf(MSG_INFO, "%s ifName:%s, type:%d", __FUNCTION__, wifiDev->ifName, ifAdd->type); + SetWifiDev(wifiDev); + } + os_free(ifAdd); + ifAdd = NULL; + return ret; +} + +static int32_t WifiRemoveIf(void *priv, enum wpa_driver_if_type type, const char *ifName) +{ + WifiDriverData *drv = priv; + WifiIfRemove ifRemove = {0}; + int32_t ret; + errno_t rc; + WifiDev *wifiDev = NULL; + if (priv == NULL || ifName == NULL) { + wpa_printf(MSG_ERROR, "%s input invalid.", __FUNCTION__); + return -EFAIL; + } + if (os_strlen(ifName) > IFNAMSIZ) { + wpa_printf(MSG_ERROR, "%s ifName invalid:%s.", __FUNCTION__, ifName); + return -EFAIL; + } + rc = memcpy_s(ifRemove.ifName, IFNAMSIZ, ifName, IFNAMSIZ); + if (rc != EOK) { + wpa_printf(MSG_ERROR, "%s can not copy interface name.", __FUNCTION__); + return -EFAIL; + } + + ret = WifiCmdRemoveIf(drv->iface, &ifRemove); + wifiDev = GetWifiDevByName(ifName); + if (wifiDev == NULL) { + wpa_printf(MSG_INFO, "%s: GetWifiDevByName is null, already free.", __FUNCTION__); + return SUCC; + } + FreeWifiDev(wifiDev); + return SUCC; +} + +int32_t WifiSetApWpsP2pIe(void *priv, const struct wpabuf *beacon, const struct wpabuf *probresp, const struct wpabuf *assocresp) +{ + int32_t loops; + int32_t ret = SUCC; + WifiAppIe *appIe = NULL; + struct wpabuf *wpabufTmp = NULL; + WifiDriverData *drv = (WifiDriverData *)priv; + WifiCmd cmdAddr[4] = {{0x1, beacon}, {0x2, probresp}, {0x4, assocresp}, {-1, NULL}}; + errno_t rc; + appIe = (WifiAppIe *)os_zalloc(sizeof(WifiAppIe)); + if (appIe == NULL) { + wpa_printf(MSG_ERROR, "%s:failed to malloc WifiAppIe.", __FUNCTION__); + return -EFAIL; + } + for (loops = 0; cmdAddr[loops].cmd != -1; loops++) { + wpabufTmp = (struct wpabuf *)cmdAddr[loops].src; + if (wpabufTmp != NULL) { + appIe->appIeType = cmdAddr[loops].cmd; + appIe->ieLen = wpabuf_len(wpabufTmp); + if ((wpabufTmp->buf != NULL) && (appIe->ieLen != 0)) { + appIe->ie = os_zalloc(appIe->ieLen); + if (appIe->ie == NULL) { + wpa_printf(MSG_ERROR, "%s appIe->ie malloc failed.", __FUNCTION__); + os_free(appIe); + return -EFAIL; + } + rc = memcpy_s(appIe->ie, appIe->ieLen, wpabuf_head(wpabufTmp), wpabuf_len(wpabufTmp)); + if (rc != EOK) { + wpa_printf(MSG_ERROR, "%s: ", __FUNCTION__); + os_free(appIe->ie); + os_free(appIe); + return -EFAIL; + } + } + wpa_printf(MSG_INFO, "%s type %d, ie_len %d.", __FUNCTION__, appIe->appIeType, appIe->ieLen); + + ret = WifiCmdSetApWpsP2pIe(drv->iface, appIe); + os_free(appIe->ie); + appIe->ie = NULL; + if (ret < 0) { + break; + } + } + } + os_free(appIe); + appIe = NULL; + return ret; +} + +int32_t WifiWpaGetDrvFlags(void *priv, uint64_t *drvFlags) +{ + WifiDriverData *drv = NULL; + WifiGetDrvFlags *params = NULL; + int32_t ret; + if (priv == NULL || drvFlags == NULL) + { + return -EFAIL; + } + drv = (WifiDriverData *)priv; + params = (WifiGetDrvFlags *)os_zalloc(sizeof(WifiGetDrvFlags)); + if (params == NULL) + { + return -EFAIL; + } + params->drvFlags = 0; + ret = WifiCmdGetDrvFlags(drv->iface, params); + if (ret != SUCC) + { + wpa_printf(MSG_ERROR, "%s WifiCmdGetDrvFlags failed, ret is %d.", __FUNCTION__, ret); + os_free(params); + return -EFAIL; + } + *drvFlags = params->drvFlags; + wpa_printf(MSG_INFO, "%s Get drvFlags done.", __FUNCTION__); + os_free(params); + return ret; +} +#endif // CONFIG_OHOS_P2P + +const struct wpa_driver_ops g_wifiDriverOps = { + .name = "hdf wifi", + .desc = "wpa hdf adaptor layer", + .get_bssid = WifiWpaGetBssid, + .get_ssid = WifiWpaGetSsid, + .set_key = WifiWpaSetKey, + .scan2 = WifiWpaScan2, + .get_scan_results2 = WifiWpaGetScanResults2, + .deauthenticate = WifiWpaDeauthenticate, + .associate = WifiWpaAssociate, + .send_eapol = WifiWpaWpaSendEapol, + .init2 = WifiWpaInit2, + .deinit = WifiWpaDeinit, + .set_ap = WifiWpaSetAp, + .send_mlme = WifiWpaSendMlme, + .get_hw_feature_data = WifiWpaGetHwFeatureData, + .sta_remove = WifiWpaStaRemove, + .hapd_init = WifiWpaHapdInit, + .hapd_deinit = WifiWpaHapdDeinit, + .hapd_send_eapol = WifiWpaHapdSendEapol, + .send_action = WifiWpaSendAction, + .get_mac_addr = WifiWpaGetMacAddr, +#ifdef CONFIG_OHOS_P2P + .remain_on_channel = WifiRemainOnChannel, + .cancel_remain_on_channel = WifiCancelRemainOnChannel, + .probe_req_report = WifiProbeReqReport, + .if_add = WifiAddIf, + .if_remove = WifiRemoveIf, + .set_ap_wps_ie = WifiSetApWpsP2pIe, +#endif // CONFIG_OHOS_P2P +}; + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif diff --git a/wpa_supplicant-2.9_standard/src/drivers/wpa_hal.h b/wpa_supplicant-2.9_standard/src/drivers/wpa_hal.h index 94a4e06c30de3c0812c744c73b1d5d9c43b5752b..70b298ab82779f6285d181501b68364a432356d3 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/wpa_hal.h +++ b/wpa_supplicant-2.9_standard/src/drivers/wpa_hal.h @@ -1,237 +1,237 @@ -/* - * Driver interaction with hdf wifi - * Copyright (c) 2020 Huawei Device Co., Ltd. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef _WPA_HAL_H_ -#define _WPA_HAL_H_ - -#include "wifi_driver_client.h" - -#ifdef __cplusplus -#if __cplusplus -extern "C" { -#endif -#endif - -#define SUCC 0 -#define EFAIL 1 -#define EINVAL 22 - -#define WEP_KEY_NUM 4 -#define DEFAULT_NUM_MODES 2 -#define WPA_BANDWIDTH_20 20 -#define WPA_BANDWIDTH_40 40 - -#define SCAN_AP_LIMIT 64 -#define SCAN_TIME_OUT 5 - -#define NETDEV_UP 0x0001 -#define NETDEV_DOWN 0x0002 - -#define EAPOL_PKT_BUF_SIZE 800 -#define CHECK_DHCP_TIME 30 - -#define WPA_WEP40_KEY_LEN 5 -#define WPA_WEP104_KEY_LEN 13 - -#define WPA_FLAG_ON 1 -#define WPA_FLAG_OFF 0 - -typedef enum { - WPA_VERSION_1 = 1 << 0, - WPA_VERSION_2 = 1 << 1, -} WpaVersions; - -typedef enum { - WIFI_CHAN_WIDTH_20_NOHT, - WIFI_CHAN_WIDTH_20, - WIFI_CHAN_WIDTH_40, - WIFI_CHAN_WIDTH_BUTT -} WifiChannelWidth; - -typedef enum { - WIFI_DISCONNECT, - WIFI_CONNECT, -} WifiConnectStatus; - -typedef enum { - WIFI_KEYTYPE_GROUP, - WIFI_KEYTYPE_PAIRWISE, - WIFI_KEYTYPE_PEERKEY, - WIFI_KEYTYPE_BUTT -} WifiKeyType; - -typedef enum { - WIFI_KEY_DEFAULT_TYPE_INVALID, - WIFI_KEY_DEFAULT_TYPE_UNICAST, - WIFI_KEY_DEFAULT_TYPE_MULTICAST, - WIFI_KEY_DEFAULT_TYPES -} WifiKeyDefaultType; - -typedef enum { - WIFI_NO_SSID_HIDING, - WIFI_HIDDEN_SSID_ZERO_LEN, - WIFI_HIDDEN_SSID_ZERO_CONTENTS -} WifiHiddenSsid; - -typedef enum { - WIFI_MESH_ENABLE_AUTO_PEER, - WIFI_MESH_ENABLE_ACCEPT_PEER, - WIFI_MESH_ENABLE_ACCEPT_STA, - WIFI_MESH_ENABLE_FLAG_BUTT -} WifiMeshEnableFlagType; - -typedef enum { - WIFI_AUTHTYPE_OPEN_SYSTEM = 0, - WIFI_AUTHTYPE_SHARED_KEY, - WIFI_AUTHTYPE_FT, - WIFI_AUTHTYPE_EAP, - WIFI_AUTHTYPE_SAE, - WIFI_AUTHTYPE_AUTOMATIC, - WIFI_AUTHTYPE_BUTT -} WifiAuthType; - -typedef enum { - WIFI_SCAN_SUCCESS, - WIFI_SCAN_FAILED, - WIFI_SCAN_REFUSED, - WIFI_SCAN_TIMEOUT -} WifiScanStatus; - -typedef struct { - int32_t numRates; - int32_t mode; -} WifiModes; - -typedef struct { - uint8_t *addr; - uint8_t plinkState; - uint8_t set; - uint8_t meshBcnPriority; - uint8_t meshIsMbr; - uint8_t meshInitiativePeering; -} WifiMeshUsrParams; - -typedef struct { - uint8_t *addr; - uint8_t *gtk; - uint8_t gtkLen; - uint8_t resv[3]; -} WifiSetMeshUsrGtk; - -typedef struct { - uint8_t *buf; - uint32_t len; -} WifiTxEapol; - -typedef struct { - void *callback; - void *contex; -} WifiEnableEapol; - -typedef struct { - int32_t start; - int32_t duration; - uint8_t count; - uint8_t resv[3]; -} WifiP2pNoa; - -typedef struct { - int32_t legacyPs; - int8_t oppPs; - uint8_t ctWindow; - int8_t resv[2]; -} WifiP2pPowerSave; - -typedef struct { - uint8_t type; - uint8_t macAddr[ETH_ADDR_LEN]; - uint8_t resv; -} WifiGetP2pAddr; - -typedef struct { - enum WifiIfType iftype; - uint8_t *macAddr; -} WifiIftypeMacAddr; - -typedef struct { - int32_t freq; -} WifiChannelSwitch; - -typedef struct { - uint8_t macAddr[ETH_ADDR_LEN]; - uint16_t reason; -} WifiMeshClosePeer; - -typedef struct { - uint8_t peerAddr[ETH_ADDR_LEN]; - uint8_t meshBcnPriority; - uint8_t meshIsMbr; - int8_t rssi; - int8_t reserved[3]; -} WifiMeshNewPeerCandidate; - -typedef struct { - struct hostapd_data *hapd; - char iface[IFNAMSIZ + 1]; - int8_t resv[3]; - uint64_t actionCookie; - void *ctx; - void *eventQueue; - - struct l2_packet_data *eapolSock; - uint8_t ownAddr[ETH_ADDR_LEN]; - - uint32_t associated; - uint8_t bssid[ETH_ADDR_LEN]; - uint8_t ssid[MAX_SSID_LEN]; - int32_t ssidLen; - - struct wpa_scan_res *scanRes[SCAN_AP_LIMIT]; - uint32_t scanNum; - uint32_t beaconSet; - uint8_t mode; -} WifiDriverData; - -typedef struct { - int32_t cmd; - const struct wpabuf *src; -} WifiCmd; - -typedef struct { - enum WifiIfType ifType; - WifiDriverData *priv; - int32_t networkId; - int32_t ifNameLen; - char ifName[IFNAMSIZ + 1]; - char reserver[1]; -} WifiDev; - -WifiDriverData *GetDrvData(); -void WifiWpaScanTimeout(void *eloop, void *ctx); -int32_t WifiWpaGetDrvFlags(void *priv, uint64_t *drvFlags); -WifiDev *GetWifiDevByName(const char *ifName); - -void WifiWpaNewStaProcess(WifiDriverData *drv, WifiNewStaInfo *staInfo); -void WifiWpaDelStaProcess(WifiDriverData *drv, uint8_t *addr); -void WifiWpaRxMgmtProcess(WifiDriverData *drv, WifiRxMgmt *rxMgmt); -void WifiWpaTxStatusProcess(WifiDriverData *drv, WifiTxStatus *txStatus); -void WifiWpaScanDoneProcess(WifiDriverData *drv, uint32_t *status); -void WifiWpaScanResultProcess(WifiDriverData *drv, WifiScanResult *scanResult); -void WifiWpaConnectResultProcess(WifiDriverData *drv, WifiConnectResult *result); -void WifiWpaDisconnectProcess(WifiDriverData *drv, WifiDisconnect *result); -void WifiWpaDriverEapolRecvProcess(WifiDriverData *drv, void *data); -void WifiWpaRemainOnChannelProcess(WifiDriverData *drv, WifiOnChannel *result); -void WifiWpaCancelRemainOnChannelProcess(WifiDriverData *drv, WifiOnChannel *result); - -#ifdef __cplusplus -#if __cplusplus -} -#endif -#endif - -#endif /* end of wpa_hal.h */ +/* + * Driver interaction with hdf wifi + * Copyright (c) 2020 Huawei Device Co., Ltd. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef _WPA_HAL_H_ +#define _WPA_HAL_H_ + +#include "wifi_driver_client.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +#define SUCC 0 +#define EFAIL 1 +#define EINVAL 22 + +#define WEP_KEY_NUM 4 +#define DEFAULT_NUM_MODES 2 +#define WPA_BANDWIDTH_20 20 +#define WPA_BANDWIDTH_40 40 + +#define SCAN_AP_LIMIT 64 +#define SCAN_TIME_OUT 5 + +#define NETDEV_UP 0x0001 +#define NETDEV_DOWN 0x0002 + +#define EAPOL_PKT_BUF_SIZE 800 +#define CHECK_DHCP_TIME 30 + +#define WPA_WEP40_KEY_LEN 5 +#define WPA_WEP104_KEY_LEN 13 + +#define WPA_FLAG_ON 1 +#define WPA_FLAG_OFF 0 + +typedef enum { + WPA_VERSION_1 = 1 << 0, + WPA_VERSION_2 = 1 << 1, +} WpaVersions; + +typedef enum { + WIFI_CHAN_WIDTH_20_NOHT, + WIFI_CHAN_WIDTH_20, + WIFI_CHAN_WIDTH_40, + WIFI_CHAN_WIDTH_BUTT +} WifiChannelWidth; + +typedef enum { + WIFI_DISCONNECT, + WIFI_CONNECT, +} WifiConnectStatus; + +typedef enum { + WIFI_KEYTYPE_GROUP, + WIFI_KEYTYPE_PAIRWISE, + WIFI_KEYTYPE_PEERKEY, + WIFI_KEYTYPE_BUTT +} WifiKeyType; + +typedef enum { + WIFI_KEY_DEFAULT_TYPE_INVALID, + WIFI_KEY_DEFAULT_TYPE_UNICAST, + WIFI_KEY_DEFAULT_TYPE_MULTICAST, + WIFI_KEY_DEFAULT_TYPES +} WifiKeyDefaultType; + +typedef enum { + WIFI_NO_SSID_HIDING, + WIFI_HIDDEN_SSID_ZERO_LEN, + WIFI_HIDDEN_SSID_ZERO_CONTENTS +} WifiHiddenSsid; + +typedef enum { + WIFI_MESH_ENABLE_AUTO_PEER, + WIFI_MESH_ENABLE_ACCEPT_PEER, + WIFI_MESH_ENABLE_ACCEPT_STA, + WIFI_MESH_ENABLE_FLAG_BUTT +} WifiMeshEnableFlagType; + +typedef enum { + WIFI_AUTHTYPE_OPEN_SYSTEM = 0, + WIFI_AUTHTYPE_SHARED_KEY, + WIFI_AUTHTYPE_FT, + WIFI_AUTHTYPE_EAP, + WIFI_AUTHTYPE_SAE, + WIFI_AUTHTYPE_AUTOMATIC, + WIFI_AUTHTYPE_BUTT +} WifiAuthType; + +typedef enum { + WIFI_SCAN_SUCCESS, + WIFI_SCAN_FAILED, + WIFI_SCAN_REFUSED, + WIFI_SCAN_TIMEOUT +} WifiScanStatus; + +typedef struct { + int32_t numRates; + int32_t mode; +} WifiModes; + +typedef struct { + uint8_t *addr; + uint8_t plinkState; + uint8_t set; + uint8_t meshBcnPriority; + uint8_t meshIsMbr; + uint8_t meshInitiativePeering; +} WifiMeshUsrParams; + +typedef struct { + uint8_t *addr; + uint8_t *gtk; + uint8_t gtkLen; + uint8_t resv[3]; +} WifiSetMeshUsrGtk; + +typedef struct { + uint8_t *buf; + uint32_t len; +} WifiTxEapol; + +typedef struct { + void *callback; + void *contex; +} WifiEnableEapol; + +typedef struct { + int32_t start; + int32_t duration; + uint8_t count; + uint8_t resv[3]; +} WifiP2pNoa; + +typedef struct { + int32_t legacyPs; + int8_t oppPs; + uint8_t ctWindow; + int8_t resv[2]; +} WifiP2pPowerSave; + +typedef struct { + uint8_t type; + uint8_t macAddr[ETH_ADDR_LEN]; + uint8_t resv; +} WifiGetP2pAddr; + +typedef struct { + enum WifiIfType iftype; + uint8_t *macAddr; +} WifiIftypeMacAddr; + +typedef struct { + int32_t freq; +} WifiChannelSwitch; + +typedef struct { + uint8_t macAddr[ETH_ADDR_LEN]; + uint16_t reason; +} WifiMeshClosePeer; + +typedef struct { + uint8_t peerAddr[ETH_ADDR_LEN]; + uint8_t meshBcnPriority; + uint8_t meshIsMbr; + int8_t rssi; + int8_t reserved[3]; +} WifiMeshNewPeerCandidate; + +typedef struct { + struct hostapd_data *hapd; + char iface[IFNAMSIZ + 1]; + int8_t resv[3]; + uint64_t actionCookie; + void *ctx; + void *eventQueue; + + struct l2_packet_data *eapolSock; + uint8_t ownAddr[ETH_ADDR_LEN]; + + uint32_t associated; + uint8_t bssid[ETH_ADDR_LEN]; + uint8_t ssid[MAX_SSID_LEN]; + int32_t ssidLen; + + struct wpa_scan_res *scanRes[SCAN_AP_LIMIT]; + uint32_t scanNum; + uint32_t beaconSet; + uint8_t mode; +} WifiDriverData; + +typedef struct { + int32_t cmd; + const struct wpabuf *src; +} WifiCmd; + +typedef struct { + enum WifiIfType ifType; + WifiDriverData *priv; + int32_t networkId; + int32_t ifNameLen; + char ifName[IFNAMSIZ + 1]; + char reserver[1]; +} WifiDev; + +WifiDriverData *GetDrvData(); +void WifiWpaScanTimeout(void *eloop, void *ctx); +int32_t WifiWpaGetDrvFlags(void *priv, uint64_t *drvFlags); +WifiDev *GetWifiDevByName(const char *ifName); + +void WifiWpaNewStaProcess(WifiDriverData *drv, WifiNewStaInfo *staInfo); +void WifiWpaDelStaProcess(WifiDriverData *drv, uint8_t *addr); +void WifiWpaRxMgmtProcess(WifiDriverData *drv, WifiRxMgmt *rxMgmt); +void WifiWpaTxStatusProcess(WifiDriverData *drv, WifiTxStatus *txStatus); +void WifiWpaScanDoneProcess(WifiDriverData *drv, uint32_t *status); +void WifiWpaScanResultProcess(WifiDriverData *drv, WifiScanResult *scanResult); +void WifiWpaConnectResultProcess(WifiDriverData *drv, WifiConnectResult *result); +void WifiWpaDisconnectProcess(WifiDriverData *drv, WifiDisconnect *result); +void WifiWpaDriverEapolRecvProcess(WifiDriverData *drv, void *data); +void WifiWpaRemainOnChannelProcess(WifiDriverData *drv, WifiOnChannel *result); +void WifiWpaCancelRemainOnChannelProcess(WifiDriverData *drv, WifiOnChannel *result); + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif + +#endif /* end of wpa_hal.h */ diff --git a/wpa_supplicant-2.9_standard/src/drivers/wpa_hal_event.c b/wpa_supplicant-2.9_standard/src/drivers/wpa_hal_event.c index 363847e9faf477654a745219bf70288930e8349b..686ad762dfd0ba2f07e67a387220464ee93310b8 100644 --- a/wpa_supplicant-2.9_standard/src/drivers/wpa_hal_event.c +++ b/wpa_supplicant-2.9_standard/src/drivers/wpa_hal_event.c @@ -1,670 +1,670 @@ -/* - * Driver interaction with hdf wifi - * Copyright (c) 2020 Huawei Device Co., Ltd. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ -#include -#include -#include "includes.h" -#include "utils/common.h" -#include "driver.h" -#include "eloop.h" -#include "l2_packet/l2_packet.h" -#include "wpa_hal.h" -#include "wpa_supplicant_i.h" -#include "securec.h" - -#ifdef __cplusplus -#if __cplusplus -extern "C" { -#endif -#endif - -static void WpaMemFree(void *mem) -{ - if (mem != NULL) { - free(mem); - mem = NULL; - } -} - -static inline int IsZeroAddr(const uint8_t *addr, const uint8_t len) -{ - if (len != ETH_ADDR_LEN) { - return -EFAIL; - } - // 0 1 2 3 4 5 : mac index - return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]); -} - -static void WifiWpaEventNewStaProcess(void *ctx, void *data) -{ - if (ctx == NULL || data == NULL) { - return; - } - WifiDriverData *drv = (WifiDriverData *)ctx; - WifiNewStaInfo *staInfo = (WifiNewStaInfo *)data; - union wpa_event_data event; - - (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); - if (IsZeroAddr(staInfo->macAddr, ETH_ADDR_LEN)) { - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); - } else { - event.assoc_info.reassoc = staInfo->reassoc; - event.assoc_info.req_ies = staInfo->ie; - event.assoc_info.req_ies_len = staInfo->ieLen; - event.assoc_info.addr = staInfo->macAddr; - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); - } - WpaMemFree(staInfo->ie); - WpaMemFree(staInfo->macAddr); - WpaMemFree(staInfo); - wpa_printf(MSG_INFO, "WifiWpaEventNewStaProcess done"); -} - -static void WifiWpaEventDelStaProcess(void *ctx, void *data) -{ - if (ctx == NULL || data == NULL) { - return; - } - wpa_printf(MSG_INFO, "WifiWpaEventDelStaProcess enter."); - WifiDriverData *drv = (WifiDriverData *)ctx; - uint8_t *addr = (uint8_t *)data; - union wpa_event_data event; - struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)drv->ctx; - if (wpa_s == NULL || wpa_s->disconnected == 1) { - wpa_printf(MSG_INFO, "WifiWpaEventDelStaProcess: already disconnected, return."); - return; - } - (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); - event.disassoc_info.addr = addr; - if (drv->ctx != NULL) { - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &event); - wpa_printf(MSG_INFO, "WifiWpaEventDelStaProcess done."); - } - WpaMemFree(addr); -} - -static void WifiWpaEventRxMgmtProcess(void *ctx, void *data) -{ - if (ctx == NULL || data == NULL) { - return; - } - WifiDriverData *drv = (WifiDriverData *)ctx; - WifiRxMgmt *rxMgmt = (WifiRxMgmt *)data; - union wpa_event_data event; - - (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); - event.rx_mgmt.frame = rxMgmt->buf; - event.rx_mgmt.frame_len = rxMgmt->len; - event.rx_mgmt.ssi_signal = rxMgmt->sigMbm; - event.rx_mgmt.freq = rxMgmt->freq; - - wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); - WpaMemFree(rxMgmt->buf); - WpaMemFree(rxMgmt); - wpa_printf(MSG_INFO, "WifiWpaEventRxMgmtProcess done"); -} - -static void WifiWpaEventTxStatusProcess(void *ctx, void *data) -{ - if (ctx == NULL || data == NULL) { - return; - } - WifiDriverData *drv = (WifiDriverData *)ctx; - WifiTxStatus *txStatus = (WifiTxStatus *)data; - uint16_t fc; - struct ieee80211_hdr *hdr = NULL; - union wpa_event_data event; - - (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); - hdr = (struct ieee80211_hdr *)txStatus->buf; - fc = le_to_host16(hdr->frame_control); - event.tx_status.type = WLAN_FC_GET_TYPE(fc); - event.tx_status.stype = WLAN_FC_GET_STYPE(fc); - event.tx_status.dst = hdr->addr1; - event.tx_status.data = txStatus->buf; - event.tx_status.data_len = txStatus->len; - event.tx_status.ack = (txStatus->ack != false); - - wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); - WpaMemFree(txStatus->buf); - WpaMemFree(txStatus); - wpa_printf(MSG_INFO, "WifiWpaEventTxStatusProcess done"); -} - -static void WifiWpaEventScanDoneProcess(void *ctx, void *data) -{ - if (ctx == NULL || data == NULL) { - return; - } - WifiDriverData *drv = (WifiDriverData *)ctx; - uint32_t *status = (uint32_t *)data; - if (drv->ctx == NULL) { - wpa_printf(MSG_ERROR, "%s: ctx is null", __func__); - goto failed; - } - eloop_cancel_timeout(WifiWpaScanTimeout, drv, drv->ctx); - if (*status != WIFI_SCAN_SUCCESS) { - goto failed; - } - wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); - wpa_printf(MSG_INFO, "WifiWpaEventScanDoneProcess done"); - -failed: - WpaMemFree(status); -} - -static void WifiWpaEventScanResultProcess(void *ctx, void *data) -{ - if (ctx == NULL || data == NULL) { - return; - } - WifiDriverData *drv = (WifiDriverData *)ctx; - WifiScanResult *scanResult = (WifiScanResult *)data; - struct wpa_scan_res *res = NULL; - errno_t rc; - - wpa_printf(MSG_INFO, "%s: ie_len=%d, beacon_ie_len=%d", __func__, scanResult->ieLen, scanResult->beaconIeLen); - res = (struct wpa_scan_res *)os_zalloc(sizeof(struct wpa_scan_res) + scanResult->ieLen + scanResult->beaconIeLen); - if (res == NULL) { - goto failed; - } - res->flags = scanResult->flags; - res->freq = scanResult->freq; - res->caps = scanResult->caps; - res->beacon_int = scanResult->beaconInt; - res->qual = 0; - res->level = scanResult->level; - res->age = 0; - res->ie_len = scanResult->ieLen; - res->beacon_ie_len = scanResult->beaconIeLen; - rc = memcpy_s(res->bssid, ETH_ADDR_LEN, scanResult->bssid, ETH_ADDR_LEN); - if (rc != EOK) { - goto failed; - } - rc = memcpy_s(&res[1], scanResult->ieLen, scanResult->ie, scanResult->ieLen); - if (rc != EOK) { - goto failed; - } - rc = memcpy_s(((uint8_t *)(&res[1]) + scanResult->ieLen), scanResult->beaconIeLen, scanResult->beaconIe, scanResult->beaconIeLen); - if (rc != EOK) { - goto failed; - } - if (drv->scanNum >= SCAN_AP_LIMIT) { - wpa_printf(MSG_ERROR, "WifiWpaEventScanResultProcess: drv->scanNum >= SCAN_AP_LIMIT"); - goto failed; - } - drv->scanRes[drv->scanNum++] = res; - WpaMemFree(scanResult->ie); - WpaMemFree(scanResult->bssid); - WpaMemFree(scanResult->beaconIe); - WpaMemFree(scanResult); - wpa_printf(MSG_INFO, "WifiWpaEventScanResultProcess done"); - return; - -failed: - if (res != NULL) { - os_free(res); - res = NULL; - } - WpaMemFree(scanResult->ie); - WpaMemFree(scanResult->bssid); - WpaMemFree(scanResult->beaconIe); - WpaMemFree(scanResult); -} - -static void WifiWpaEventConnectResultProcess(void *ctx, void *data) -{ - if (ctx == NULL || data == NULL) { - return; - } - WifiDriverData *drv = (WifiDriverData *)ctx; - WifiConnectResult *result = (WifiConnectResult *)data; - union wpa_event_data event; - errno_t rc; - - (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); - if (result->status != 0) { - drv->associated = WIFI_DISCONNECT; - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); - } else { - drv->associated = WIFI_CONNECT; - rc = memcpy_s(drv->bssid, ETH_ADDR_LEN, result->bssid, ETH_ALEN); - if (rc != EOK) { - goto failed; - } - event.assoc_info.req_ies = result->reqIe; - event.assoc_info.req_ies_len = result->reqIeLen; - event.assoc_info.resp_ies = result->respIe; - event.assoc_info.resp_ies_len = result->respIeLen; - event.assoc_info.addr = result->bssid; - event.assoc_info.freq = result->freq; - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); - } - wpa_printf(MSG_INFO, "WifiWpaEventConnectResultProcess done"); - -failed: - WpaMemFree(result->bssid); - WpaMemFree(result->reqIe); - WpaMemFree(result->respIe); - WpaMemFree(result); -} - -static void WifiWpaEventDisconnectProcess(void *ctx, void *data) -{ - if (ctx == NULL || data == NULL) { - return; - } - wpa_printf(MSG_INFO, "WifiWpaEventDisconnectProcess enter."); - WifiDriverData *drv = (WifiDriverData *)ctx; - WifiDisconnect *result = (WifiDisconnect *)data; - union wpa_event_data event; - struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)drv->ctx; - if (wpa_s == NULL || wpa_s->disconnected == 1) { - wpa_printf(MSG_INFO, "WifiWpaEventDisconnectProcess: already disconnected, return."); - return; - } - - (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); - drv->associated = WIFI_DISCONNECT; - event.disassoc_info.reason_code = result->reason; - event.disassoc_info.ie = result->ie; - event.disassoc_info.ie_len = result->ieLen; - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &event); - wpa_printf(MSG_INFO, "WifiWpaEventDisconnectProcess done"); - WpaMemFree(result->ie); - WpaMemFree(result); -} - -extern void l2_packet_receive(void *eloop_ctx, void *sock_ctx); -static inline void WifiWpaDriverEventEapolRecvProcess(void *ctx, void *data) -{ - WifiDriverData *drv = (WifiDriverData *)ctx; - wpa_printf(MSG_INFO, "WifiWpaDriverEventEapolRecvProcess call"); - eloop_register_timeout(0, 0, l2_packet_receive, drv->eapolSock, NULL); -} - -static void WifiWpaEventRemainOnChannelProcess(void *ctx, void *data) -{ - if (ctx == NULL || data == NULL) { - return; - } - WifiDriverData *drv = (WifiDriverData *)ctx; - WifiOnChannel *result = (WifiOnChannel *)data; - union wpa_event_data event; - (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); - - event.remain_on_channel.freq = result->freq; - event.remain_on_channel.duration = result->duration; - wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &event); - wpa_printf(MSG_INFO, "%s done.", __FUNCTION__); - WpaMemFree(result); -} - -static void WifiWpaEventCancelRemainOnChannelProcess(void *ctx, void *data) -{ - if (ctx == NULL || data == NULL) { - return; - } - WifiDriverData *drv = (WifiDriverData *)ctx; - WifiOnChannel *result = (WifiOnChannel *)data; - union wpa_event_data event; - (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); - - event.remain_on_channel.freq = result->freq; - wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &event); - wpa_printf(MSG_INFO, "%s done.", __FUNCTION__); - WpaMemFree(result); -} -static int32_t AllocAndCopyIe(uint8_t *dstIe, uint32_t ieLen, uint8_t *srcIe) -{ - int32_t ret = 0; - if (ieLen == 0) { - dstIe = NULL; - return SUCC; - } - dstIe = (uint8_t *)os_zalloc(ieLen); - if (dstIe == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return -EFAIL; - } - ret = memcpy_s(dstIe, ieLen, srcIe, ieLen); - if (ret != SUCC) { - WpaMemFree(dstIe); - return -EFAIL; - } - return SUCC; -} - -void WifiWpaNewStaProcess(WifiDriverData *drv, WifiNewStaInfo *staInfo) -{ - WifiNewStaInfo *copyStaInfo = NULL; - uint8_t *ie = NULL; - uint8_t *macAddr = NULL; - int ret = 0; - - copyStaInfo = (WifiNewStaInfo *)os_zalloc(sizeof(WifiNewStaInfo)); - if (copyStaInfo == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return; - } - ie = (uint8_t *)os_zalloc(staInfo->ieLen); - if (ie == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - goto failed3; - } - ret = memcpy_s(ie, staInfo->ieLen, staInfo->ie, staInfo->ieLen); - if (ret != SUCC) { - goto failed2; - } - macAddr = (uint8_t *)os_zalloc(ETH_ADDR_LEN); - if (macAddr == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - goto failed2; - } - ret = memcpy_s(macAddr, ETH_ADDR_LEN, staInfo->macAddr, ETH_ADDR_LEN); - if (ret != SUCC) { - goto failed1; - } - - copyStaInfo->reassoc = staInfo->reassoc; - copyStaInfo->ie = ie; - copyStaInfo->ieLen = staInfo->ieLen; - copyStaInfo->macAddr = macAddr; - eloop_register_timeout(0, 0, WifiWpaEventNewStaProcess, drv, copyStaInfo); - return; - -failed1: - WpaMemFree(macAddr); -failed2: - WpaMemFree(ie); -failed3: - WpaMemFree(copyStaInfo); -} - -void WifiWpaDelStaProcess(WifiDriverData *drv, uint8_t *addr) -{ - uint8_t *copyAddr = NULL; - int ret = 0; - - copyAddr = (uint8_t *)os_zalloc(sizeof(ETH_ADDR_LEN)); - if (copyAddr == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return; - } - ret = memcpy_s(copyAddr, ETH_ADDR_LEN, addr, ETH_ADDR_LEN); - if (ret != SUCC) { - WpaMemFree(copyAddr); - return; - } - eloop_register_timeout(0, 0, WifiWpaEventDelStaProcess, drv, copyAddr); -} - -void WifiWpaRxMgmtProcess(WifiDriverData *drv, WifiRxMgmt *rxMgmt) -{ - WifiRxMgmt *copyRxMgmt = NULL; - uint8_t *buf = NULL; - int ret = 0; - - copyRxMgmt = (WifiRxMgmt *)os_zalloc(sizeof(WifiRxMgmt)); - if (copyRxMgmt == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return; - } - buf = (uint8_t *)os_zalloc(rxMgmt->len); - if (buf == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - WpaMemFree(copyRxMgmt); - return; - } - ret = memcpy_s(buf, rxMgmt->len, rxMgmt->buf, rxMgmt->len); - if (ret != SUCC) { - WpaMemFree(copyRxMgmt); - WpaMemFree(buf); - return; - } - copyRxMgmt->buf = buf; - copyRxMgmt->len = rxMgmt->len; - copyRxMgmt->sigMbm = rxMgmt->sigMbm; - copyRxMgmt->freq = rxMgmt->freq; - eloop_register_timeout(0, 0, WifiWpaEventRxMgmtProcess, drv, copyRxMgmt); -} - -void WifiWpaTxStatusProcess(WifiDriverData *drv, WifiTxStatus *txStatus) -{ - WifiTxStatus *copyTxStatus = NULL; - uint8_t *buf = NULL; - int ret = 0; - - copyTxStatus = (WifiTxStatus *)os_zalloc(sizeof(WifiTxStatus)); - if (copyTxStatus == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return; - } - buf = (uint8_t *)os_zalloc(txStatus->len); - if (buf == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - WpaMemFree(copyTxStatus); - return; - } - ret = memcpy_s(buf, txStatus->len, txStatus->buf, txStatus->len); - if (ret != SUCC) { - WpaMemFree(copyTxStatus); - WpaMemFree(buf); - return; - } - copyTxStatus->buf = buf; - copyTxStatus->ack = txStatus->ack; - copyTxStatus->len = txStatus->len; - eloop_register_timeout(0, 0, WifiWpaEventTxStatusProcess, drv, copyTxStatus); -} - -void WifiWpaScanDoneProcess(WifiDriverData *drv, uint32_t *status) -{ - uint32_t *copyStatus = NULL; - int ret = 0; - - copyStatus = (uint32_t *)os_zalloc(sizeof(uint32_t)); - if (copyStatus == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return; - } - ret = memcpy_s(copyStatus, sizeof(uint32_t), status, sizeof(uint32_t)); - if (ret != SUCC) { - WpaMemFree(copyStatus); - return; - } - eloop_register_timeout(0, 0, WifiWpaEventScanDoneProcess, drv, copyStatus); -} - -void WifiWpaScanResultProcess(WifiDriverData *drv, WifiScanResult *scanResult) -{ - WifiScanResult *copyScanResult = NULL; - uint8_t *ie = NULL; - uint8_t *beaconIe = NULL; - uint8_t *bssid = NULL; - int ret = 0; - - copyScanResult = (WifiScanResult *)os_zalloc(sizeof(WifiScanResult)); - if (copyScanResult == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return; - } - bssid = (uint8_t *)os_zalloc(ETH_ADDR_LEN); - if (bssid == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - goto failed4; - } - ret = memcpy_s(bssid, ETH_ADDR_LEN, scanResult->bssid, ETH_ADDR_LEN); - if (ret != SUCC) { - goto failed3; - } - - ie = (uint8_t *)os_zalloc(scanResult->ieLen); - if (ie == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - goto failed3; - } - ret = memcpy_s(ie, scanResult->ieLen, scanResult->ie, scanResult->ieLen); - if (ret != SUCC) { - goto failed2; - } - - beaconIe = (uint8_t *)os_zalloc(scanResult->beaconIeLen); - if (beaconIe == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - goto failed2; - } - ret = memcpy_s(beaconIe, scanResult->beaconIeLen, scanResult->beaconIe, scanResult->beaconIeLen); - if (ret != SUCC) { - goto failed1; - } - - copyScanResult->flags = scanResult->flags; - copyScanResult->freq = scanResult->freq; - copyScanResult->caps = scanResult->caps; - copyScanResult->beaconInt = scanResult->beaconInt; - copyScanResult->level = scanResult->level; - copyScanResult->ieLen = scanResult->ieLen; - copyScanResult->beaconIeLen = scanResult->beaconIeLen; - copyScanResult->bssid = bssid; - copyScanResult->ie = ie; - copyScanResult->beaconIe = beaconIe; - eloop_register_timeout(0, 0, WifiWpaEventScanResultProcess, drv, copyScanResult); - return; - -failed1: - WpaMemFree(beaconIe); -failed2: - WpaMemFree(ie); -failed3: - WpaMemFree(bssid); -failed4: - WpaMemFree(copyScanResult); -} - -void WifiWpaConnectResultProcess(WifiDriverData *drv, WifiConnectResult *result) -{ - WifiConnectResult *copyResult = NULL; - uint8_t *reqIe = NULL; - uint8_t *respIe = NULL; - uint8_t *bssid = NULL; - int ret = 0; - - copyResult = (WifiConnectResult *)os_zalloc(sizeof(WifiConnectResult)); - if (copyResult == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return; - } - bssid = (uint8_t *)os_zalloc(ETH_ADDR_LEN); - if (bssid == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - goto failed4; - } - ret = memcpy_s(bssid, ETH_ADDR_LEN, result->bssid, ETH_ADDR_LEN); - if (ret != SUCC) { - goto failed3; - } - - reqIe = (uint8_t *)os_zalloc(result->reqIeLen); - if (reqIe == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - goto failed3; - } - ret = memcpy_s(reqIe, result->reqIeLen, result->reqIe, result->reqIeLen); - if (ret != SUCC) { - goto failed2; - } - - respIe = (uint8_t *)os_zalloc(result->respIeLen); - if (respIe == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - goto failed2; - } - ret = memcpy_s(respIe, result->respIeLen, result->respIe, result->respIeLen); - if (ret != SUCC) { - goto failed1; - } - - copyResult->status = result->status; - copyResult->freq = result->freq; - copyResult->reqIeLen = result->reqIeLen; - copyResult->respIeLen = result->respIeLen; - copyResult->reqIe = reqIe; - copyResult->respIe = respIe; - copyResult->bssid = bssid; - eloop_register_timeout(0, 0, WifiWpaEventConnectResultProcess, drv, copyResult); - return; - -failed1: - WpaMemFree(respIe); -failed2: - WpaMemFree(reqIe); -failed3: - WpaMemFree(bssid); -failed4: - WpaMemFree(copyResult); -} - -void WifiWpaDisconnectProcess(WifiDriverData *drv, WifiDisconnect *result) -{ - WifiDisconnect *copyResult = NULL; - uint8_t *ie = NULL; - int32_t ret = 0; - - copyResult = (WifiDisconnect *)os_zalloc(sizeof(WifiDisconnect)); - if (copyResult == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return; - } - ret = AllocAndCopyIe(ie, result->ieLen, result->ie); - if (ret != SUCC) { - WpaMemFree(copyResult); - return; - } - copyResult->ie = ie; - copyResult->ieLen = result->ieLen; - copyResult->reason = result->reason; - eloop_register_timeout(0, 0, WifiWpaEventDisconnectProcess, drv, copyResult); -} - -void WifiWpaDriverEapolRecvProcess(WifiDriverData *drv, void *data) -{ - eloop_register_timeout(0, 0, WifiWpaDriverEventEapolRecvProcess, drv, data); -} - -void WifiWpaRemainOnChannelProcess(WifiDriverData *drv, WifiOnChannel *result) -{ - WifiOnChannel *copyResult = NULL; - - copyResult = (WifiOnChannel *)os_zalloc(sizeof(WifiOnChannel)); - if (copyResult == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return; - } - copyResult->freq = result->freq; - copyResult->duration = result->duration; - eloop_register_timeout(0, 0, WifiWpaEventRemainOnChannelProcess, drv, copyResult); -} - -void WifiWpaCancelRemainOnChannelProcess(WifiDriverData *drv, WifiOnChannel *result) -{ - WifiOnChannel *copyResult = NULL; - - copyResult = (WifiOnChannel *)os_zalloc(sizeof(WifiOnChannel)); - if (copyResult == NULL) { - wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); - return; - } - copyResult->freq = result->freq; - eloop_register_timeout(0, 0, WifiWpaEventCancelRemainOnChannelProcess, drv, copyResult); -} - -#ifdef __cplusplus -#if __cplusplus -} -#endif -#endif +/* + * Driver interaction with hdf wifi + * Copyright (c) 2020 Huawei Device Co., Ltd. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include +#include +#include "includes.h" +#include "utils/common.h" +#include "driver.h" +#include "eloop.h" +#include "l2_packet/l2_packet.h" +#include "wpa_hal.h" +#include "wpa_supplicant_i.h" +#include "securec.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif +#endif + +static void WpaMemFree(void *mem) +{ + if (mem != NULL) { + free(mem); + mem = NULL; + } +} + +static inline int IsZeroAddr(const uint8_t *addr, const uint8_t len) +{ + if (len != ETH_ADDR_LEN) { + return -EFAIL; + } + // 0 1 2 3 4 5 : mac index + return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]); +} + +static void WifiWpaEventNewStaProcess(void *ctx, void *data) +{ + if (ctx == NULL || data == NULL) { + return; + } + WifiDriverData *drv = (WifiDriverData *)ctx; + WifiNewStaInfo *staInfo = (WifiNewStaInfo *)data; + union wpa_event_data event; + + (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); + if (IsZeroAddr(staInfo->macAddr, ETH_ADDR_LEN)) { + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); + } else { + event.assoc_info.reassoc = staInfo->reassoc; + event.assoc_info.req_ies = staInfo->ie; + event.assoc_info.req_ies_len = staInfo->ieLen; + event.assoc_info.addr = staInfo->macAddr; + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); + } + WpaMemFree(staInfo->ie); + WpaMemFree(staInfo->macAddr); + WpaMemFree(staInfo); + wpa_printf(MSG_INFO, "WifiWpaEventNewStaProcess done"); +} + +static void WifiWpaEventDelStaProcess(void *ctx, void *data) +{ + if (ctx == NULL || data == NULL) { + return; + } + wpa_printf(MSG_INFO, "WifiWpaEventDelStaProcess enter."); + WifiDriverData *drv = (WifiDriverData *)ctx; + uint8_t *addr = (uint8_t *)data; + union wpa_event_data event; + struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)drv->ctx; + if (wpa_s == NULL || wpa_s->disconnected == 1) { + wpa_printf(MSG_INFO, "WifiWpaEventDelStaProcess: already disconnected, return."); + return; + } + (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); + event.disassoc_info.addr = addr; + if (drv->ctx != NULL) { + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &event); + wpa_printf(MSG_INFO, "WifiWpaEventDelStaProcess done."); + } + WpaMemFree(addr); +} + +static void WifiWpaEventRxMgmtProcess(void *ctx, void *data) +{ + if (ctx == NULL || data == NULL) { + return; + } + WifiDriverData *drv = (WifiDriverData *)ctx; + WifiRxMgmt *rxMgmt = (WifiRxMgmt *)data; + union wpa_event_data event; + + (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); + event.rx_mgmt.frame = rxMgmt->buf; + event.rx_mgmt.frame_len = rxMgmt->len; + event.rx_mgmt.ssi_signal = rxMgmt->sigMbm; + event.rx_mgmt.freq = rxMgmt->freq; + + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); + WpaMemFree(rxMgmt->buf); + WpaMemFree(rxMgmt); + wpa_printf(MSG_INFO, "WifiWpaEventRxMgmtProcess done"); +} + +static void WifiWpaEventTxStatusProcess(void *ctx, void *data) +{ + if (ctx == NULL || data == NULL) { + return; + } + WifiDriverData *drv = (WifiDriverData *)ctx; + WifiTxStatus *txStatus = (WifiTxStatus *)data; + uint16_t fc; + struct ieee80211_hdr *hdr = NULL; + union wpa_event_data event; + + (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); + hdr = (struct ieee80211_hdr *)txStatus->buf; + fc = le_to_host16(hdr->frame_control); + event.tx_status.type = WLAN_FC_GET_TYPE(fc); + event.tx_status.stype = WLAN_FC_GET_STYPE(fc); + event.tx_status.dst = hdr->addr1; + event.tx_status.data = txStatus->buf; + event.tx_status.data_len = txStatus->len; + event.tx_status.ack = (txStatus->ack != false); + + wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); + WpaMemFree(txStatus->buf); + WpaMemFree(txStatus); + wpa_printf(MSG_INFO, "WifiWpaEventTxStatusProcess done"); +} + +static void WifiWpaEventScanDoneProcess(void *ctx, void *data) +{ + if (ctx == NULL || data == NULL) { + return; + } + WifiDriverData *drv = (WifiDriverData *)ctx; + uint32_t *status = (uint32_t *)data; + if (drv->ctx == NULL) { + wpa_printf(MSG_ERROR, "%s: ctx is null", __func__); + goto failed; + } + eloop_cancel_timeout(WifiWpaScanTimeout, drv, drv->ctx); + if (*status != WIFI_SCAN_SUCCESS) { + goto failed; + } + wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); + wpa_printf(MSG_INFO, "WifiWpaEventScanDoneProcess done"); + +failed: + WpaMemFree(status); +} + +static void WifiWpaEventScanResultProcess(void *ctx, void *data) +{ + if (ctx == NULL || data == NULL) { + return; + } + WifiDriverData *drv = (WifiDriverData *)ctx; + WifiScanResult *scanResult = (WifiScanResult *)data; + struct wpa_scan_res *res = NULL; + errno_t rc; + + wpa_printf(MSG_INFO, "%s: ie_len=%d, beacon_ie_len=%d", __func__, scanResult->ieLen, scanResult->beaconIeLen); + res = (struct wpa_scan_res *)os_zalloc(sizeof(struct wpa_scan_res) + scanResult->ieLen + scanResult->beaconIeLen); + if (res == NULL) { + goto failed; + } + res->flags = scanResult->flags; + res->freq = scanResult->freq; + res->caps = scanResult->caps; + res->beacon_int = scanResult->beaconInt; + res->qual = 0; + res->level = scanResult->level; + res->age = 0; + res->ie_len = scanResult->ieLen; + res->beacon_ie_len = scanResult->beaconIeLen; + rc = memcpy_s(res->bssid, ETH_ADDR_LEN, scanResult->bssid, ETH_ADDR_LEN); + if (rc != EOK) { + goto failed; + } + rc = memcpy_s(&res[1], scanResult->ieLen, scanResult->ie, scanResult->ieLen); + if (rc != EOK) { + goto failed; + } + rc = memcpy_s(((uint8_t *)(&res[1]) + scanResult->ieLen), scanResult->beaconIeLen, scanResult->beaconIe, scanResult->beaconIeLen); + if (rc != EOK) { + goto failed; + } + if (drv->scanNum >= SCAN_AP_LIMIT) { + wpa_printf(MSG_ERROR, "WifiWpaEventScanResultProcess: drv->scanNum >= SCAN_AP_LIMIT"); + goto failed; + } + drv->scanRes[drv->scanNum++] = res; + WpaMemFree(scanResult->ie); + WpaMemFree(scanResult->bssid); + WpaMemFree(scanResult->beaconIe); + WpaMemFree(scanResult); + wpa_printf(MSG_INFO, "WifiWpaEventScanResultProcess done"); + return; + +failed: + if (res != NULL) { + os_free(res); + res = NULL; + } + WpaMemFree(scanResult->ie); + WpaMemFree(scanResult->bssid); + WpaMemFree(scanResult->beaconIe); + WpaMemFree(scanResult); +} + +static void WifiWpaEventConnectResultProcess(void *ctx, void *data) +{ + if (ctx == NULL || data == NULL) { + return; + } + WifiDriverData *drv = (WifiDriverData *)ctx; + WifiConnectResult *result = (WifiConnectResult *)data; + union wpa_event_data event; + errno_t rc; + + (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); + if (result->status != 0) { + drv->associated = WIFI_DISCONNECT; + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); + } else { + drv->associated = WIFI_CONNECT; + rc = memcpy_s(drv->bssid, ETH_ADDR_LEN, result->bssid, ETH_ALEN); + if (rc != EOK) { + goto failed; + } + event.assoc_info.req_ies = result->reqIe; + event.assoc_info.req_ies_len = result->reqIeLen; + event.assoc_info.resp_ies = result->respIe; + event.assoc_info.resp_ies_len = result->respIeLen; + event.assoc_info.addr = result->bssid; + event.assoc_info.freq = result->freq; + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); + } + wpa_printf(MSG_INFO, "WifiWpaEventConnectResultProcess done"); + +failed: + WpaMemFree(result->bssid); + WpaMemFree(result->reqIe); + WpaMemFree(result->respIe); + WpaMemFree(result); +} + +static void WifiWpaEventDisconnectProcess(void *ctx, void *data) +{ + if (ctx == NULL || data == NULL) { + return; + } + wpa_printf(MSG_INFO, "WifiWpaEventDisconnectProcess enter."); + WifiDriverData *drv = (WifiDriverData *)ctx; + WifiDisconnect *result = (WifiDisconnect *)data; + union wpa_event_data event; + struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)drv->ctx; + if (wpa_s == NULL || wpa_s->disconnected == 1) { + wpa_printf(MSG_INFO, "WifiWpaEventDisconnectProcess: already disconnected, return."); + return; + } + + (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); + drv->associated = WIFI_DISCONNECT; + event.disassoc_info.reason_code = result->reason; + event.disassoc_info.ie = result->ie; + event.disassoc_info.ie_len = result->ieLen; + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &event); + wpa_printf(MSG_INFO, "WifiWpaEventDisconnectProcess done"); + WpaMemFree(result->ie); + WpaMemFree(result); +} + +extern void l2_packet_receive(void *eloop_ctx, void *sock_ctx); +static inline void WifiWpaDriverEventEapolRecvProcess(void *ctx, void *data) +{ + WifiDriverData *drv = (WifiDriverData *)ctx; + wpa_printf(MSG_INFO, "WifiWpaDriverEventEapolRecvProcess call"); + eloop_register_timeout(0, 0, l2_packet_receive, drv->eapolSock, NULL); +} + +static void WifiWpaEventRemainOnChannelProcess(void *ctx, void *data) +{ + if (ctx == NULL || data == NULL) { + return; + } + WifiDriverData *drv = (WifiDriverData *)ctx; + WifiOnChannel *result = (WifiOnChannel *)data; + union wpa_event_data event; + (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); + + event.remain_on_channel.freq = result->freq; + event.remain_on_channel.duration = result->duration; + wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &event); + wpa_printf(MSG_INFO, "%s done.", __FUNCTION__); + WpaMemFree(result); +} + +static void WifiWpaEventCancelRemainOnChannelProcess(void *ctx, void *data) +{ + if (ctx == NULL || data == NULL) { + return; + } + WifiDriverData *drv = (WifiDriverData *)ctx; + WifiOnChannel *result = (WifiOnChannel *)data; + union wpa_event_data event; + (void)memset_s(&event, sizeof(union wpa_event_data), 0, sizeof(union wpa_event_data)); + + event.remain_on_channel.freq = result->freq; + wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &event); + wpa_printf(MSG_INFO, "%s done.", __FUNCTION__); + WpaMemFree(result); +} +static int32_t AllocAndCopyIe(uint8_t *dstIe, uint32_t ieLen, uint8_t *srcIe) +{ + int32_t ret = 0; + if (ieLen == 0) { + dstIe = NULL; + return SUCC; + } + dstIe = (uint8_t *)os_zalloc(ieLen); + if (dstIe == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return -EFAIL; + } + ret = memcpy_s(dstIe, ieLen, srcIe, ieLen); + if (ret != SUCC) { + WpaMemFree(dstIe); + return -EFAIL; + } + return SUCC; +} + +void WifiWpaNewStaProcess(WifiDriverData *drv, WifiNewStaInfo *staInfo) +{ + WifiNewStaInfo *copyStaInfo = NULL; + uint8_t *ie = NULL; + uint8_t *macAddr = NULL; + int ret = 0; + + copyStaInfo = (WifiNewStaInfo *)os_zalloc(sizeof(WifiNewStaInfo)); + if (copyStaInfo == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return; + } + ie = (uint8_t *)os_zalloc(staInfo->ieLen); + if (ie == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + goto failed3; + } + ret = memcpy_s(ie, staInfo->ieLen, staInfo->ie, staInfo->ieLen); + if (ret != SUCC) { + goto failed2; + } + macAddr = (uint8_t *)os_zalloc(ETH_ADDR_LEN); + if (macAddr == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + goto failed2; + } + ret = memcpy_s(macAddr, ETH_ADDR_LEN, staInfo->macAddr, ETH_ADDR_LEN); + if (ret != SUCC) { + goto failed1; + } + + copyStaInfo->reassoc = staInfo->reassoc; + copyStaInfo->ie = ie; + copyStaInfo->ieLen = staInfo->ieLen; + copyStaInfo->macAddr = macAddr; + eloop_register_timeout(0, 0, WifiWpaEventNewStaProcess, drv, copyStaInfo); + return; + +failed1: + WpaMemFree(macAddr); +failed2: + WpaMemFree(ie); +failed3: + WpaMemFree(copyStaInfo); +} + +void WifiWpaDelStaProcess(WifiDriverData *drv, uint8_t *addr) +{ + uint8_t *copyAddr = NULL; + int ret = 0; + + copyAddr = (uint8_t *)os_zalloc(sizeof(ETH_ADDR_LEN)); + if (copyAddr == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return; + } + ret = memcpy_s(copyAddr, ETH_ADDR_LEN, addr, ETH_ADDR_LEN); + if (ret != SUCC) { + WpaMemFree(copyAddr); + return; + } + eloop_register_timeout(0, 0, WifiWpaEventDelStaProcess, drv, copyAddr); +} + +void WifiWpaRxMgmtProcess(WifiDriverData *drv, WifiRxMgmt *rxMgmt) +{ + WifiRxMgmt *copyRxMgmt = NULL; + uint8_t *buf = NULL; + int ret = 0; + + copyRxMgmt = (WifiRxMgmt *)os_zalloc(sizeof(WifiRxMgmt)); + if (copyRxMgmt == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return; + } + buf = (uint8_t *)os_zalloc(rxMgmt->len); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + WpaMemFree(copyRxMgmt); + return; + } + ret = memcpy_s(buf, rxMgmt->len, rxMgmt->buf, rxMgmt->len); + if (ret != SUCC) { + WpaMemFree(copyRxMgmt); + WpaMemFree(buf); + return; + } + copyRxMgmt->buf = buf; + copyRxMgmt->len = rxMgmt->len; + copyRxMgmt->sigMbm = rxMgmt->sigMbm; + copyRxMgmt->freq = rxMgmt->freq; + eloop_register_timeout(0, 0, WifiWpaEventRxMgmtProcess, drv, copyRxMgmt); +} + +void WifiWpaTxStatusProcess(WifiDriverData *drv, WifiTxStatus *txStatus) +{ + WifiTxStatus *copyTxStatus = NULL; + uint8_t *buf = NULL; + int ret = 0; + + copyTxStatus = (WifiTxStatus *)os_zalloc(sizeof(WifiTxStatus)); + if (copyTxStatus == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return; + } + buf = (uint8_t *)os_zalloc(txStatus->len); + if (buf == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + WpaMemFree(copyTxStatus); + return; + } + ret = memcpy_s(buf, txStatus->len, txStatus->buf, txStatus->len); + if (ret != SUCC) { + WpaMemFree(copyTxStatus); + WpaMemFree(buf); + return; + } + copyTxStatus->buf = buf; + copyTxStatus->ack = txStatus->ack; + copyTxStatus->len = txStatus->len; + eloop_register_timeout(0, 0, WifiWpaEventTxStatusProcess, drv, copyTxStatus); +} + +void WifiWpaScanDoneProcess(WifiDriverData *drv, uint32_t *status) +{ + uint32_t *copyStatus = NULL; + int ret = 0; + + copyStatus = (uint32_t *)os_zalloc(sizeof(uint32_t)); + if (copyStatus == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return; + } + ret = memcpy_s(copyStatus, sizeof(uint32_t), status, sizeof(uint32_t)); + if (ret != SUCC) { + WpaMemFree(copyStatus); + return; + } + eloop_register_timeout(0, 0, WifiWpaEventScanDoneProcess, drv, copyStatus); +} + +void WifiWpaScanResultProcess(WifiDriverData *drv, WifiScanResult *scanResult) +{ + WifiScanResult *copyScanResult = NULL; + uint8_t *ie = NULL; + uint8_t *beaconIe = NULL; + uint8_t *bssid = NULL; + int ret = 0; + + copyScanResult = (WifiScanResult *)os_zalloc(sizeof(WifiScanResult)); + if (copyScanResult == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return; + } + bssid = (uint8_t *)os_zalloc(ETH_ADDR_LEN); + if (bssid == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + goto failed4; + } + ret = memcpy_s(bssid, ETH_ADDR_LEN, scanResult->bssid, ETH_ADDR_LEN); + if (ret != SUCC) { + goto failed3; + } + + ie = (uint8_t *)os_zalloc(scanResult->ieLen); + if (ie == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + goto failed3; + } + ret = memcpy_s(ie, scanResult->ieLen, scanResult->ie, scanResult->ieLen); + if (ret != SUCC) { + goto failed2; + } + + beaconIe = (uint8_t *)os_zalloc(scanResult->beaconIeLen); + if (beaconIe == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + goto failed2; + } + ret = memcpy_s(beaconIe, scanResult->beaconIeLen, scanResult->beaconIe, scanResult->beaconIeLen); + if (ret != SUCC) { + goto failed1; + } + + copyScanResult->flags = scanResult->flags; + copyScanResult->freq = scanResult->freq; + copyScanResult->caps = scanResult->caps; + copyScanResult->beaconInt = scanResult->beaconInt; + copyScanResult->level = scanResult->level; + copyScanResult->ieLen = scanResult->ieLen; + copyScanResult->beaconIeLen = scanResult->beaconIeLen; + copyScanResult->bssid = bssid; + copyScanResult->ie = ie; + copyScanResult->beaconIe = beaconIe; + eloop_register_timeout(0, 0, WifiWpaEventScanResultProcess, drv, copyScanResult); + return; + +failed1: + WpaMemFree(beaconIe); +failed2: + WpaMemFree(ie); +failed3: + WpaMemFree(bssid); +failed4: + WpaMemFree(copyScanResult); +} + +void WifiWpaConnectResultProcess(WifiDriverData *drv, WifiConnectResult *result) +{ + WifiConnectResult *copyResult = NULL; + uint8_t *reqIe = NULL; + uint8_t *respIe = NULL; + uint8_t *bssid = NULL; + int ret = 0; + + copyResult = (WifiConnectResult *)os_zalloc(sizeof(WifiConnectResult)); + if (copyResult == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return; + } + bssid = (uint8_t *)os_zalloc(ETH_ADDR_LEN); + if (bssid == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + goto failed4; + } + ret = memcpy_s(bssid, ETH_ADDR_LEN, result->bssid, ETH_ADDR_LEN); + if (ret != SUCC) { + goto failed3; + } + + reqIe = (uint8_t *)os_zalloc(result->reqIeLen); + if (reqIe == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + goto failed3; + } + ret = memcpy_s(reqIe, result->reqIeLen, result->reqIe, result->reqIeLen); + if (ret != SUCC) { + goto failed2; + } + + respIe = (uint8_t *)os_zalloc(result->respIeLen); + if (respIe == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + goto failed2; + } + ret = memcpy_s(respIe, result->respIeLen, result->respIe, result->respIeLen); + if (ret != SUCC) { + goto failed1; + } + + copyResult->status = result->status; + copyResult->freq = result->freq; + copyResult->reqIeLen = result->reqIeLen; + copyResult->respIeLen = result->respIeLen; + copyResult->reqIe = reqIe; + copyResult->respIe = respIe; + copyResult->bssid = bssid; + eloop_register_timeout(0, 0, WifiWpaEventConnectResultProcess, drv, copyResult); + return; + +failed1: + WpaMemFree(respIe); +failed2: + WpaMemFree(reqIe); +failed3: + WpaMemFree(bssid); +failed4: + WpaMemFree(copyResult); +} + +void WifiWpaDisconnectProcess(WifiDriverData *drv, WifiDisconnect *result) +{ + WifiDisconnect *copyResult = NULL; + uint8_t *ie = NULL; + int32_t ret = 0; + + copyResult = (WifiDisconnect *)os_zalloc(sizeof(WifiDisconnect)); + if (copyResult == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return; + } + ret = AllocAndCopyIe(ie, result->ieLen, result->ie); + if (ret != SUCC) { + WpaMemFree(copyResult); + return; + } + copyResult->ie = ie; + copyResult->ieLen = result->ieLen; + copyResult->reason = result->reason; + eloop_register_timeout(0, 0, WifiWpaEventDisconnectProcess, drv, copyResult); +} + +void WifiWpaDriverEapolRecvProcess(WifiDriverData *drv, void *data) +{ + eloop_register_timeout(0, 0, WifiWpaDriverEventEapolRecvProcess, drv, data); +} + +void WifiWpaRemainOnChannelProcess(WifiDriverData *drv, WifiOnChannel *result) +{ + WifiOnChannel *copyResult = NULL; + + copyResult = (WifiOnChannel *)os_zalloc(sizeof(WifiOnChannel)); + if (copyResult == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return; + } + copyResult->freq = result->freq; + copyResult->duration = result->duration; + eloop_register_timeout(0, 0, WifiWpaEventRemainOnChannelProcess, drv, copyResult); +} + +void WifiWpaCancelRemainOnChannelProcess(WifiDriverData *drv, WifiOnChannel *result) +{ + WifiOnChannel *copyResult = NULL; + + copyResult = (WifiOnChannel *)os_zalloc(sizeof(WifiOnChannel)); + if (copyResult == NULL) { + wpa_printf(MSG_ERROR, "%s fail: os_zalloc fail!", __func__); + return; + } + copyResult->freq = result->freq; + eloop_register_timeout(0, 0, WifiWpaEventCancelRemainOnChannelProcess, drv, copyResult); +} + +#ifdef __cplusplus +#if __cplusplus +} +#endif +#endif diff --git a/wpa_supplicant-2.9_standard/src/eap_common/eap_defs.h b/wpa_supplicant-2.9_standard/src/eap_common/eap_defs.h index 70999c4e3e1757c541d5d9ec220261958be1ea40..3346ec53b9a66cf30d6cef5c5bf483a90fcfa19f 100644 --- a/wpa_supplicant-2.9_standard/src/eap_common/eap_defs.h +++ b/wpa_supplicant-2.9_standard/src/eap_common/eap_defs.h @@ -72,7 +72,7 @@ enum eap_type { EAP_TYPE_MD5 = 4, /* RFC 3748 */ EAP_TYPE_OTP = 5 /* RFC 3748 */, EAP_TYPE_GTC = 6, /* RFC 3748 */ - EAP_TYPE_TLS = 13 /* RFC 2716 */, + EAP_TYPE_TLS = 13 /* RFC 5216 */, EAP_TYPE_LEAP = 17 /* Cisco proprietary */, EAP_TYPE_SIM = 18 /* RFC 4186 */, EAP_TYPE_TTLS = 21 /* RFC 5281 */, diff --git a/wpa_supplicant-2.9_standard/src/eap_common/eap_pwd_common.c b/wpa_supplicant-2.9_standard/src/eap_common/eap_pwd_common.c index ff22b29b087a9d1f31093baf053072e5f7d679d0..ff8ad8d72a9ddcc887f3c8cd90ed36240e9286c8 100644 --- a/wpa_supplicant-2.9_standard/src/eap_common/eap_pwd_common.c +++ b/wpa_supplicant-2.9_standard/src/eap_common/eap_pwd_common.c @@ -275,7 +275,7 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, crypto_bignum_sub(prime, y, y) < 0 || crypto_bignum_to_bin(y, x_y + MAX_ECC_PRIME_LEN, MAX_ECC_PRIME_LEN, primebytelen) < 0) { - wpa_printf(MSG_DEBUG, "SAE: Could not solve y"); + wpa_printf(MSG_DEBUG, "EAP-pwd: Could not solve y"); goto fail; } @@ -356,9 +356,19 @@ int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k, return -1; } eap_pwd_h_update(hash, (const u8 *) ciphersuite, sizeof(u32)); - crypto_bignum_to_bin(peer_scalar, cruft, order_len, order_len); + if (crypto_bignum_to_bin(peer_scalar, cruft, order_len, + order_len) < 0) { + os_free(cruft); + return -1; + } + eap_pwd_h_update(hash, cruft, order_len); - crypto_bignum_to_bin(server_scalar, cruft, order_len, order_len); + if (crypto_bignum_to_bin(server_scalar, cruft, order_len, + order_len) < 0) { + os_free(cruft); + return -1; + } + eap_pwd_h_update(hash, cruft, order_len); eap_pwd_h_final(hash, &session_id[1]); @@ -368,7 +378,12 @@ int compute_keys(EAP_PWD_group *grp, const struct crypto_bignum *k, os_free(cruft); return -1; } - crypto_bignum_to_bin(k, cruft, prime_len, prime_len); + + if (crypto_bignum_to_bin(k, cruft, prime_len, prime_len) < 0) { + os_free(cruft); + return -1; + } + eap_pwd_h_update(hash, cruft, prime_len); os_free(cruft); eap_pwd_h_update(hash, confirm_peer, SHA256_MAC_LEN); diff --git a/wpa_supplicant-2.9_standard/src/eap_common/eap_sake_common.c b/wpa_supplicant-2.9_standard/src/eap_common/eap_sake_common.c index 8ee9e32e1e48846787d478e442fe6740c08249a5..a4256e2a76ed909b4f843502f098bd4f80267580 100644 --- a/wpa_supplicant-2.9_standard/src/eap_common/eap_sake_common.c +++ b/wpa_supplicant-2.9_standard/src/eap_common/eap_sake_common.c @@ -164,26 +164,33 @@ int eap_sake_parse_attributes(const u8 *buf, size_t len, os_memset(attr, 0, sizeof(*attr)); while (pos < end) { + u8 attr_id, attr_len; + if (end - pos < 2) { wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute"); return -1; } - if (pos[1] < 2) { - wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute " - "length (%d)", pos[1]); + attr_id = *pos++; + attr_len = *pos++; + /* Attribute length value includes the Type and Length fields */ + if (attr_len < 2) { + wpa_printf(MSG_DEBUG, + "EAP-SAKE: Invalid attribute length (%d)", + attr_len); return -1; } + attr_len -= 2; - if (pos + pos[1] > end) { + if (attr_len > end - pos) { wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow"); return -1; } - if (eap_sake_parse_add_attr(attr, pos[0], pos[1] - 2, pos + 2)) + if (eap_sake_parse_add_attr(attr, attr_id, attr_len, pos)) return -1; - pos += pos[1]; + pos += attr_len; } return 0; diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap.c index a73e8b6885a9666e9148c161890dea5624dacf90..5d77c15234ae036fecdb34b8d1f41a675b97a71e 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap.c @@ -267,6 +267,7 @@ SM_STATE(EAP, INITIALIZE) sm->reauthInit = false; sm->erp_seq = (u32) -1; sm->use_machine_cred = 0; + sm->eap_fast_mschapv2 = false; } @@ -1702,6 +1703,7 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted) struct wpabuf *resp; const u8 *identity; size_t identity_len; + struct wpabuf *privacy_identity = NULL; if (config == NULL) { wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration " @@ -1724,6 +1726,30 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted) identity_len = config->machine_identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity", identity, identity_len); + } else if (config->imsi_privacy_cert && config->identity && + config->identity_len > 0) { + const u8 *pos = config->identity; + const u8 *end = config->identity + config->identity_len; + + privacy_identity = wpabuf_alloc(9 + config->identity_len); + if (!privacy_identity) + return NULL; + + /* Include method prefix */ + if (*pos == '0' || *pos == '1' || *pos == '6') + wpabuf_put_u8(privacy_identity, *pos); + wpabuf_put_str(privacy_identity, "anonymous"); + + /* Include realm */ + while (pos < end && *pos != '@') + pos++; + wpabuf_put_data(privacy_identity, pos, end - pos); + + identity = wpabuf_head(privacy_identity); + identity_len = wpabuf_len(privacy_identity); + wpa_hexdump_ascii(MSG_DEBUG, + "EAP: using IMSI privacy anonymous identity", + identity, identity_len); } else { identity = config->identity; identity_len = config->identity_len; @@ -1761,6 +1787,12 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted) wpabuf_put_data(resp, identity, identity_len); + os_free(sm->identity); + sm->identity = os_memdup(identity, identity_len); + sm->identity_len = identity_len; + + wpabuf_free(privacy_identity); + return resp; } @@ -2175,6 +2207,11 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev, eap_notify_status(sm, "remote TLS alert", data->alert.description); break; + case TLS_UNSAFE_RENEGOTIATION_DISABLED: + wpa_printf(MSG_INFO, + "TLS handshake failed due to the server not supporting safe renegotiation (RFC 5746); phase1 parameter allow_unsafe_renegotiation=1 can be used to work around this"); + eap_notify_status(sm, "unsafe server renegotiation", "failure"); + break; } os_free(hash_hex); @@ -2271,6 +2308,7 @@ void eap_peer_sm_deinit(struct eap_sm *sm) sm->ssl_ctx = NULL; } eap_peer_erp_free_keys(sm); + os_free(sm->identity); os_free(sm); sm = NULL; wpa_printf(MSG_INFO, "Leave eap_peer_sm_deinit"); diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_aka.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_aka.c index 8c475f13f162a9b5f72148bebe68b4f08b2308c3..72d4ee50571060447ea07f8fafa7b397b6873a80 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_aka.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_aka.c @@ -9,6 +9,7 @@ #include "includes.h" #include "common.h" +#include "utils/base64.h" #include "pcsc_funcs.h" #include "crypto/crypto.h" #include "crypto/sha1.h" @@ -40,8 +41,8 @@ struct eap_aka_data { size_t reauth_id_len; int reauth; unsigned int counter, counter_too_small; - u8 *last_eap_identity; - size_t last_eap_identity_len; + u8 *mk_identity; + size_t mk_identity_len; enum { CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE } state; @@ -58,6 +59,7 @@ struct eap_aka_data { u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX]; size_t last_kdf_count; int error_code; + struct crypto_rsa_key *imsi_privacy_key; }; @@ -101,6 +103,25 @@ static void * eap_aka_init(struct eap_sm *sm) data->eap_method = EAP_TYPE_AKA; + if (config && config->imsi_privacy_cert) { +#ifdef CRYPTO_RSA_OAEP_SHA256 + data->imsi_privacy_key = crypto_rsa_key_read( + config->imsi_privacy_cert, false); + if (!data->imsi_privacy_key) { + wpa_printf(MSG_ERROR, + "EAP-AKA: Failed to read/parse IMSI privacy certificate %s", + config->imsi_privacy_cert); + os_free(data); + return NULL; + } +#else /* CRYPTO_RSA_OAEP_SHA256 */ + wpa_printf(MSG_ERROR, + "EAP-AKA: No support for imsi_privacy_cert in the build"); + os_free(data); + return NULL; +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + } + /* Zero is a valid error code, so we need to initialize */ data->error_code = NO_EAP_METHOD_ERROR; @@ -119,6 +140,13 @@ static void * eap_aka_init(struct eap_sm *sm) } } + if (sm->identity) { + /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY + * is not used. */ + data->mk_identity = os_memdup(sm->identity, sm->identity_len); + data->mk_identity_len = sm->identity_len; + } + return data; } @@ -156,10 +184,13 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv) if (data) { os_free(data->pseudonym); os_free(data->reauth_id); - os_free(data->last_eap_identity); + os_free(data->mk_identity); wpabuf_free(data->id_msgs); os_free(data->network_name); eap_aka_clear_keys(data, 0); +#ifdef CRYPTO_RSA_OAEP_SHA256 + crypto_rsa_key_free(data->imsi_privacy_key); +#endif /* CRYPTO_RSA_OAEP_SHA256 */ os_free(data); } } @@ -349,7 +380,6 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data) #define CLEAR_PSEUDONYM 0x01 #define CLEAR_REAUTH_ID 0x02 -#define CLEAR_EAP_ID 0x04 static void eap_aka_clear_identities(struct eap_sm *sm, struct eap_aka_data *data, int id) @@ -368,12 +398,6 @@ static void eap_aka_clear_identities(struct eap_sm *sm, data->reauth_id = NULL; data->reauth_id_len = 0; } - if ((id & CLEAR_EAP_ID) && data->last_eap_identity) { - wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id"); - os_free(data->last_eap_identity); - data->last_eap_identity = NULL; - data->last_eap_identity_len = 0; - } } @@ -617,6 +641,55 @@ static struct wpabuf * eap_aka_synchronization_failure( } +#ifdef CRYPTO_RSA_OAEP_SHA256 +static struct wpabuf * +eap_aka_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key, + const u8 *identity, size_t identity_len, + const char *attr) +{ + struct wpabuf *imsi_buf, *enc; + char *b64; + size_t b64_len, len; + + wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypt permanent identity", + identity, identity_len); + + imsi_buf = wpabuf_alloc_copy(identity, identity_len); + if (!imsi_buf) + return NULL; + enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf); + wpabuf_free(imsi_buf); + if (!enc) + return NULL; + + b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len); + wpabuf_free(enc); + if (!b64) + return NULL; + + len = 1 + b64_len; + if (attr) + len += 1 + os_strlen(attr); + enc = wpabuf_alloc(len); + if (!enc) { + os_free(b64); + return NULL; + } + wpabuf_put_u8(enc, '\0'); + wpabuf_put_data(enc, b64, b64_len); + os_free(b64); + if (attr) { + wpabuf_put_u8(enc, ','); + wpabuf_put_str(enc, attr); + } + wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Encrypted permanent identity", + wpabuf_head(enc), wpabuf_len(enc)); + + return enc; +} +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + + static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, struct eap_aka_data *data, u8 id, @@ -625,6 +698,9 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, const u8 *identity = NULL; size_t identity_len = 0; struct eap_sim_msg *msg; + struct wpabuf *enc_identity = NULL; + struct eap_peer_config *config = NULL; + bool use_imsi_identity = false; data->reauth = 0; if (id_req == ANY_ID && data->reauth_id) { @@ -648,10 +724,38 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, data->pseudonym_len)) ids &= ~CLEAR_PSEUDONYM; eap_aka_clear_identities(sm, data, ids); + + config = eap_get_config(sm); + if (config && config->imsi_identity) + use_imsi_identity = true; + } +#ifdef CRYPTO_RSA_OAEP_SHA256 + if (identity && data->imsi_privacy_key) { + const char *attr = NULL; + + config = eap_get_config(sm); + if (config) + attr = config->imsi_privacy_attr; + enc_identity = eap_aka_encrypt_identity( + data->imsi_privacy_key, + identity, identity_len, attr); + if (!enc_identity) { + wpa_printf(MSG_INFO, + "EAP-AKA: Failed to encrypt permanent identity"); + return eap_aka_client_error( + data, id, + EAP_AKA_UNABLE_TO_PROCESS_PACKET); + } + /* Use the real identity, not the encrypted one, in MK + * derivation. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(identity, identity_len); + data->mk_identity_len = identity_len; + identity = wpabuf_head(enc_identity); + identity_len = wpabuf_len(enc_identity); } +#endif /* CRYPTO_RSA_OAEP_SHA256 */ } - if (id_req != NO_ID_REQ) - eap_aka_clear_identities(sm, data, CLEAR_EAP_ID); wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id); msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, @@ -662,7 +766,24 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, identity, identity_len); eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len, identity, identity_len); + if (use_imsi_identity && config && config->imsi_identity) { + /* Use the IMSI identity override, i.e., the not + * encrypted one, in MK derivation, when using + * externally encrypted identity in configuration. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup( + config->imsi_identity, + config->imsi_identity_len); + data->mk_identity_len = config->imsi_identity_len; + } else if (!enc_identity) { + /* Use the last AT_IDENTITY value as the identity in + * MK derivation. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(identity, identity_len); + data->mk_identity_len = identity_len; + } } + wpabuf_free(enc_identity); return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0); } @@ -1050,25 +1171,9 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm, data->network_name_len); } #endif /* EAP_AKA_PRIME */ - if (data->last_eap_identity) { - identity = data->last_eap_identity; - identity_len = data->last_eap_identity_len; - } else if (data->pseudonym && - !eap_sim_anonymous_username(data->pseudonym, - data->pseudonym_len)) { - identity = data->pseudonym; - identity_len = data->pseudonym_len; - } else { - struct eap_peer_config *config; - - config = eap_get_config(sm); - if (config && config->imsi_identity) { - identity = config->imsi_identity; - identity_len = config->imsi_identity_len; - } else { - identity = eap_get_config_identity(sm, &identity_len); - } - } + + identity = data->mk_identity; + identity_len = data->mk_identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK " "derivation", identity, identity_len); if (data->eap_method == EAP_TYPE_AKA_PRIME) { @@ -1097,7 +1202,7 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm, * other words, if no new identities are received, full * authentication will be used on next reauthentication (using * pseudonym identity or permanent identity). */ - eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID); if (attr->encr_data) { u8 *decrypted; @@ -1307,14 +1412,8 @@ static struct wpabuf * eap_aka_process_reauthentication( /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current * reauth_id must not be used to start a new reauthentication. - * However, since it was used in the last EAP-Response-Identity - * packet, it has to saved for the following fullauth to be - * used in MK derivation. */ - os_free(data->last_eap_identity); - data->last_eap_identity = data->reauth_id; - data->last_eap_identity_len = data->reauth_id_len; - data->reauth_id = NULL; - data->reauth_id_len = 0; + */ + eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID); res = eap_aka_response_reauth(data, id, 1, eattr.nonce_s); os_free(decrypted); @@ -1339,7 +1438,7 @@ static struct wpabuf * eap_aka_process_reauthentication( data->nonce_s, data->mk, data->msk, data->emsk); } - eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID); eap_aka_learn_ids(sm, data, &eattr); if (data->result_ind && attr->result_ind) @@ -1355,8 +1454,7 @@ static struct wpabuf * eap_aka_process_reauthentication( if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) { wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of " "fast reauths performed - force fullauth"); - eap_aka_clear_identities(sm, data, - CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID); } os_free(decrypted); return eap_aka_response_reauth(data, id, 0, data->nonce_s); @@ -1472,7 +1570,10 @@ static bool eap_aka_has_reauth_data(struct eap_sm *sm, void *priv) static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv) { struct eap_aka_data *data = priv; - eap_aka_clear_identities(sm, data, CLEAR_EAP_ID); + + os_free(data->mk_identity); + data->mk_identity = NULL; + data->mk_identity_len = 0; data->prev_id = -1; wpabuf_free(data->id_msgs); data->id_msgs = NULL; @@ -1485,6 +1586,15 @@ static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv) static void * eap_aka_init_for_reauth(struct eap_sm *sm, void *priv) { struct eap_aka_data *data = priv; + + if (sm->identity) { + /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY + * is not used. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(sm->identity, sm->identity_len); + data->mk_identity_len = sm->identity_len; + } + data->num_id_req = 0; data->num_notification = 0; eap_aka_state(data, CONTINUE); diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_config.h b/wpa_supplicant-2.9_standard/src/eap_peer/eap_config.h index 1321541549fc173ec11656f4506262ae29deacef..f6a97cd06a91d96beffa3ee9d3a4b2c1e1995e28 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_config.h +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_config.h @@ -103,24 +103,6 @@ struct eap_peer_cert_config { */ char *private_key_passwd; - /** - * dh_file - File path to DH/DSA parameters file (in PEM format) - * - * This is an optional configuration file for setting parameters for an - * ephemeral DH key exchange. In most cases, the default RSA - * authentication does not use this configuration. However, it is - * possible setup RSA to use ephemeral DH key exchange. In addition, - * ciphers with DSA keys always use ephemeral DH keys. This can be used - * to achieve forward secrecy. If the file is in DSA parameters format, - * it will be automatically converted into DH params. Full path to the - * file should be used since working directory may change when - * wpa_supplicant is run in the background. - * - * Alternatively, a named configuration blob can be used by setting - * this to blob://blob_name. - */ - char *dh_file; - /** * subject_match - Constraint for server certificate subject * @@ -335,6 +317,26 @@ struct eap_peer_config { u8 *imsi_identity; size_t imsi_identity_len; + /** + * imsi_privacy_cert - IMSI privacy certificate + * + * This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent + * identity (IMSI) to improve privacy. The referenced PEM-encoded + * X.509v3 certificate needs to include a 2048-bit RSA public key and + * this is from the operator who authenticates the SIM/USIM. + */ + char *imsi_privacy_cert; + + /** + * imsi_privacy_attr - IMSI privacy attribute + * + * This field is used to help the EAP-SIM/AKA/AKA' server to identify + * the used certificate (and as such, the matching private key). This + * is set to an attribute in name=value format if the operator needs + * this information. + */ + char *imsi_privacy_attr; + /** * machine_identity - EAP Identity for machine credential * diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_fast.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_fast.c index b12cfee31ad8ec9862c99f473ecbf1359fecc185..d7677ca97d60fdf0970e1bfdd66e660eaa960188 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_fast.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_fast.c @@ -354,6 +354,7 @@ static int eap_fast_init_phase2_method(struct eap_sm *sm, sm->auth_challenge = data->key_block_p->server_challenge; sm->peer_challenge = data->key_block_p->client_challenge; } + sm->eap_fast_mschapv2 = true; sm->init_phase2 = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; @@ -693,18 +694,7 @@ static int eap_fast_get_phase2_key(struct eap_sm *sm, if (key_len > isk_len) key_len = isk_len; - if (key_len == 32 && - data->phase2_method->vendor == EAP_VENDOR_IETF && - data->phase2_method->method == EAP_TYPE_MSCHAPV2) { - /* - * EAP-FAST uses reverse order for MS-MPPE keys when deriving - * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct - * ISK for EAP-FAST cryptobinding. - */ - os_memcpy(isk, key + 16, 16); - os_memcpy(isk + 16, key, 16); - } else - os_memcpy(isk, key, key_len); + os_memcpy(isk, key, key_len); os_free(key); return 0; diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_i.h b/wpa_supplicant-2.9_standard/src/eap_peer/eap_i.h index f43891e39d1cfd52e5be7beefebc68860010b22f..21681658d68875b8db4ca500d1d6b0376fe77908 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_i.h +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_i.h @@ -365,6 +365,11 @@ struct eap_sm { /* Optional challenges generated in Phase 1 (EAP-FAST) */ u8 *peer_challenge, *auth_challenge; + /* Whether to use the EAP-FAST-MSCHAPv2 instantiation of EAP-MSCHAPv2. + * That variant is otherwise identical, but it generates the MSK using + * MS-MPPE keys in reverse order. */ + bool eap_fast_mschapv2; + int num_rounds; int num_rounds_short; int force_disabled; @@ -385,6 +390,10 @@ struct eap_sm { unsigned int use_machine_cred:1; struct dl_list erp_keys; /* struct eap_erp_key */ + + /* Identity used in EAP-Response/Identity */ + u8 *identity; + size_t identity_len; }; const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len); diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_mschapv2.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_mschapv2.c index 8ad4d18b3535393b6f893452bbe0aa08abba208d..e84ae16b47be90a6b89dc89a64b4e03b7669d4fe 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_mschapv2.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_mschapv2.c @@ -108,6 +108,12 @@ static void * eap_mschapv2_init(struct eap_sm *sm) if (data == NULL) return NULL; + wpa_printf(MSG_DEBUG, "EAP-%sMSCHAPv2 init%s%s", + sm->eap_fast_mschapv2 ? "FAST-" : "", + sm->peer_challenge && sm->auth_challenge ? + " with preset challenges" : "", + sm->init_phase2 ? " for Phase 2" : ""); + if (sm->peer_challenge) { data->peer_challenge = os_memdup(sm->peer_challenge, MSCHAPV2_CHAL_LEN); @@ -844,6 +850,7 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) struct eap_mschapv2_data *data = priv; u8 *key; int key_len; + bool first_is_send; if (!data->master_key_valid || !data->success) return NULL; @@ -854,12 +861,25 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) if (key == NULL) return NULL; - /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e., - * peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */ - if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, - 0) < 0 || + /* + * [MS-CHAP], 3.1.5.1 (Master Session Key (MSK) Derivation + * MSK = MasterReceiveKey + MasterSendKey + 32 bytes zeros (padding) + * On a Peer: + * MS-MPPE-Recv-Key = MasterSendKey + * MS-MPPE-Send-Key = MasterReceiveKey + * + * RFC 5422, 3.2.3 (Authenticating Using EAP-FAST-MSCHAPv2) + * MSK = MasterSendKey + MasterReceiveKey + * (i.e., reverse order and no padding) + * + * On Peer, EAP-MSCHAPv2 starts with Send key and EAP-FAST-MSCHAPv2 + * starts with Receive key. + */ + first_is_send = !sm->eap_fast_mschapv2; + if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, + first_is_send, 0) < 0 || get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, - MSCHAPV2_KEY_LEN, 0, 0) < 0) { + MSCHAPV2_KEY_LEN, !first_is_send, 0) < 0) { os_free(key); return NULL; } diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_peap.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_peap.c index 6080697199a62eb2859153c6443e563c75454f08..b1d0c314ccfb2a3ca8ceccc5db8b385fa6c48c65 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_peap.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_peap.c @@ -700,7 +700,7 @@ static int eap_peap_phase2_request(struct eap_sm *sm, } } #endif /* EAP_TNC */ - /* fall through */ + __attribute__((fallthrough)); default: vendor = EAP_VENDOR_IETF; method = *pos; diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_pwd.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_pwd.c index 605feb24f8512a953377425e4dd0d38aecf004cf..97f4dd216f5ece0eea2a54a85becaa00f0bb0f34 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_pwd.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_pwd.c @@ -666,7 +666,10 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, * sufficiently smaller than the prime or order might need pre-pending * with zeros. */ - crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len); + if (crypto_bignum_to_bin(data->my_scalar, scalar, order_len, + order_len) < 0) + goto fin; + if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element, element + prime_len) != 0) { wpa_printf(MSG_INFO, "EAP-PWD (peer): point assignment fail"); @@ -742,7 +745,9 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, * zero the memory each time because this is mod prime math and some * value may start with a few zeros and the previous one did not. */ - crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); + if (crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, prime_len); /* server element: x, y */ @@ -755,7 +760,10 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, eap_pwd_h_update(hash, cruft, prime_len * 2); /* server scalar */ - crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len); + if (crypto_bignum_to_bin(data->server_scalar, cruft, order_len, + order_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, order_len); /* my element: x, y */ @@ -768,7 +776,10 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, eap_pwd_h_update(hash, cruft, prime_len * 2); /* my scalar */ - crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); + if (crypto_bignum_to_bin(data->my_scalar, cruft, order_len, + order_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, order_len); /* the ciphersuite */ @@ -796,7 +807,9 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, goto fin; /* k */ - crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); + if (crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, prime_len); /* my element */ @@ -809,7 +822,10 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, eap_pwd_h_update(hash, cruft, prime_len * 2); /* my scalar */ - crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); + if (crypto_bignum_to_bin(data->my_scalar, cruft, order_len, + order_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, order_len); /* server element: x, y */ @@ -822,7 +838,10 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, eap_pwd_h_update(hash, cruft, prime_len * 2); /* server scalar */ - crypto_bignum_to_bin(data->server_scalar, cruft, order_len, order_len); + if (crypto_bignum_to_bin(data->server_scalar, cruft, order_len, + order_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, order_len); /* the ciphersuite */ diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_sim.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_sim.c index 09866277d6a85720a7aa812500e7c6c911a15a04..b5e3240232727096202fd8721e9c9e9e0d0f0649 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_sim.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_sim.c @@ -9,7 +9,9 @@ #include "includes.h" #include "common.h" +#include "utils/base64.h" #include "pcsc_funcs.h" +#include "crypto/crypto.h" #include "crypto/milenage.h" #include "crypto/random.h" #include "eap_peer/eap_i.h" @@ -41,14 +43,15 @@ struct eap_sim_data { size_t reauth_id_len; int reauth; unsigned int counter, counter_too_small; - u8 *last_eap_identity; - size_t last_eap_identity_len; + u8 *mk_identity; + size_t mk_identity_len; enum { CONTINUE, START_DONE, RESULT_SUCCESS, SUCCESS, FAILURE } state; int result_ind, use_result_ind; int use_pseudonym; int error_code; + struct crypto_rsa_key *imsi_privacy_key; }; @@ -98,6 +101,25 @@ static void * eap_sim_init(struct eap_sm *sm) return NULL; } + if (config && config->imsi_privacy_cert) { +#ifdef CRYPTO_RSA_OAEP_SHA256 + data->imsi_privacy_key = crypto_rsa_key_read( + config->imsi_privacy_cert, false); + if (!data->imsi_privacy_key) { + wpa_printf(MSG_ERROR, + "EAP-SIM: Failed to read/parse IMSI privacy certificate %s", + config->imsi_privacy_cert); + os_free(data); + return NULL; + } +#else /* CRYPTO_RSA_OAEP_SHA256 */ + wpa_printf(MSG_ERROR, + "EAP-SIM: No support for imsi_privacy_cert in the build"); + os_free(data); + return NULL; +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + } + /* Zero is a valid error code, so we need to initialize */ data->error_code = NO_EAP_METHOD_ERROR; @@ -111,6 +133,9 @@ static void * eap_sim_init(struct eap_sm *sm) "sim_min_num_chal configuration " "(%lu, expected 2 or 3)", (unsigned long) data->min_num_chal); +#ifdef CRYPTO_RSA_OAEP_SHA256 + crypto_rsa_key_free(data->imsi_privacy_key); +#endif /* CRYPTO_RSA_OAEP_SHA256 */ os_free(data); return NULL; } @@ -133,6 +158,13 @@ static void * eap_sim_init(struct eap_sm *sm) } } + if (sm->identity) { + /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY + * is not used. */ + data->mk_identity = os_memdup(sm->identity, sm->identity_len); + data->mk_identity_len = sm->identity_len; + } + eap_sim_state(data, CONTINUE); return data; @@ -160,8 +192,11 @@ static void eap_sim_deinit(struct eap_sm *sm, void *priv) os_free(data->ver_list); os_free(data->pseudonym); os_free(data->reauth_id); - os_free(data->last_eap_identity); + os_free(data->mk_identity); eap_sim_clear_keys(data, 0); +#ifdef CRYPTO_RSA_OAEP_SHA256 + crypto_rsa_key_free(data->imsi_privacy_key); +#endif /* CRYPTO_RSA_OAEP_SHA256 */ os_free(data); } } @@ -371,7 +406,6 @@ static int eap_sim_supported_ver(int version) #define CLEAR_PSEUDONYM 0x01 #define CLEAR_REAUTH_ID 0x02 -#define CLEAR_EAP_ID 0x04 static void eap_sim_clear_identities(struct eap_sm *sm, struct eap_sim_data *data, int id) @@ -390,12 +424,6 @@ static void eap_sim_clear_identities(struct eap_sm *sm, data->reauth_id = NULL; data->reauth_id_len = 0; } - if ((id & CLEAR_EAP_ID) && data->last_eap_identity) { - wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id"); - os_free(data->last_eap_identity); - data->last_eap_identity = NULL; - data->last_eap_identity_len = 0; - } } @@ -481,6 +509,55 @@ static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id, } +#ifdef CRYPTO_RSA_OAEP_SHA256 +static struct wpabuf * +eap_sim_encrypt_identity(struct crypto_rsa_key *imsi_privacy_key, + const u8 *identity, size_t identity_len, + const char *attr) +{ + struct wpabuf *imsi_buf, *enc; + char *b64; + size_t b64_len, len; + + wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypt permanent identity", + identity, identity_len); + + imsi_buf = wpabuf_alloc_copy(identity, identity_len); + if (!imsi_buf) + return NULL; + enc = crypto_rsa_oaep_sha256_encrypt(imsi_privacy_key, imsi_buf); + wpabuf_free(imsi_buf); + if (!enc) + return NULL; + + b64 = base64_encode_no_lf(wpabuf_head(enc), wpabuf_len(enc), &b64_len); + wpabuf_free(enc); + if (!b64) + return NULL; + + len = 1 + b64_len; + if (attr) + len += 1 + os_strlen(attr); + enc = wpabuf_alloc(len); + if (!enc) { + os_free(b64); + return NULL; + } + wpabuf_put_u8(enc, '\0'); + wpabuf_put_data(enc, b64, b64_len); + os_free(b64); + if (attr) { + wpabuf_put_u8(enc, ','); + wpabuf_put_str(enc, attr); + } + wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Encrypted permanent identity", + wpabuf_head(enc), wpabuf_len(enc)); + + return enc; +} +#endif /* CRYPTO_RSA_OAEP_SHA256 */ + + static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, struct eap_sim_data *data, u8 id, enum eap_sim_id_req id_req) @@ -489,6 +566,9 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, size_t identity_len = 0; struct eap_sim_msg *msg; struct wpabuf *resp; + struct wpabuf *enc_identity = NULL; + struct eap_peer_config *config = NULL; + bool use_imsi_identity = false; data->reauth = 0; if (id_req == ANY_ID && data->reauth_id) { @@ -512,10 +592,38 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, data->pseudonym_len)) ids &= ~CLEAR_PSEUDONYM; eap_sim_clear_identities(sm, data, ids); + + config = eap_get_config(sm); + if (config && config->imsi_identity) + use_imsi_identity = true; } +#ifdef CRYPTO_RSA_OAEP_SHA256 + if (identity && data->imsi_privacy_key) { + const char *attr = NULL; + + config = eap_get_config(sm); + if (config) + attr = config->imsi_privacy_attr; + enc_identity = eap_sim_encrypt_identity( + data->imsi_privacy_key, + identity, identity_len, attr); + if (!enc_identity) { + wpa_printf(MSG_INFO, + "EAP-SIM: Failed to encrypt permanent identity"); + return eap_sim_client_error( + data, id, + EAP_SIM_UNABLE_TO_PROCESS_PACKET); + } + /* Use the real identity, not the encrypted one, in MK + * derivation. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(identity, identity_len); + data->mk_identity_len = identity_len; + identity = wpabuf_head(enc_identity); + identity_len = wpabuf_len(enc_identity); + } +#endif /* CRYPTO_RSA_OAEP_SHA256 */ } - if (id_req != NO_ID_REQ) - eap_sim_clear_identities(sm, data, CLEAR_EAP_ID); wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id); msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, @@ -525,7 +633,24 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, identity, identity_len); eap_sim_msg_add(msg, EAP_SIM_AT_IDENTITY, identity_len, identity, identity_len); + if (use_imsi_identity && config && config->imsi_identity) { + /* Use the IMSI identity override, i.e., the not + * encrypted one, in MK derivation, when using + * externally encrypted identity in configuration. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup( + config->imsi_identity, + config->imsi_identity_len); + data->mk_identity_len = config->imsi_identity_len; + } else if (!enc_identity) { + /* Use the last AT_IDENTITY value as the identity in + * MK derivation. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(identity, identity_len); + data->mk_identity_len = identity_len; + } } + wpabuf_free(enc_identity); if (!data->reauth) { wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT", data->nonce_mt, EAP_SIM_NONCE_MT_LEN); @@ -785,25 +910,9 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, return eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET); } - if (data->last_eap_identity) { - identity = data->last_eap_identity; - identity_len = data->last_eap_identity_len; - } else if (data->pseudonym && - !eap_sim_anonymous_username(data->pseudonym, - data->pseudonym_len)) { - identity = data->pseudonym; - identity_len = data->pseudonym_len; - } else { - struct eap_peer_config *config; - - config = eap_get_config(sm); - if (config && config->imsi_identity) { - identity = config->imsi_identity; - identity_len = config->imsi_identity_len; - } else { - identity = eap_get_config_identity(sm, &identity_len); - } - } + + identity = data->mk_identity; + identity_len = data->mk_identity_len; wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK " "derivation", identity, identity_len); eap_sim_derive_mk(identity, identity_len, data->nonce_mt, @@ -829,7 +938,7 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, * other words, if no new reauth identity is received, full * authentication will be used on next reauthentication (using * pseudonym identity or permanent identity). */ - eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID); if (attr->encr_data) { u8 *decrypted; @@ -1039,14 +1148,8 @@ static struct wpabuf * eap_sim_process_reauthentication( /* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current * reauth_id must not be used to start a new reauthentication. - * However, since it was used in the last EAP-Response-Identity - * packet, it has to saved for the following fullauth to be - * used in MK derivation. */ - os_free(data->last_eap_identity); - data->last_eap_identity = data->reauth_id; - data->last_eap_identity_len = data->reauth_id_len; - data->reauth_id = NULL; - data->reauth_id_len = 0; + */ + eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID); res = eap_sim_response_reauth(data, id, 1, eattr.nonce_s); os_free(decrypted); @@ -1063,7 +1166,7 @@ static struct wpabuf * eap_sim_process_reauthentication( data->reauth_id, data->reauth_id_len, data->nonce_s, data->mk, data->msk, data->emsk); - eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID); eap_sim_learn_ids(sm, data, &eattr); if (data->result_ind && attr->result_ind) @@ -1079,8 +1182,7 @@ static struct wpabuf * eap_sim_process_reauthentication( if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) { wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of " "fast reauths performed - force fullauth"); - eap_sim_clear_identities(sm, data, - CLEAR_REAUTH_ID | CLEAR_EAP_ID); + eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID); } os_free(decrypted); return eap_sim_response_reauth(data, id, 0, data->nonce_s); @@ -1189,7 +1291,10 @@ static bool eap_sim_has_reauth_data(struct eap_sm *sm, void *priv) static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv) { struct eap_sim_data *data = priv; - eap_sim_clear_identities(sm, data, CLEAR_EAP_ID); + + os_free(data->mk_identity); + data->mk_identity = NULL; + data->mk_identity_len = 0; data->use_result_ind = 0; eap_sim_clear_keys(data, 1); } @@ -1204,6 +1309,15 @@ static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv) eap_sim_deinit(sm, data); return NULL; } + + if (sm->identity) { + /* Use the EAP-Response/Identity in MK derivation if AT_IDENTITY + * is not used. */ + os_free(data->mk_identity); + data->mk_identity = os_memdup(sm->identity, sm->identity_len); + data->mk_identity_len = sm->identity_len; + } + data->num_id_req = 0; data->num_notification = 0; eap_sim_state(data, CONTINUE); diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_teap.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_teap.c index bc7f6f4f5abe0ac5ad40966f5adce769bafa0cd4..ced7b164292cb4809fb2c958b3f8b28039c9260c 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_teap.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_teap.c @@ -319,6 +319,13 @@ static int eap_teap_init_phase2_method(struct eap_sm *sm, if (!data->phase2_method) return -1; + /* While RFC 7170 does not describe this, EAP-TEAP has been deployed + * with implementations that use the EAP-FAST-MSCHAPv2, instead of the + * EAP-MSCHAPv2, way of deriving the MSK for IMSK. Use that design here + * to interoperate. + */ + sm->eap_fast_mschapv2 = true; + sm->init_phase2 = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; @@ -1298,6 +1305,33 @@ static int eap_teap_process_decrypted(struct eap_sm *sm, goto done; } + if (tlv.crypto_binding) { + if (tlv.iresult != TEAP_STATUS_SUCCESS && + tlv.result != TEAP_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, + "EAP-TEAP: Unexpected Crypto-Binding TLV without Result TLV or Intermediate-Result TLV indicating success"); + failed = 1; + error = TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED; + goto done; + } + + tmp = eap_teap_process_crypto_binding(sm, data, ret, + tlv.crypto_binding, + tlv.crypto_binding_len); + if (!tmp) { + failed = 1; + error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR; + } else { + resp = wpabuf_concat(resp, tmp); + if (tlv.result == TEAP_STATUS_SUCCESS && !failed) + data->result_success_done = 1; + if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed) { + data->inner_method_done = 0; + data->iresult_verified = 1; + } + } + } + if (tlv.identity_type == TEAP_IDENTITY_TYPE_MACHINE) { struct eap_peer_config *config = eap_get_config(sm); @@ -1353,33 +1387,6 @@ static int eap_teap_process_decrypted(struct eap_sm *sm, } } - if (tlv.crypto_binding) { - if (tlv.iresult != TEAP_STATUS_SUCCESS && - tlv.result != TEAP_STATUS_SUCCESS) { - wpa_printf(MSG_DEBUG, - "EAP-TEAP: Unexpected Crypto-Binding TLV without Result TLV or Intermediate-Result TLV indicating success"); - failed = 1; - error = TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED; - goto done; - } - - tmp = eap_teap_process_crypto_binding(sm, data, ret, - tlv.crypto_binding, - tlv.crypto_binding_len); - if (!tmp) { - failed = 1; - error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR; - } else { - resp = wpabuf_concat(resp, tmp); - if (tlv.result == TEAP_STATUS_SUCCESS && !failed) - data->result_success_done = 1; - if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed) { - data->inner_method_done = 0; - data->iresult_verified = 1; - } - } - } - if (data->result_success_done && data->session_ticket_used && eap_teap_derive_msk(data) == 0) { /* Assume the server might accept authentication without going diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_tls.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_tls.c index 0d479f1c298c4d1a51e4cc54f324ec68f5b86e24..4167e992b3f56ae00daf94d43f2312c87185dd1a 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_tls.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_tls.c @@ -1,5 +1,5 @@ /* - * EAP peer method: EAP-TLS (RFC 2716) + * EAP peer method: EAP-TLS (RFC 5216, RFC 9190) * Copyright (c) 2004-2008, 2012-2019, Jouni Malinen * * This software may be distributed under the terms of the BSD license. @@ -26,6 +26,7 @@ struct eap_tls_data { void *ssl_ctx; u8 eap_type; struct wpabuf *pending_resp; + bool prot_success_received; }; @@ -302,15 +303,20 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv, return NULL; } - /* draft-ietf-emu-eap-tls13-13 Section 2.5 */ + /* RFC 9190 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"); + wpa_printf(MSG_DEBUG, + "EAP-TLS: ACKing protected success indication (appl data 0x00)"); eap_peer_tls_reset_output(&data->ssl); res = 1; + ret->methodState = METHOD_DONE; + ret->decision = DECISION_UNCOND_SUCC; + data->prot_success_received = true; } - if (tls_connection_established(data->ssl_ctx, data->ssl.conn)) + if (tls_connection_established(data->ssl_ctx, data->ssl.conn) && + (!data->ssl.tls_v13 || data->prot_success_received)) eap_tls_success(sm, data, ret); if (res == 1) { @@ -335,6 +341,7 @@ static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) wpabuf_free(data->pending_resp); data->pending_resp = NULL; + data->prot_success_received = false; } diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_tls_common.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_tls_common.c index a53eeb158f797d5d5d803513fa72fc5bf763b866..966cbd6c7009d24a67894e1fb2edab566ec333cf 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_tls_common.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_tls_common.c @@ -102,6 +102,10 @@ static void eap_tls_params_flags(struct tls_connection_params *params, params->flags |= TLS_CONN_SUITEB_NO_ECDH; if (os_strstr(txt, "tls_suiteb_no_ecdh=0")) params->flags &= ~TLS_CONN_SUITEB_NO_ECDH; + if (os_strstr(txt, "allow_unsafe_renegotiation=1")) + params->flags |= TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION; + if (os_strstr(txt, "allow_unsafe_renegotiation=0")) + params->flags &= ~TLS_CONN_ALLOW_UNSAFE_RENEGOTIATION; } @@ -113,7 +117,6 @@ static void eap_tls_cert_params_from_conf(struct tls_connection_params *params, params->client_cert = config->client_cert; params->private_key = config->private_key; params->private_key_passwd = config->private_key_passwd; - params->dh_file = config->dh_file; params->subject_match = config->subject_match; params->altsubject_match = config->altsubject_match; params->check_cert_subject = config->check_cert_subject; @@ -192,18 +195,20 @@ static int eap_tls_params_from_conf(struct eap_sm *sm, * TLS v1.3 changes, so disable this by default for now. */ params->flags |= TLS_CONN_DISABLE_TLSv1_3; } +#ifndef EAP_TLSV1_3 if (data->eap_type == EAP_TYPE_TLS || data->eap_type == EAP_UNAUTH_TLS_TYPE || data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE) { /* While the current EAP-TLS implementation is more or less - * complete for TLS v1.3, there has been no interoperability - * testing with other implementations, so disable for by default - * for now until there has been chance to confirm that no - * significant interoperability issues show up with TLS version - * update. + * complete for TLS v1.3, there has been only minimal + * interoperability testing with other implementations, so + * disable it by default for now until there has been chance to + * confirm that no significant interoperability issues show up + * with TLS version update. */ params->flags |= TLS_CONN_DISABLE_TLSv1_3; } +#endif /* EAP_TLSV1_3 */ if (phase2 && sm->use_machine_cred) { wpa_printf(MSG_DEBUG, "TLS: using machine config options"); eap_tls_params_from_conf2m(params, config); @@ -228,9 +233,7 @@ static int eap_tls_params_from_conf(struct eap_sm *sm, ¶ms->client_cert_blob_len) || eap_tls_check_blob(sm, ¶ms->private_key, ¶ms->private_key_blob, - ¶ms->private_key_blob_len) || - eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, - ¶ms->dh_blob_len)) { + ¶ms->private_key_blob_len)) { wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); return -1; } diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_ttls.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_ttls.c index c4019154d9556f5b9a0056eefe561abba592cfa0..6adc22277c3616818ce2d5f17281cf180c4bf729 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_ttls.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_ttls.c @@ -65,9 +65,30 @@ struct eap_ttls_data { int ready_for_tnc; int tnc_started; #endif /* EAP_TNC */ + + enum { NO_AUTH, FOR_INITIAL, ALWAYS } phase2_auth; }; +static void eap_ttls_parse_phase1(struct eap_ttls_data *data, + const char *phase1) +{ + if (os_strstr(phase1, "phase2_auth=0")) { + data->phase2_auth = NO_AUTH; + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Do not require Phase 2 authentication"); + } else if (os_strstr(phase1, "phase2_auth=1")) { + data->phase2_auth = FOR_INITIAL; + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Require Phase 2 authentication for initial connection"); + } else if (os_strstr(phase1, "phase2_auth=2")) { + data->phase2_auth = ALWAYS; + wpa_printf(MSG_DEBUG, + "EAP-TTLS: Require Phase 2 authentication for all cases"); + } +} + + static void * eap_ttls_init(struct eap_sm *sm) { struct eap_ttls_data *data; @@ -82,6 +103,10 @@ static void * eap_ttls_init(struct eap_sm *sm) selected = "EAP"; selected_non_eap = 0; data->phase2_type = EAP_TTLS_PHASE2_EAP; + data->phase2_auth = FOR_INITIAL; + + if (config && config->phase1) + eap_ttls_parse_phase1(data, config->phase1); /* * Either one auth= type or one or more autheap= methods can be @@ -1473,11 +1498,11 @@ start: goto start; } - /* draft-ietf-emu-eap-tls13-13 Section 2.5 */ + /* RFC 9190 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-TLS: ACKing protected success indication (appl data 0x00)"); eap_peer_tls_reset_output(&data->ssl); wpabuf_free(in_decrypted); return 1; @@ -1703,8 +1728,9 @@ static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv, static bool eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) { struct eap_ttls_data *data = priv; + return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - data->phase2_success; + data->phase2_success && data->phase2_auth != ALWAYS; } diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_wsc.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_wsc.c index 1381bbe62caf8c0c6074c41b800168c6d9ea482d..2a881d4c75d331b93cefea8b7ad3c52e09b28355 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_wsc.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_wsc.c @@ -18,6 +18,8 @@ #include "eloop.h" #endif +#define EAP_FAIL_TIMEOUT 30000 + struct eap_wsc_data { enum { WAIT_START, MESG, WAIT_FRAG_ACK, FAIL } state; int registrar; @@ -257,8 +259,18 @@ static void * eap_wsc_init(struct eap_sm *sm) cfg.new_ap_settings = &new_ap_settings; } - if (os_strstr(phase1, "multi_ap=1")) - cfg.multi_ap_backhaul_sta = 1; + pos = os_strstr(phase1, "multi_ap="); + if (pos) { + u16 id = atoi(pos + 9); + + if (id != 0) { + cfg.multi_ap_backhaul_sta = 1; + cfg.multi_ap_profile = id; + } else { + wpa_printf(MSG_DEBUG, + "EAP-WSC: Invalid multi_ap setting"); + } + } data->wps = wps_init(&cfg); if (data->wps == NULL) { @@ -365,6 +377,7 @@ static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, return resp; } + static int eap_wsc_process_cont(struct eap_wsc_data *data, const u8 *buf, size_t len, u8 op_code) { @@ -581,7 +594,7 @@ send_msg: /* miss GO'EAP-Failure frame issue */ if ((res == WPS_CONTINUE) && (wps_check_msg_done(data->wps))) { eloop_cancel_timeout(wps_eap_fail_timeout, NULL, NULL); - eloop_register_timeout(0, 30000, wps_eap_fail_timeout, NULL, NULL); + eloop_register_timeout(0, EAP_FAIL_TIMEOUT, wps_eap_fail_timeout, NULL, NULL); wpa_printf(MSG_DEBUG, "EAPOL: register eap_fail_timeout sm=%p\n", sm); } #endif diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap.h b/wpa_supplicant-2.9_standard/src/eap_server/eap.h index 61032cc016bcbd586f70699b6b883ee73d0dac9a..d965a25c409c106f92d48e26f2e148ad474913a6 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap.h +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap.h @@ -124,6 +124,9 @@ struct eap_config { * callback context. */ void *eap_sim_db_priv; + + struct crypto_rsa_key *imsi_privacy_key; + bool backend_auth; int eap_server; @@ -206,6 +209,7 @@ struct eap_config { EAP_TEAP_ID_REQUEST_MACHINE_ACCEPT_USER = 4, EAP_TEAP_ID_REQUIRE_USER_AND_MACHINE = 5, } eap_teap_id; + int eap_teap_method_sequence; /** * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication @@ -216,6 +220,10 @@ struct eap_config { int eap_sim_aka_result_ind; int eap_sim_id; + /* Maximum number of fast re-authentications allowed after each full + * EAP-SIM/AKA authentication. */ + int eap_sim_aka_fast_reauth_limit; + /** * tnc - Trusted Network Connect (TNC) * @@ -258,6 +266,10 @@ struct eap_config { unsigned int max_auth_rounds; unsigned int max_auth_rounds_short; + +#ifdef CONFIG_TESTING_OPTIONS + bool skip_prot_success; +#endif /* CONFIG_TESTING_OPTIONS */ }; struct eap_session_data { diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_i.h b/wpa_supplicant-2.9_standard/src/eap_server/eap_i.h index 28bb564e9331b160794f325c08f1948a8fd858d7..10affa431c0e0e685fd7cbb0c0228d9f281570c2 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_i.h +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_i.h @@ -160,6 +160,7 @@ struct eap_sm { size_t identity_len; char *serial_num; char imsi[20]; + char sim_aka_permanent[20]; /* Whether Phase 2 method should validate identity match */ int require_identity_match; int lastId; /* Identifier used in the last EAP-Packet */ @@ -176,9 +177,15 @@ struct eap_sm { METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT } method_pending; + /* Optional challenges generated in Phase 1 (EAP-FAST) */ u8 *auth_challenge; u8 *peer_challenge; + /* Whether to use the EAP-FAST-MSCHAPv2 instantiation of EAP-MSCHAPv2. + * That variant is otherwise identical, but it generates the MSK using + * MS-MPPE keys in reverse order. */ + bool eap_fast_mschapv2; + struct wpabuf *assoc_wps_ie; struct wpabuf *assoc_p2p_ie; diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_aka.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_aka.c index e9bf0300c16f967b255f84d40ae2307312ff31cb..880ffa3d68e5529ab54e12d4a12ab09595f2ad0e 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_aka.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_aka.c @@ -9,6 +9,7 @@ #include "includes.h" #include "common.h" +#include "utils/base64.h" #include "crypto/sha256.h" #include "crypto/crypto.h" #include "crypto/random.h" @@ -109,7 +110,29 @@ static int eap_aka_check_identity_reauth(struct eap_sm *sm, return 0; } - wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication"); + if (data->reauth->counter > sm->cfg->eap_sim_aka_fast_reauth_limit) { + wpa_printf(MSG_DEBUG, + "EAP-AKA: Too many fast re-authentication attemps - fall back to full authentication"); + if (sm->cfg->eap_sim_id & 0x04) { + wpa_printf(MSG_DEBUG, + "EAP-AKA: Permanent identity recognized - skip AKA-Identity exchange"); + os_strlcpy(data->permanent, data->reauth->permanent, + sizeof(data->permanent)); + os_strlcpy(sm->sim_aka_permanent, + data->reauth->permanent, + sizeof(sm->sim_aka_permanent)); + eap_sim_db_remove_reauth(sm->cfg->eap_sim_db_priv, + data->reauth); + data->reauth = NULL; + eap_aka_fullauth(sm, data); + return 1; + } + return 0; + } + + wpa_printf(MSG_DEBUG, + "EAP-AKA: Using fast re-authentication (counter=%d)", + data->reauth->counter); os_strlcpy(data->permanent, data->reauth->permanent, sizeof(data->permanent)); data->counter = data->reauth->counter; @@ -133,10 +156,17 @@ static void eap_aka_check_identity(struct eap_sm *sm, struct eap_aka_data *data) { char *username; + const u8 *identity = sm->identity; + size_t identity_len = sm->identity_len; + + if (sm->sim_aka_permanent[0]) { + identity = (const u8 *) sm->sim_aka_permanent; + identity_len = os_strlen(sm->sim_aka_permanent); + } /* Check if we already know the identity from EAP-Response/Identity */ - username = sim_get_username(sm->identity, sm->identity_len); + username = sim_get_username(identity, identity_len); if (username == NULL) return; @@ -149,6 +179,16 @@ static void eap_aka_check_identity(struct eap_sm *sm, return; } + if (sm->sim_aka_permanent[0] && data->state == IDENTITY) { + /* Skip AKA/Identity exchange since the permanent identity + * was recognized. */ + os_free(username); + os_strlcpy(data->permanent, sm->sim_aka_permanent, + sizeof(data->permanent)); + eap_aka_fullauth(sm, data); + return; + } + if ((data->eap_method == EAP_TYPE_AKA_PRIME && username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) || (data->eap_method == EAP_TYPE_AKA && @@ -737,11 +777,8 @@ static void eap_aka_determine_identity(struct eap_sm *sm, sm->identity, sm->identity_len); username = sim_get_username(sm->identity, sm->identity_len); - if (username == NULL) { - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); - return; - } + if (!username) + goto fail; if (eap_aka_check_identity_reauth(sm, data, username) > 0) { os_free(username); @@ -785,16 +822,87 @@ static void eap_aka_determine_identity(struct eap_sm *sm, username); os_strlcpy(data->permanent, username, sizeof(data->permanent)); os_free(username); +#ifdef CRYPTO_RSA_OAEP_SHA256 + } else if (sm->identity_len > 1 && sm->identity[0] == '\0') { + char *enc_id, *pos, *end; + size_t enc_id_len; + u8 *decoded_id; + size_t decoded_id_len; + struct wpabuf *enc, *dec; + u8 *new_id; + + os_free(username); + if (!sm->cfg->imsi_privacy_key) { + wpa_printf(MSG_DEBUG, + "EAP-AKA: Received encrypted identity, but no IMSI privacy key configured to decrypt it"); + goto fail; + } + + enc_id = (char *) &sm->identity[1]; + end = (char *) &sm->identity[sm->identity_len]; + for (pos = enc_id; pos < end; pos++) { + if (*pos == ',') + break; + } + enc_id_len = pos - enc_id; + + wpa_hexdump_ascii(MSG_DEBUG, + "EAP-AKA: Encrypted permanent identity", + enc_id, enc_id_len); + decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len); + if (!decoded_id) { + wpa_printf(MSG_DEBUG, + "EAP-AKA: Could not base64 decode encrypted identity"); + goto fail; + } + wpa_hexdump(MSG_DEBUG, + "EAP-AKA: Decoded encrypted permanent identity", + decoded_id, decoded_id_len); + enc = wpabuf_alloc_copy(decoded_id, decoded_id_len); + os_free(decoded_id); + if (!enc) + goto fail; + dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key, + enc); + wpabuf_free(enc); + if (!dec) { + wpa_printf(MSG_DEBUG, + "EAP-AKA: Failed to decrypt encrypted identity"); + goto fail; + } + wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Decrypted permanent identity", + wpabuf_head(dec), wpabuf_len(dec)); + username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec)); + if (!username) { + wpabuf_free(dec); + goto fail; + } + new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec)); + if (!new_id) { + wpabuf_free(dec); + goto fail; + } + os_free(sm->identity); + sm->identity = new_id; + sm->identity_len = wpabuf_len(dec); + wpabuf_free(dec); + os_strlcpy(data->permanent, username, sizeof(data->permanent)); + os_free(username); +#endif /* CRYPTO_RSA_OAEP_SHA256 */ } else { wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'", username); os_free(username); - data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; - eap_aka_state(data, NOTIFICATION); + goto fail; return; } eap_aka_fullauth(sm, data); + return; + +fail: + data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH; + eap_aka_state(data, NOTIFICATION); } diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_eke.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_eke.c index eac3245cd1f296da81b8d77d142411a4c6cd95b5..544067076f04c2e9fe85e063a29b75e008044894 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_eke.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_eke.c @@ -276,6 +276,7 @@ static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm, if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) { wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH"); + wpabuf_free(msg); eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); return eap_eke_build_failure(data, id); } diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_fast.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_fast.c index 55d48d91f6069c191b2bca8cf1c47b5804a1a5d5..8064c16be339013d47da3fa60d9ce81d1301fd98 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_fast.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_fast.c @@ -357,18 +357,7 @@ static int eap_fast_get_phase2_key(struct eap_sm *sm, if (key_len > isk_len) key_len = isk_len; - if (key_len == 32 && - data->phase2_method->vendor == EAP_VENDOR_IETF && - data->phase2_method->method == EAP_TYPE_MSCHAPV2) { - /* - * EAP-FAST uses reverse order for MS-MPPE keys when deriving - * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct - * ISK for EAP-FAST cryptobinding. - */ - os_memcpy(isk, key + 16, 16); - os_memcpy(isk + 16, key, 16); - } else - os_memcpy(isk, key, key_len); + os_memcpy(isk, key, key_len); os_free(key); return 0; @@ -961,6 +950,7 @@ static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data, sm->auth_challenge = data->key_block_p->server_challenge; sm->peer_challenge = data->key_block_p->client_challenge; } + sm->eap_fast_mschapv2 = true; sm->init_phase2 = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; @@ -1534,7 +1524,7 @@ static void eap_fast_process_msg(struct eap_sm *sm, void *priv, if (eap_fast_process_phase1(sm, data)) break; - /* fall through */ + __attribute__((fallthrough)); case PHASE2_START: eap_fast_process_phase2_start(sm, data); break; diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_ikev2.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_ikev2.c index ef3cc8cccebfe5dcb5a1f1a6e652f7fb0fae03f8..00b18494a375a52f0d0a502bdebb46511c39f02b 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_ikev2.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_ikev2.c @@ -223,7 +223,7 @@ static struct wpabuf * eap_ikev2_buildReq(struct eap_sm *sm, void *priv, u8 id) } data->out_used = 0; } - /* fall through */ + __attribute__((fallthrough)); case WAIT_FRAG_ACK: return eap_ikev2_build_msg(data, id); case FRAG_ACK: diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_mschapv2.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_mschapv2.c index 9b3eb26ef4532bdf57ba945a554e7c07009442ae..3dc6a39418c26241fc508e117a375ec05920a115 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_mschapv2.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_mschapv2.c @@ -64,6 +64,12 @@ static void * eap_mschapv2_init(struct eap_sm *sm) return NULL; data->state = CHALLENGE; + wpa_printf(MSG_DEBUG, "EAP-%sMSCHAPv2 init%s%s", + sm->eap_fast_mschapv2 ? "FAST-" : "", + sm->peer_challenge && sm->auth_challenge ? + " with preset challenges" : "", + sm->init_phase2 ? " for Phase 2" : ""); + if (sm->auth_challenge) { os_memcpy(data->auth_challenge, sm->auth_challenge, CHALLENGE_LEN); @@ -542,6 +548,7 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_mschapv2_data *data = priv; u8 *key; + bool first_is_send; if (data->state != SUCCESS || !data->master_key_valid) return NULL; @@ -550,11 +557,26 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) key = os_malloc(*len); if (key == NULL) return NULL; + /* + * [MS-CHAP], 3.1.5.1 (Master Session Key (MSK) Derivation + * MSK = MasterReceiveKey + MasterSendKey + 32 bytes zeros (padding) + * On an Authenticator: + * MS-MPPE-Recv-Key = MasterReceiveKey + * MS-MPPE-Send-Key = MasterSendKey + * + * RFC 5422, 3.2.3 (Authenticating Using EAP-FAST-MSCHAPv2) + * MSK = MasterSendKey + MasterReceiveKey + * (i.e., reverse order and no padding) + * + * On Peer, EAP-MSCHAPv2 starts with Send key and EAP-FAST-MSCHAPv2 + * starts with Receive key. + */ + first_is_send = sm->eap_fast_mschapv2; /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */ - if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, - 1) < 0 || + if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, + first_is_send, 1) < 0 || get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, - MSCHAPV2_KEY_LEN, 1, 1) < 0) { + MSCHAPV2_KEY_LEN, !first_is_send, 1) < 0) { os_free(key); return NULL; } diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_peap.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_peap.c index f526e8bf7377c7df56d0860dfcdec34199df8a7b..998d0e8ae417f8c9a8d8f41fc157c43bf460bce9 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_peap.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_peap.c @@ -56,6 +56,10 @@ struct eap_peap_data { }; +static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data, + int vendor, enum eap_type eap_type); + + static const char * eap_peap_state_txt(int state) { switch (state) { @@ -558,10 +562,24 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id) wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, " "starting Phase2"); eap_peap_state(data, PHASE2_START); + if (data->ssl.tls_v13 && data->ssl.tls_out && + wpabuf_len(data->ssl.tls_out) == 0) { + /* This can happen with TLS 1.3 when a new + * session ticket is not generated and the + * Finished message from the peer terminates + * Phase 1. */ + wpa_printf(MSG_DEBUG, + "EAP-PEAP: No pending data to send - move directly to Phase 2 ID query"); + eap_peap_state(data, PHASE2_ID); + eap_peap_phase2_init(sm, data, EAP_VENDOR_IETF, + EAP_TYPE_IDENTITY); + goto phase2_id; + } } break; case PHASE2_ID: case PHASE2_METHOD: + phase2_id: wpabuf_free(data->ssl.tls_out); data->ssl.tls_out_pos = 0; data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id); diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_pwd.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_pwd.c index 81cddca607f5f7683ddb57ab29e1c34aaf04d0ed..afafaefc265ed186810cffbb597d80454eacb1d5 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_pwd.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_pwd.c @@ -293,7 +293,10 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm, /* We send the element as (x,y) followed by the scalar */ element = wpabuf_put(data->outbuf, 2 * prime_len); scalar = wpabuf_put(data->outbuf, order_len); - crypto_bignum_to_bin(data->my_scalar, scalar, order_len, order_len); + if (crypto_bignum_to_bin(data->my_scalar, scalar, order_len, + order_len) < 0) + goto fin; + if (crypto_ec_point_to_bin(data->grp->group, data->my_element, element, element + prime_len) < 0) { wpa_printf(MSG_INFO, "EAP-PWD (server): point assignment " @@ -349,7 +352,9 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm, * * First is k */ - crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); + if (crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, prime_len); /* server element: x, y */ @@ -362,7 +367,10 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm, eap_pwd_h_update(hash, cruft, prime_len * 2); /* server scalar */ - crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); + if (crypto_bignum_to_bin(data->my_scalar, cruft, order_len, + order_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, order_len); /* peer element: x, y */ @@ -375,7 +383,10 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm, eap_pwd_h_update(hash, cruft, prime_len * 2); /* peer scalar */ - crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len); + if (crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, + order_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, order_len); /* ciphersuite */ @@ -785,7 +796,9 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, goto fin; /* k */ - crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len); + if (crypto_bignum_to_bin(data->k, cruft, prime_len, prime_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, prime_len); /* peer element: x, y */ @@ -798,7 +811,10 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, eap_pwd_h_update(hash, cruft, prime_len * 2); /* peer scalar */ - crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, order_len); + if (crypto_bignum_to_bin(data->peer_scalar, cruft, order_len, + order_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, order_len); /* server element: x, y */ @@ -811,7 +827,10 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, eap_pwd_h_update(hash, cruft, prime_len * 2); /* server scalar */ - crypto_bignum_to_bin(data->my_scalar, cruft, order_len, order_len); + if (crypto_bignum_to_bin(data->my_scalar, cruft, order_len, + order_len) < 0) + goto fin; + eap_pwd_h_update(hash, cruft, order_len); /* ciphersuite */ diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_sim.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_sim.c index 8a68289620796a85546a455b1d8af0c01858a225..e418c076e241f56ba1c23027556015f892e9889b 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_sim.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_sim.c @@ -9,6 +9,8 @@ #include "includes.h" #include "common.h" +#include "utils/base64.h" +#include "crypto/crypto.h" #include "crypto/random.h" #include "eap_server/eap_i.h" #include "eap_common/eap_sim_common.h" @@ -104,12 +106,28 @@ static struct wpabuf * eap_sim_build_start(struct eap_sm *sm, { struct eap_sim_msg *msg; u8 ver[2]; + bool id_req = true; wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start"); msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START); data->start_round++; - if (data->start_round == 1) { + + if (data->start_round == 1 && (sm->cfg->eap_sim_id & 0x04)) { + char *username; + + username = sim_get_username(sm->identity, sm->identity_len); + if (username && username[0] == EAP_SIM_REAUTH_ID_PREFIX && + eap_sim_db_get_reauth_entry(sm->cfg->eap_sim_db_priv, + username)) + id_req = false; + + os_free(username); + } + + if (!id_req) { + wpa_printf(MSG_DEBUG, " No identity request"); + } else if (data->start_round == 1) { /* * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is * ignored and the SIM/Start is used to request the identity. @@ -432,6 +450,7 @@ static void eap_sim_process_start(struct eap_sm *sm, struct wpabuf *respData, struct eap_sim_attrs *attr) { + const u8 *identity; size_t identity_len; u8 ver_list[2]; u8 *new_identity; @@ -447,9 +466,13 @@ static void eap_sim_process_start(struct eap_sm *sm, goto skip_id_update; } + if ((sm->cfg->eap_sim_id & 0x04) && + (!attr->identity || attr->identity_len == 0)) + goto skip_id_attr; + /* - * We always request identity in SIM/Start, so the peer is required to - * have replied with one. + * Unless explicitly configured otherwise, we always request identity + * in SIM/Start, so the peer is required to have replied with one. */ if (!attr->identity || attr->identity_len == 0) { wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any " @@ -465,9 +488,17 @@ static void eap_sim_process_start(struct eap_sm *sm, os_memcpy(sm->identity, attr->identity, attr->identity_len); sm->identity_len = attr->identity_len; +skip_id_attr: + if (sm->sim_aka_permanent[0]) { + identity = (const u8 *) sm->sim_aka_permanent; + identity_len = os_strlen(sm->sim_aka_permanent); + } else { + identity = sm->identity; + identity_len = sm->identity_len; + } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", - sm->identity, sm->identity_len); - username = sim_get_username(sm->identity, sm->identity_len); + identity, identity_len); + username = sim_get_username(identity, identity_len); if (username == NULL) goto failed; @@ -483,7 +514,30 @@ static void eap_sim_process_start(struct eap_sm *sm, /* Remain in START state for another round */ return; } - wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication"); + + if (data->reauth->counter > + sm->cfg->eap_sim_aka_fast_reauth_limit && + (sm->cfg->eap_sim_id & 0x04)) { + wpa_printf(MSG_DEBUG, + "EAP-SIM: Too many fast re-authentication attemps - fall back to full authentication"); + wpa_printf(MSG_DEBUG, + "EAP-SIM: Permanent identity recognized - skip new Identity query"); + os_strlcpy(data->permanent, + data->reauth->permanent, + sizeof(data->permanent)); + os_strlcpy(sm->sim_aka_permanent, + data->reauth->permanent, + sizeof(sm->sim_aka_permanent)); + eap_sim_db_remove_reauth( + sm->cfg->eap_sim_db_priv, + data->reauth); + data->reauth = NULL; + goto skip_id_update; + } + + wpa_printf(MSG_DEBUG, + "EAP-SIM: Using fast re-authentication (counter=%d)", + data->reauth->counter); os_strlcpy(data->permanent, data->reauth->permanent, sizeof(data->permanent)); data->counter = data->reauth->counter; @@ -512,6 +566,73 @@ static void eap_sim_process_start(struct eap_sm *sm, username); os_strlcpy(data->permanent, username, sizeof(data->permanent)); os_free(username); +#ifdef CRYPTO_RSA_OAEP_SHA256 + } else if (sm->identity_len > 1 && sm->identity[0] == '\0') { + char *enc_id, *pos, *end; + size_t enc_id_len; + u8 *decoded_id; + size_t decoded_id_len; + struct wpabuf *enc, *dec; + u8 *new_id; + + os_free(username); + if (!sm->cfg->imsi_privacy_key) { + wpa_printf(MSG_DEBUG, + "EAP-SIM: Received encrypted identity, but no IMSI privacy key configured to decrypt it"); + goto failed; + } + + enc_id = (char *) &sm->identity[1]; + end = (char *) &sm->identity[sm->identity_len]; + for (pos = enc_id; pos < end; pos++) { + if (*pos == ',') + break; + } + enc_id_len = pos - enc_id; + + wpa_hexdump_ascii(MSG_DEBUG, + "EAP-SIM: Encrypted permanent identity", + enc_id, enc_id_len); + decoded_id = base64_decode(enc_id, enc_id_len, &decoded_id_len); + if (!decoded_id) { + wpa_printf(MSG_DEBUG, + "EAP-SIM: Could not base64 decode encrypted identity"); + goto failed; + } + wpa_hexdump(MSG_DEBUG, + "EAP-SIM: Decoded encrypted permanent identity", + decoded_id, decoded_id_len); + enc = wpabuf_alloc_copy(decoded_id, decoded_id_len); + os_free(decoded_id); + if (!enc) + goto failed; + dec = crypto_rsa_oaep_sha256_decrypt(sm->cfg->imsi_privacy_key, + enc); + wpabuf_free(enc); + if (!dec) { + wpa_printf(MSG_DEBUG, + "EAP-SIM: Failed to decrypt encrypted identity"); + goto failed; + } + wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Decrypted permanent identity", + wpabuf_head(dec), wpabuf_len(dec)); + username = sim_get_username(wpabuf_head(dec), wpabuf_len(dec)); + if (!username) { + wpabuf_free(dec); + goto failed; + } + new_id = os_memdup(wpabuf_head(dec), wpabuf_len(dec)); + if (!new_id) { + wpabuf_free(dec); + goto failed; + } + os_free(sm->identity); + sm->identity = new_id; + sm->identity_len = wpabuf_len(dec); + wpabuf_free(dec); + os_strlcpy(data->permanent, username, sizeof(data->permanent)); + os_free(username); +#endif /* CRYPTO_RSA_OAEP_SHA256 */ } else { wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'", username); diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_teap.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_teap.c index 691b44a8d3463d5c93cda2049bb837af15a22d55..545a73840cd9a9854f0f93fb237b36a71dc97090 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_teap.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_teap.c @@ -74,11 +74,15 @@ struct eap_teap_data { enum teap_error_codes error_code; enum teap_identity_types cur_id_type; + + bool check_crypto_binding; }; static int eap_teap_process_phase2_start(struct eap_sm *sm, struct eap_teap_data *data); +static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data, + int vendor, enum eap_type eap_type); static const char * eap_teap_state_txt(int state) @@ -704,6 +708,8 @@ static struct wpabuf * eap_teap_build_crypto_binding( wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC", cb->msk_compound_mac, sizeof(cb->msk_compound_mac)); + data->check_crypto_binding = true; + return buf; } @@ -889,6 +895,7 @@ static struct wpabuf * eap_teap_buildReq(struct eap_sm *sm, void *priv, u8 id) struct eap_teap_data *data = priv; struct wpabuf *req = NULL; int piggyback = 0; + bool move_to_method = true; if (data->ssl.state == FRAG_ACK) { return eap_server_tls_build_ack(id, EAP_TYPE_TEAP, @@ -940,6 +947,21 @@ static struct wpabuf * eap_teap_buildReq(struct eap_sm *sm, void *priv, u8 id) break; case CRYPTO_BINDING: req = eap_teap_build_crypto_binding(sm, data); + if (req && sm->cfg->eap_teap_auth == 0 && + data->inner_eap_not_done && + !data->phase2_method && + sm->cfg->eap_teap_method_sequence == 0) { + wpa_printf(MSG_DEBUG, + "EAP-TEAP: Continue with inner EAP authentication for second credential (optimized)"); + eap_teap_state(data, PHASE2_ID); + if (eap_teap_phase2_init(sm, data, EAP_VENDOR_IETF, + EAP_TYPE_IDENTITY) < 0) { + eap_teap_state(data, FAILURE); + wpabuf_free(req); + return NULL; + } + move_to_method = false; + } if (data->phase2_method) { /* * Include the start of the next EAP method in the @@ -950,7 +972,8 @@ static struct wpabuf * eap_teap_buildReq(struct eap_sm *sm, void *priv, u8 id) eap = eap_teap_build_phase2_req(sm, data, id); req = wpabuf_concat(req, eap); - eap_teap_state(data, PHASE2_METHOD); + if (move_to_method) + eap_teap_state(data, PHASE2_METHOD); } break; case REQUEST_PAC: @@ -1008,6 +1031,13 @@ static int eap_teap_phase2_init(struct eap_sm *sm, struct eap_teap_data *data, if (!data->phase2_method) return -1; + /* While RFC 7170 does not describe this, EAP-TEAP has been deployed + * with implementations that use the EAP-FAST-MSCHAPv2, instead of the + * EAP-MSCHAPv2, way of deriving the MSK for IMSK. Use that design here + * to interoperate. + */ + sm->eap_fast_mschapv2 = true; + sm->init_phase2 = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; @@ -1503,7 +1533,8 @@ static void eap_teap_process_phase2_tlvs(struct eap_sm *sm, struct wpabuf *in_data) { struct eap_teap_tlv_parse tlv; - int check_crypto_binding = data->state == CRYPTO_BINDING; + bool check_crypto_binding = data->state == CRYPTO_BINDING || + data->check_crypto_binding; if (eap_teap_parse_tlvs(in_data, &tlv) < 0) { wpa_printf(MSG_DEBUG, @@ -1586,6 +1617,7 @@ static void eap_teap_process_phase2_tlvs(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-TEAP: Valid Crypto-Binding TLV received"); + data->check_crypto_binding = false; if (data->final_result) { wpa_printf(MSG_DEBUG, "EAP-TEAP: Authentication completed successfully"); @@ -1664,7 +1696,8 @@ static void eap_teap_process_phase2_tlvs(struct eap_sm *sm, "EAP-TEAP: Continue with basic password authentication for second credential"); eap_teap_state(data, PHASE2_BASIC_AUTH); } else if (check_crypto_binding && data->state == CRYPTO_BINDING && - sm->cfg->eap_teap_auth == 0 && data->inner_eap_not_done) { + sm->cfg->eap_teap_auth == 0 && data->inner_eap_not_done && + sm->cfg->eap_teap_method_sequence == 1) { wpa_printf(MSG_DEBUG, "EAP-TEAP: Continue with inner EAP authentication for second credential"); eap_teap_state(data, PHASE2_ID); @@ -1839,7 +1872,7 @@ static void eap_teap_process_msg(struct eap_sm *sm, void *priv, if (eap_teap_process_phase1(sm, data)) break; - /* fall through */ + __attribute__((fallthrough)); case PHASE2_START: eap_teap_process_phase2_start(sm, data); break; diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_tls.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_tls.c index 00a496f2c61f5c62f17e6896f8582fea441b654e..443c293ce6586bd5eba771286577399bf0b929a8 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_tls.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_tls.c @@ -1,5 +1,5 @@ /* - * hostapd / EAP-TLS (RFC 2716) + * hostapd / EAP-TLS (RFC 5216, RFC 9190) * Copyright (c) 2004-2008, Jouni Malinen * * This software may be distributed under the terms of the BSD license. @@ -306,6 +306,14 @@ static void eap_tls_process(struct eap_sm *sm, void *priv, wpa_printf(MSG_DEBUG, "EAP-TLS: Resuming previous session"); + + if (data->ssl.tls_v13 && data->ssl.tls_out) { + wpa_hexdump_buf(MSG_DEBUG, + "EAP-TLS: Additional data to be sent for TLS 1.3", + data->ssl.tls_out); + return; + } + eap_tls_state(data, SUCCESS); tls_connection_set_success_data_resumed(data->ssl.conn); /* TODO: Cache serial number with session and update EAP user diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_tls_common.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_tls_common.c index a9b53b1a06546a4efa661bb8cd618ff3544a63dc..717af2e89b71b2ef928eb0085bc6a8a266fb66dd 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_tls_common.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_tls_common.c @@ -94,6 +94,11 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, if (data->tls_out_limit > 100) data->tls_out_limit -= 100; } + +#ifdef CONFIG_TESTING_OPTIONS + data->skip_prot_success = sm->cfg->skip_prot_success; +#endif /* CONFIG_TESTING_OPTIONS */ + return 0; } @@ -367,14 +372,14 @@ int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) sm->cfg->ssl_ctx, data->conn); /* - * https://tools.ietf.org/html/draft-ietf-emu-eap-tls13#section-2.5 + * RFC 9190 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 + * sent. So this is done always for EAP-TLS but notably not for PEAP * even on resumption. */ if (data->tls_v13 && @@ -390,8 +395,15 @@ int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) break; /* fallthrough */ case EAP_TYPE_TLS: +#ifdef CONFIG_TESTING_OPTIONS + if (data->skip_prot_success) { + wpa_printf(MSG_INFO, + "TESTING: Do not send protected success indication"); + break; + } +#endif /* CONFIG_TESTING_OPTIONS */ wpa_printf(MSG_DEBUG, - "EAP-TLS: Send Commitment Message"); + "EAP-TLS: Send protected success indication (appl data 0x00)"); plain = wpabuf_alloc(1); if (!plain) diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_ttls.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_ttls.c index b89352244148ea0666bda40deed6155e286ebf4f..b21f12da7919d91f0b8b604b57c643127b7f5cb2 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_ttls.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_ttls.c @@ -445,7 +445,8 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2( sizeof(data->mschapv2_auth_response)); } else { pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_ERROR, - RADIUS_VENDOR_ID_MICROSOFT, 1, 6); + RADIUS_VENDOR_ID_MICROSOFT, 1, 7); + *pos++ = data->mschapv2_ident; os_memcpy(pos, "Failed", 6); pos += 6; AVP_PAD(req, pos); diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_wsc.c b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_wsc.c index 98663c9ef473f296ec2ee280defd6ecbe522e2f8..2848f406eaa0271591e97bf62d5c624e7f1c214a 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_server_wsc.c +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_server_wsc.c @@ -265,7 +265,7 @@ static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id) } data->out_used = 0; } - /* fall through */ + __attribute__((fallthrough)); case WAIT_FRAG_ACK: return eap_wsc_build_msg(data, id); case FRAG_ACK: diff --git a/wpa_supplicant-2.9_standard/src/eap_server/eap_tls_common.h b/wpa_supplicant-2.9_standard/src/eap_server/eap_tls_common.h index b0723a1fa492cafee461da39c1ed9b68c8f7ee9c..ad28c796267256b47a0b925a0d5fbdddb0df49e9 100644 --- a/wpa_supplicant-2.9_standard/src/eap_server/eap_tls_common.h +++ b/wpa_supplicant-2.9_standard/src/eap_server/eap_tls_common.h @@ -55,6 +55,8 @@ struct eap_ssl_data { * tls_v13 - Whether TLS v1.3 or newer is used */ int tls_v13; + + bool skip_prot_success; /* testing behavior only for TLS v1.3 */ }; diff --git a/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm.c b/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm.c index ca54f8f6fd6adaeffa9743b17ceb7191c16a533d..0cf8199e87b0d1409ee233458c8be4d3770ec0f2 100644 --- a/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm.c +++ b/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm.c @@ -217,6 +217,9 @@ SM_STATE(AUTH_PAE, INITIALIZE) SM_STATE(AUTH_PAE, DISCONNECTED) { int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE; + bool pre_auth_logoff = sm->auth_pae_state == AUTH_PAE_ABORTING && + sm->eapolLogoff && !sm->authenticated; + bool logoff = sm->eapolLogoff; if (sm->eapolLogoff) { if (sm->auth_pae_state == AUTH_PAE_CONNECTING) @@ -231,10 +234,14 @@ SM_STATE(AUTH_PAE, DISCONNECTED) setPortUnauthorized(); sm->reAuthCount = 0; sm->eapolLogoff = false; - if (!from_initialize) { - sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, - sm->flags & EAPOL_SM_PREAUTH, - sm->remediation); + if (!from_initialize && !pre_auth_logoff) { + if (sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, + sm->flags & EAPOL_SM_PREAUTH, + sm->remediation, logoff)) { + wpa_printf(MSG_DEBUG, + "EAPOL: Do not restart since lower layers will disconnect the port after EAPOL-Logoff"); + sm->stopped = true; + } } } @@ -291,7 +298,8 @@ SM_STATE(AUTH_PAE, HELD) eap_server_get_name(0, sm->eap_type_supp)); } sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0, - sm->flags & EAPOL_SM_PREAUTH, sm->remediation); + sm->flags & EAPOL_SM_PREAUTH, sm->remediation, + false); } @@ -316,8 +324,11 @@ SM_STATE(AUTH_PAE, AUTHENTICATED) sm->eap_type_authsrv, eap_server_get_name(0, sm->eap_type_authsrv), extra); + if (sm->authSuccess) + sm->authenticated++; sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1, - sm->flags & EAPOL_SM_PREAUTH, sm->remediation); + sm->flags & EAPOL_SM_PREAUTH, sm->remediation, + false); } @@ -397,7 +408,8 @@ SM_STEP(AUTH_PAE) SM_ENTER(AUTH_PAE, DISCONNECTED); break; case AUTH_PAE_DISCONNECTED: - SM_ENTER(AUTH_PAE, RESTART); + if (!sm->stopped) + SM_ENTER(AUTH_PAE, RESTART); break; case AUTH_PAE_RESTART: if (!sm->eap_if->eapRestart) diff --git a/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm.h b/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm.h index 5fe89c64b3a35dae2878a6818b8e8050ab53f721..7296a3acaafe7008a5bc3554413b7eda41b2523c 100644 --- a/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm.h +++ b/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm.h @@ -23,6 +23,7 @@ struct eapol_auth_config { size_t eap_req_id_text_len; int erp_send_reauth_start; char *erp_domain; /* a copy of this will be allocated */ + bool eap_skip_prot_success; /* Opaque context pointer to owner data for callback functions */ void *ctx; @@ -45,8 +46,8 @@ struct eapol_auth_cb { size_t datalen); void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data, size_t datalen); - void (*finished)(void *ctx, void *sta_ctx, int success, int preauth, - int remediation); + bool (*finished)(void *ctx, void *sta_ctx, int success, int preauth, + int remediation, bool logoff); int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, int phase2, struct eap_user *user); int (*sta_entry_alive)(void *ctx, const u8 *addr); diff --git a/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm_i.h b/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm_i.h index 3c689831028463c15af1cc42c9c30068ce444831..a0cef0f8ec061a6fec55a59fc05eb2ac9534bd89 100644 --- a/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm_i.h +++ b/wpa_supplicant-2.9_standard/src/eapol_auth/eapol_auth_sm_i.h @@ -171,6 +171,10 @@ struct eapol_state_machine { int remediation; u64 acct_multi_session_id; + + unsigned int authenticated; /* The number of times authentication has + * been completed successfully. */ + bool stopped; }; #endif /* EAPOL_AUTH_SM_I_H */ diff --git a/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.c b/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.c index e2abee21fcf27ce4b76540ebafef79928be22e36..79047cfd6953434c0ce1b79439a7d0981f035336 100644 --- a/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.c +++ b/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.c @@ -22,6 +22,8 @@ #define STATE_MACHINE_DATA struct eapol_sm #define STATE_MACHINE_DEBUG_PREFIX "EAPOL" +#define EAP_FAIL_REASON 4 +#define EAP_SM_ID_LEN 5 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */ @@ -1290,11 +1292,12 @@ int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen) * @src: Source MAC address of the EAPOL packet * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) * @len: Length of the EAPOL frame + * @encrypted: Whether the frame was encrypted * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine, * -1 failure */ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, - size_t len) + size_t len, enum frame_encryption encrypted) { const struct ieee802_1x_hdr *hdr; const struct ieee802_1x_eapol_key *key; @@ -1304,6 +1307,14 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, if (sm == NULL) return 0; + + if (encrypted == FRAME_NOT_ENCRYPTED && sm->ctx->encryption_required && + sm->ctx->encryption_required(sm->ctx->ctx)) { + wpa_printf(MSG_DEBUG, + "EAPOL: Discard unencrypted EAPOL frame when encryption since encryption was expected"); + return 0; + } + sm->dot1xSuppEapolFramesRx++; if (len < sizeof(*hdr)) { sm->dot1xSuppInvalidEapolFramesRx++; @@ -1380,7 +1391,7 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, /* miss GO'EAP-Failure frame issue */ const struct eap_hdr *ehdr = (const struct eap_hdr *) (hdr + 1); seapol_sm = sm; - if (ehdr->code == 4) { + if (ehdr->code == EAP_FAIL_REASON) { wpa_printf(MSG_DEBUG, "EAPOL: cancel eap_fail_timeout as it was received. sm=%p\n", sm); eloop_cancel_timeout(wps_eap_fail_timeout, NULL, NULL); } @@ -1463,8 +1474,9 @@ void wps_eap_fail_timeout(void *eloop_data, void *user_ctx) return; } sm = seapol_sm; - data[5] = eapol_sm_get_lastId(sm->eap); + data[EAP_SM_ID_LEN] = eapol_sm_get_lastId(sm->eap); wpa_printf(MSG_DEBUG, "WPS build eap-fail for its timed out"); + // adapt 2.11 version, add last param eapol_sm_rx_eapol(sm, sm->dot1xSuppLastEapolFrameSource, (const u8 *)data, 8); wpa_printf(MSG_DEBUG, "EAPOL: run eap_fail_timeout sm=%p \n", sm); } @@ -2328,4 +2340,4 @@ struct eap_sm* eapol_sm_get_eap(struct eapol_sm *sm) return NULL; } } -#endif +#endif \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.h b/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.h index 12f78be2f86942501e3c6f01a1b2eac35d9dc0fb..d0eb523914d6d0f37aab41932dbbc012a65639ca 100644 --- a/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.h +++ b/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.h @@ -313,6 +313,13 @@ struct eapol_ctx { * Automatically triggers a reconnect when not. */ int (*confirm_auth_cb)(void *ctx); + + /** + * encryption_required - Check whether encryption is required + * @ctx: eapol_ctx from eap_peer_sm_init() call + * Returns: Whether the current session requires encryption + */ + bool (*encryption_required)(void *ctx); }; @@ -329,7 +336,7 @@ int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen); void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod, int startPeriod, int maxStart); int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, - size_t len); + size_t len, enum frame_encryption encrypted); void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm); void eapol_sm_notify_portEnabled(struct eapol_sm *sm, bool enabled); void eapol_sm_notify_portValid(struct eapol_sm *sm, bool valid); @@ -395,7 +402,8 @@ static inline void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, { } static inline int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, - const u8 *buf, size_t len) + const u8 *buf, size_t len, + enum frame_encryption encrypted) { return 0; } diff --git a/wpa_supplicant-2.9_standard/src/fst/fst_ctrl_iface.c b/wpa_supplicant-2.9_standard/src/fst/fst_ctrl_iface.c index 45607b6d90d6df80a49dd27ccc58bd144fd575c4..bccabfca0b01dfc051f7e2528dfb6aefd49af1b1 100644 --- a/wpa_supplicant-2.9_standard/src/fst/fst_ctrl_iface.c +++ b/wpa_supplicant-2.9_standard/src/fst/fst_ctrl_iface.c @@ -49,7 +49,7 @@ static bool format_session_state_extra(const union fst_event_extra *extra, if (ss->extra.to_initial.reject_code != WLAN_STATUS_SUCCESS) os_snprintf(reject_str, sizeof(reject_str), "%u", ss->extra.to_initial.reject_code); - /* fall through */ + __attribute__((fallthrough)); case REASON_TEARDOWN: case REASON_SWITCH: switch (ss->extra.to_initial.initiator) { diff --git a/wpa_supplicant-2.9_standard/src/fst/fst_group.c b/wpa_supplicant-2.9_standard/src/fst/fst_group.c index de3657ffd281a92da286514e0d91340951eaf27e..3bd880e84d240a2c2c24bf9468ed2b3058ef21da 100644 --- a/wpa_supplicant-2.9_standard/src/fst/fst_group.c +++ b/wpa_supplicant-2.9_standard/src/fst/fst_group.c @@ -28,8 +28,13 @@ static void fst_dump_mb_ies(const char *group_id, const char *ifname, while (s >= 2) { const struct multi_band_ie *mbie = (const struct multi_band_ie *) p; + size_t len; + WPA_ASSERT(mbie->eid == WLAN_EID_MULTI_BAND); WPA_ASSERT(2U + mbie->len >= sizeof(*mbie)); + len = 2 + mbie->len; + if (len > s) + break; fst_printf(MSG_WARNING, "%s: %s: mb_ctrl=%u band_id=%u op_class=%u chan=%u bssid=" @@ -45,8 +50,8 @@ static void fst_dump_mb_ies(const char *group_id, const char *ifname, mbie->mb_connection_capability, mbie->fst_session_tmout); - p += 2 + mbie->len; - s -= 2 + mbie->len; + p += len; + s -= len; } } @@ -359,8 +364,7 @@ fst_group_get_peer_other_connection_2(struct fst_iface *iface, cur_mbie, this_band_id); if (!this_peer_addr) continue; - if (os_memcmp(this_peer_addr, peer_addr, ETH_ALEN) == - 0) { + if (ether_addr_equal(this_peer_addr, peer_addr)) { os_memcpy(other_peer_addr, cur_peer_addr, ETH_ALEN); return other_iface; diff --git a/wpa_supplicant-2.9_standard/src/fst/fst_iface.c b/wpa_supplicant-2.9_standard/src/fst/fst_iface.c index 90c5fc0357ede4efa462e3715d0514ca7c60690b..96b2847383eea14b64ba249040925d528e7a5422 100644 --- a/wpa_supplicant-2.9_standard/src/fst/fst_iface.c +++ b/wpa_supplicant-2.9_standard/src/fst/fst_iface.c @@ -56,7 +56,7 @@ bool fst_iface_is_connected(struct fst_iface *iface, const u8 *addr, const u8 *a = fst_iface_get_peer_first(iface, &ctx, mb_only); for (; a != NULL; a = fst_iface_get_peer_next(iface, &ctx, mb_only)) - if (os_memcmp(addr, a, ETH_ALEN) == 0) + if (ether_addr_equal(addr, a)) return true; return false; diff --git a/wpa_supplicant-2.9_standard/src/fst/fst_session.c b/wpa_supplicant-2.9_standard/src/fst/fst_session.c index ebd6eacea4c42d6395a030e28a8b0b8491801da2..6e6b7677f216afe15f9521c2bd7f8880670a69ce 100644 --- a/wpa_supplicant-2.9_standard/src/fst/fst_session.c +++ b/wpa_supplicant-2.9_standard/src/fst/fst_session.c @@ -238,10 +238,8 @@ fst_find_session_in_progress(const u8 *peer_addr, struct fst_group *g) foreach_fst_session(s) { if (s->group == g && - (os_memcmp(s->data.old_peer_addr, peer_addr, - ETH_ALEN) == 0 || - os_memcmp(s->data.new_peer_addr, peer_addr, - ETH_ALEN) == 0) && + (ether_addr_equal(s->data.old_peer_addr, peer_addr) || + ether_addr_equal(s->data.new_peer_addr, peer_addr)) && fst_session_is_in_progress(s)) return s; } diff --git a/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_freebsd.c b/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_freebsd.c index 60de9fe6bba960cfef2c2203eb530e0f820f3a91..481c8ca4d5d6e4fe44002d254bdb85c08696c39a 100644 --- a/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_freebsd.c +++ b/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_freebsd.c @@ -20,6 +20,7 @@ #include #endif /* __sun__ */ +#include #include #include #include @@ -29,6 +30,9 @@ #include "eloop.h" #include "l2_packet.h" +#ifndef ETHER_VLAN_ENCAP_LEN +#define ETHER_VLAN_ENCAP_LEN 4 +#endif static const u8 pae_group_addr[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; @@ -94,6 +98,13 @@ static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) } else { buf = (unsigned char *) (ethhdr + 1); len = hdr.caplen - sizeof(*ethhdr); + + /* Handle IEEE 802.1Q encapsulated frames */ + if (len >= ETHER_VLAN_ENCAP_LEN && + ethhdr->h_proto == htons(ETH_P_8021Q)) { + buf += ETHER_VLAN_ENCAP_LEN; + len -= ETHER_VLAN_ENCAP_LEN; + } } l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len); } @@ -122,10 +133,10 @@ static int l2_packet_init_libpcap(struct l2_packet_data *l2, os_snprintf(pcap_filter, sizeof(pcap_filter), "not ether src " MACSTR " and " "( ether dst " MACSTR " or ether dst " MACSTR " ) and " - "ether proto 0x%x", + "( ether proto 0x%x or ( vlan 0 and ether proto 0x%x ) )", MAC2STR(l2->own_addr), /* do not receive own packets */ MAC2STR(l2->own_addr), MAC2STR(pae_group_addr), - protocol); + protocol, protocol); if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) { fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap)); return -1; diff --git a/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_linux.c b/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_linux.c index b0fb9bef54a6439c19b8067c0f857bd02944e46c..7acbe7097b17ab9a2e413b1950621dd556bf2911 100755 --- a/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_linux.c +++ b/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_linux.c @@ -176,7 +176,7 @@ int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, } -void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) +static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) { struct l2_packet_data *l2 = eloop_ctx; u8 buf[2300]; @@ -246,7 +246,7 @@ void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx) * authorization has been completed (in dormant state). */ if (l2->num_rx_br <= 1 && - (os_memcmp(eth->h_dest, l2->own_addr, ETH_ALEN) == 0 || + (ether_addr_equal(eth->h_dest, l2->own_addr) || is_multicast_ether_addr(eth->h_dest))) { wpa_printf(MSG_DEBUG, "l2_packet_receive: Main packet socket for %s seems to have working RX - close workaround bridge socket", @@ -311,7 +311,7 @@ static void l2_packet_receive_br(int sock, void *eloop_ctx, void *sock_ctx) wpa_printf(MSG_DEBUG, "%s: src=" MACSTR_SEC " len=%d", __func__, MAC2STR_SEC(ll.sll_addr), (int) res); - if (os_memcmp(ll.sll_addr, l2->own_addr, ETH_ALEN) == 0) { + if (ether_addr_equal(ll.sll_addr, l2->own_addr)) { wpa_printf(MSG_DEBUG, "%s: Drop RX of own frame", __func__); return; } diff --git a/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_rtos.c b/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_rtos.c index d8ed0399581fcdf4ced952511be22ce453480409..394e759b7024368864ebf4efc693447c217d40ca 100644 --- a/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_rtos.c +++ b/wpa_supplicant-2.9_standard/src/l2_packet/l2_packet_rtos.c @@ -1,156 +1,156 @@ -/* - * L2 packet implement for hdf wifi - * Copyright (c) 2020 Huawei Device Co., Ltd. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include -#include -#include "common.h" -#ifdef CONFIG_DRIVER_HDF -#include "drivers/wpa_hal.h" -#endif /* CONFIG_DRIVER_HDF */ -#include "securec.h" - -struct l2_packet_data { - char ifname[IFNAMSIZ + 1]; - u8 own_addr[ETH_ALEN]; - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len); - void *rx_callback_ctx; - int l2_hdr; /* whether to include layer 2 (Ethernet) header data - * buffers */ -}; - -int l2_packet_get_own_addr(const struct l2_packet_data *l2, u8 *addr) -{ - - if ((l2 == NULL) || (addr == NULL)) - return -1; - if (memcpy_s(addr, sizeof(l2->own_addr), l2->own_addr, sizeof(l2->own_addr)) != EOK){ - return -1; - } - return 0; -} - -int l2_packet_send(const struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, - const u8 *buf, size_t len) -{ - int ret =0; - - (void)proto; - if (l2 == NULL) - return -1; -#ifdef CONFIG_DRIVER_HDF - ret = WifiEapolPacketSend(l2->ifname, l2->own_addr, dst_addr, (unsigned char *)buf, len); -#endif /* CONFIG_DRIVER_HDF */ - - return ret; -} - -void l2_packet_receive(void *eloop_ctx, void *sock_ctx) -{ - struct l2_packet_data *l2 = eloop_ctx; - - (void)sock_ctx; - - printf("\r\n l2_packet_receive1 \r\n "); - -#ifdef CONFIG_DRIVER_HDF - WifiRxEapol st_rx_eapol = { 0 }; - unsigned char *puc_src; - const int addr_offset = 6; - - /* Callback is called only once per multiple packets, drain all of them */ - printf("\r\n l2_packet_receive2 \r\n "); - if (SUCC == WifiEapolPacketReceive(l2->ifname, &st_rx_eapol)) { - puc_src = (unsigned char *)(st_rx_eapol.buf + addr_offset); - printf("\r\n l2_packet_receive3 \r\n "); - if (l2->rx_callback != NULL) { - printf("\r\n rx_callback \r\n "); - l2->rx_callback(l2->rx_callback_ctx, puc_src, st_rx_eapol.buf, st_rx_eapol.len); - } - - free(st_rx_eapol.buf); - st_rx_eapol.buf = NULL; - } - - if (st_rx_eapol.buf != NULL) { - free(st_rx_eapol.buf); - st_rx_eapol.buf = NULL; - } -#endif /* CONFIG_DRIVER_HDF */ -} - -struct l2_packet_data * l2_packet_init( - const char *ifname, const u8 *own_addr, unsigned short protocol, - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len), - void *rx_callback_ctx, int l2_hdr) -{ - struct l2_packet_data *l2 = NULL; - - (void)own_addr; - (void)protocol; - if (ifname == NULL) - return NULL; - l2 = os_zalloc(sizeof(struct l2_packet_data)); - if (l2 == NULL) { - return NULL; - } - if (strcpy_s(l2->ifname, sizeof(l2->ifname), ifname) != EOK) { - os_free(l2); - return NULL; - } - - l2->rx_callback = rx_callback; - l2->rx_callback_ctx = rx_callback_ctx; - l2->l2_hdr = l2_hdr; - -#ifdef CONFIG_DRIVER_HDF - (void)WifiEapolEnable(l2->ifname); -#endif /* CONFIG_DRIVER_HDF */ -#ifdef CONFIG_DRIVER_HDF - (void)WifiCmdGetOwnMac(l2->ifname, (char *)l2->own_addr, ETH_ALEN); -#endif /* CONFIG_DRIVER_HDF */ - return l2; -} - -struct l2_packet_data * l2_packet_init_bridge( - const char *br_ifname, const char *ifname, const u8 *own_addr, - unsigned short protocol, - void (*rx_callback)(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len), - void *rx_callback_ctx, int l2_hdr) -{ - (void)ifname; - return l2_packet_init(br_ifname, own_addr, protocol, rx_callback, - rx_callback_ctx, l2_hdr); -} - -void l2_packet_deinit(struct l2_packet_data *l2) -{ - if (l2 == NULL) - return; - -#ifdef CONFIG_DRIVER_HDF - (void)WifiEapolDisable(l2->ifname); -#endif /* CONFIG_DRIVER_HDF */ - - os_free(l2); -} - -int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) -{ - (void)l2; - (void)buf; - (void)len; - return 0; -} - -void l2_packet_notify_auth_start(struct l2_packet_data *l2) -{ - (void)l2; -} +/* + * L2 packet implement for hdf wifi + * Copyright (c) 2020 Huawei Device Co., Ltd. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include +#include "common.h" +#ifdef CONFIG_DRIVER_HDF +#include "drivers/wpa_hal.h" +#endif /* CONFIG_DRIVER_HDF */ +#include "securec.h" + +struct l2_packet_data { + char ifname[IFNAMSIZ + 1]; + u8 own_addr[ETH_ALEN]; + void (*rx_callback)(void *ctx, const u8 *src_addr, + const u8 *buf, size_t len); + void *rx_callback_ctx; + int l2_hdr; /* whether to include layer 2 (Ethernet) header data + * buffers */ +}; + +int l2_packet_get_own_addr(const struct l2_packet_data *l2, u8 *addr) +{ + + if ((l2 == NULL) || (addr == NULL)) + return -1; + if (memcpy_s(addr, sizeof(l2->own_addr), l2->own_addr, sizeof(l2->own_addr)) != EOK){ + return -1; + } + return 0; +} + +int l2_packet_send(const struct l2_packet_data *l2, const u8 *dst_addr, u16 proto, + const u8 *buf, size_t len) +{ + int ret =0; + + (void)proto; + if (l2 == NULL) + return -1; +#ifdef CONFIG_DRIVER_HDF + ret = WifiEapolPacketSend(l2->ifname, l2->own_addr, dst_addr, (unsigned char *)buf, len); +#endif /* CONFIG_DRIVER_HDF */ + + return ret; +} + +void l2_packet_receive(void *eloop_ctx, void *sock_ctx) +{ + struct l2_packet_data *l2 = eloop_ctx; + + (void)sock_ctx; + + printf("\r\n l2_packet_receive1 \r\n "); + +#ifdef CONFIG_DRIVER_HDF + WifiRxEapol st_rx_eapol = { 0 }; + unsigned char *puc_src; + const int addr_offset = 6; + + /* Callback is called only once per multiple packets, drain all of them */ + printf("\r\n l2_packet_receive2 \r\n "); + if (SUCC == WifiEapolPacketReceive(l2->ifname, &st_rx_eapol)) { + puc_src = (unsigned char *)(st_rx_eapol.buf + addr_offset); + printf("\r\n l2_packet_receive3 \r\n "); + if (l2->rx_callback != NULL) { + printf("\r\n rx_callback \r\n "); + l2->rx_callback(l2->rx_callback_ctx, puc_src, st_rx_eapol.buf, st_rx_eapol.len); + } + + free(st_rx_eapol.buf); + st_rx_eapol.buf = NULL; + } + + if (st_rx_eapol.buf != NULL) { + free(st_rx_eapol.buf); + st_rx_eapol.buf = NULL; + } +#endif /* CONFIG_DRIVER_HDF */ +} + +struct l2_packet_data * l2_packet_init( + const char *ifname, const u8 *own_addr, unsigned short protocol, + void (*rx_callback)(void *ctx, const u8 *src_addr, + const u8 *buf, size_t len), + void *rx_callback_ctx, int l2_hdr) +{ + struct l2_packet_data *l2 = NULL; + + (void)own_addr; + (void)protocol; + if (ifname == NULL) + return NULL; + l2 = os_zalloc(sizeof(struct l2_packet_data)); + if (l2 == NULL) { + return NULL; + } + if (strcpy_s(l2->ifname, sizeof(l2->ifname), ifname) != EOK) { + os_free(l2); + return NULL; + } + + l2->rx_callback = rx_callback; + l2->rx_callback_ctx = rx_callback_ctx; + l2->l2_hdr = l2_hdr; + +#ifdef CONFIG_DRIVER_HDF + (void)WifiEapolEnable(l2->ifname); +#endif /* CONFIG_DRIVER_HDF */ +#ifdef CONFIG_DRIVER_HDF + (void)WifiCmdGetOwnMac(l2->ifname, (char *)l2->own_addr, ETH_ALEN); +#endif /* CONFIG_DRIVER_HDF */ + return l2; +} + +struct l2_packet_data * l2_packet_init_bridge( + const char *br_ifname, const char *ifname, const u8 *own_addr, + unsigned short protocol, + void (*rx_callback)(void *ctx, const u8 *src_addr, + const u8 *buf, size_t len), + void *rx_callback_ctx, int l2_hdr) +{ + (void)ifname; + return l2_packet_init(br_ifname, own_addr, protocol, rx_callback, + rx_callback_ctx, l2_hdr); +} + +void l2_packet_deinit(struct l2_packet_data *l2) +{ + if (l2 == NULL) + return; + +#ifdef CONFIG_DRIVER_HDF + (void)WifiEapolDisable(l2->ifname); +#endif /* CONFIG_DRIVER_HDF */ + + os_free(l2); +} + +int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len) +{ + (void)l2; + (void)buf; + (void)len; + return 0; +} + +void l2_packet_notify_auth_start(struct l2_packet_data *l2) +{ + (void)l2; +} diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p.c b/wpa_supplicant-2.9_standard/src/p2p/p2p.c index d8b4f21ee94d90bacdc50aaaf00e3b6af934ba18..a5545621a7680caf5dfb4c881f39551230aae033 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p.c +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p.c @@ -372,6 +372,8 @@ static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc) #endif p2p_dbg(p2p, "Failed to start listen mode"); p2p->pending_listen_freq = 0; + } else { + p2p->pending_listen_wait_drv = true; } wpabuf_free(ies); } @@ -421,6 +423,7 @@ int p2p_listen(struct p2p_data *p2p, unsigned int timeout) wpabuf_free(ies); return -1; } + p2p->pending_listen_wait_drv = true; wpabuf_free(ies); p2p_set_state(p2p, P2P_LISTEN_ONLY); @@ -449,7 +452,7 @@ struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr) { struct p2p_device *dev; dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - if (os_memcmp(dev->info.p2p_device_addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(dev->info.p2p_device_addr, addr)) return dev; } return NULL; @@ -467,7 +470,7 @@ struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p, { struct p2p_device *dev; dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - if (os_memcmp(dev->interface_addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(dev->interface_addr, addr)) return dev; } return NULL; @@ -512,6 +515,7 @@ static struct p2p_device * p2p_create_device(struct p2p_data *p2p, return NULL; dl_list_add(&p2p->devices, &dev->list); os_memcpy(dev->info.p2p_device_addr, addr, ETH_ALEN); + dev->support_6ghz = false; return dev; } @@ -554,8 +558,8 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr, * group, the information will be restored in the loop following this. */ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - if (os_memcmp(dev->member_in_go_iface, go_interface_addr, - ETH_ALEN) == 0) { + if (ether_addr_equal(dev->member_in_go_iface, + go_interface_addr)) { os_memset(dev->member_in_go_iface, 0, ETH_ALEN); os_memset(dev->member_in_go_dev, 0, ETH_ALEN); } @@ -563,8 +567,7 @@ static int p2p_add_group_clients(struct p2p_data *p2p, const u8 *go_dev_addr, for (c = 0; c < info.num_clients; c++) { struct p2p_client_info *cli = &info.client[c]; - if (os_memcmp(cli->p2p_device_addr, p2p->cfg->dev_addr, - ETH_ALEN) == 0) + if (ether_addr_equal(cli->p2p_device_addr, p2p->cfg->dev_addr)) continue; /* ignore our own entry */ dev = p2p_get_device(p2p, cli->p2p_device_addr); if (dev) { @@ -680,6 +683,8 @@ static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev, dev->info.group_capab = msg->capability[1]; } + p2p_update_peer_6ghz_capab(dev, msg); + if (msg->ext_listen_timing) { dev->ext_listen_period = WPA_GET_LE16(msg->ext_listen_timing); dev->ext_listen_interval = @@ -703,6 +708,15 @@ static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev, } +void p2p_update_peer_6ghz_capab(struct p2p_device *dev, + const struct p2p_message *msg) +{ + if (msg->capability && + (msg->capability[0] & P2P_DEV_CAPAB_6GHZ_BAND_CAPABLE)) + dev->support_6ghz = true; +} + + static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies, size_t ies_len) { @@ -811,7 +825,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, } if (!is_zero_ether_addr(p2p->peer_filter) && - os_memcmp(p2p_dev_addr, p2p->peer_filter, ETH_ALEN) != 0) { + !ether_addr_equal(p2p_dev_addr, p2p->peer_filter)) { p2p_dbg(p2p, "Do not add peer filter for " MACSTR_SEC " due to peer filter", MAC2STR_SEC(p2p_dev_addr)); p2p_parse_free(&msg); @@ -856,7 +870,7 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY | P2P_DEV_LAST_SEEN_AS_GROUP_CLIENT); - if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0) + if (!ether_addr_equal(addr, p2p_dev_addr)) os_memcpy(dev->interface_addr, addr, ETH_ALEN); if (msg.ssid && msg.ssid[1] <= sizeof(dev->oper_ssid) && @@ -1099,6 +1113,7 @@ static void p2p_search(struct p2p_data *p2p) return; } p2p->cfg->stop_listen(p2p->cfg->cb_ctx); + p2p->pending_listen_wait_drv = false; if (p2p->find_pending_full && (p2p->find_type == P2P_FIND_PROGRESSIVE || @@ -1336,6 +1351,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, p2p->pending_listen_freq = 0; } p2p->cfg->stop_listen(p2p->cfg->cb_ctx); + p2p->pending_listen_wait_drv = false; p2p->find_pending_full = 0; p2p->find_type = type; if (freq != 2412 && freq != 2437 && freq != 2462 && freq != 60480) @@ -1363,7 +1379,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, p2p->find_pending_full = 1; p2p->find_type = P2P_FIND_START_WITH_FULL; } - /* fall through */ + __attribute__((fallthrough)); #endif case P2P_FIND_START_WITH_FULL: if (freq > 0) { @@ -1379,7 +1395,7 @@ int p2p_find(struct p2p_data *p2p, unsigned int timeout, p2p->include_6ghz); break; } - /* fall through */ + __attribute__((fallthrough)); case P2P_FIND_PROGRESSIVE: res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, P2P_SCAN_FULL, 0, p2p->num_req_dev_types, @@ -1441,6 +1457,10 @@ void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq) void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq) { + p2p_dbg(p2p, + "%s(freq=%d) pending_listen_freq=%d in_listen=%d drv_in_listen=%d", + __func__, freq, p2p->pending_listen_freq, p2p->in_listen, + p2p->drv_in_listen); if (freq > 0 && ((p2p->drv_in_listen == freq && p2p->in_listen) || p2p->pending_listen_freq == (unsigned int) freq)) { @@ -1460,7 +1480,15 @@ void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq) p2p_dbg(p2p, "Clear drv_in_listen (%d)", p2p->drv_in_listen); p2p->drv_in_listen = 0; } + if (p2p->pending_listen_freq && + p2p->pending_listen_freq != (unsigned int) freq && + !p2p->drv_in_listen && p2p->pending_listen_wait_drv) { + p2p_dbg(p2p, + "Clear pending_listen_freq since the started listen did not complete before being stopped"); + p2p->pending_listen_freq = 0; + } p2p->cfg->stop_listen(p2p->cfg->cb_ctx); + p2p->pending_listen_wait_drv = false; } @@ -1602,11 +1630,12 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p) } else { /* Select any random available channel from the first available * operating class */ - p2p_channel_select(&p2p->cfg->channels, NULL, - &p2p->op_reg_class, - &p2p->op_channel); - p2p_dbg(p2p, "Select random available channel %d from operating class %d as operating channel preference", - p2p->op_channel, p2p->op_reg_class); + if (p2p_channel_select(&p2p->cfg->channels, NULL, + &p2p->op_reg_class, + &p2p->op_channel) == 0) + p2p_dbg(p2p, + "Select random available channel %d from operating class %d as operating channel preference", + p2p->op_channel, p2p->op_reg_class); } p2p_copy_channels(&p2p->channels, &p2p->cfg->channels, p2p->allow_6ghz); @@ -1912,6 +1941,7 @@ int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params) p2p->ssid_set = 0; p2p_random(params->passphrase, p2p->cfg->passphrase_len); + params->passphrase[p2p->cfg->passphrase_len] = '\0'; return 0; } @@ -1944,6 +1974,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len); res.ssid_len = p2p->ssid_len; p2p_random(res.passphrase, p2p->cfg->passphrase_len); + res.passphrase[p2p->cfg->passphrase_len] = '\0'; } else { res.freq = peer->oper_freq; if (p2p->ssid_len) { @@ -2121,6 +2152,7 @@ static void p2p_go_neg_start(void *eloop_ctx, void *timeout_ctx) p2p->pending_listen_freq = 0; } p2p->cfg->stop_listen(p2p->cfg->cb_ctx); + p2p->pending_listen_wait_drv = false; p2p->go_neg_peer->status = P2P_SC_SUCCESS; /* * Set new timeout to make sure a previously set one does not expire @@ -2141,6 +2173,7 @@ static void p2p_invite_start(void *eloop_ctx, void *timeout_ctx) p2p->pending_listen_freq = 0; } p2p->cfg->stop_listen(p2p->cfg->cb_ctx); + p2p->pending_listen_wait_drv = false; p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr, p2p->invite_dev_pw_id); } @@ -2190,6 +2223,7 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr, } } + p2p_update_peer_6ghz_capab(dev, &msg); os_get_reltime(&dev->last_seen); p2p_parse_free(&msg); return; /* already known */ @@ -2479,7 +2513,7 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst, } if (dst && !is_broadcast_ether_addr(dst) && - os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) { + !ether_addr_equal(dst, p2p->cfg->dev_addr)) { /* Not sent to the broadcast address or our P2P Device Address */ p2p_dbg(p2p, "Probe Req DA " MACSTR_SEC " not ours - ignore it", @@ -2567,7 +2601,7 @@ p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *dst, } if (msg.device_id && - os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN) != 0) { + !ether_addr_equal(msg.device_id, p2p->cfg->dev_addr)) { /* Device ID did not match */ p2p_dbg(p2p, "Probe Req requested Device ID " MACSTR_SEC " did not match - ignore it", MAC2STR_SEC(msg.device_id)); @@ -2656,8 +2690,7 @@ p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst, */ if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) && p2p->go_neg_peer && - os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) - == 0 && + ether_addr_equal(addr, p2p->go_neg_peer->info.p2p_device_addr) && !(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) { /* Received a Probe Request from GO Negotiation peer */ p2p_dbg(p2p, "Found GO Negotiation peer - try to start GO negotiation from timeout"); @@ -2669,8 +2702,7 @@ p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst, if ((p2p->state == P2P_INVITE || p2p->state == P2P_INVITE_LISTEN) && p2p->invite_peer && (p2p->invite_peer->flags & P2P_DEV_WAIT_INV_REQ_ACK) && - os_memcmp(addr, p2p->invite_peer->info.p2p_device_addr, ETH_ALEN) - == 0) { + ether_addr_equal(addr, p2p->invite_peer->info.p2p_device_addr)) { /* Received a Probe Request from Invite peer */ p2p_dbg(p2p, "Found Invite peer - try to start Invite from timeout"); eloop_cancel_timeout(p2p_invite_start, p2p, NULL); @@ -3023,8 +3055,7 @@ void p2p_wps_success_cb(struct p2p_data *p2p, const u8 *mac_addr) return; /* No pending Group Formation */ } - if (os_memcmp(mac_addr, p2p->go_neg_peer->intended_addr, ETH_ALEN) != - 0) { + if (!ether_addr_equal(mac_addr, p2p->go_neg_peer->intended_addr)) { p2p_dbg(p2p, "Ignore WPS registration success notification for " MACSTR_SEC " (GO Negotiation peer " MACSTR_SEC ")", MAC2STR_SEC(mac_addr), @@ -3451,7 +3482,7 @@ skip_sd: } -static void p2p_sd_cb(struct p2p_data *p2p, int success) +void p2p_sd_query_cb(struct p2p_data *p2p, int success) { p2p_dbg(p2p, "Service Discovery Query TX callback: success=%d", success); @@ -3515,8 +3546,8 @@ static void p2p_retry_pd(struct p2p_data *p2p) */ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - if (os_memcmp(p2p->pending_pd_devaddr, - dev->info.p2p_device_addr, ETH_ALEN) != 0) + if (!ether_addr_equal(p2p->pending_pd_devaddr, + dev->info.p2p_device_addr)) continue; if (!dev->req_config_methods) continue; @@ -3964,7 +3995,7 @@ void p2p_send_action_cb(struct p2p_data *p2p, unsigned int freq, const u8 *dst, p2p_go_neg_conf_cb(p2p, result); break; case P2P_PENDING_SD: - p2p_sd_cb(p2p, success); + p2p_sd_query_cb(p2p, success); break; case P2P_PENDING_PD: p2p_prov_disc_cb(p2p, success); @@ -4011,7 +4042,7 @@ void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq, p2p_dbg(p2p, "Starting Listen timeout(%u,%u) on freq=%u based on callback", p2p->pending_listen_sec, p2p->pending_listen_usec, p2p->pending_listen_freq); - + p2p->pending_listen_wait_drv = false; p2p->in_listen = 1; p2p->drv_in_listen = freq; if (p2p->pending_listen_sec || p2p->pending_listen_usec) { @@ -4020,7 +4051,7 @@ void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq, * remain-on-channel end event, i.e., give driver more time to * complete the operation before our timeout expires. */ - + #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) p2p_set_timeout(p2p, p2p->pending_listen_sec, p2p->pending_listen_usec + HM_P2P_LISTEN_EXTRA_WAIT_TIME); @@ -4037,7 +4068,6 @@ void p2p_listen_cb(struct p2p_data *p2p, unsigned int freq, int p2p_listen_end(struct p2p_data *p2p, unsigned int freq) { p2p_dbg(p2p, "Driver ended Listen state (freq=%u)", freq); - p2p->drv_in_listen = 0; if (p2p->in_listen) return 0; /* Internal timeout will trigger the next step */ @@ -4177,6 +4207,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->pending_listen_wait_drv = false; if (p2p->pending_listen_freq) { p2p_dbg(p2p, "Clear pending_listen_freq for %s", __func__); p2p->pending_listen_freq = 0; @@ -4230,8 +4261,8 @@ static void p2p_timeout_prov_disc_req(struct p2p_data *p2p) int for_join = 0; dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - if (os_memcmp(p2p->pending_pd_devaddr, - dev->info.p2p_device_addr, ETH_ALEN) != 0) + if (!ether_addr_equal(p2p->pending_pd_devaddr, + dev->info.p2p_device_addr)) continue; if (dev->req_config_methods && (dev->flags & P2P_DEV_PD_FOR_JOIN)) @@ -4263,9 +4294,11 @@ static void p2p_timeout_invite(struct p2p_data *p2p) /* * Better remain on operating channel instead of listen channel * when running a group. + * Wait 120 ms to let the P2P GO to send its beacon on the + * intended TBTT. */ p2p_dbg(p2p, "Inviting in active GO role - wait on operating channel"); - p2p_set_timeout(p2p, 0, 100000); + p2p_set_timeout(p2p, 0, 120000); return; } p2p_listen_in_find(p2p, 0); @@ -4305,6 +4338,7 @@ static void p2p_state_timeout(void *eloop_ctx, void *timeout_ctx) if (p2p->drv_in_listen) { p2p_dbg(p2p, "Driver is still in listen state - stop it"); p2p->cfg->stop_listen(p2p->cfg->cb_ctx); + p2p->pending_listen_wait_drv = false; } switch (p2p->state) { @@ -4699,8 +4733,8 @@ static void p2p_process_presence_req(struct p2p_data *p2p, const u8 *da, p2p_dbg(p2p, "Received P2P Action - P2P Presence Request"); for (g = 0; g < p2p->num_groups; g++) { - if (os_memcmp(da, p2p_group_get_interface_addr(p2p->groups[g]), - ETH_ALEN) == 0) { + if (ether_addr_equal( + da, p2p_group_get_interface_addr(p2p->groups[g]))) { group = p2p->groups[g]; break; } @@ -4799,21 +4833,12 @@ static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx) #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL); -#endif +#endif eloop_register_timeout(p2p->ext_listen_interval_sec, p2p->ext_listen_interval_usec, p2p_ext_listen_timeout, p2p, NULL); } - if ((p2p->cfg->is_p2p_in_progress && - p2p->cfg->is_p2p_in_progress(p2p->cfg->cb_ctx)) || - (p2p->pending_action_state == P2P_PENDING_PD && - p2p->pd_retries > 0)) { - p2p_dbg(p2p, "Operation in progress - skip Extended Listen timeout (%s)", - p2p_state_txt(p2p->state)); - return; - } - if (p2p->state == P2P_LISTEN_ONLY && p2p->ext_listen_only) { /* * This should not really happen, but it looks like the Listen @@ -4826,13 +4851,21 @@ static void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx) p2p_set_state(p2p, P2P_IDLE); } + if ((p2p->cfg->is_p2p_in_progress && + p2p->cfg->is_p2p_in_progress(p2p->cfg->cb_ctx)) || + (p2p->pending_action_state == P2P_PENDING_PD && + p2p->pd_retries > 0)) { + p2p_dbg(p2p, "Operation in progress - skip Extended Listen timeout (%s)", + p2p_state_txt(p2p->state)); + return; + } + if (p2p->state != P2P_IDLE) { p2p_dbg(p2p, "Skip Extended Listen timeout in active state (%s)", p2p_state_txt(p2p->state)); return; } p2p_dbg(p2p, "Extended Listen timeout"); - p2p->ext_listen_only = 1; if (p2p_listen(p2p, p2p->ext_listen_period) < 0) { p2p_dbg(p2p, "Failed to start Listen state for Extended Listen Timing"); @@ -4866,13 +4899,13 @@ int p2p_ext_listen(struct p2p_data *p2p, unsigned int period, p2p_dbg(p2p, "Enabling Extended Listen Timing: period %u msec, interval %u msec", period, interval); - + #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) p2p->enable_ext_listen = TRUE; p2p->on_op_channel_listen = FALSE; p2p->cfg->channel = p2p->original_listen_channel; p2p->cfg->reg_class = p2p->original_reg_class; -#endif +#endif p2p->ext_listen_period = period; p2p->ext_listen_interval = interval; p2p->ext_listen_interval_sec = interval / 1000; @@ -5765,7 +5798,7 @@ void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx) void p2p_set_own_pref_freq_list(struct p2p_data *p2p, - const unsigned int *pref_freq_list, + const struct weighted_pcl *pref_freq_list, unsigned int size) { unsigned int i; @@ -5773,10 +5806,11 @@ void p2p_set_own_pref_freq_list(struct p2p_data *p2p, if (size > P2P_MAX_PREF_CHANNELS) size = P2P_MAX_PREF_CHANNELS; p2p->num_pref_freq = size; + os_memcpy(p2p->pref_freq_list, pref_freq_list, + size * sizeof(struct weighted_pcl)); for (i = 0; i < size; i++) { - p2p->pref_freq_list[i] = pref_freq_list[i]; p2p_dbg(p2p, "Own preferred frequency list[%u]=%u MHz", - i, p2p->pref_freq_list[i]); + i, p2p->pref_freq_list[i].freq); } } @@ -5828,7 +5862,7 @@ bool p2p_is_peer_6ghz_capab(struct p2p_data *p2p, const u8 *addr) if (!dev) return false; - return !!(dev->info.dev_capab & P2P_DEV_CAPAB_6GHZ_BAND_CAPABLE); + return dev->support_6ghz; } @@ -5938,4 +5972,4 @@ void p2p_set_persistent_group_need_remove_flag(struct p2p_data *p2p, int value) p2p->persistent_group_need_remove = value; } #endif -#endif \ No newline at end of file +#endif diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p.h b/wpa_supplicant-2.9_standard/src/p2p/p2p.h index 3099f5df55fbc51fb8c4e2ce48a61c9cd4411dfd..aeb206a36c4e7da88fe40b792c21ff51c30bc4b1 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p.h +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p.h @@ -12,6 +12,8 @@ #include "common/ieee802_11_defs.h" #include "wps/wps.h" +struct weighted_pcl; + /* P2P ASP Setup Capability */ #define P2PS_SETUP_NONE 0 #define P2PS_SETUP_NEW BIT(0) @@ -1152,7 +1154,8 @@ struct p2p_config { * the driver specific to a particular interface type. */ int (*get_pref_freq_list)(void *ctx, int go, - unsigned int *len, unsigned int *freq_list); + unsigned int *len, + struct weighted_pcl *freq_list); }; @@ -2365,6 +2368,8 @@ struct wpabuf * p2p_build_nfc_handover_sel(struct p2p_data *p2p, const u8 *go_dev_addr, const u8 *ssid, size_t ssid_len); +bool p2p_pref_freq_allowed(const struct weighted_pcl *freq_list, bool go); + struct p2p_nfc_params { int sel; const u8 *wsc_attr; @@ -2410,6 +2415,7 @@ void p2p_set_process_go_neg_opt(struct p2p_data * p2p, int status); void p2p_set_enable_go_neg_opt(struct p2p_data * p2p, int status); #endif + #ifdef HARMONY_CONNECTIVITY_PATCH #ifndef OPEN_HARMONY_MIRACAST_SINK_OPT int p2p_get_persistent_group_need_remove_flag(struct p2p_data *p2p); @@ -2439,7 +2445,7 @@ struct p2ps_advertisement * p2p_get_p2ps_adv_list(struct p2p_data *p2p); void p2p_expire_peers(struct p2p_data *p2p); void p2p_set_own_pref_freq_list(struct p2p_data *p2p, - const unsigned int *pref_freq_list, + const struct weighted_pcl *pref_freq_list, unsigned int size); void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class, u8 chan); @@ -2464,7 +2470,8 @@ bool p2p_peer_wfd_enabled(struct p2p_data *p2p, const u8 *peer_addr); bool p2p_wfd_enabled(struct p2p_data *p2p); bool is_p2p_allow_6ghz(struct p2p_data *p2p); void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value); -int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size); +int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size); +int p2p_channel_to_freq(int op_class, int channel); #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) void p2p_ext_listen_timeout(void *eloop_ctx, void *timeout_ctx); diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p_build.c b/wpa_supplicant-2.9_standard/src/p2p/p2p_build.c index d34c94e09cfd0f9fbaefa56b974e8a9cd42f7a5e..e85919a8973825ad6614af1e2749bce39134614e 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p_build.c +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p_build.c @@ -10,6 +10,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" #include "common/qca-vendor.h" #include "wps/wps_i.h" #include "p2p_i.h" @@ -111,7 +112,7 @@ void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country, void p2p_buf_add_pref_channel_list(struct wpabuf *buf, - const unsigned int *preferred_freq_list, + const struct weighted_pcl *pref_freq_list, unsigned int size) { unsigned int i, count = 0; @@ -126,8 +127,9 @@ void p2p_buf_add_pref_channel_list(struct wpabuf *buf, * of the vendor IE size. */ for (i = 0; i < size; i++) { - if (p2p_freq_to_channel(preferred_freq_list[i], &op_class, - &op_channel) == 0) + if (p2p_freq_to_channel(pref_freq_list[i].freq, &op_class, + &op_channel) == 0 && + !(pref_freq_list[i].flag & WEIGHTED_PCL_EXCLUDE)) count++; } @@ -136,10 +138,11 @@ void p2p_buf_add_pref_channel_list(struct wpabuf *buf, wpabuf_put_be24(buf, OUI_QCA); wpabuf_put_u8(buf, QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST); for (i = 0; i < size; i++) { - if (p2p_freq_to_channel(preferred_freq_list[i], &op_class, - &op_channel) < 0) { + if (p2p_freq_to_channel(pref_freq_list[i].freq, &op_class, + &op_channel) < 0 || + (pref_freq_list[i].flag & WEIGHTED_PCL_EXCLUDE)) { wpa_printf(MSG_DEBUG, "Unsupported frequency %u MHz", - preferred_freq_list[i]); + pref_freq_list[i].freq); continue; } wpabuf_put_u8(buf, op_class); @@ -149,7 +152,7 @@ void p2p_buf_add_pref_channel_list(struct wpabuf *buf, void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, - struct p2p_channels *chan) + struct p2p_channels *chan, bool is_6ghz_capab) { u8 *len; size_t i; @@ -161,6 +164,9 @@ void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, for (i = 0; i < chan->reg_classes; i++) { struct p2p_reg_class *c = &chan->reg_class[i]; + + if (is_6ghz_op_class(c->reg_class) && !is_6ghz_capab) + continue; wpabuf_put_u8(buf, c->reg_class); wpabuf_put_u8(buf, c->channels); wpabuf_put_data(buf, c->channel, c->channels); diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p_dev_disc.c b/wpa_supplicant-2.9_standard/src/p2p/p2p_dev_disc.c index aa2b6322a722bec536b26a905c4b9b179ffe3369..fb75c89828f70b24ff0eabe6e9347169eb3e782b 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p_dev_disc.c +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p_dev_disc.c @@ -223,7 +223,7 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa, go = p2p->pending_client_disc_go; if (go == NULL || - os_memcmp(sa, go->info.p2p_device_addr, ETH_ALEN) != 0) { + !ether_addr_equal(sa, go->info.p2p_device_addr)) { p2p_dbg(p2p, "Ignore unexpected Device Discoverability Response"); return; } @@ -249,10 +249,10 @@ void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa, p2p_dbg(p2p, "Device Discoverability Response status %u", status); if (p2p->go_neg_peer == NULL || - os_memcmp(p2p->pending_client_disc_addr, - p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) != 0 || - os_memcmp(p2p->go_neg_peer->member_in_go_dev, - go->info.p2p_device_addr, ETH_ALEN) != 0) { + !ether_addr_equal(p2p->pending_client_disc_addr, + p2p->go_neg_peer->info.p2p_device_addr) || + !ether_addr_equal(p2p->go_neg_peer->member_in_go_dev, + go->info.p2p_device_addr)) { p2p_dbg(p2p, "No pending operation with the client discoverability peer anymore"); return; } diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p_go_neg.c b/wpa_supplicant-2.9_standard/src/p2p/p2p_go_neg.c index d0f578d0169bd3b3866c307aec1d9e3ef1b62f51..9fd5ad416ad92a8b20386693ea5ffd6a219814ae 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p_go_neg.c +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p_go_neg.c @@ -11,6 +11,7 @@ #include "common.h" #include "utils/eloop.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" #include "wps/wps_defs.h" #include "p2p_i.h" @@ -167,6 +168,7 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, u8 group_capab; size_t extra = 0; u16 pw_id; + bool is_6ghz_capab; #ifdef CONFIG_WIFI_DISPLAY if (p2p->wfd_ie_go_neg) @@ -204,7 +206,22 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period, p2p->ext_listen_interval); p2p_buf_add_intended_addr(buf, p2p->intended_addr); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); + is_6ghz_capab = is_p2p_6ghz_capable(p2p) && + p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); + if (p2p->num_pref_freq) { + bool go = p2p->go_intent == 15; + struct p2p_channels pref_chanlist; + + p2p_pref_channel_filter(&p2p->channels, p2p->pref_freq_list, + p2p->num_pref_freq, &pref_chanlist, go); + p2p_channels_dump(p2p, "channel list after filtering", + &pref_chanlist); + p2p_buf_add_channel_list(buf, p2p->cfg->country, + &pref_chanlist, is_6ghz_capab); + } else { + p2p_buf_add_channel_list(buf, p2p->cfg->country, + &p2p->channels, is_6ghz_capab); + } p2p_buf_add_device_info(buf, p2p, peer); p2p_buf_add_operating_channel(buf, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); @@ -303,6 +320,8 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, u8 group_capab; size_t extra = 0; u16 pw_id; + bool is_6ghz_capab; + struct p2p_channels pref_chanlist; p2p_dbg(p2p, "Building GO Negotiation Response"); @@ -353,17 +372,35 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, p2p->op_channel); } p2p_buf_add_intended_addr(buf, p2p->intended_addr); + if (p2p->num_pref_freq) { + bool go = (peer && peer->go_state == LOCAL_GO) || + p2p->go_intent == 15; + + p2p_pref_channel_filter(&p2p->channels, p2p->pref_freq_list, + p2p->num_pref_freq, &pref_chanlist, go); + p2p_channels_dump(p2p, "channel list after filtering", + &pref_chanlist); + } else { + p2p_copy_channels(&pref_chanlist, &p2p->channels, + p2p->allow_6ghz); + } if (status || peer == NULL) { p2p_buf_add_channel_list(buf, p2p->cfg->country, - &p2p->channels); + &pref_chanlist, false); } else if (peer->go_state == REMOTE_GO) { + is_6ghz_capab = is_p2p_6ghz_capable(p2p) && + p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); p2p_buf_add_channel_list(buf, p2p->cfg->country, - &p2p->channels); + &pref_chanlist, is_6ghz_capab); } else { struct p2p_channels res; - p2p_channels_intersect(&p2p->channels, &peer->channels, + + is_6ghz_capab = is_p2p_6ghz_capable(p2p) && + p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); + p2p_channels_intersect(&pref_chanlist, &peer->channels, &res); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &res); + p2p_buf_add_channel_list(buf, p2p->cfg->country, &res, + is_6ghz_capab); } p2p_buf_add_device_info(buf, p2p, peer); if (peer && peer->go_state == LOCAL_GO) { @@ -683,7 +720,8 @@ int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev, static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go, struct p2p_device *dev, struct p2p_message *msg, - unsigned freq_list[], unsigned int size) + const struct weighted_pcl freq_list[], + unsigned int size) { u8 op_class, op_channel; unsigned int oper_freq = 0, i, j; @@ -698,10 +736,11 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go, */ for (i = 0; i < size && !found; i++) { /* Make sure that the common frequency is supported by peer. */ - oper_freq = freq_list[i]; + oper_freq = freq_list[i].freq; if (p2p_freq_to_channel(oper_freq, &op_class, - &op_channel) < 0) - continue; /* cannot happen due to earlier check */ + &op_channel) < 0 || + !p2p_pref_freq_allowed(&freq_list[i], go)) + continue; for (j = 0; j < msg->channel_list_len; j++) { if (!msg->channel_list || op_channel != msg->channel_list[j]) @@ -730,7 +769,8 @@ static void p2p_check_pref_chan_no_recv(struct p2p_data *p2p, int go, static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go, struct p2p_device *dev, struct p2p_message *msg, - unsigned freq_list[], unsigned int size) + const struct weighted_pcl freq_list[], + unsigned int size) { u8 op_class, op_channel; unsigned int oper_freq = 0, i, j; @@ -746,11 +786,13 @@ static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go, oper_freq = p2p_channel_to_freq( msg->pref_freq_list[2 * j], msg->pref_freq_list[2 * j + 1]); - if (freq_list[i] != oper_freq) + if (freq_list[i].freq != oper_freq) continue; if (p2p_freq_to_channel(oper_freq, &op_class, &op_channel) < 0) continue; /* cannot happen */ + if (!p2p_pref_freq_allowed(&freq_list[i], go)) + break; p2p->op_reg_class = op_class; p2p->op_channel = op_channel; os_memcpy(&p2p->channels, &p2p->cfg->channels, @@ -773,10 +815,11 @@ static void p2p_check_pref_chan_recv(struct p2p_data *p2p, int go, void p2p_check_pref_chan(struct p2p_data *p2p, int go, struct p2p_device *dev, struct p2p_message *msg) { - unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size; + unsigned int size; unsigned int i; u8 op_class, op_channel; char txt[100], *pos, *end; + bool is_6ghz_capab; int res; /* @@ -790,25 +833,34 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, /* Obtain our preferred frequency list from driver based on P2P role. */ size = P2P_MAX_PREF_CHANNELS; - if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size, - freq_list)) + if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, + &p2p->num_pref_freq, + p2p->pref_freq_list)) + return; + size = p2p->num_pref_freq; + if (!size) return; /* Filter out frequencies that are not acceptable for P2P use */ + is_6ghz_capab = is_p2p_6ghz_capable(p2p) && + p2p_is_peer_6ghz_capab(p2p, dev->info.p2p_device_addr); i = 0; while (i < size) { - if (p2p_freq_to_channel(freq_list[i], &op_class, - &op_channel) < 0 || + if (p2p_freq_to_channel(p2p->pref_freq_list[i].freq, + &op_class, &op_channel) < 0 || (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel) && (go || !p2p_channels_includes(&p2p->cfg->cli_channels, - op_class, op_channel)))) { + op_class, op_channel))) || + (is_6ghz_freq(p2p->pref_freq_list[i].freq) && + !is_6ghz_capab)) { p2p_dbg(p2p, "Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)", - freq_list[i], go); + p2p->pref_freq_list[i].freq, go); if (size - i - 1 > 0) - os_memmove(&freq_list[i], &freq_list[i + 1], + os_memmove(&p2p->pref_freq_list[i], + &p2p->pref_freq_list[i + 1], (size - i - 1) * - sizeof(unsigned int)); + sizeof(struct weighted_pcl)); size--; continue; } @@ -820,7 +872,8 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, pos = txt; end = pos + sizeof(txt); for (i = 0; i < size; i++) { - res = os_snprintf(pos, end - pos, " %u", freq_list[i]); + res = os_snprintf(pos, end - pos, " %u", + p2p->pref_freq_list[i].freq); if (os_snprintf_error(end - pos, res)) break; pos += res; @@ -834,11 +887,14 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, * our preferred channel list. */ for (i = 0; i < size; i++) { - if (freq_list[i] == (unsigned int) dev->oper_freq) + if (p2p->pref_freq_list[i].freq == + (unsigned int) dev->oper_freq && + p2p_pref_freq_allowed(&p2p->pref_freq_list[i], go)) break; } if (i != size && - p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) == 0) { + p2p_freq_to_channel(p2p->pref_freq_list[i].freq, &op_class, + &op_channel) == 0) { /* Peer operating channel preference matches our preference */ p2p->op_reg_class = op_class; p2p->op_channel = op_channel; @@ -856,9 +912,11 @@ void p2p_check_pref_chan(struct p2p_data *p2p, int go, * _not_ included in the GO Negotiation Request or Invitation Request. */ if (msg->pref_freq_list_len == 0) - p2p_check_pref_chan_no_recv(p2p, go, dev, msg, freq_list, size); + p2p_check_pref_chan_no_recv(p2p, go, dev, msg, + p2p->pref_freq_list, size); else - p2p_check_pref_chan_recv(p2p, go, dev, msg, freq_list, size); + p2p_check_pref_chan_recv(p2p, go, dev, msg, + p2p->pref_freq_list, size); } @@ -922,7 +980,7 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, goto fail; } - if (os_memcmp(msg.p2p_device_addr, sa, ETH_ALEN) != 0) { + if (!ether_addr_equal(msg.p2p_device_addr, sa)) { p2p_dbg(p2p, "Unexpected GO Negotiation Request SA=" MACSTR_SEC " != dev_addr=" MACSTR_SEC, MAC2STR_SEC(sa), MAC2STR_SEC(msg.p2p_device_addr)); @@ -990,6 +1048,9 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, #endif /* HARMONY_P2P_CONNECTIVITY_PATCH */ } + if (dev) + p2p_update_peer_6ghz_capab(dev, &msg); + if (p2p->go_neg_peer && p2p->go_neg_peer == dev) eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL); @@ -1209,7 +1270,7 @@ fail: else freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel); -#endif +#endif if (freq < 0) { p2p_dbg(p2p, "Unknown regulatory class/channel"); wpabuf_free(resp); @@ -1252,6 +1313,7 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, struct p2p_channels res; u8 group_capab; size_t extra = 0; + bool is_6ghz_capab; p2p_dbg(p2p, "Building GO Negotiation Confirm"); @@ -1295,7 +1357,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, p2p_buf_add_operating_channel(buf, (const char *) resp_chan, resp_chan[3], resp_chan[4]); p2p_channels_intersect(&p2p->channels, &peer->channels, &res); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &res); + is_6ghz_capab = is_p2p_6ghz_capable(p2p) && + p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); + p2p_buf_add_channel_list(buf, p2p->cfg->country, &res, is_6ghz_capab); if (go) { p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid, p2p->ssid_len); @@ -1350,6 +1414,7 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, return; } dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE; + p2p_update_peer_6ghz_capab(dev, &msg); if (msg.dialog_token != dev->dialog_token) { p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)", @@ -1657,6 +1722,8 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa, return; } + p2p_update_peer_6ghz_capab(dev, &msg); + if (dev->go_state == REMOTE_GO && msg.group_id) { /* Store SSID for Provisioning step */ p2p->ssid_len = msg.group_id_len - ETH_ALEN; diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p_group.c b/wpa_supplicant-2.9_standard/src/p2p/p2p_group.c index c0960c1247f8fb948ff4ef361a570e451d5be24e..4cf0c05cc8a226d6dd297ebf9582514a705c60fb 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p_group.c +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p_group.c @@ -615,7 +615,7 @@ static int p2p_group_remove_member(struct p2p_group *group, const u8 *addr) m = group->members; prev = NULL; while (m) { - if (os_memcmp(m->addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(m->addr, addr)) break; prev = m; m = m->next; @@ -829,11 +829,11 @@ int p2p_group_match_dev_id(struct p2p_group *group, struct wpabuf *p2p) if (!msg.device_id) return 1; /* No filter on Device ID */ - if (os_memcmp(msg.device_id, group->p2p->cfg->dev_addr, ETH_ALEN) == 0) + if (ether_addr_equal(msg.device_id, group->p2p->cfg->dev_addr)) return 1; /* Match with our P2P Device Address */ for (m = group->members; m; m = m->next) { - if (os_memcmp(msg.device_id, m->dev_addr, ETH_ALEN) == 0) + if (ether_addr_equal(msg.device_id, m->dev_addr)) return 1; /* Match with group client P2P Device Address */ } @@ -888,7 +888,7 @@ static struct p2p_group_member * p2p_group_get_client(struct p2p_group *group, struct p2p_group_member *m; for (m = group->members; m; m = m->next) { - if (os_memcmp(dev_id, m->dev_addr, ETH_ALEN) == 0) + if (ether_addr_equal(dev_id, m->dev_addr)) return m; } @@ -916,7 +916,7 @@ static struct p2p_group_member * p2p_group_get_client_iface( struct p2p_group_member *m; for (m = group->members; m; m = m->next) { - if (os_memcmp(interface_addr, m->addr, ETH_ALEN) == 0) + if (ether_addr_equal(interface_addr, m->addr)) return m; } @@ -1082,7 +1082,7 @@ int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr) struct p2p_group_member *m; for (m = group->members; m; m = m->next) { - if (os_memcmp(m->dev_addr, dev_addr, ETH_ALEN) == 0) + if (ether_addr_equal(m->dev_addr, dev_addr)) return 1; } @@ -1095,7 +1095,7 @@ int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id, { if (group_id_len != ETH_ALEN + group->cfg->ssid_len) return 0; - if (os_memcmp(group_id, group->p2p->cfg->dev_addr, ETH_ALEN) != 0) + if (!ether_addr_equal(group_id, group->p2p->cfg->dev_addr)) return 0; return os_memcmp(group_id + ETH_ALEN, group->cfg->ssid, group->cfg->ssid_len) == 0; diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p_i.h b/wpa_supplicant-2.9_standard/src/p2p/p2p_i.h index bcf12b782ef8c1d9366e2c0407f77ace17065207..f2cdd4bc4ec623c36333eb1035716b7692338fe0 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p_i.h +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p_i.h @@ -10,6 +10,7 @@ #define P2P_I_H #include "utils/list.h" +#include "drivers/driver.h" #include "p2p.h" #define P2P_GO_NEG_CNF_MAX_RETRY_COUNT 1 @@ -148,6 +149,7 @@ struct p2p_device { struct wpabuf *go_neg_conf; int sd_pending_bcast_queries; + bool support_6ghz; }; struct p2p_sd_query { @@ -414,6 +416,7 @@ struct p2p_data { unsigned int pending_listen_freq; unsigned int pending_listen_sec; unsigned int pending_listen_usec; + bool pending_listen_wait_drv; u8 dev_capab; @@ -572,7 +575,7 @@ struct p2p_data { struct wpabuf **vendor_elem; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS]; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; unsigned int num_pref_freq; /* Override option for preferred operating channel in GO Negotiation */ @@ -745,7 +748,6 @@ struct p2p_group_info { /* p2p_utils.c */ int p2p_random(char *buf, size_t len); -int p2p_channel_to_freq(int op_class, int channel); int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel); void p2p_channels_intersect(const struct p2p_channels *a, const struct p2p_channels *b, @@ -824,7 +826,7 @@ void p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country, void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country, u8 reg_class, u8 channel); void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country, - struct p2p_channels *chan); + struct p2p_channels *chan, bool is_6ghz_capab); void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout, u8 client_timeout); void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr); @@ -855,7 +857,7 @@ void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr, int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, int all_attr); void p2p_buf_add_pref_channel_list(struct wpabuf *buf, - const unsigned int *preferred_freq_list, + const struct weighted_pcl *pref_freq_list, unsigned int size); /* p2p_sd.c */ @@ -930,6 +932,8 @@ void p2p_continue_find(struct p2p_data *p2p); struct p2p_device * p2p_add_dev_from_go_neg_req(struct p2p_data *p2p, const u8 *addr, struct p2p_message *msg); +void p2p_update_peer_6ghz_capab(struct p2p_device *dev, + const struct p2p_message *msg); void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr, struct p2p_device *dev, struct p2p_message *msg); int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, @@ -957,6 +961,13 @@ int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev, void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx); int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev, u8 *status); +void p2p_pref_channel_filter(const struct p2p_channels *a, + const struct weighted_pcl *freq_list, + unsigned int num_channels, + struct p2p_channels *res, bool go); + +void p2p_sd_query_cb(struct p2p_data *p2p, int success); + void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...) PRINTF_FORMAT(2, 3); void p2p_info(struct p2p_data *p2p, const char *fmt, ...) diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p_invitation.c b/wpa_supplicant-2.9_standard/src/p2p/p2p_invitation.c index f1f7335d4875bf367e30cd56d54a6c474f9570ac..615c379b98c7bc074c9fd501576053502aa5e8e5 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p_invitation.c +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p_invitation.c @@ -31,6 +31,7 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, u8 *len; const u8 *dev_addr; size_t extra = 0; + bool is_6ghz_capab; #ifdef CONFIG_WIFI_DISPLAY struct wpabuf *wfd_ie = p2p->wfd_ie_invitation; @@ -39,8 +40,8 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, for (i = 0; i < p2p->num_groups; i++) { struct p2p_group *g = p2p->groups[i]; struct wpabuf *ie; - if (os_memcmp(p2p_group_get_interface_addr(g), - p2p->inv_bssid, ETH_ALEN) != 0) + if (!ether_addr_equal(p2p_group_get_interface_addr(g), + p2p->inv_bssid)) continue; ie = p2p_group_get_wfd_ie(g); if (ie) { @@ -81,7 +82,10 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, p2p->op_channel); if (p2p->inv_bssid_set) p2p_buf_add_group_bssid(buf, p2p->inv_bssid); - p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); + is_6ghz_capab = is_p2p_6ghz_capable(p2p) && + p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); + p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels, + is_6ghz_capab); if (go_dev_addr) dev_addr = go_dev_addr; else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT) @@ -130,8 +134,8 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p, for (i = 0; i < p2p->num_groups; i++) { struct p2p_group *g = p2p->groups[i]; struct wpabuf *ie; - if (os_memcmp(p2p_group_get_interface_addr(g), - group_bssid, ETH_ALEN) != 0) + if (!ether_addr_equal(p2p_group_get_interface_addr(g), + group_bssid)) continue; ie = p2p_group_get_wfd_ie(g); if (ie) { @@ -162,8 +166,14 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p, reg_class, channel); if (group_bssid) p2p_buf_add_group_bssid(buf, group_bssid); - if (channels) - p2p_buf_add_channel_list(buf, p2p->cfg->country, channels); + if (channels) { + bool is_6ghz_capab; + + is_6ghz_capab = is_p2p_6ghz_capable(p2p) && + p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr); + p2p_buf_add_channel_list(buf, p2p->cfg->country, channels, + is_6ghz_capab); + } p2p_buf_update_ie_hdr(buf, len); #ifdef CONFIG_WIFI_DISPLAY @@ -640,9 +650,14 @@ int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST; p2p->invite_peer = dev; dev->invitation_reqs++; + + /* In case of an active P2P GO use a shorter wait time to avoid + * issues if not sending out multiple consecutive Beacon frames. */ if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, p2p->cfg->dev_addr, dev->info.p2p_device_addr, - wpabuf_head(req), wpabuf_len(req), 500) < 0) { + wpabuf_head(req), wpabuf_len(req), + p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO ? + 150 : 500) < 0) { p2p_dbg(p2p, "Failed to send Action frame"); /* Use P2P find to recover and retry */ p2p_set_timeout(p2p, 0, 0); diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p_parse.c b/wpa_supplicant-2.9_standard/src/p2p/p2p_parse.c index b1e471242c6ff4ac8439410f6f64f4fa1dee7ce2..14fb006dda1475f35f89c4a0627bff5ef3f41662 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p_parse.c +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p_parse.c @@ -93,6 +93,12 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, return -1; } msg->listen_channel = data; + if (has_ctrl_char(data, 2)) { + wpa_printf(MSG_EXCESSIVE, + "P2P: * Listen Channel: Country(binary) %02x %02x (0x%02x) Regulatory Class %d Channel Number %d", + data[0], data[1], data[2], data[3], data[4]); + break; + } wpa_printf(MSG_EXCESSIVE, "P2P: * Listen Channel: " "Country %c%c(0x%02x) Regulatory " "Class %d Channel Number %d", data[0], data[1], @@ -110,7 +116,13 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, return -1; } msg->operating_channel = data; - wpa_printf(MSG_INFO, "P2P: * Operating Channel: " + if (has_ctrl_char(data, 2)) { + wpa_printf(MSG_INFO, + "P2P: * Operating Channel: Country(binary) ** Regulatory Class %d Channel Number %d", + data[3], data[4]); + break; + } + wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " "Country ** Regulatory " "Class %d Channel Number %d", data[3], data[4]); break; @@ -122,8 +134,15 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, } msg->channel_list = data; msg->channel_list_len = len; - wpa_printf(MSG_INFO, "P2P: * Channel List: Country String " - "'**(0x%02x)'", data[2]); + if (has_ctrl_char(data, 2)) { + wpa_printf(MSG_INFO, + "P2P: * Channel List: Country String (binary) ** (0x%02x)", + data[2]); + } else { + wpa_printf(MSG_INFO, + "P2P: * Channel List: Country String '**(0x%02x)'", + data[2]); + } wpa_hexdump(MSG_MSGDUMP, "P2P: Channel List", msg->channel_list, msg->channel_list_len); break; @@ -524,7 +543,9 @@ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg) { struct ieee802_11_elems elems; - ieee802_11_parse_elems(data, len, &elems, 0); + if (ieee802_11_parse_elems(data, len, &elems, 0) == ParseFailed) + return -1; + if (elems.ds_params) msg->ds_params = elems.ds_params; if (elems.ssid) diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p_pd.c b/wpa_supplicant-2.9_standard/src/p2p/p2p_pd.c index 3d38b605dfab32680f2097ac9a3b5958334f4224..2a26bbf4b8fbbb119f36b576e640aed719e80df0 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p_pd.c +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p_pd.c @@ -124,9 +124,15 @@ static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev, } if (shared_group || - (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW))) + (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW))) { + bool is_6ghz_capab; + + is_6ghz_capab = is_p2p_6ghz_capable(p2p) && + p2p_is_peer_6ghz_capab( + p2p, dev->info.p2p_device_addr); p2p_buf_add_channel_list(buf, p2p->cfg->country, - &p2p->channels); + &p2p->channels, is_6ghz_capab); + } if ((shared_group && !is_zero_ether_addr(intended_addr)) || (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW))) @@ -356,9 +362,15 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, } if (persist || - (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER))) + (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER))) { + bool is_6ghz_capab; + + is_6ghz_capab = is_p2p_6ghz_capable(p2p) && dev && + p2p_is_peer_6ghz_capab( + p2p, dev->info.p2p_device_addr); p2p_buf_add_channel_list(buf, p2p->cfg->country, - &p2p->channels); + &p2p->channels, is_6ghz_capab); + } if (!persist && conncap) p2p_buf_add_connection_capability(buf, conncap); @@ -532,7 +544,7 @@ do { \ if (msg->persistent_dev) { channel_list = 1; config_timeout = 1; - if (os_memcmp(msg->persistent_dev, addr, ETH_ALEN) == 0) { + if (ether_addr_equal(msg->persistent_dev, addr)) { intended_addr = 1; operating_channel = 1; } @@ -607,6 +619,8 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); } + p2p_update_peer_6ghz_capab(dev, &msg); + if (!msg.adv_id) { allowed_config_methods |= WPS_CONFIG_PUSHBUTTON; if (!(msg.wps_config_methods & allowed_config_methods)) { @@ -716,7 +730,7 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, if (!msg.status) { unsigned int forced_freq, pref_freq; - if (os_memcmp(p2p->cfg->dev_addr, msg.adv_mac, ETH_ALEN)) { + if (!ether_addr_equal(p2p->cfg->dev_addr, msg.adv_mac)) { p2p_dbg(p2p, "P2PS PD adv mac does not match the local one"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; @@ -878,14 +892,14 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, goto out; if (p2p->p2ps_prov->adv_id != adv_id || - os_memcmp(p2p->p2ps_prov->adv_mac, msg.adv_mac, ETH_ALEN)) { + !ether_addr_equal(p2p->p2ps_prov->adv_mac, msg.adv_mac)) { p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Advertisement ID/MAC"); goto out; } if (p2p->p2ps_prov->session_id != session_id || - os_memcmp(p2p->p2ps_prov->session_mac, msg.session_mac, ETH_ALEN)) { + !ether_addr_equal(p2p->p2ps_prov->session_mac, msg.session_mac)) { p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC"); goto out; } @@ -1225,8 +1239,7 @@ static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p, return -1; } - if (os_memcmp(p2p->p2ps_prov->session_mac, msg->session_mac, - ETH_ALEN)) { + if (!ether_addr_equal(p2p->p2ps_prov->session_mac, msg->session_mac)) { p2p_dbg(p2p, "Ignore PD Response with unexpected Session MAC"); return -1; @@ -1238,7 +1251,7 @@ static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p, return -1; } - if (os_memcmp(p2p->p2ps_prov->adv_mac, msg->adv_mac, ETH_ALEN) != 0) { + if (!ether_addr_equal(p2p->p2ps_prov->adv_mac, msg->adv_mac)) { p2p_dbg(p2p, "Ignore PD Response with unexpected Advertisement MAC"); return -1; @@ -1355,6 +1368,8 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); } + p2p_update_peer_6ghz_capab(dev, &msg); + if (dev->dialog_token != msg.dialog_token) { p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)", msg.dialog_token, dev->dialog_token); @@ -1380,7 +1395,7 @@ void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, * was sent earlier, we reset that state info here. */ if (p2p->user_initiated_pd && - os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0) + ether_addr_equal(p2p->pending_pd_devaddr, sa)) p2p_reset_pending_pd(p2p); if (msg.wps_config_methods != req_config_methods) { @@ -1742,8 +1757,8 @@ void p2p_reset_pending_pd(struct p2p_data *p2p) struct p2p_device *dev; dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { - if (os_memcmp(p2p->pending_pd_devaddr, - dev->info.p2p_device_addr, ETH_ALEN)) + if (!ether_addr_equal(p2p->pending_pd_devaddr, + dev->info.p2p_device_addr)) continue; if (!dev->req_config_methods) continue; diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p_sd.c b/wpa_supplicant-2.9_standard/src/p2p/p2p_sd.c index 6f69b7df999f18562606d1c664e3393c9720bdfd..ad9f8911d1ee23ad30d2fcb0d19448a682375613 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p_sd.c +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p_sd.c @@ -79,8 +79,7 @@ struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p, count++; } if (!q->for_all_peers && - os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) == - 0) + ether_addr_equal(q->peer, dev->info.p2p_device_addr)) goto found; } @@ -289,8 +288,7 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev) if (query == NULL) return -1; if (p2p->state == P2P_SEARCH && - os_memcmp(p2p->sd_query_no_ack, dev->info.p2p_device_addr, - ETH_ALEN) == 0) { + ether_addr_equal(p2p->sd_query_no_ack, dev->info.p2p_device_addr)) { p2p_dbg(p2p, "Do not start Service Discovery with " MACSTR_SEC " due to it being the first no-ACK peer in this search iteration", MAC2STR_SEC(dev->info.p2p_device_addr)); @@ -491,12 +489,21 @@ void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, u16 slen; u16 update_indic; - if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || - os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { + if ((p2p->state != P2P_SD_DURING_FIND && p2p->state != P2P_SEARCH) || + !p2p->sd_peer || + !ether_addr_equal(sa, p2p->sd_peer->info.p2p_device_addr)) { p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from " MACSTR_SEC, MAC2STR_SEC(sa)); return; } + if (p2p->state == P2P_SEARCH) { + /* It is possible for the TX status and RX response events to be + * reordered, so assume the request was ACKed if a response is + * received. */ + p2p_dbg(p2p, + "GAS Initial Request had not yet received TX status - process the response anyway"); + p2p_sd_query_cb(p2p, 1); + } p2p->cfg->send_action_done(p2p->cfg->cb_ctx); p2p_clear_timeout(p2p); @@ -642,7 +649,7 @@ void p2p_rx_gas_comeback_req(struct p2p_data *p2p, const u8 *sa, p2p_dbg(p2p, "No pending SD response fragment available"); return; } - if (os_memcmp(sa, p2p->sd_resp_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(sa, p2p->sd_resp_addr)) { p2p_dbg(p2p, "No pending SD response fragment for " MACSTR_SEC, MAC2STR_SEC(sa)); return; @@ -707,7 +714,7 @@ void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len); if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || - os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { + !ether_addr_equal(sa, p2p->sd_peer->info.p2p_device_addr)) { p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from " MACSTR_SEC, MAC2STR_SEC(sa)); return; diff --git a/wpa_supplicant-2.9_standard/src/p2p/p2p_utils.c b/wpa_supplicant-2.9_standard/src/p2p/p2p_utils.c index 2a8a30f82a668bb5a72722df2b4195191913adc2..1c7ba7cb9e0627aff4dd0b857c5559fc7695d2fa 100644 --- a/wpa_supplicant-2.9_standard/src/p2p/p2p_utils.c +++ b/wpa_supplicant-2.9_standard/src/p2p/p2p_utils.c @@ -526,7 +526,7 @@ void p2p_copy_channels(struct p2p_channels *dst, return; } - for (i = 0, j = 0; i < P2P_MAX_REG_CLASSES; i++) { + for (i = 0, j = 0; i < src->reg_classes; i++) { if (is_6ghz_op_class(src->reg_class[i].reg_class)) continue; os_memcpy(&dst->reg_class[j], &src->reg_class[i], @@ -537,14 +537,14 @@ void p2p_copy_channels(struct p2p_channels *dst, } -int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size) +int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size) { int i; for (i = 0; i < size; i++) { - if (is_6ghz_freq(pref_freq_list[i])) { + if (is_6ghz_freq(pref_freq_list[i].freq)) { wpa_printf(MSG_DEBUG, "P2P: Remove 6 GHz channel %d", - pref_freq_list[i]); + pref_freq_list[i].freq); size--; os_memmove(&pref_freq_list[i], &pref_freq_list[i + 1], (size - i) * sizeof(pref_freq_list[0])); @@ -553,3 +553,79 @@ int p2p_remove_6ghz_channels(unsigned int *pref_freq_list, int size) } return i; } + + +/** + * p2p_pref_freq_allowed - Based on the flags set, check if the preferred + * frequency is allowed + * @freq_list: Weighted preferred channel list + * @go: Whether the local device is the group owner + * Returns: Whether the preferred frequency is allowed + */ +bool p2p_pref_freq_allowed(const struct weighted_pcl *freq_list, bool go) +{ + if (freq_list->flag & WEIGHTED_PCL_EXCLUDE) + return false; + if (!(freq_list->flag & WEIGHTED_PCL_CLI) && !go) + return false; + if (!(freq_list->flag & WEIGHTED_PCL_GO) && go) + return false; + return true; +} + + +static int p2p_check_pref_channel(int channel, u8 op_class, + const struct weighted_pcl *freq_list, + unsigned int num_channels, bool go) +{ + unsigned int i; + + /* If the channel is present in the preferred channel list, check if it + * has appropriate flags for the role. + */ + for (i = 0; i < num_channels; i++) { + if (p2p_channel_to_freq(op_class, channel) != + (int) freq_list[i].freq) + continue; + if (!p2p_pref_freq_allowed(&freq_list[i], go)) + return -1; + break; + } + + return 0; +} + + +void p2p_pref_channel_filter(const struct p2p_channels *p2p_chan, + const struct weighted_pcl *freq_list, + unsigned int num_channels, + struct p2p_channels *res, bool go) +{ + size_t i, j; + + os_memset(res, 0, sizeof(*res)); + + for (i = 0; i < p2p_chan->reg_classes; i++) { + const struct p2p_reg_class *reg = &p2p_chan->reg_class[i]; + struct p2p_reg_class *res_reg = &res->reg_class[i]; + + if (num_channels > 0) { + for (j = 0; j < reg->channels; j++) { + if (p2p_check_pref_channel(reg->channel[j], + reg->reg_class, + freq_list, + num_channels, + go) < 0) + continue; + + res_reg->channel[res_reg->channels++] = + reg->channel[j]; + } + } + + if (res_reg->channels == 0) + continue; + res->reg_classes++; + res_reg->reg_class = reg->reg_class; + } +} diff --git a/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_cp.c b/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_cp.c index cf41d8dbf2f97f65ea541f70e5589cc5a1d89b35..d06ad862a2dbcd0b48eb096b685d4dc43588edf4 100644 --- a/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_cp.c +++ b/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_cp.c @@ -20,7 +20,7 @@ #define STATE_MACHINE_DATA struct ieee802_1x_cp_sm #define STATE_MACHINE_DEBUG_PREFIX "CP" -static u64 default_cs_id = CS_ID_GCM_AES_128; +static u64 cs_id[] = { CS_ID_GCM_AES_128, CS_ID_GCM_AES_256 }; /* The variable defined in clause 12 in IEEE Std 802.1X-2010 */ enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE }; @@ -84,6 +84,7 @@ struct ieee802_1x_cp_sm { /* not defined IEEE Std 802.1X-2010 */ struct ieee802_1x_kay *kay; + u8 offload; }; static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx, @@ -188,6 +189,7 @@ SM_STATE(CP, AUTHENTICATED) sm->protect_frames = false; sm->replay_protect = false; sm->validate_frames = Checked; + sm->offload = sm->kay->macsec_offload; sm->port_valid = false; sm->controlled_port_enabled = true; @@ -197,6 +199,7 @@ SM_STATE(CP, AUTHENTICATED) secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt); secy_cp_control_validate_frames(sm->kay, sm->validate_frames); secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); + secy_cp_control_offload(sm->kay, sm->offload); } @@ -208,9 +211,9 @@ SM_STATE(CP, SECURED) sm->protect_frames = sm->kay->macsec_protect; sm->replay_protect = sm->kay->macsec_replay_protect; + sm->offload = sm->kay->macsec_offload; sm->validate_frames = sm->kay->macsec_validate; - /* NOTE: now no other than default cipher suite (AES-GCM-128) */ sm->current_cipher_suite = sm->cipher_suite; secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite); @@ -224,6 +227,7 @@ SM_STATE(CP, SECURED) secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt); secy_cp_control_validate_frames(sm->kay, sm->validate_frames); secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); + secy_cp_control_offload(sm->kay, sm->offload); } @@ -463,6 +467,7 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay) sm->validate_frames = kay->macsec_validate; sm->replay_protect = kay->macsec_replay_protect; sm->replay_window = kay->macsec_replay_window; + sm->offload = kay->macsec_offload; sm->controlled_port_enabled = false; @@ -473,8 +478,8 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay) sm->orx = false; sm->otx = false; - sm->current_cipher_suite = default_cs_id; - sm->cipher_suite = default_cs_id; + sm->current_cipher_suite = cs_id[kay->macsec_csindex]; + sm->cipher_suite = cs_id[kay->macsec_csindex]; sm->cipher_offset = CONFIDENTIALITY_OFFSET_0; sm->confidentiality_offset = sm->cipher_offset; sm->transmit_delay = MKA_LIFE_TIME; @@ -491,6 +496,8 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay) secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); secy_cp_control_confidentiality_offset(sm->kay, sm->confidentiality_offset); + secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite); + secy_cp_control_offload(sm->kay, sm->offload); SM_STEP_RUN(CP); diff --git a/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_kay.c b/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_kay.c index 2a208e66c6e92929c9ddb1bd711e35971b127d27..5268d333daaa5ce7a3d5a802a9e4ce3bed6701ab 100644 --- a/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_kay.c +++ b/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_kay.c @@ -221,8 +221,16 @@ ieee802_1x_mka_dump_dist_sak_body(struct ieee802_1x_mka_dist_sak_body *body) wpa_printf(MSG_DEBUG, "\tKey Number............: %d", be_to_host32(body->kn)); - /* TODO: Other than GCM-AES-128 case: MACsec Cipher Suite */ - wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", body->sak, 24); + if (body_len == 28) { + wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", + body->sak, 24); + } else if (body_len > CS_ID_LEN - sizeof(body->kn)) { + wpa_hexdump(MSG_DEBUG, "\tMACsec Cipher Suite...:", + body->sak, CS_ID_LEN); + wpa_hexdump(MSG_DEBUG, "\tAES Key Wrap of SAK...:", + body->sak + CS_ID_LEN, + body_len - CS_ID_LEN - sizeof(body->kn)); + } } @@ -1197,7 +1205,7 @@ ieee802_1x_mka_decode_potential_peer_body( /* My message id is used by other participant */ if (peer_mn > participant->mn && !reset_participant_mi(participant)) - wpa_printf(MSG_DEBUG, "KaY: Could not update mi"); + wpa_printf(MSG_DEBUG, "KaY: Could not update MI"); continue; } } @@ -1827,6 +1835,18 @@ ieee802_1x_mka_decode_dist_sak_body( kay->rcvd_keys++; participant->to_use_sak = true; + /* + * The key server may not include dist sak and use sak in one packet. + * Meanwhile, after dist sak, the current participant (non-key server) + * will install SC or SA(s) after decoding the dist sak which may take + * few seconds in real physical platforms. Meanwhile, the peer expire + * time is always initialized at adding the key server to peer list. + * The gap between adding the key server to peer list and processing + * next use sak packet may exceed the threshold of MKA_LIFE_TIME (6 s). + * It will cause an unexpected cleanup (delete SC and SA(s)), so, + * update the expire timeout at dist sak also. */ + peer->expire = time(NULL) + MKA_LIFE_TIME / 1000; + return 0; } @@ -2506,7 +2526,7 @@ ieee802_1x_participant_send_mkpdu( } if (ieee802_1x_kay_encode_mkpdu(participant, buf)) { - wpa_printf(MSG_ERROR, "KaY: encode mkpdu fail"); + wpa_printf(MSG_ERROR, "KaY: encode MKPDU fail"); return -1; } @@ -2542,6 +2562,7 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx) struct ieee802_1x_kay_peer *peer, *pre_peer; time_t now = time(NULL); bool lp_changed; + bool key_server_removed; struct receive_sc *rxsc, *pre_rxsc; struct transmit_sa *txsa, *pre_txsa; @@ -2566,13 +2587,12 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx) } lp_changed = false; + key_server_removed = false; dl_list_for_each_safe(peer, pre_peer, &participant->live_peers, struct ieee802_1x_kay_peer, list) { if (now > peer->expire) { wpa_printf(MSG_DEBUG, "KaY: Live peer removed"); - wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, - sizeof(peer->mi)); - wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn); + ieee802_1x_kay_dump_peer(peer); dl_list_for_each_safe(rxsc, pre_rxsc, &participant->rxsc_list, struct receive_sc, list) { @@ -2581,12 +2601,32 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx) participant, rxsc); } } + key_server_removed |= peer->is_key_server; dl_list_del(&peer->list); os_free(peer); lp_changed = true; } } + /* The key server may be removed due to the ingress packets delay. + * In this situation, the endpoint of the key server may not be aware + * of this participant who has removed the key server from the peer + * list. Because the egress traffic is normal, the key server will not + * remove this participant from the peer list of the key server. So in + * the next MKA message, the key server will not dispatch a new SAK to + * this participant. And this participant cannot be aware that that is + * a new round of communication so it will not update its MI at + * re-adding the key server to its peer list. So we need to update MI + * to avoid the failure of the re-establishment MKA session. */ + if (key_server_removed) { + if (!reset_participant_mi(participant)) + wpa_printf(MSG_WARNING, + "KaY: Could not update MI on key server removal"); + else + wpa_printf(MSG_DEBUG, + "KaY: Update MI on key server removal"); + } + if (lp_changed) { if (dl_list_empty(&participant->live_peers)) { participant->advised_desired = false; @@ -2628,9 +2668,7 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx) struct ieee802_1x_kay_peer, list) { if (now > peer->expire) { wpa_printf(MSG_DEBUG, "KaY: Potential peer removed"); - wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi, - sizeof(peer->mi)); - wpa_printf(MSG_DEBUG, "\tMN: %d", peer->mn); + ieee802_1x_kay_dump_peer(peer); dl_list_del(&peer->list); os_free(peer); } @@ -3087,7 +3125,7 @@ static int ieee802_1x_kay_mkpdu_validity_check(struct ieee802_1x_kay *kay, be_to_host16(eth_hdr->ethertype)); /* the destination address shall not be an individual address */ - if (os_memcmp(eth_hdr->dest, pae_group_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(eth_hdr->dest, pae_group_addr)) { wpa_printf(MSG_DEBUG, "KaY: ethernet destination address is not PAE group address"); return -1; @@ -3331,7 +3369,7 @@ static int ieee802_1x_kay_decode_mkpdu(struct ieee802_1x_kay *kay, "KaY: Discarding Rx MKPDU: decode of parameter set type (%d) failed", MKA_SAK_USE); if (!reset_participant_mi(participant)) - wpa_printf(MSG_DEBUG, "KaY: Could not update mi"); + wpa_printf(MSG_DEBUG, "KaY: Could not update MI"); else wpa_printf(MSG_DEBUG, "KaY: Selected a new random MI: %s", @@ -3456,7 +3494,8 @@ static void kay_l2_receive(void *ctx, const u8 *src_addr, const u8 *buf, struct ieee802_1x_kay * ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, bool macsec_replay_protect, u32 macsec_replay_window, - u16 port, u8 priority, const char *ifname, const u8 *addr) + u8 macsec_offload, u16 port, u8 priority, + u32 macsec_csindex, const char *ifname, const u8 *addr) { struct ieee802_1x_kay *kay; @@ -3493,7 +3532,7 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, kay->dist_time = 0; kay->pn_exhaustion = PENDING_PN_EXHAUSTION; - kay->macsec_csindex = DEFAULT_CS_INDEX; + kay->macsec_csindex = macsec_csindex; kay->mka_algindex = DEFAULT_MKA_ALG_INDEX; kay->mka_version = MKA_VERSION_ID; @@ -3515,6 +3554,7 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, kay->macsec_validate = Disabled; kay->macsec_replay_protect = false; kay->macsec_replay_window = 0; + kay->macsec_offload = 0; kay->macsec_confidentiality = CONFIDENTIALITY_NONE; kay->mka_hello_time = MKA_HELLO_TIME; } else { @@ -3531,6 +3571,7 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, kay->macsec_validate = Strict; kay->macsec_replay_protect = macsec_replay_protect; kay->macsec_replay_window = macsec_replay_window; + kay->macsec_offload = macsec_offload; kay->mka_hello_time = MKA_HELLO_TIME; } @@ -3542,7 +3583,7 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, goto error; } - wpa_printf(MSG_DEBUG, "KaY: secy init macsec done"); + wpa_printf(MSG_DEBUG, "KaY: SecY init MACsec done"); /* init CP */ kay->cp = ieee802_1x_cp_sm_init(kay); @@ -3633,7 +3674,7 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, kay->if_name, mode_txt(mode), yes_no(is_authenticator)); if (!kay || !ckn || !cak) { - wpa_printf(MSG_ERROR, "KaY: ckn or cak is null"); + wpa_printf(MSG_ERROR, "KaY: CKN or CAK is null"); return NULL; } @@ -3731,6 +3772,7 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, secy_cp_control_protect_frames(kay, kay->macsec_protect); secy_cp_control_replay(kay, kay->macsec_replay_protect, kay->macsec_replay_window); + secy_cp_control_offload(kay, kay->macsec_offload); if (secy_create_transmit_sc(kay, participant->txsc)) goto fail; diff --git a/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_kay.h b/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_kay.h index 1d3c2acb72f4498e7edb3f34d9d750398f62857c..11464f7fc602e3fdf466cb506b7c3728c1bee363 100644 --- a/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_kay.h +++ b/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_kay.h @@ -166,6 +166,7 @@ struct ieee802_1x_kay_ctx { int (*delete_transmit_sa)(void *ctx, struct transmit_sa *sa); int (*enable_transmit_sa)(void *ctx, struct transmit_sa *sa); int (*disable_transmit_sa)(void *ctx, struct transmit_sa *sa); + int (*set_offload)(void *ctx, u8 offload); }; struct ieee802_1x_kay { @@ -206,6 +207,7 @@ struct ieee802_1x_kay { bool is_key_server; bool is_obliged_key_server; char if_name[IFNAMSIZ]; + u8 macsec_offload; unsigned int macsec_csindex; /* MACsec cipher suite table index */ int mka_algindex; /* MKA alg table index */ @@ -240,7 +242,8 @@ u64 mka_sci_u64(struct ieee802_1x_mka_sci *sci); struct ieee802_1x_kay * ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, bool macsec_replay_protect, u32 macsec_replay_window, - u16 port, u8 priority, const char *ifname, const u8 *addr); + u8 macsec_offload, u16 port, u8 priority, + u32 macsec_csindex, const char *ifname, const u8 *addr); void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay); struct ieee802_1x_mka_participant * diff --git a/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_secy_ops.c b/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_secy_ops.c index 0f36e6b536b15d088406bb7eb8c01c99d296201b..f35baadbfb372bf8e799cacc5539e4dc4e2cbf39 100644 --- a/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_secy_ops.c +++ b/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_secy_ops.c @@ -85,6 +85,26 @@ int secy_cp_control_replay(struct ieee802_1x_kay *kay, bool enabled, u32 win) } +int secy_cp_control_offload(struct ieee802_1x_kay *kay, u8 offload) +{ + struct ieee802_1x_kay_ctx *ops; + + if (!kay) { + wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__); + return -1; + } + + ops = kay->ctx; + if (!ops || !ops->set_offload) { + wpa_printf(MSG_ERROR, + "KaY: secy set_offload operation not supported"); + return -1; + } + + return ops->set_offload(ops->ctx, offload); +} + + int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs) { struct ieee802_1x_kay_ctx *ops; diff --git a/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_secy_ops.h b/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_secy_ops.h index 18c06f665aa319846dd9c71a5a15a893dbd692e5..b82507bca4dc5471dfea3e3712c3f11e357d80ae 100644 --- a/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_secy_ops.h +++ b/wpa_supplicant-2.9_standard/src/pae/ieee802_1x_secy_ops.h @@ -23,6 +23,7 @@ int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay, int secy_cp_control_protect_frames(struct ieee802_1x_kay *kay, bool flag); int secy_cp_control_encrypt(struct ieee802_1x_kay *kay, bool enabled); int secy_cp_control_replay(struct ieee802_1x_kay *kay, bool flag, u32 win); +int secy_cp_control_offload(struct ieee802_1x_kay *kay, u8 offload); int secy_cp_control_current_cipher_suite(struct ieee802_1x_kay *kay, u64 cs); int secy_cp_control_confidentiality_offset(struct ieee802_1x_kay *kay, enum confidentiality_offset co); diff --git a/wpa_supplicant-2.9_standard/src/pasn/Makefile b/wpa_supplicant-2.9_standard/src/pasn/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a5b2c6b3f672fea182f369713f36dede81451e7d --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/pasn/Makefile @@ -0,0 +1,16 @@ +CFLAGS += -DCONFIG_SAE +CFLAGS += -DCONFIG_FILS +CFLAGS += -DIEEE8021X_EAPOL +CFLAGS += -DCONFIG_IEEE80211R +CFLAGS += -DCONFIG_TESTING_OPTIONS +CFLAGS += -DCONFIG_SAE_PK +CFLAGS += -DCONFIG_SHA256 +CFLAGS += -DCONFIG_SHA384 +CFLAGS += -DCONFIG_SHA512 +CFLAGS += -DCONFIG_PASN + +LIB_OBJS= \ + pasn_initiator.o \ + pasn_responder.o + +include ../lib.rules diff --git a/wpa_supplicant-2.9_standard/src/pasn/pasn_common.c b/wpa_supplicant-2.9_standard/src/pasn/pasn_common.c new file mode 100644 index 0000000000000000000000000000000000000000..e2c668136300659d860dad107ef6aa3d1d082bd8 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/pasn/pasn_common.c @@ -0,0 +1,232 @@ +/* + * PASN common processing + * + * Copyright (C) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/wpa_common.h" +#include "common/sae.h" +#include "crypto/sha384.h" +#include "crypto/crypto.h" +#include "common/ieee802_11_defs.h" +#include "pasn_common.h" + + +struct pasn_data * pasn_data_init(void) +{ + struct pasn_data *pasn = os_zalloc(sizeof(struct pasn_data)); + + return pasn; +} + + +void pasn_data_deinit(struct pasn_data *pasn) +{ + bin_clear_free(pasn, sizeof(struct pasn_data)); +} + + +void pasn_register_callbacks(struct pasn_data *pasn, void *cb_ctx, + int (*send_mgmt)(void *ctx, const u8 *data, + size_t data_len, int noack, + unsigned int freq, + unsigned int wait), + int (*validate_custom_pmkid)(void *ctx, + const u8 *addr, + const u8 *pmkid)) +{ + if (!pasn) + return; + + pasn->cb_ctx = cb_ctx; + pasn->send_mgmt = send_mgmt; + pasn->validate_custom_pmkid = validate_custom_pmkid; +} + + +void pasn_enable_kdk_derivation(struct pasn_data *pasn) +{ + if (!pasn) + return; + pasn->derive_kdk = true; + pasn->kdk_len = WPA_KDK_MAX_LEN; +} + + +void pasn_disable_kdk_derivation(struct pasn_data *pasn) +{ + if (!pasn) + return; + pasn->derive_kdk = false; + pasn->kdk_len = 0; +} + + +void pasn_set_akmp(struct pasn_data *pasn, int akmp) +{ + if (!pasn) + return; + pasn->akmp = akmp; +} + + +void pasn_set_cipher(struct pasn_data *pasn, int cipher) +{ + if (!pasn) + return; + pasn->cipher = cipher; +} + + +void pasn_set_own_addr(struct pasn_data *pasn, const u8 *addr) +{ + if (!pasn || !addr) + return; + os_memcpy(pasn->own_addr, addr, ETH_ALEN); +} + + +void pasn_set_peer_addr(struct pasn_data *pasn, const u8 *addr) +{ + if (!pasn || !addr) + return; + os_memcpy(pasn->peer_addr, addr, ETH_ALEN); +} + + +void pasn_set_bssid(struct pasn_data *pasn, const u8 *addr) +{ + if (!pasn || !addr) + return; + os_memcpy(pasn->bssid, addr, ETH_ALEN); +} + + +int pasn_set_pt(struct pasn_data *pasn, struct sae_pt *pt) +{ + if (!pasn) + return -1; +#ifdef CONFIG_SAE + pasn->pt = pt; + return 0; +#else /* CONFIG_SAE */ + return -1; +#endif /* CONFIG_SAE */ +} + + +void pasn_set_password(struct pasn_data *pasn, const char *password) +{ + if (!pasn) + return; + pasn->password = password; +} + + +void pasn_set_wpa_key_mgmt(struct pasn_data *pasn, int key_mgmt) +{ + if (!pasn) + return; + pasn->wpa_key_mgmt = key_mgmt; +} + + +void pasn_set_rsn_pairwise(struct pasn_data *pasn, int rsn_pairwise) +{ + if (!pasn) + return; + pasn->rsn_pairwise = rsn_pairwise; +} + + +void pasn_set_rsnxe_caps(struct pasn_data *pasn, u16 rsnxe_capab) +{ + if (!pasn) + return; + pasn->rsnxe_capab = rsnxe_capab; +} + + +void pasn_set_rsnxe_ie(struct pasn_data *pasn, const u8 *rsnxe_ie) +{ + if (!pasn || !rsnxe_ie) + return; + pasn->rsnxe_ie = rsnxe_ie; +} + + +void pasn_set_custom_pmkid(struct pasn_data *pasn, const u8 *pmkid) +{ + if (!pasn || !pmkid) + return; + os_memcpy(pasn->custom_pmkid, pmkid, PMKID_LEN); + pasn->custom_pmkid_valid = true; +} + + +int pasn_set_extra_ies(struct pasn_data *pasn, const u8 *extra_ies, + size_t extra_ies_len) +{ + if (!pasn || !extra_ies_len || !extra_ies) + return -1; + + if (pasn->extra_ies) { + os_free((u8 *) pasn->extra_ies); + pasn->extra_ies_len = extra_ies_len; + } + + pasn->extra_ies = os_memdup(extra_ies, extra_ies_len); + if (!pasn->extra_ies) { + wpa_printf(MSG_ERROR, + "PASN: Extra IEs memory allocation failed"); + return -1; + } + pasn->extra_ies_len = extra_ies_len; + return 0; +} + + +int pasn_get_akmp(struct pasn_data *pasn) +{ + if (!pasn) + return 0; + return pasn->akmp; +} + + +int pasn_get_cipher(struct pasn_data *pasn) +{ + if (!pasn) + return 0; + return pasn->cipher; +} + + +size_t pasn_get_pmk_len(struct pasn_data *pasn) +{ + if (!pasn) + return 0; + return pasn->pmk_len; +} + + +u8 * pasn_get_pmk(struct pasn_data *pasn) +{ + if (!pasn) + return NULL; + return pasn->pmk; +} + + +struct wpa_ptk * pasn_get_ptk(struct pasn_data *pasn) +{ + if (!pasn) + return NULL; + return &pasn->ptk; +} diff --git a/wpa_supplicant-2.9_standard/src/pasn/pasn_common.h b/wpa_supplicant-2.9_standard/src/pasn/pasn_common.h new file mode 100644 index 0000000000000000000000000000000000000000..36710c2b70e91a0a1b0392c700aed55ad72004f7 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/pasn/pasn_common.h @@ -0,0 +1,228 @@ +/* + * PASN info for initiator and responder + * + * Copyright (C) 2019, Intel Corporation + * Copyright (c) 2022, Jouni Malinen + * Copyright (C) 2022, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef PASN_COMMON_H +#define PASN_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum pasn_fils_state { + PASN_FILS_STATE_NONE = 0, + PASN_FILS_STATE_PENDING_AS, + PASN_FILS_STATE_COMPLETE +}; + +struct pasn_fils { + u8 state; + u8 nonce[FILS_NONCE_LEN]; + u8 anonce[FILS_NONCE_LEN]; + u8 session[FILS_SESSION_LEN]; + u8 erp_pmkid[PMKID_LEN]; + bool completed; + struct wpabuf *erp_resp; +}; + +struct pasn_data { + /* External modules access below variables using setter and getter + * functions */ + int akmp; + int cipher; + u8 own_addr[ETH_ALEN]; + u8 peer_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + struct rsn_pmksa_cache *pmksa; + bool derive_kdk; + size_t kdk_len; + void *cb_ctx; + +#ifdef CONFIG_SAE + struct sae_pt *pt; +#endif /* CONFIG_SAE */ + + /* Responder */ + const char *password; + int wpa_key_mgmt; + int rsn_pairwise; + u16 rsnxe_capab; + const u8 *rsnxe_ie; + bool custom_pmkid_valid; + u8 custom_pmkid[PMKID_LEN]; + + /* + * Extra elements to add into Authentication frames. These can be used, + * e.g., for Wi-Fi Aware use cases. + */ + const u8 *extra_ies; + size_t extra_ies_len; + + /* External modules do not access below variables */ + u16 group; + bool secure_ltf; + int freq; + + u8 trans_seq; + u8 status; + + 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; + + struct wpabuf *comeback; + u16 comeback_after; + +#ifdef CONFIG_SAE + struct sae_data sae; +#endif /* CONFIG_SAE */ + +#ifdef CONFIG_FILS + bool fils_eapol; + bool fils_wd_valid; + 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 */ + /* Note that this pointers to RSN PMKSA cache are actually defined + * differently for the PASN initiator (using RSN Supplicant + * implementation) and PASN responser (using RSN Authenticator + * implementation). Functions cannot be mixed between those cases. */ + struct rsn_pmksa_cache_entry *pmksa_entry; + struct eapol_sm *eapol; + int fast_reauth; +#ifdef CONFIG_TESTING_OPTIONS + int corrupt_mic; +#endif /* CONFIG_TESTING_OPTIONS */ + int network_id; + + u8 wrapped_data_format; + struct wpabuf *secret; + + /* Responder */ + bool noauth; /* Whether PASN without mutual authentication is enabled */ + int disable_pmksa_caching; + int *pasn_groups; + struct wpabuf *wrapped_data; + int use_anti_clogging; + const u8 *rsn_ie; + size_t rsn_ie_len; + + u8 *comeback_key; + struct os_reltime last_comeback_key_update; + u16 comeback_idx; + u16 *comeback_pending_idx; + + /** + * send_mgmt - Function handler to transmit a Management frame + * @ctx: Callback context from cb_ctx + * @frame_buf : Frame to transmit + * @frame_len: Length of frame to transmit + * @freq: Frequency in MHz for the channel on which to transmit + * @wait_dur: How many milliseconds to wait for a response frame + * Returns: 0 on success, -1 on failure + */ + int (*send_mgmt)(void *ctx, const u8 *data, size_t data_len, int noack, + unsigned int freq, unsigned int wait); + /** + * validate_custom_pmkid - Handler to validate vendor specific PMKID + * @ctx: Callback context from cb_ctx + * @addr : MAC address of the peer + * @pmkid: Custom PMKID + * Returns: 0 on success (valid PMKID), -1 on failure + */ + int (*validate_custom_pmkid)(void *ctx, const u8 *addr, + const u8 *pmkid); +}; + +/* Initiator */ +void wpa_pasn_reset(struct pasn_data *pasn); +int wpas_pasn_start(struct pasn_data *pasn, const u8 *own_addr, + const u8 *peer_addr, 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, + const struct wpabuf *comeback); +int wpa_pasn_verify(struct pasn_data *pasn, const u8 *own_addr, + const u8 *peer_addr, 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, + const struct wpabuf *comeback); +int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len, + struct wpa_pasn_params_data *pasn_params); +int wpa_pasn_auth_tx_status(struct pasn_data *pasn, + const u8 *data, size_t data_len, u8 acked); + +/* Responder */ +int handle_auth_pasn_1(struct pasn_data *pasn, + const u8 *own_addr, const u8 *peer_addr, + const struct ieee80211_mgmt *mgmt, size_t len); +int handle_auth_pasn_3(struct pasn_data *pasn, const u8 *own_addr, + const u8 *peer_addr, + const struct ieee80211_mgmt *mgmt, size_t len); +int handle_auth_pasn_resp(struct pasn_data *pasn, const u8 *own_addr, + const u8 *peer_addr, + struct rsn_pmksa_cache_entry *pmksa, u16 status); + +struct pasn_data * pasn_data_init(void); +void pasn_data_deinit(struct pasn_data *pasn); +void pasn_register_callbacks(struct pasn_data *pasn, void *cb_ctx, + int (*send_mgmt)(void *ctx, const u8 *data, + size_t data_len, int noack, + unsigned int freq, + unsigned int wait), + int (*validate_custom_pmkid)(void *ctx, + const u8 *addr, + const u8 *pmkid)); +void pasn_enable_kdk_derivation(struct pasn_data *pasn); +void pasn_disable_kdk_derivation(struct pasn_data *pasn); + +void pasn_set_akmp(struct pasn_data *pasn, int akmp); +void pasn_set_cipher(struct pasn_data *pasn, int cipher); +void pasn_set_own_addr(struct pasn_data *pasn, const u8 *addr); +void pasn_set_peer_addr(struct pasn_data *pasn, const u8 *addr); +void pasn_set_bssid(struct pasn_data *pasn, const u8 *addr); +void pasn_set_initiator_pmksa(struct pasn_data *pasn, + struct rsn_pmksa_cache *pmksa); +void pasn_set_responder_pmksa(struct pasn_data *pasn, + struct rsn_pmksa_cache *pmksa); +int pasn_set_pt(struct pasn_data *pasn, struct sae_pt *pt); + +/* Responder */ +void pasn_set_password(struct pasn_data *pasn, const char *password); +void pasn_set_wpa_key_mgmt(struct pasn_data *pasn, int key_mgmt); +void pasn_set_rsn_pairwise(struct pasn_data *pasn, int rsn_pairwise); +void pasn_set_rsnxe_caps(struct pasn_data *pasn, u16 rsnxe_capab); +void pasn_set_rsnxe_ie(struct pasn_data *pasn, const u8 *rsnxe_ie); +void pasn_set_custom_pmkid(struct pasn_data *pasn, const u8 *pmkid); +int pasn_set_extra_ies(struct pasn_data *pasn, const u8 *extra_ies, + size_t extra_ies_len); + +int pasn_get_akmp(struct pasn_data *pasn); +int pasn_get_cipher(struct pasn_data *pasn); +size_t pasn_get_pmk_len(struct pasn_data *pasn); +u8 * pasn_get_pmk(struct pasn_data *pasn); +struct wpa_ptk * pasn_get_ptk(struct pasn_data *pasn); + +#ifdef __cplusplus +} +#endif +#endif /* PASN_COMMON_H */ diff --git a/wpa_supplicant-2.9_standard/src/pasn/pasn_initiator.c b/wpa_supplicant-2.9_standard/src/pasn/pasn_initiator.c new file mode 100644 index 0000000000000000000000000000000000000000..de18c2f05151e5cdf9b2007b51206f999f8a1543 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/pasn/pasn_initiator.c @@ -0,0 +1,1406 @@ +/* + * PASN initiator processing + * + * Copyright (C) 2019, Intel Corporation + * Copyright (C) 2022, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/wpa_common.h" +#include "common/sae.h" +#include "common/ieee802_11_common.h" +#include "common/ieee802_11_defs.h" +#include "common/dragonfly.h" +#include "crypto/sha384.h" +#include "crypto/crypto.h" +#include "crypto/random.h" +#include "eap_common/eap_defs.h" +#include "eapol_supp/eapol_supp_sm.h" +#include "rsn_supp/wpa.h" +#include "rsn_supp/pmksa_cache.h" +#include "pasn_common.h" + + +void pasn_set_initiator_pmksa(struct pasn_data *pasn, + struct rsn_pmksa_cache *pmksa) +{ + if (pasn) + pasn->pmksa = pmksa; +} + + +#ifdef CONFIG_SAE + +static struct wpabuf * wpas_pasn_wd_sae_commit(struct pasn_data *pasn) +{ + struct wpabuf *buf = NULL; + int ret; + + ret = sae_set_group(&pasn->sae, pasn->group); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group"); + return NULL; + } + + ret = sae_prepare_commit_pt(&pasn->sae, pasn->pt, + pasn->own_addr, pasn->peer_addr, + NULL, NULL); + 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_SAE_HASH_TO_ELEMENT); + + sae_write_commit(&pasn->sae, buf, NULL, 0); + pasn->sae.state = SAE_COMMITTED; + + return buf; +} + + +static int wpas_pasn_wd_sae_rx(struct pasn_data *pasn, struct wpabuf *wd) +{ + 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); + + if (alg != WLAN_AUTH_SAE || seq != 1 || + status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) { + wpa_printf(MSG_DEBUG, "PASN: SAE: dropping peer commit"); + return -1; + } + + res = sae_parse_commit(&pasn->sae, data + 6, len - 6, NULL, 0, groups, + 1, NULL); + 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, NULL); + 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 pasn_data *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 pasn_data *pasn) +{ + struct wpabuf *buf = NULL; + struct wpabuf *erp_msg; + int ret; + + erp_msg = eapol_sm_build_erp_reauth_start(pasn->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 struct wpabuf * wpas_pasn_wd_fils_auth(struct pasn_data *pasn) +{ + 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->fils_eapol) { + wpa_printf(MSG_DEBUG, + "PASN: FILS: Missing Indication IE or PFS"); + return NULL; + } + + return wpas_pasn_fils_build_auth(pasn); +} + + +static int wpas_pasn_wd_fils_rx(struct pasn_data *pasn, struct wpabuf *wd) +{ + 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 RSNE"); + 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.wrapped_data, elems.wrapped_data_len, + true); + + if (!fils_wd) { + wpa_printf(MSG_DEBUG, + "PASN: FILS: Failed getting wrapped data"); + return -1; + } + + eapol_sm_process_erp_finish(pasn->eapol, wpabuf_head(fils_wd), + wpabuf_len(fils_wd)); + + wpabuf_free(fils_wd); + fils_wd = NULL; + + if (eapol_sm_failed(pasn->eapol)) { + wpa_printf(MSG_DEBUG, "PASN: FILS: ERP finish failed"); + return -1; + } + + rmsk_len = ERP_MAX_KEY_LEN; + ret = eapol_sm_get_key(pasn->eapol, rmsk, rmsk_len); + + if (ret == PMK_LEN) { + rmsk_len = PMK_LEN; + ret = eapol_sm_get_key(pasn->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"); + + pasn->pmksa_entry = pmksa_cache_add(pasn->pmksa, pasn->pmk, + pasn->pmk_len, pasn->fils.erp_pmkid, + NULL, 0, pasn->peer_addr, + pasn->own_addr, NULL, + pasn->akmp, 0); + + pasn->fils.completed = true; + return 0; +} + +#endif /* CONFIG_FILS */ + + +static struct wpabuf * wpas_pasn_get_wrapped_data(struct pasn_data *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(pasn); + if (pasn->trans_seq == 2) + return wpas_pasn_wd_sae_confirm(pasn); +#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(pasn); +#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 pasn_data *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 pasn_data *pasn, + const struct wpabuf *comeback, + bool verify) +{ + struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL; + const u8 *pmkid; + u8 wrapped_data; + int ret; + + 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, + pasn->own_addr, pasn->peer_addr, + pasn->trans_seq + 1, WLAN_STATUS_SUCCESS); + + pmkid = NULL; + if (wpa_key_mgmt_ft(pasn->akmp)) { +#ifdef CONFIG_IEEE80211R + pmkid = pasn->pmk_r1_name; +#else /* CONFIG_IEEE80211R */ + goto fail; +#endif /* CONFIG_IEEE80211R */ + } else if (wrapped_data != WPA_PASN_WRAPPED_DATA_NO) { + struct rsn_pmksa_cache_entry *pmksa; + + pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, + pasn->own_addr, NULL, NULL, pasn->akmp); + if (pmksa && pasn->custom_pmkid_valid) + pmkid = pasn->custom_pmkid; + else 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. + */ + if (!verify) + wrapped_data_buf = wpas_pasn_get_wrapped_data(pasn); + } + + 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, true, comeback, -1); + + if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0) + goto fail; + + wpa_pasn_add_rsnxe(buf, pasn->rsnxe_capab); + + wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len); + + 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 pasn_data *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, + pasn->own_addr, pasn->peer_addr, + pasn->trans_seq + 1, WLAN_STATUS_SUCCESS); + + wrapped_data_buf = wpas_pasn_get_wrapped_data(pasn); + + if (!wrapped_data_buf) + wrapped_data = WPA_PASN_WRAPPED_DATA_NO; + + wpa_pasn_add_parameter_ie(buf, pasn->group, wrapped_data, + NULL, false, 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, + pasn->own_addr, pasn->peer_addr, + pasn->hash, mic_len * 2, data, data_len, mic); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: frame 3: Failed MIC calculation"); + goto fail; + } + +#ifdef CONFIG_TESTING_OPTIONS + if (pasn->corrupt_mic) { + wpa_printf(MSG_DEBUG, "PASN: frame 3: Corrupt MIC"); + mic[0] = ~mic[0]; + } +#endif /* CONFIG_TESTING_OPTIONS */ + + 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; +} + + +void wpa_pasn_reset(struct pasn_data *pasn) +{ + wpa_printf(MSG_DEBUG, "PASN: Reset"); + + crypto_ecdh_deinit(pasn->ecdh); + pasn->ecdh = 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; + + wpabuf_free(pasn->comeback); + pasn->comeback = NULL; + pasn->comeback_after = 0; + +#ifdef CONFIG_SAE + sae_clear_data(&pasn->sae); + if (pasn->pt) { + sae_deinit_pt(pasn->pt); + pasn->pt = NULL; + } +#endif /* CONFIG_SAE */ + +#ifdef CONFIG_FILS + pasn->fils_eapol = false; + 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; + pasn->pmksa_entry = NULL; +#ifdef CONFIG_TESTING_OPTIONS + pasn->corrupt_mic = 0; +#endif /* CONFIG_TESTING_OPTIONS */ + pasn->network_id = 0; + pasn->derive_kdk = false; + pasn->rsn_ie = NULL; + pasn->rsn_ie_len = 0; + pasn->rsnxe_ie = NULL; + pasn->custom_pmkid_valid = false; + + if (pasn->extra_ies) { + os_free((u8 *) pasn->extra_ies); + pasn->extra_ies = NULL; + } +} + + +static int wpas_pasn_set_pmk(struct pasn_data *pasn, + 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'}; + + 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) { + int ret; + struct rsn_pmksa_cache_entry *pmksa; + const u8 *pmkid = NULL; + + if (pasn->custom_pmkid_valid) { + ret = pasn->validate_custom_pmkid(pasn->cb_ctx, + pasn->peer_addr, + rsn_data->pmkid); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: Failed custom PMKID validation"); + return -1; + } + } else { + pmkid = rsn_data->pmkid; + } + + pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, + pasn->own_addr, + 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(pasn, 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); + + pasn->pmksa_entry = pmksa_cache_add(pasn->pmksa, pasn->pmk, + pasn->pmk_len, + pasn->sae.pmkid, + NULL, 0, pasn->peer_addr, + pasn->own_addr, NULL, + pasn->akmp, 0); + 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(pasn, 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_send_auth_1(struct pasn_data *pasn, const u8 *own_addr, + const u8 *peer_addr, 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, + const struct wpabuf *comeback, bool verify) +{ + struct wpabuf *frame; + int ret; + + pasn->ecdh = crypto_ecdh_init(group); + if (!pasn->ecdh) { + wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH"); + goto fail; + } + + if (beacon_rsne && beacon_rsne_len) { + 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->own_addr, own_addr, ETH_ALEN); + os_memcpy(pasn->peer_addr, peer_addr, ETH_ALEN); + os_memcpy(pasn->bssid, bssid, ETH_ALEN); + + wpa_printf(MSG_DEBUG, + "PASN: Init%s: " MACSTR_SEC " akmp=0x%x, cipher=0x%x, group=%u", + verify ? " (verify)" : "", + MAC2STR_SEC(pasn->peer_addr), pasn->akmp, pasn->cipher, + pasn->group); + + frame = wpas_pasn_build_auth_1(pasn, comeback, verify); + if (!frame) { + wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame"); + goto fail; + } + + ret = pasn->send_mgmt(pasn->cb_ctx, + 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; + } + + return 0; + +fail: + return -1; +} + + +int wpas_pasn_start(struct pasn_data *pasn, const u8 *own_addr, + const u8 *peer_addr, 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, + const struct wpabuf *comeback) +{ + /* TODO: Currently support only ECC groups */ + if (!dragonfly_suitable_group(group, 1)) { + wpa_printf(MSG_DEBUG, + "PASN: Reject unsuitable group %u", group); + return -1; + } + + switch (akmp) { + case WPA_KEY_MGMT_PASN: + break; +#ifdef CONFIG_SAE + case WPA_KEY_MGMT_SAE: + + if (beacon_rsnxe && + !ieee802_11_rsnx_capab(beacon_rsnxe, + WLAN_RSNX_CAPAB_SAE_H2E)) { + wpa_printf(MSG_DEBUG, + "PASN: AP does not support SAE H2E"); + return -1; + } + + pasn->sae.state = SAE_NOTHING; + pasn->sae.send_confirm = 0; + break; +#endif /* CONFIG_SAE */ +#ifdef CONFIG_FILS + case WPA_KEY_MGMT_FILS_SHA256: + case WPA_KEY_MGMT_FILS_SHA384: + 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; + } + + return wpas_pasn_send_auth_1(pasn, own_addr, peer_addr, bssid, akmp, + cipher, group, + freq, beacon_rsne, beacon_rsne_len, + beacon_rsnxe, beacon_rsnxe_len, comeback, + false); +} + +/* + * Wi-Fi Aware uses PASN handshake to authenticate peer devices. + * Devices can simply verify each other for subsequent sessions using + * pairing verification procedure. + * + * In pairing verification, Wi-Fi aware devices use PASN authentication + * frames with a custom PMKID and Wi-Fi Aware R4 specific verification IEs. + * It does not use wrapped data in the Authentication frames. This function + * provides support to construct PASN Authentication frames for pairing + * verification. + */ +int wpa_pasn_verify(struct pasn_data *pasn, const u8 *own_addr, + const u8 *peer_addr, 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, + const struct wpabuf *comeback) +{ + return wpas_pasn_send_auth_1(pasn, own_addr, peer_addr, bssid, akmp, + cipher, group, freq, beacon_rsne, + beacon_rsne_len, beacon_rsnxe, + beacon_rsnxe_len, comeback, true); +} + + +static bool is_pasn_auth_frame(struct pasn_data *pasn, + const struct ieee80211_mgmt *mgmt, + size_t len, bool rx) +{ + u16 fc; + + if (!mgmt || len < offsetof(struct ieee80211_mgmt, u.auth.variable)) + return false; + + /* Not an Authentication frame; do nothing */ + fc = le_to_host16(mgmt->frame_control); + if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || + WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_AUTH) + return false; + + /* Not our frame; do nothing */ + if (!ether_addr_equal(mgmt->bssid, pasn->bssid)) + return false; + + if (rx && (!ether_addr_equal(mgmt->da, pasn->own_addr) || + !ether_addr_equal(mgmt->sa, pasn->peer_addr))) + return false; + + if (!rx && (!ether_addr_equal(mgmt->sa, pasn->own_addr) || + !ether_addr_equal(mgmt->da, pasn->peer_addr))) + return false; + + /* Not PASN; do nothing */ + if (mgmt->u.auth.auth_alg != host_to_le16(WLAN_AUTH_PASN)) + return false; + + return true; +} + + +int wpa_pasn_auth_rx(struct pasn_data *pasn, const u8 *data, size_t len, + struct wpa_pasn_params_data *pasn_params) + +{ + struct ieee802_11_elems elems; + struct wpa_ie_data rsn_data; + const struct ieee80211_mgmt *mgmt = + (const struct ieee80211_mgmt *) data; + 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, inc_y; + u8 *copy = NULL; + size_t mic_offset, copy_len; + + if (!is_pasn_auth_frame(pasn, mgmt, len, true)) + 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 -3; + } + + 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); + goto fail; + } + + 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; + } + os_memcpy(mic, elems.mic, mic_len); + } + + if (!elems.pasn_params || !elems.pasn_params_len) { + wpa_printf(MSG_DEBUG, + "PASN: Missing PASN Parameters IE"); + goto fail; + } + + if (!pasn_params) { + wpa_printf(MSG_DEBUG, "PASN: pasn_params == NULL"); + 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; + } + + if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) { + wpa_printf(MSG_DEBUG, + "PASN: Authentication temporarily rejected"); + + if (pasn_params->comeback && pasn_params->comeback_len) { + wpa_printf(MSG_DEBUG, + "PASN: Comeback token available. After=%u", + pasn_params->after); + + if (!pasn_params->after) + return 1; + + pasn->comeback = wpabuf_alloc_copy( + pasn_params->comeback, + pasn_params->comeback_len); + if (pasn->comeback) + pasn->comeback_after = pasn_params->after; + } + + pasn->status = status; + goto fail; + } + + if (!elems.rsn_ie) { + wpa_printf(MSG_DEBUG, "PASN: Missing RSNE"); + 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 RSNE"); + 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; + } + + if (pasn_params->pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) { + inc_y = 1; + } else if (pasn_params->pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 || + pasn_params->pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) { + inc_y = 0; + } else { + wpa_printf(MSG_DEBUG, + "PASN: Invalid first octet in pubkey=0x%x", + pasn_params->pubkey[0]); + goto fail; + } + + secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y, + pasn_params->pubkey + 1, + pasn_params->pubkey_len - 1); + + 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.wrapped_data, + elems.wrapped_data_len, + true); + + if (!wrapped_data) { + wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data"); + goto fail; + } + } + + ret = wpas_pasn_set_pmk(pasn, &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, + pasn->own_addr, pasn->peer_addr, + wpabuf_head(secret), wpabuf_len(secret), + &pasn->ptk, pasn->akmp, pasn->cipher, + pasn->kdk_len); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK"); + goto fail; + } + + if (pasn->secure_ltf) { + ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, pasn->cipher); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: Failed to derive LTF keyseed"); + goto fail; + } + } + + wpabuf_free(wrapped_data); + wrapped_data = NULL; + wpabuf_free(secret); + secret = NULL; + + /* Use a copy of the message since we need to clear the MIC field */ + if (!elems.mic) + goto fail; + mic_offset = elems.mic - (const u8 *) &mgmt->u.auth; + copy_len = len - offsetof(struct ieee80211_mgmt, u.auth); + if (mic_offset + mic_len > copy_len) + goto fail; + copy = os_memdup(&mgmt->u.auth, copy_len); + if (!copy) + goto fail; + os_memset(copy + mic_offset, 0, mic_len); + + if (pasn->beacon_rsne_rsnxe) { + /* Verify the MIC */ + ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher, + pasn->peer_addr, pasn->own_addr, + wpabuf_head(pasn->beacon_rsne_rsnxe), + wpabuf_len(pasn->beacon_rsne_rsnxe), + copy, copy_len, out_mic); + } else { + u8 *rsne_rsnxe; + size_t rsne_rsnxe_len = 0; + + /* + * Note: When Beacon rsne_rsnxe is not initialized, it is likely + * that this is for Wi-Fi Aware using PASN handshake for which + * Beacon RSNE/RSNXE are same as RSNE/RSNXE in the + * Authentication frame + */ + if (elems.rsn_ie && elems.rsn_ie_len) + rsne_rsnxe_len += elems.rsn_ie_len + 2; + if (elems.rsnxe && elems.rsnxe_len) + rsne_rsnxe_len += elems.rsnxe_len + 2; + + rsne_rsnxe = os_zalloc(rsne_rsnxe_len); + if (!rsne_rsnxe) + goto fail; + + if (elems.rsn_ie && elems.rsn_ie_len) + os_memcpy(rsne_rsnxe, elems.rsn_ie - 2, + elems.rsn_ie_len + 2); + if (elems.rsnxe && elems.rsnxe_len) + os_memcpy(rsne_rsnxe + elems.rsn_ie_len + 2, + elems.rsnxe - 2, elems.rsnxe_len + 2); + + wpa_hexdump_key(MSG_DEBUG, "PASN: RSN + RSNXE buf", + rsne_rsnxe, rsne_rsnxe_len); + + /* Verify the MIC */ + ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher, + pasn->peer_addr, pasn->own_addr, + rsne_rsnxe, + rsne_rsnxe_len, + copy, copy_len, out_mic); + + os_free(rsne_rsnxe); + } + os_free(copy); + copy = NULL; + + 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(pasn); + if (!frame) { + wpa_printf(MSG_DEBUG, "PASN: Failed building 3rd auth frame"); + goto fail; + } + + ret = pasn->send_mgmt(pasn->cb_ctx, + 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"); + + pasn->status = WLAN_STATUS_SUCCESS; + + return 0; +fail: + wpa_printf(MSG_DEBUG, "PASN: Failed RX processing - terminating"); + wpabuf_free(wrapped_data); + wpabuf_free(secret); + os_free(copy); + + /* + * 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. + */ + if (status == WLAN_STATUS_SUCCESS) + pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE; + else + pasn->status = status; + + return -1; +} + + +int wpa_pasn_auth_tx_status(struct pasn_data *pasn, + const u8 *data, size_t data_len, u8 acked) + +{ + const struct ieee80211_mgmt *mgmt = + (const struct ieee80211_mgmt *) data; + + wpa_printf(MSG_DEBUG, "PASN: auth_tx_status: acked=%u", acked); + + if (!is_pasn_auth_frame(pasn, mgmt, data_len, false)) + 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_SEC, + MAC2STR_SEC(pasn->peer_addr)); + /* + * 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. + */ + return 1; + } + + return 0; +} diff --git a/wpa_supplicant-2.9_standard/src/pasn/pasn_responder.c b/wpa_supplicant-2.9_standard/src/pasn/pasn_responder.c new file mode 100644 index 0000000000000000000000000000000000000000..236a8267e7ac836ca972dd7f6e8be665764c3808 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/pasn/pasn_responder.c @@ -0,0 +1,1032 @@ +/* + * PASN responder processing + * + * Copyright (C) 2019, Intel Corporation + * Copyright (C) 2022, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/wpa_common.h" +#include "common/sae.h" +#include "common/ieee802_11_common.h" +#include "common/ieee802_11_defs.h" +#include "crypto/sha384.h" +#include "crypto/sha256.h" +#include "crypto/random.h" +#include "crypto/crypto.h" +#include "ap/hostapd.h" +#include "ap/comeback_token.h" +#include "ap/ieee802_1x.h" +#include "ap/pmksa_cache_auth.h" +#include "pasn_common.h" + + +void pasn_set_responder_pmksa(struct pasn_data *pasn, + struct rsn_pmksa_cache *pmksa) +{ + if (pasn) + pasn->pmksa = pmksa; +} + + +#ifdef CONFIG_PASN +#ifdef CONFIG_SAE + +static int pasn_wd_handle_sae_commit(struct pasn_data *pasn, + const u8 *own_addr, const u8 *peer_addr, + struct wpabuf *wd) +{ + 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=%zu", + 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); + + if (alg != WLAN_AUTH_SAE || seq != 1 || + status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) { + 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; + } + + if (!pasn->password || !pasn->pt) { + wpa_printf(MSG_DEBUG, "PASN: No SAE PT found"); + return -1; + } + + ret = sae_prepare_commit_pt(&pasn->sae, pasn->pt, own_addr, peer_addr, + NULL, NULL); + 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, NULL); + 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 pasn_data *pasn, + const u8 *peer_addr, struct wpabuf *wd) +{ + 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=%zu", + 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, NULL); + 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. + */ + if (pasn->disable_pmksa_caching) + return 0; + + wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", + pasn->sae.pmk, pasn->sae.pmk_len); + if (!pasn->sae.akmp) + pasn->sae.akmp = WPA_KEY_MGMT_SAE; + + pmksa_cache_auth_add(pasn->pmksa, pasn->sae.pmk, pasn->sae.pmk_len, + pasn->sae.pmkid, NULL, 0, pasn->own_addr, + peer_addr, 0, NULL, pasn->sae.akmp); + return 0; +} + + +static struct wpabuf * pasn_get_sae_wd(struct pasn_data *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_SAE_HASH_TO_ELEMENT); + + /* 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 pasn_data *pasn) +{ + struct pasn_fils *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; +} + +#endif /* CONFIG_FILS */ + +static struct wpabuf * pasn_get_wrapped_data(struct pasn_data *pasn) +{ + switch (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(pasn); +#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(pasn); +#endif /* CONFIG_FILS */ + __attribute__((fallthrough)); + 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", + pasn->akmp); + return NULL; + } +} + + +static int +pasn_derive_keys(struct pasn_data *pasn, + const u8 *own_addr, const u8 *peer_addr, + 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 (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 (pasn->akmp) { +#ifdef CONFIG_SAE + case WPA_KEY_MGMT_SAE: + if (pasn->sae.state == SAE_COMMITTED) { + pmk_len = PMK_LEN; + os_memcpy(pmk, pasn->sae.pmk, PMK_LEN); + break; + } +#endif /* CONFIG_SAE */ + __attribute__((fallthrough)); + default: + /* TODO: Derive PMK based on wrapped data */ + wpa_printf(MSG_DEBUG, + "PASN: Missing PMK derivation"); + return -1; + } + } + + pasn->pmk_len = pmk_len; + os_memcpy(pasn->pmk, pmk, pmk_len); + ret = pasn_pmk_to_ptk(pmk, pmk_len, peer_addr, own_addr, + wpabuf_head(secret), wpabuf_len(secret), + &pasn->ptk, pasn->akmp, + pasn->cipher, pasn->kdk_len); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK"); + return -1; + } + + if (pasn->secure_ltf) { + ret = wpa_ltf_keyseed(&pasn->ptk, pasn->akmp, + pasn->cipher); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: Failed to derive LTF keyseed"); + return -1; + } + } + + wpa_printf(MSG_DEBUG, "PASN: PTK successfully derived"); + return 0; +} + + +static void handle_auth_pasn_comeback(struct pasn_data *pasn, + const u8 *own_addr, const u8 *peer_addr, + u16 group) +{ + struct wpabuf *buf, *comeback; + int ret; + + wpa_printf(MSG_DEBUG, + "PASN: Building comeback frame 2. Comeback after=%u", + pasn->comeback_after); + + buf = wpabuf_alloc(1500); + if (!buf) + return; + + wpa_pasn_build_auth_header(buf, pasn->bssid, own_addr, peer_addr, 2, + WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY); + + /* + * Do not include the group as a part of the token since it is not going + * to be used. + */ + comeback = auth_build_token_req(&pasn->last_comeback_key_update, + pasn->comeback_key, pasn->comeback_idx, + pasn->comeback_pending_idx, + sizeof(u16) * COMEBACK_PENDING_IDX_SIZE, + 0, peer_addr, 0); + if (!comeback) { + wpa_printf(MSG_DEBUG, + "PASN: Failed sending auth with comeback"); + wpabuf_free(buf); + return; + } + + wpa_pasn_add_parameter_ie(buf, group, + WPA_PASN_WRAPPED_DATA_NO, + NULL, 0, comeback, + pasn->comeback_after); + wpabuf_free(comeback); + + wpa_printf(MSG_DEBUG, + "PASN: comeback: STA=" MACSTR_SEC, MAC2STR_SEC(peer_addr)); + + ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf), + wpabuf_len(buf), 0, 0, 0); + if (ret) + wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2"); + + wpabuf_free(buf); +} + + +int handle_auth_pasn_resp(struct pasn_data *pasn, const u8 *own_addr, + const u8 *peer_addr, + struct rsn_pmksa_cache_entry *pmksa, u16 status) +{ + struct wpabuf *buf, *pubkey = NULL, *wrapped_data_buf = NULL; + struct wpabuf *rsn_buf = NULL; + u8 mic[WPA_PASN_MAX_MIC_LEN]; + u8 mic_len; + u8 *ptr; + const u8 *frame, *data, *rsn_ie, *rsnxe_ie; + u8 *data_buf = NULL; + size_t frame_len, data_len; + int ret; + const u8 *pmkid = NULL; + + 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, pasn->bssid, own_addr, peer_addr, 2, + status); + + if (status != WLAN_STATUS_SUCCESS) + goto done; + + if (pmksa && pasn->custom_pmkid_valid) + pmkid = pasn->custom_pmkid; + else if (pmksa) { + pmkid = pmksa->pmkid; +#ifdef CONFIG_SAE + } else if (pasn->akmp == WPA_KEY_MGMT_SAE) { + wpa_printf(MSG_DEBUG, "PASN: Use SAE PMKID"); + pmkid = pasn->sae.pmkid; +#endif /* CONFIG_SAE */ +#ifdef CONFIG_FILS + } else if (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 || + pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) { + wpa_printf(MSG_DEBUG, "PASN: Use FILS ERP PMKID"); + pmkid = pasn->fils.erp_pmkid; +#endif /* CONFIG_FILS */ + } + + if (wpa_pasn_add_rsne(buf, pmkid, + pasn->akmp, pasn->cipher) < 0) + goto fail; + + /* No need to derive PMK if PMKSA is given */ + if (!pmksa) + wrapped_data_buf = pasn_get_wrapped_data(pasn); + else + pasn->wrapped_data_format = WPA_PASN_WRAPPED_DATA_NO; + + /* 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; + } + + wpa_pasn_add_parameter_ie(buf, pasn->group, + pasn->wrapped_data_format, + pubkey, true, 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 = pasn->rsnxe_ie; + if (rsnxe_ie) + wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]); + + wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len); + + /* 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); + + frame = wpabuf_head_u8(buf) + IEEE80211_HDRLEN; + frame_len = wpabuf_len(buf) - IEEE80211_HDRLEN; + + if (pasn->rsn_ie && pasn->rsn_ie_len) { + rsn_ie = pasn->rsn_ie; + } else { + /* + * Note: when pasn->rsn_ie is NULL, it is likely that Beacon + * frame RSNE is not initialized. This is possible in case of + * PASN authentication used for Wi-Fi Aware for which Beacon + * frame RSNE and RSNXE are same as RSNE and RSNXE in the + * Authentication frame. + */ + rsn_buf = wpabuf_alloc(500); + if (!rsn_buf) + goto fail; + + if (wpa_pasn_add_rsne(rsn_buf, pmkid, + pasn->akmp, pasn->cipher) < 0) + goto fail; + + rsn_ie = wpabuf_head_u8(rsn_buf); + } + + /* + * 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(pasn->ptk.kck, pasn->akmp, pasn->cipher, + own_addr, peer_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; + } + +#ifdef CONFIG_TESTING_OPTIONS + if (pasn->corrupt_mic) { + wpa_printf(MSG_DEBUG, "PASN: frame 2: Corrupt MIC"); + mic[0] = ~mic[0]; + } +#endif /* CONFIG_TESTING_OPTIONS */ + + os_memcpy(ptr, mic, mic_len); + +done: + wpa_printf(MSG_DEBUG, + "PASN: Building frame 2: success; resp STA=" MACSTR_SEC, + MAC2STR_SEC(peer_addr)); + + ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf), + wpabuf_len(buf), 0, 0, 0); + if (ret) + wpa_printf(MSG_INFO, "send_auth_reply: Send failed"); + + wpabuf_free(rsn_buf); + wpabuf_free(buf); + return ret; +fail: + wpabuf_free(wrapped_data_buf); + wpabuf_free(pubkey); + wpabuf_free(rsn_buf); + wpabuf_free(buf); + return -1; +} + + +int handle_auth_pasn_1(struct pasn_data *pasn, + const u8 *own_addr, const u8 *peer_addr, + 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; + struct wpabuf *wrapped_data = NULL, *secret = NULL; + const int *groups = pasn->pasn_groups; + static const int default_groups[] = { 19, 0 }; + u16 status = WLAN_STATUS_SUCCESS; + int ret, inc_y; + 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; + } + + if (!elems.rsn_ie) { + wpa_printf(MSG_DEBUG, "PASN: No RSNE"); + status = WLAN_STATUS_INVALID_RSNIE; + 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 RSNE"); + 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 & pasn->wpa_key_mgmt) || + !(rsn_data.pairwise_cipher & pasn->rsn_pairwise)) { + wpa_printf(MSG_DEBUG, "PASN: Mismatch in AKMP/cipher"); + status = WLAN_STATUS_INVALID_RSNIE; + goto send_resp; + } + + pasn->akmp = rsn_data.key_mgmt; + pasn->cipher = rsn_data.pairwise_cipher; + + if (pasn->derive_kdk && + ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len, + WLAN_RSNX_CAPAB_SECURE_LTF)) + pasn->secure_ltf = true; + + if (pasn->derive_kdk) + pasn->kdk_len = WPA_KDK_MAX_LEN; + else + pasn->kdk_len = 0; + + wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len); + + 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_INVALID_PARAMETERS; + goto send_resp; + } + + if (pasn_params.comeback) { + wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token"); + + ret = check_comeback_token(pasn->comeback_key, + pasn->comeback_pending_idx, + peer_addr, + pasn_params.comeback, + pasn_params.comeback_len); + + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token"); + status = WLAN_STATUS_INVALID_PARAMETERS; + goto send_resp; + } + } else if (pasn->use_anti_clogging) { + wpa_printf(MSG_DEBUG, "PASN: Respond with comeback"); + handle_auth_pasn_comeback(pasn, own_addr, peer_addr, + pasn_params.group); + return -1; + } + + pasn->ecdh = crypto_ecdh_init(pasn_params.group); + if (!pasn->ecdh) { + wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + pasn->group = pasn_params.group; + + if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) { + inc_y = 1; + } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 || + pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) { + inc_y = 0; + } else { + wpa_printf(MSG_DEBUG, + "PASN: Invalid first octet in pubkey=0x%x", + pasn_params.pubkey[0]); + status = WLAN_STATUS_INVALID_PUBLIC_KEY; + goto send_resp; + } + + secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y, + pasn_params.pubkey + 1, + pasn_params.pubkey_len - 1); + if (!secret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + + if (!pasn->noauth && pasn->akmp == WPA_KEY_MGMT_PASN) { + wpa_printf(MSG_DEBUG, "PASN: Refuse PASN-UNAUTH"); + 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.wrapped_data, + elems.wrapped_data_len, true); + if (!wrapped_data) { + wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + +#ifdef CONFIG_SAE + if (pasn->akmp == WPA_KEY_MGMT_SAE) { + ret = pasn_wd_handle_sae_commit(pasn, own_addr, + peer_addr, + 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 (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 || + pasn->akmp == WPA_KEY_MGMT_FILS_SHA384) { + if (!pasn->fils_wd_valid) { + wpa_printf(MSG_DEBUG, + "PASN: Invalid 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 */ + } + + pasn->wrapped_data_format = pasn_params.wrapped_data_format; + + ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher, + ((const u8 *) mgmt) + IEEE80211_HDRLEN, + len - IEEE80211_HDRLEN, 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"); + pasn->secret = secret; + wpabuf_free(wrapped_data); + return 0; + } + + if (rsn_data.num_pmkid) { + if (wpa_key_mgmt_ft(pasn->akmp)) { +#ifdef CONFIG_IEEE80211R_AP + wpa_printf(MSG_DEBUG, "PASN: FT: Fetch PMK-R1"); + + if (!pasn->pmk_r1_len) { + wpa_printf(MSG_DEBUG, + "PASN: FT: Failed getting PMK-R1"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + cached_pmk = pasn->pmk_r1; + cached_pmk_len = pasn->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"); + + if (pasn->pmksa) { + const u8 *pmkid = NULL; + + if (pasn->custom_pmkid_valid) { + ret = pasn->validate_custom_pmkid( + pasn->cb_ctx, peer_addr, + rsn_data.pmkid); + if (ret) { + wpa_printf(MSG_DEBUG, + "PASN: Failed custom PMKID validation"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + } else { + pmkid = rsn_data.pmkid; + } + + pmksa = pmksa_cache_auth_get(pasn->pmksa, + peer_addr, + 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(pasn, own_addr, peer_addr, + cached_pmk, cached_pmk_len, + &pasn_params, wrapped_data, secret); + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Failed to derive keys"); + status = WLAN_STATUS_PASN_BASE_AKMP_FAILED; + goto send_resp; + } + + ret = pasn_auth_frame_hash(pasn->akmp, pasn->cipher, + ((const u8 *) mgmt) + IEEE80211_HDRLEN, + len - IEEE80211_HDRLEN, 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(pasn, own_addr, peer_addr, 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) + return -1; + + return 0; +} + + +int handle_auth_pasn_3(struct pasn_data *pasn, const u8 *own_addr, + const u8 *peer_addr, + 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; + u8 *copy = NULL; + size_t copy_len, mic_offset; + + 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 (!elems.mic || elems.mic_len != mic_len) { + wpa_printf(MSG_DEBUG, + "PASN: Invalid MIC. Expecting len=%u", mic_len); + goto fail; + } + os_memcpy(mic, elems.mic, 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 */ + copy_len = len - offsetof(struct ieee80211_mgmt, u.auth); + mic_offset = elems.mic - (const u8 *) &mgmt->u.auth; + copy_len = len - offsetof(struct ieee80211_mgmt, u.auth); + if (mic_offset + mic_len > copy_len) + goto fail; + copy = os_memdup(&mgmt->u.auth, copy_len); + if (!copy) + goto fail; + os_memset(copy + mic_offset, 0, mic_len); + ret = pasn_mic(pasn->ptk.kck, pasn->akmp, pasn->cipher, + peer_addr, own_addr, + pasn->hash, mic_len * 2, + copy, copy_len, out_mic); + os_free(copy); + copy = NULL; + + 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.wrapped_data, + elems.wrapped_data_len, + true); + + if (!wrapped_data) { + wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data"); + goto fail; + } + +#ifdef CONFIG_SAE + if (pasn->akmp == WPA_KEY_MGMT_SAE) { + ret = pasn_wd_handle_sae_confirm(pasn, peer_addr, + 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 (pasn->akmp == WPA_KEY_MGMT_FILS_SHA256 || + 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"); + return 0; + +fail: + os_free(copy); + return -1; +} + +#endif /* CONFIG_PASN */ diff --git a/wpa_supplicant-2.9_standard/src/radius/radius.c b/wpa_supplicant-2.9_standard/src/radius/radius.c index be16e27b9d7c30c0ab43f0dd50a6298fb106d48a..37aa216b170b777bbb2fc0801a919346e120974a 100644 --- a/wpa_supplicant-2.9_standard/src/radius/radius.c +++ b/wpa_supplicant-2.9_standard/src/radius/radius.c @@ -1,6 +1,6 @@ /* * RADIUS message processing - * Copyright (c) 2002-2009, 2011-2015, Jouni Malinen + * Copyright (c) 2002-2009, 2011-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -159,7 +159,8 @@ static const char *radius_code_string(u8 code) struct radius_attr_type { - u8 type; + u16 type; /* 0..255 for basic types; + * (241 << 8) | for extended types */ char *name; enum { RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, @@ -175,6 +176,7 @@ static const struct radius_attr_type radius_attrs[] = { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 }, { RADIUS_ATTR_SERVICE_TYPE, "Service-Type", RADIUS_ATTR_INT32 }, { RADIUS_ATTR_FRAMED_IP_ADDRESS, "Framed-IP-Address", RADIUS_ATTR_IP }, + { RADIUS_ATTR_FILTER_ID, "Filter-Id", RADIUS_ATTR_TEXT }, { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 }, { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT }, { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST }, @@ -260,11 +262,31 @@ static const struct radius_attr_type radius_attrs[] = RADIUS_ATTR_HEXDUMP }, { RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher", RADIUS_ATTR_HEXDUMP }, + { RADIUS_ATTR_EXT_TYPE_1, "Extended-Type-1", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_TYPE_2, "Extended-Type-2", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_TYPE_3, "Extended-Type-3", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_TYPE_4, "Extended-Type-4", RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_LONG_EXT_TYPE_1, "Long-Extended-Type-1", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_LONG_EXT_TYPE_2, "Long-Extended-Type-2", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1, "Extended-Vendor-Specific-1", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2, "Extended-Vendor-Specific-2", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3, "Extended-Vendor-Specific-3", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4, "Extended-Vendor-Specific-4", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5, "Extended-Vendor-Specific-5", + RADIUS_ATTR_UNDIST }, + { RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6, "Extended-Vendor-Specific-6", + RADIUS_ATTR_UNDIST }, }; #define RADIUS_ATTRS ARRAY_SIZE(radius_attrs) -static const struct radius_attr_type *radius_get_attr_type(u8 type) +static const struct radius_attr_type * radius_get_attr_type(u16 type) { size_t i; @@ -277,23 +299,60 @@ static const struct radius_attr_type *radius_get_attr_type(u8 type) } +static bool radius_is_long_ext_type(u8 type) +{ + return type == RADIUS_ATTR_LONG_EXT_TYPE_1 || + type == RADIUS_ATTR_LONG_EXT_TYPE_2; +} + + +static bool radius_is_ext_type(u8 type) +{ + return type >= RADIUS_ATTR_EXT_TYPE_1 && + type <= RADIUS_ATTR_LONG_EXT_TYPE_2; +} + + static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) { + struct radius_attr_hdr_ext *ext = NULL; const struct radius_attr_type *attr; int len; unsigned char *pos; char buf[1000]; - attr = radius_get_attr_type(hdr->type); + if (hdr->length < sizeof(struct radius_attr_hdr)) + return; - wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d", - hdr->type, attr ? attr->name : "?Unknown?", hdr->length); + if (radius_is_ext_type(hdr->type)) { + if (hdr->length < 4) { + wpa_printf(MSG_INFO, + " Invalid attribute %d (too short for extended type)", + hdr->type); + return; + } - if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr)) - return; + ext = (struct radius_attr_hdr_ext *) hdr; + } - len = hdr->length - sizeof(struct radius_attr_hdr); - pos = (unsigned char *) (hdr + 1); + if (ext) { + attr = radius_get_attr_type((ext->type << 8) | ext->ext_type); + wpa_printf(MSG_INFO, " Attribute %d.%d (%s) length=%d", + ext->type, ext->ext_type, + attr ? attr->name : "?Unknown?", ext->length); + pos = (unsigned char *) (ext + 1); + len = ext->length - sizeof(struct radius_attr_hdr_ext); + } else { + attr = radius_get_attr_type(hdr->type); + wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d", + hdr->type, attr ? attr->name : "?Unknown?", + hdr->length); + pos = (unsigned char *) (hdr + 1); + len = hdr->length - sizeof(struct radius_attr_hdr); + } + + if (!attr) + return; switch (attr->data_type) { case RADIUS_ATTR_TEXT: @@ -364,25 +423,54 @@ void radius_msg_dump(struct radius_msg *msg) } +u8 * radius_msg_add_msg_auth(struct radius_msg *msg) +{ + u8 auth[MD5_MAC_LEN]; + struct radius_attr_hdr *attr; + + os_memset(auth, 0, MD5_MAC_LEN); + attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, + auth, MD5_MAC_LEN); + if (!attr) { + wpa_printf(MSG_ERROR, + "WARNING: Could not add Message-Authenticator"); + return NULL; + } + + return (u8 *) (attr + 1); +} + + +static u8 * radius_msg_auth_pos(struct radius_msg *msg) +{ + u8 *pos; + size_t alen; + + if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, + &pos, &alen, NULL) == 0 && + alen == MD5_MAC_LEN) { + /* Use already added Message-Authenticator attribute */ + return pos; + } + + /* Add a Message-Authenticator attribute */ + return radius_msg_add_msg_auth(msg); +} + + int radius_msg_finish(struct radius_msg *msg, const u8 *secret, size_t secret_len) { if (secret) { - u8 auth[MD5_MAC_LEN]; - struct radius_attr_hdr *attr; - - os_memset(auth, 0, MD5_MAC_LEN); - attr = radius_msg_add_attr(msg, - RADIUS_ATTR_MESSAGE_AUTHENTICATOR, - auth, MD5_MAC_LEN); - if (attr == NULL) { - wpa_printf(MSG_WARNING, "RADIUS: Could not add " - "Message-Authenticator"); + u8 *pos; + + pos = radius_msg_auth_pos(msg); + if (!pos) return -1; - } msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); - hmac_md5(secret, secret_len, wpabuf_head(msg->buf), - wpabuf_len(msg->buf), (u8 *) (attr + 1)); + if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf), + wpabuf_len(msg->buf), pos) < 0) + return -1; } else msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); @@ -398,23 +486,19 @@ int radius_msg_finish(struct radius_msg *msg, const u8 *secret, int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, size_t secret_len, const u8 *req_authenticator) { - u8 auth[MD5_MAC_LEN]; - struct radius_attr_hdr *attr; const u8 *addr[4]; size_t len[4]; + u8 *pos; - os_memset(auth, 0, MD5_MAC_LEN); - attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, - auth, MD5_MAC_LEN); - if (attr == NULL) { - wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator"); + pos = radius_msg_auth_pos(msg); + if (!pos) return -1; - } msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); os_memcpy(msg->hdr->authenticator, req_authenticator, sizeof(msg->hdr->authenticator)); - hmac_md5(secret, secret_len, wpabuf_head(msg->buf), - wpabuf_len(msg->buf), (u8 *) (attr + 1)); + if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf), + wpabuf_len(msg->buf), pos) < 0) + return -1; /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = (u8 *) msg->hdr; @@ -442,21 +526,17 @@ int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, { const u8 *addr[2]; size_t len[2]; - u8 auth[MD5_MAC_LEN]; - struct radius_attr_hdr *attr; + u8 *pos; - os_memset(auth, 0, MD5_MAC_LEN); - attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, - auth, MD5_MAC_LEN); - if (attr == NULL) { - wpa_printf(MSG_WARNING, "Could not add Message-Authenticator"); + pos = radius_msg_auth_pos(msg); + if (!pos) return -1; - } msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16); - hmac_md5(secret, secret_len, wpabuf_head(msg->buf), - wpabuf_len(msg->buf), (u8 *) (attr + 1)); + if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf), + wpabuf_len(msg->buf), pos) < 0) + return -1; /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = wpabuf_head_u8(msg->buf); @@ -627,22 +707,54 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg, } -struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, - const u8 *data, size_t data_len) +struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type, + const u8 *data, size_t data_len) { - size_t buf_needed; - struct radius_attr_hdr *attr; + size_t buf_needed, max_len; + struct radius_attr_hdr *attr = NULL; + struct radius_attr_hdr_ext *ext; + u8 ext_type = 0; if (TEST_FAIL()) return NULL; - if (data_len > RADIUS_MAX_ATTR_LEN) { - wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)", - (unsigned long) data_len); - return NULL; + if (type > 255) { + if (!radius_is_ext_type(type >> 8)) { + wpa_printf(MSG_ERROR, + "%s: Undefined extended type %d.%d", + __func__, type >> 8, type & 0xff); + return NULL; + } + ext_type = type & 0xff; + type >>= 8; + } else if (radius_is_ext_type(type)) { + wpa_printf(MSG_ERROR, "%s: Unexpected extended type use for %d", + __func__, type); } - buf_needed = sizeof(*attr) + data_len; + if (radius_is_long_ext_type(type)) { + size_t hdr_len = sizeof(struct radius_attr_hdr_ext) + 1; + size_t plen = 255 - hdr_len; + size_t num; + + max_len = 4096; + num = (data_len + plen - 1) / plen; + if (num == 0) + num = 1; + buf_needed = num * hdr_len + data_len; + } else if (radius_is_ext_type(type)) { + max_len = RADIUS_MAX_EXT_ATTR_LEN; + buf_needed = sizeof(struct radius_attr_hdr_ext) + data_len; + } else { + max_len = RADIUS_MAX_ATTR_LEN; + buf_needed = sizeof(*attr) + data_len; + } + if (data_len > max_len) { + wpa_printf(MSG_ERROR, + "%s: too long attribute (%zu > %zu bytes)", + __func__, data_len, max_len); + return NULL; + } if (wpabuf_tailroom(msg->buf) < buf_needed) { /* allocate more space for message buffer */ @@ -651,13 +763,44 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, msg->hdr = wpabuf_mhead(msg->buf); } - attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); - attr->type = type; - attr->length = sizeof(*attr) + data_len; - wpabuf_put_data(msg->buf, data, data_len); - - if (radius_msg_add_attr_to_array(msg, attr)) - return NULL; + if (radius_is_long_ext_type(type)) { + size_t plen = 255 - sizeof(struct radius_attr_hdr_ext) - 1; + size_t alen; + + do { + alen = data_len > plen ? plen : data_len; + ext = wpabuf_put(msg->buf, + sizeof(struct radius_attr_hdr_ext)); + if (!attr) + attr = (struct radius_attr_hdr *) ext; + ext->type = type; + ext->length = sizeof(*ext) + 1 + alen; + ext->ext_type = ext_type; + wpabuf_put_u8(msg->buf, data_len > alen ? 0x80 : 0); + wpabuf_put_data(msg->buf, data, data_len); + data += alen; + data_len -= alen; + if (radius_msg_add_attr_to_array( + msg, (struct radius_attr_hdr *) ext)) + return NULL; + } while (data_len > 0); + } else if (radius_is_ext_type(type)) { + ext = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr_ext)); + attr = (struct radius_attr_hdr *) ext; + ext->type = type; + ext->length = sizeof(*ext) + data_len; + ext->ext_type = ext_type; + wpabuf_put_data(msg->buf, data, data_len); + if (radius_msg_add_attr_to_array(msg, attr)) + return NULL; + } else { + attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); + attr->type = type; + attr->length = sizeof(*attr) + data_len; + wpabuf_put_data(msg->buf, data, data_len); + if (radius_msg_add_attr_to_array(msg, attr)) + return NULL; + } return attr; } @@ -858,6 +1001,20 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret, return 1; } + if (!auth) { + u8 *pos; + size_t alen; + + if (radius_msg_get_attr_ptr(msg, + RADIUS_ATTR_MESSAGE_AUTHENTICATOR, + &pos, &alen, NULL) == 0) { + /* Check the Message-Authenticator attribute since it + * was included even if we are configured to not + * require it. */ + auth = 1; + } + } + if (auth && radius_msg_verify_msg_auth(msg, secret, secret_len, sent_msg->hdr->authenticator)) { @@ -1285,6 +1442,28 @@ int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, } +int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id, + u8 vendor_type, const u8 *data, size_t len) +{ + struct radius_attr_hdr *attr; + u8 *buf, *pos; + size_t alen; + + alen = 4 + 1 + len; + buf = os_malloc(alen); + if (!buf) + return 0; + pos = buf; + WPA_PUT_BE32(pos, vendor_id); + pos += 4; + *pos++ = vendor_type; + os_memcpy(pos, data, len); + attr = radius_msg_add_attr(msg, type, buf, alen); + os_free(buf); + return attr != NULL; +} + + int radius_user_password_hide(struct radius_msg *msg, const u8 *data, size_t data_len, const u8 *secret, size_t secret_len, diff --git a/wpa_supplicant-2.9_standard/src/radius/radius.h b/wpa_supplicant-2.9_standard/src/radius/radius.h index fb814818072a0947c536e9d8fa61ad8fc118f394..05fddbaf25bf4cbd3e974c97ba1b64cc415c3b6e 100644 --- a/wpa_supplicant-2.9_standard/src/radius/radius.h +++ b/wpa_supplicant-2.9_standard/src/radius/radius.h @@ -1,6 +1,6 @@ /* * RADIUS message processing - * Copyright (c) 2002-2009, 2012, 2014-2015, Jouni Malinen + * Copyright (c) 2002-2009, 2012, 2014-2022, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -46,7 +46,15 @@ struct radius_attr_hdr { /* followed by length-2 octets of attribute value */ } STRUCT_PACKED; +struct radius_attr_hdr_ext { + u8 type; + u8 length; /* including this header */ + u8 ext_type; + /* followed by length-3 octets of attribute value */ +} STRUCT_PACKED; + #define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr)) +#define RADIUS_MAX_EXT_ATTR_LEN (255 - sizeof(struct radius_attr_hdr_ext)) enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_USER_PASSWORD = 2, @@ -54,6 +62,7 @@ enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_NAS_PORT = 5, RADIUS_ATTR_SERVICE_TYPE = 6, RADIUS_ATTR_FRAMED_IP_ADDRESS = 8, + RADIUS_ATTR_FILTER_ID = 11, RADIUS_ATTR_FRAMED_MTU = 12, RADIUS_ATTR_REPLY_MESSAGE = 18, RADIUS_ATTR_STATE = 24, @@ -113,6 +122,18 @@ enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_WLAN_GROUP_CIPHER = 187, RADIUS_ATTR_WLAN_AKM_SUITE = 188, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER = 189, + RADIUS_ATTR_EXT_TYPE_1 = 241, + RADIUS_ATTR_EXT_TYPE_2 = 242, + RADIUS_ATTR_EXT_TYPE_3 = 243, + RADIUS_ATTR_EXT_TYPE_4 = 244, + RADIUS_ATTR_LONG_EXT_TYPE_1 = 245, + RADIUS_ATTR_LONG_EXT_TYPE_2 = 246, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_1 = (241 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_2 = (242 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_3 = (243 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_4 = (244 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5 = (245 << 8) | 26, + RADIUS_ATTR_EXT_VENDOR_SPECIFIC_6 = (246 << 8) | 26, }; @@ -188,6 +209,13 @@ enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16, RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17 }; +/* FreeRADIUS vendor-specific attributes */ +#define RADIUS_VENDOR_ID_FREERADIUS 11344 +/* Extended-Vendor-Specific-5 (245.26; long extended header) */ +enum { + RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE = 1, + RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG = 2, +}; /* Hotspot 2.0 - WFA Vendor-specific RADIUS Attributes */ #define RADIUS_VENDOR_ID_WFA 40808 @@ -240,6 +268,7 @@ struct wpabuf * radius_msg_get_buf(struct radius_msg *msg); struct radius_msg * radius_msg_new(u8 code, u8 identifier); void radius_msg_free(struct radius_msg *msg); void radius_msg_dump(struct radius_msg *msg); +u8 * radius_msg_add_msg_auth(struct radius_msg *msg); int radius_msg_finish(struct radius_msg *msg, const u8 *secret, size_t secret_len); int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, @@ -257,7 +286,7 @@ int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, size_t secret_len, int require_message_authenticator); -struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type, +struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u16 type, const u8 *data, size_t data_len); struct radius_msg * radius_msg_parse(const u8 *data, size_t len); int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, @@ -284,6 +313,8 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg, const u8 *recv_key, size_t recv_key_len); int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, size_t len); +int radius_msg_add_ext_vs(struct radius_msg *msg, u16 type, u32 vendor_id, + u8 vendor_type, const u8 *data, size_t len); int radius_user_password_hide(struct radius_msg *msg, const u8 *data, size_t data_len, const u8 *secret, size_t secret_len, diff --git a/wpa_supplicant-2.9_standard/src/radius/radius_client.c b/wpa_supplicant-2.9_standard/src/radius/radius_client.c index a8c29f8c9135aa000c00f0578c1a67482aa663b4..5f26576006bc300522b2cee8ad89d518ad3a1d2e 100644 --- a/wpa_supplicant-2.9_standard/src/radius/radius_client.c +++ b/wpa_supplicant-2.9_standard/src/radius/radius_client.c @@ -1,18 +1,20 @@ /* * RADIUS client - * Copyright (c) 2002-2015, Jouni Malinen + * Copyright (c) 2002-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. */ #include "includes.h" +#include #include #include "common.h" +#include "eloop.h" +#include "crypto/tls.h" #include "radius.h" #include "radius_client.h" -#include "eloop.h" /* Defaults for RADIUS retransmit values (exponential backoff) */ @@ -169,34 +171,34 @@ struct radius_client_data { struct hostapd_radius_servers *conf; /** - * auth_serv_sock - IPv4 socket for RADIUS authentication messages + * auth_sock - Currently used socket for RADIUS authentication server */ - int auth_serv_sock; + int auth_sock; /** - * acct_serv_sock - IPv4 socket for RADIUS accounting messages + * auth_tls - Whether current authentication connection uses TLS */ - int acct_serv_sock; + bool auth_tls; /** - * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages + * auth_tls_ready - Whether authentication TLS is ready */ - int auth_serv_sock6; + bool auth_tls_ready; /** - * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages + * acct_sock - Currently used socket for RADIUS accounting server */ - int acct_serv_sock6; + int acct_sock; /** - * auth_sock - Currently used socket for RADIUS authentication server + * acct_tls - Whether current accounting connection uses TLS */ - int auth_sock; + bool acct_tls; /** - * acct_sock - Currently used socket for RADIUS accounting server + * acct_tls_ready - Whether accounting TLS is ready */ - int acct_sock; + bool acct_tls_ready; /** * auth_handlers - Authentication message handlers @@ -242,6 +244,12 @@ struct radius_client_data { * interim_error_cb_ctx - interim_error_cb() context data */ void *interim_error_cb_ctx; + +#ifdef CONFIG_RADIUS_TLS + void *tls_ctx; + struct tls_connection *auth_tls_conn; + struct tls_connection *acct_tls_conn; +#endif /* CONFIG_RADIUS_TLS */ }; @@ -249,7 +257,7 @@ static int radius_change_server(struct radius_client_data *radius, struct hostapd_radius_server *nserv, struct hostapd_radius_server *oserv, - int sock, int sock6, int auth); + int auth); static int radius_client_init_acct(struct radius_client_data *radius); static int radius_client_init_auth(struct radius_client_data *radius); static void radius_client_auth_failover(struct radius_client_data *radius); @@ -374,9 +382,19 @@ static int radius_client_retransmit(struct radius_client_data *radius, u8 *acct_delay_time; size_t acct_delay_time_len; int num_servers; +#ifdef CONFIG_RADIUS_TLS + struct wpabuf *out = NULL; + struct tls_connection *conn = NULL; + bool acct = false; +#endif /* CONFIG_RADIUS_TLS */ if (entry->msg_type == RADIUS_ACCT || entry->msg_type == RADIUS_ACCT_INTERIM) { +#ifdef CONFIG_RADIUS_TLS + acct = true; + if (radius->acct_tls) + conn = radius->acct_tls_conn; +#endif /* CONFIG_RADIUS_TLS */ num_servers = conf->num_acct_servers; if (radius->acct_sock < 0) radius_client_init_acct(radius); @@ -394,6 +412,10 @@ static int radius_client_retransmit(struct radius_client_data *radius, conf->acct_server->retransmissions++; } } else { +#ifdef CONFIG_RADIUS_TLS + if (radius->auth_tls) + conn = radius->auth_tls_conn; +#endif /* CONFIG_RADIUS_TLS */ num_servers = conf->num_auth_servers; if (radius->auth_sock < 0) radius_client_init_auth(radius); @@ -429,6 +451,15 @@ static int radius_client_retransmit(struct radius_client_data *radius, return 1; } +#ifdef CONFIG_RADIUS_TLS + if ((acct && radius->acct_tls && !radius->acct_tls_ready) || + (!acct && radius->auth_tls && !radius->auth_tls_ready)) { + wpa_printf(MSG_DEBUG, + "RADIUS: TLS connection not yet ready for TX"); + goto not_ready; + } +#endif /* CONFIG_RADIUS_TLS */ + if (entry->msg_type == RADIUS_ACCT && radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME, &acct_delay_time, &acct_delay_time_len, @@ -473,11 +504,37 @@ static int radius_client_retransmit(struct radius_client_data *radius, os_get_reltime(&entry->last_attempt); buf = radius_msg_get_buf(entry->msg); +#ifdef CONFIG_RADIUS_TLS + if (conn) { + out = tls_connection_encrypt(radius->tls_ctx, conn, buf); + if (!out) { + wpa_printf(MSG_INFO, + "RADIUS: Failed to encrypt RADIUS message (TLS)"); + return -1; + } + wpa_printf(MSG_DEBUG, + "RADIUS: TLS encryption of %zu bytes of plaintext to %zu bytes of ciphertext", + wpabuf_len(buf), wpabuf_len(out)); + buf = out; + } +#endif /* CONFIG_RADIUS_TLS */ + + wpa_printf(MSG_DEBUG, "RADIUS: Send %zu bytes to the server", + wpabuf_len(buf)); if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) { if (radius_client_handle_send_error(radius, s, entry->msg_type) - > 0) + > 0) { +#ifdef CONFIG_RADIUS_TLS + wpabuf_free(out); +#endif /* CONFIG_RADIUS_TLS */ return 0; + } } +#ifdef CONFIG_RADIUS_TLS + wpabuf_free(out); + +not_ready: +#endif /* CONFIG_RADIUS_TLS */ entry->next_try = now + entry->next_wait; entry->next_wait *= 2; @@ -601,9 +658,7 @@ static void radius_client_auth_failover(struct radius_client_data *radius) if (next > &(conf->auth_servers[conf->num_auth_servers - 1])) next = conf->auth_servers; conf->auth_server = next; - radius_change_server(radius, next, old, - radius->auth_serv_sock, - radius->auth_serv_sock6, 1); + radius_change_server(radius, next, old, 1); } @@ -634,9 +689,7 @@ static void radius_client_acct_failover(struct radius_client_data *radius) if (next > &conf->acct_servers[conf->num_acct_servers - 1]) next = conf->acct_servers; conf->acct_server = next; - radius_change_server(radius, next, old, - radius->acct_serv_sock, - radius->acct_serv_sock6, 0); + radius_change_server(radius, next, old, 0); } @@ -725,6 +778,52 @@ static void radius_client_list_add(struct radius_client_data *radius, } +static int radius_client_disable_pmtu_discovery(int s) +{ + int r = -1; +#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) + /* Turn off Path MTU discovery on IPv4/UDP sockets. */ + int action = IP_PMTUDISC_DONT; + r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, + sizeof(action)); + if (r == -1) + wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s", + strerror(errno)); +#endif + return r; +} + + +static void radius_close_auth_socket(struct radius_client_data *radius) +{ + if (radius->auth_sock >= 0) { +#ifdef CONFIG_RADIUS_TLS + if (radius->conf->auth_server->tls) + eloop_unregister_sock(radius->auth_sock, + EVENT_TYPE_WRITE); +#endif /* CONFIG_RADIUS_TLS */ + eloop_unregister_read_sock(radius->auth_sock); + close(radius->auth_sock); + radius->auth_sock = -1; + } +} + + +static void radius_close_acct_socket(struct radius_client_data *radius) +{ + if (radius->acct_sock >= 0) { +#ifdef CONFIG_RADIUS_TLS + if (radius->conf->acct_server->tls) + eloop_unregister_sock(radius->acct_sock, + EVENT_TYPE_WRITE); +#endif /* CONFIG_RADIUS_TLS */ + eloop_unregister_read_sock(radius->acct_sock); + close(radius->acct_sock); + radius->acct_sock = -1; + } +} + + /** * radius_client_send - Send a RADIUS request * @radius: RADIUS client context from radius_client_init() @@ -760,8 +859,18 @@ int radius_client_send(struct radius_client_data *radius, char *name; int s, res; struct wpabuf *buf; +#ifdef CONFIG_RADIUS_TLS + struct wpabuf *out = NULL; + struct tls_connection *conn = NULL; + bool acct = false; +#endif /* CONFIG_RADIUS_TLS */ if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) { +#ifdef CONFIG_RADIUS_TLS + acct = true; + if (radius->acct_tls) + conn = radius->acct_tls_conn; +#endif /* CONFIG_RADIUS_TLS */ if (conf->acct_server && radius->acct_sock < 0) radius_client_init_acct(radius); @@ -780,6 +889,10 @@ int radius_client_send(struct radius_client_data *radius, s = radius->acct_sock; conf->acct_server->requests++; } else { +#ifdef CONFIG_RADIUS_TLS + if (radius->auth_tls) + conn = radius->auth_tls_conn; +#endif /* CONFIG_RADIUS_TLS */ if (conf->auth_server && radius->auth_sock < 0) radius_client_init_auth(radius); @@ -805,11 +918,42 @@ int radius_client_send(struct radius_client_data *radius, if (conf->msg_dumps) radius_msg_dump(msg); +#ifdef CONFIG_RADIUS_TLS + if ((acct && radius->acct_tls && !radius->acct_tls_ready) || + (!acct && radius->auth_tls && !radius->auth_tls_ready)) { + wpa_printf(MSG_DEBUG, + "RADIUS: TLS connection not yet ready for TX"); + goto skip_send; + } +#endif /* CONFIG_RADIUS_TLS */ + buf = radius_msg_get_buf(msg); +#ifdef CONFIG_RADIUS_TLS + if (conn) { + out = tls_connection_encrypt(radius->tls_ctx, conn, buf); + if (!out) { + wpa_printf(MSG_INFO, + "RADIUS: Failed to encrypt RADIUS message (TLS)"); + return -1; + } + wpa_printf(MSG_DEBUG, + "RADIUS: TLS encryption of %zu bytes of plaintext to %zu bytes of ciphertext", + wpabuf_len(buf), wpabuf_len(out)); + buf = out; + } +#endif /* CONFIG_RADIUS_TLS */ + wpa_printf(MSG_DEBUG, "RADIUS: Send %zu bytes to the server", + wpabuf_len(buf)); res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0); +#ifdef CONFIG_RADIUS_TLS + wpabuf_free(out); +#endif /* CONFIG_RADIUS_TLS */ if (res < 0) radius_client_handle_send_error(radius, s, msg_type); +#ifdef CONFIG_RADIUS_TLS +skip_send: +#endif /* CONFIG_RADIUS_TLS */ radius_client_list_add(radius, msg, msg_type, shared_secret, shared_secret_len, addr); @@ -817,6 +961,137 @@ int radius_client_send(struct radius_client_data *radius, } +#ifdef CONFIG_RADIUS_TLS + +static void radius_client_close_tcp(struct radius_client_data *radius, + int sock, RadiusType msg_type) +{ + wpa_printf(MSG_DEBUG, "RADIUS: Closing TCP connection (sock %d)", + sock); + if (msg_type == RADIUS_ACCT) { + radius->acct_tls_ready = false; + radius_close_acct_socket(radius); + } else { + radius->auth_tls_ready = false; + radius_close_auth_socket(radius); + } +} + + +static void +radius_client_process_tls_handshake(struct radius_client_data *radius, + int sock, RadiusType msg_type, + u8 *buf, size_t len) +{ + struct wpabuf *in, *out = NULL, *appl; + struct tls_connection *conn; + int res; + bool ready = false; + + wpa_printf(MSG_DEBUG, + "RADIUS: Process %zu bytes of received TLS handshake message", + len); + + if (msg_type == RADIUS_ACCT) + conn = radius->acct_tls_conn; + else + conn = radius->auth_tls_conn; + + in = wpabuf_alloc_copy(buf, len); + if (!in) + return; + + appl = NULL; + out = tls_connection_handshake(radius->tls_ctx, conn, in, &appl); + wpabuf_free(in); + if (!out) { + wpa_printf(MSG_DEBUG, + "RADIUS: Could not generate TLS handshake data"); + goto fail; + } + + if (tls_connection_get_failed(radius->tls_ctx, conn)) { + wpa_printf(MSG_INFO, "RADIUS: TLS handshake failed"); + goto fail; + } + + if (tls_connection_established(radius->tls_ctx, conn)) { + wpa_printf(MSG_DEBUG, + "RADIUS: TLS connection established (sock=%d)", + sock); + if (msg_type == RADIUS_ACCT) + radius->acct_tls_ready = true; + else + radius->auth_tls_ready = true; + ready = true; + } + + wpa_printf(MSG_DEBUG, "RADIUS: Sending %zu bytes of TLS handshake", + wpabuf_len(out)); + res = send(sock, wpabuf_head(out), wpabuf_len(out), 0); + if (res < 0) { + wpa_printf(MSG_INFO, "RADIUS: send: %s", strerror(errno)); + goto fail; + } + if ((size_t) res != wpabuf_len(out)) { + wpa_printf(MSG_INFO, + "RADIUS: Could not send all data for TLS handshake: only %d bytes sent", + res); + goto fail; + } + wpabuf_free(out); + + if (ready) { + struct radius_msg_list *entry, *prev, *tmp; + struct os_reltime now; + + /* Send all pending message of matching type since the TLS + * tunnel has now been established. */ + + os_get_reltime(&now); + + entry = radius->msgs; + prev = NULL; + while (entry) { + if (entry->msg_type != msg_type) { + prev = entry; + entry = entry->next; + continue; + } + + if (radius_client_retransmit(radius, entry, now.sec)) { + if (prev) + prev->next = entry->next; + else + radius->msgs = entry->next; + + tmp = entry; + entry = entry->next; + radius_client_msg_free(tmp); + radius->num_msgs--; + continue; + } + + prev = entry; + entry = entry->next; + } + } + + return; + +fail: + wpabuf_free(out); + tls_connection_deinit(radius->tls_ctx, conn); + if (msg_type == RADIUS_ACCT) + radius->acct_tls_conn = NULL; + else + radius->auth_tls_conn = NULL; + radius_client_close_tcp(radius, sock, msg_type); +} + +#endif /* CONFIG_RADIUS_TLS */ + + static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) { struct radius_client_data *radius = eloop_ctx; @@ -834,12 +1109,28 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) struct os_reltime now; struct hostapd_radius_server *rconf; int invalid_authenticator = 0; +#ifdef CONFIG_RADIUS_TLS + struct tls_connection *conn = NULL; + bool tls, tls_ready; +#endif /* CONFIG_RADIUS_TLS */ if (msg_type == RADIUS_ACCT) { +#ifdef CONFIG_RADIUS_TLS + if (radius->acct_tls) + conn = radius->acct_tls_conn; + tls = radius->acct_tls; + tls_ready = radius->acct_tls_ready; +#endif /* CONFIG_RADIUS_TLS */ handlers = radius->acct_handlers; num_handlers = radius->num_acct_handlers; rconf = conf->acct_server; } else { +#ifdef CONFIG_RADIUS_TLS + if (radius->auth_tls) + conn = radius->auth_tls_conn; + tls = radius->auth_tls; + tls_ready = radius->auth_tls_ready; +#endif /* CONFIG_RADIUS_TLS */ handlers = radius->auth_handlers; num_handlers = radius->num_auth_handlers; rconf = conf->auth_server; @@ -855,6 +1146,52 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) wpa_printf(MSG_INFO, "recvmsg[RADIUS]: %s", strerror(errno)); return; } +#ifdef CONFIG_RADIUS_TLS + if (tls && len == 0) { + wpa_printf(MSG_DEBUG, "RADIUS: No TCP data available"); + goto close_tcp; + } + + if (tls && !tls_ready) { + radius_client_process_tls_handshake(radius, sock, msg_type, + buf, len); + return; + } + + if (conn) { + struct wpabuf *out, *in; + + in = wpabuf_alloc_copy(buf, len); + if (!in) + return; + wpa_printf(MSG_DEBUG, + "RADIUS: Process %d bytes of encrypted TLS data", + len); + out = tls_connection_decrypt(radius->tls_ctx, conn, in); + wpabuf_free(in); + if (!out) { + wpa_printf(MSG_INFO, + "RADIUS: Failed to decrypt TLS data"); + goto close_tcp; + } + if (wpabuf_len(out) == 0) { + wpa_printf(MSG_DEBUG, + "RADIUS: Full message not yet received - continue waiting for additional TLS data"); + wpabuf_free(out); + return; + } + if (wpabuf_len(out) > RADIUS_MAX_MSG_LEN) { + wpa_printf(MSG_INFO, + "RADIUS: Too long RADIUS message from TLS: %zu", + wpabuf_len(out)); + wpabuf_free(out); + goto close_tcp; + } + os_memcpy(buf, wpabuf_head(out), wpabuf_len(out)); + len = wpabuf_len(out); + wpabuf_free(out); + } +#endif /* CONFIG_RADIUS_TLS */ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS " @@ -943,13 +1280,13 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) switch (res) { case RADIUS_RX_PROCESSED: radius_msg_free(msg); - /* fall through */ + __attribute__((fallthrough)); case RADIUS_RX_QUEUED: radius_client_msg_free(req); return; case RADIUS_RX_INVALID_AUTHENTICATOR: invalid_authenticator++; - /* fall through */ + __attribute__((fallthrough)); case RADIUS_RX_UNKNOWN: /* continue with next handler */ break; @@ -970,9 +1307,121 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) fail: radius_msg_free(msg); + return; + +#ifdef CONFIG_RADIUS_TLS +close_tcp: + radius_client_close_tcp(radius, sock, msg_type); +#endif /* CONFIG_RADIUS_TLS */ } +#ifdef CONFIG_RADIUS_TLS +static void radius_client_write_ready(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct radius_client_data *radius = eloop_ctx; + RadiusType msg_type = (uintptr_t) sock_ctx; + struct tls_connection *conn = NULL; + struct wpabuf *in, *out = NULL, *appl; + int res = -1; + struct tls_connection_params params; + struct hostapd_radius_server *server; + + wpa_printf(MSG_DEBUG, "RADIUS: TCP connection established - start TLS handshake (sock=%d)", + sock); + + if (msg_type == RADIUS_ACCT) { + eloop_unregister_sock(sock, EVENT_TYPE_WRITE); + eloop_register_read_sock(sock, radius_client_receive, radius, + (void *) RADIUS_ACCT); + if (radius->acct_tls_conn) { + wpa_printf(MSG_DEBUG, + "RADIUS: Deinit previously used TLS connection"); + tls_connection_deinit(radius->tls_ctx, + radius->acct_tls_conn); + radius->acct_tls_conn = NULL; + } + server = radius->conf->acct_server; + } else { + eloop_unregister_sock(sock, EVENT_TYPE_WRITE); + eloop_register_read_sock(sock, radius_client_receive, radius, + (void *) RADIUS_AUTH); + if (radius->auth_tls_conn) { + wpa_printf(MSG_DEBUG, + "RADIUS: Deinit previously used TLS connection"); + tls_connection_deinit(radius->tls_ctx, + radius->auth_tls_conn); + radius->auth_tls_conn = NULL; + } + server = radius->conf->auth_server; + } + + if (!server) + goto fail; + + conn = tls_connection_init(radius->tls_ctx); + if (!conn) { + wpa_printf(MSG_INFO, + "RADIUS: Failed to initiate TLS connection"); + goto fail; + } + + os_memset(¶ms, 0, sizeof(params)); + params.ca_cert = server->ca_cert; + params.client_cert = server->client_cert; + params.private_key = server->private_key; + params.private_key_passwd = server->private_key_passwd; + params.flags = TLS_CONN_DISABLE_TLSv1_0 | TLS_CONN_DISABLE_TLSv1_1; + if (tls_connection_set_params(radius->tls_ctx, conn, ¶ms)) { + wpa_printf(MSG_INFO, + "RADIUS: Failed to set TLS connection parameters"); + goto fail; + } + + in = NULL; + appl = NULL; + out = tls_connection_handshake(radius->tls_ctx, conn, in, &appl); + if (!out) { + wpa_printf(MSG_DEBUG, + "RADIUS: Could not generate TLS handshake data"); + goto fail; + } + + if (tls_connection_get_failed(radius->tls_ctx, conn)) { + wpa_printf(MSG_INFO, "RADIUS: TLS handshake failed"); + goto fail; + } + + wpa_printf(MSG_DEBUG, "RADIUS: Sending %zu bytes of TLS handshake", + wpabuf_len(out)); + res = send(sock, wpabuf_head(out), wpabuf_len(out), 0); + if (res < 0) { + wpa_printf(MSG_INFO, "RADIUS: send: %s", strerror(errno)); + goto fail; + } + if ((size_t) res != wpabuf_len(out)) { + wpa_printf(MSG_INFO, + "RADIUS: Could not send all data for TLS handshake: only %d bytes sent", + res); + goto fail; + } + wpabuf_free(out); + + if (msg_type == RADIUS_ACCT) + radius->acct_tls_conn = conn; + else + radius->auth_tls_conn = conn; + return; + +fail: + wpa_printf(MSG_INFO, "RADIUS: Failed to perform TLS handshake"); + tls_connection_deinit(radius->tls_ctx, conn); + wpabuf_free(out); + radius_client_close_tcp(radius, sock, msg_type); +} +#endif /* CONFIG_RADIUS_TLS */ + + /** * radius_client_get_id - Get an identifier for a new RADIUS message * @radius: RADIUS client context from radius_client_init() @@ -1077,7 +1526,7 @@ static int radius_change_server(struct radius_client_data *radius, struct hostapd_radius_server *nserv, struct hostapd_radius_server *oserv, - int sock, int sock6, int auth) + int auth) { struct sockaddr_in serv, claddr; #ifdef CONFIG_IPV6 @@ -1089,9 +1538,17 @@ radius_change_server(struct radius_client_data *radius, int sel_sock; struct radius_msg_list *entry; struct hostapd_radius_servers *conf = radius->conf; - struct sockaddr_in disconnect_addr = { - .sin_family = AF_UNSPEC, - }; + int type = SOCK_DGRAM; + bool tls = nserv->tls; + + if (tls) { +#ifdef CONFIG_RADIUS_TLS + type = SOCK_STREAM; +#else /* CONFIG_RADIUS_TLS */ + wpa_printf(MSG_ERROR, "RADIUS: TLS not supported"); + return -1; +#endif /* CONFIG_RADIUS_TLS */ + } hostapd_logger_only_for_cb(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, @@ -1154,7 +1611,9 @@ radius_change_server(struct radius_client_data *radius, serv.sin_port = htons(nserv->port); addr = (struct sockaddr *) &serv; addrlen = sizeof(serv); - sel_sock = sock; + sel_sock = socket(PF_INET, type, 0); + if (sel_sock >= 0) + radius_client_disable_pmtu_discovery(sel_sock); break; #ifdef CONFIG_IPV6 case AF_INET6: @@ -1165,7 +1624,7 @@ radius_change_server(struct radius_client_data *radius, serv6.sin6_port = htons(nserv->port); addr = (struct sockaddr *) &serv6; addrlen = sizeof(serv6); - sel_sock = sock6; + sel_sock = socket(PF_INET6, type, 0); break; #endif /* CONFIG_IPV6 */ default: @@ -1174,15 +1633,19 @@ radius_change_server(struct radius_client_data *radius, if (sel_sock < 0) { wpa_printf(MSG_INFO, - "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d", - nserv->addr.af, sock, sock6, auth); + "RADIUS: Failed to open server socket (af=%d auth=%d)", + nserv->addr.af, auth); return -1; } - /* Force a reconnect by disconnecting the socket first */ - if (connect(sel_sock, (struct sockaddr *) &disconnect_addr, - sizeof(disconnect_addr)) < 0) - wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno)); +#ifdef CONFIG_RADIUS_TLS + if (tls && fcntl(sel_sock, F_SETFL, O_NONBLOCK) != 0) { + wpa_printf(MSG_DEBUG, "RADIUS: fnctl(O_NONBLOCK) failed: %s", + strerror(errno)); + close(sel_sock); + return -1; + } +#endif /* CONFIG_RADIUS_TLS */ #ifdef __linux__ if (conf->force_client_dev && conf->force_client_dev[0]) { @@ -1224,19 +1687,29 @@ radius_change_server(struct radius_client_data *radius, break; #endif /* CONFIG_IPV6 */ default: + close(sel_sock); return -1; } if (bind(sel_sock, cl_addr, claddrlen) < 0) { wpa_printf(MSG_INFO, "bind[radius]: %s", strerror(errno)); - return -1; + close(sel_sock); + return -2; } } if (connect(sel_sock, addr, addrlen) < 0) { - wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno)); - return -1; + if (nserv->tls && errno == EINPROGRESS) { + wpa_printf(MSG_DEBUG, + "RADIUS: TCP connection establishment in progress (sock %d)", + sel_sock); + } else { + wpa_printf(MSG_INFO, "connect[radius]: %s", + strerror(errno)); + close(sel_sock); + return -2; + } } #ifndef CONFIG_NATIVE_WINDOWS @@ -1266,10 +1739,34 @@ radius_change_server(struct radius_client_data *radius, } #endif /* CONFIG_NATIVE_WINDOWS */ - if (auth) + if (auth) { + radius_close_auth_socket(radius); radius->auth_sock = sel_sock; - else + } else { + radius_close_acct_socket(radius); radius->acct_sock = sel_sock; + } + + if (!tls) + eloop_register_read_sock(sel_sock, radius_client_receive, + radius, + auth ? (void *) RADIUS_AUTH : + (void *) RADIUS_ACCT); +#ifdef CONFIG_RADIUS_TLS + if (tls) + eloop_register_sock(sel_sock, EVENT_TYPE_WRITE, + radius_client_write_ready, radius, + auth ? (void *) RADIUS_AUTH : + (void *) RADIUS_ACCT); +#endif /* CONFIG_RADIUS_TLS */ + + if (auth) { + radius->auth_tls = nserv->tls; + radius->auth_tls_ready = false; + } else { + radius->acct_tls = nserv->tls; + radius->acct_tls_ready = false; + } return 0; } @@ -1286,12 +1783,10 @@ static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx) oserv = conf->auth_server; conf->auth_server = conf->auth_servers; if (radius_change_server(radius, conf->auth_server, oserv, - radius->auth_serv_sock, - radius->auth_serv_sock6, 1) < 0) { + 1) < 0) { conf->auth_server = oserv; radius_change_server(radius, oserv, conf->auth_server, - radius->auth_serv_sock, - radius->auth_serv_sock6, 1); + 1); } } @@ -1300,12 +1795,10 @@ static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx) oserv = conf->acct_server; conf->acct_server = conf->acct_servers; if (radius_change_server(radius, conf->acct_server, oserv, - radius->acct_serv_sock, - radius->acct_serv_sock6, 0) < 0) { + 0) < 0) { conf->acct_server = oserv; radius_change_server(radius, oserv, conf->acct_server, - radius->acct_serv_sock, - radius->acct_serv_sock6, 0); + 0); } } @@ -1316,170 +1809,27 @@ static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx) } -static int radius_client_disable_pmtu_discovery(int s) -{ - int r = -1; -#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) - /* Turn off Path MTU discovery on IPv4/UDP sockets. */ - int action = IP_PMTUDISC_DONT; - r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, - sizeof(action)); - if (r == -1) - wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s", - strerror(errno)); -#endif - return r; -} - - -static void radius_close_auth_sockets(struct radius_client_data *radius) -{ - radius->auth_sock = -1; - - if (radius->auth_serv_sock >= 0) { - eloop_unregister_read_sock(radius->auth_serv_sock); - close(radius->auth_serv_sock); - radius->auth_serv_sock = -1; - } -#ifdef CONFIG_IPV6 - if (radius->auth_serv_sock6 >= 0) { - eloop_unregister_read_sock(radius->auth_serv_sock6); - close(radius->auth_serv_sock6); - radius->auth_serv_sock6 = -1; - } -#endif /* CONFIG_IPV6 */ -} - - -static void radius_close_acct_sockets(struct radius_client_data *radius) -{ - radius->acct_sock = -1; - - if (radius->acct_serv_sock >= 0) { - eloop_unregister_read_sock(radius->acct_serv_sock); - close(radius->acct_serv_sock); - radius->acct_serv_sock = -1; - } -#ifdef CONFIG_IPV6 - if (radius->acct_serv_sock6 >= 0) { - eloop_unregister_read_sock(radius->acct_serv_sock6); - close(radius->acct_serv_sock6); - radius->acct_serv_sock6 = -1; - } -#endif /* CONFIG_IPV6 */ -} - - static int radius_client_init_auth(struct radius_client_data *radius) { - struct hostapd_radius_servers *conf = radius->conf; - int ok = 0; - - radius_close_auth_sockets(radius); - - radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (radius->auth_serv_sock < 0) - wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s", - strerror(errno)); - else { - radius_client_disable_pmtu_discovery(radius->auth_serv_sock); - ok++; - } - -#ifdef CONFIG_IPV6 - radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); - if (radius->auth_serv_sock6 < 0) - wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s", - strerror(errno)); - else - ok++; -#endif /* CONFIG_IPV6 */ - - if (ok == 0) - return -1; - - radius_change_server(radius, conf->auth_server, NULL, - radius->auth_serv_sock, radius->auth_serv_sock6, - 1); - - if (radius->auth_serv_sock >= 0 && - eloop_register_read_sock(radius->auth_serv_sock, - radius_client_receive, radius, - (void *) RADIUS_AUTH)) { - wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server"); - radius_close_auth_sockets(radius); - return -1; - } - -#ifdef CONFIG_IPV6 - if (radius->auth_serv_sock6 >= 0 && - eloop_register_read_sock(radius->auth_serv_sock6, - radius_client_receive, radius, - (void *) RADIUS_AUTH)) { - wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server"); - radius_close_auth_sockets(radius); - return -1; - } -#endif /* CONFIG_IPV6 */ - - return 0; + radius_close_auth_socket(radius); + return radius_change_server(radius, radius->conf->auth_server, NULL, 1); } static int radius_client_init_acct(struct radius_client_data *radius) { - struct hostapd_radius_servers *conf = radius->conf; - int ok = 0; - - radius_close_acct_sockets(radius); - - radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); - if (radius->acct_serv_sock < 0) - wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s", - strerror(errno)); - else { - radius_client_disable_pmtu_discovery(radius->acct_serv_sock); - ok++; - } - -#ifdef CONFIG_IPV6 - radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); - if (radius->acct_serv_sock6 < 0) - wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s", - strerror(errno)); - else - ok++; -#endif /* CONFIG_IPV6 */ - - if (ok == 0) - return -1; - - radius_change_server(radius, conf->acct_server, NULL, - radius->acct_serv_sock, radius->acct_serv_sock6, - 0); - - if (radius->acct_serv_sock >= 0 && - eloop_register_read_sock(radius->acct_serv_sock, - radius_client_receive, radius, - (void *) RADIUS_ACCT)) { - wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server"); - radius_close_acct_sockets(radius); - return -1; - } + radius_close_acct_socket(radius); + return radius_change_server(radius, radius->conf->acct_server, NULL, 0); +} -#ifdef CONFIG_IPV6 - if (radius->acct_serv_sock6 >= 0 && - eloop_register_read_sock(radius->acct_serv_sock6, - radius_client_receive, radius, - (void *) RADIUS_ACCT)) { - wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server"); - radius_close_acct_sockets(radius); - return -1; - } -#endif /* CONFIG_IPV6 */ - return 0; +#ifdef CONFIG_RADIUS_TLS +static void radius_tls_event_cb(void *ctx, enum tls_event ev, + union tls_event_data *data) +{ + wpa_printf(MSG_DEBUG, "RADIUS: TLS event %d", ev); } +#endif /* CONFIG_RADIUS_TLS */ /** @@ -1503,16 +1853,14 @@ radius_client_init(void *ctx, struct hostapd_radius_servers *conf) radius->ctx = ctx; radius->conf = conf; - radius->auth_serv_sock = radius->acct_serv_sock = - radius->auth_serv_sock6 = radius->acct_serv_sock6 = - radius->auth_sock = radius->acct_sock = -1; + radius->auth_sock = radius->acct_sock = -1; - if (conf->auth_server && radius_client_init_auth(radius)) { + if (conf->auth_server && radius_client_init_auth(radius) == -1) { radius_client_deinit(radius); return NULL; } - if (conf->acct_server && radius_client_init_acct(radius)) { + if (conf->acct_server && radius_client_init_acct(radius) == -1) { radius_client_deinit(radius); return NULL; } @@ -1522,6 +1870,22 @@ radius_client_init(void *ctx, struct hostapd_radius_servers *conf) radius_retry_primary_timer, radius, NULL); +#ifdef CONFIG_RADIUS_TLS + if ((conf->auth_server && conf->auth_server->tls) || + (conf->acct_server && conf->acct_server->tls)) { + struct tls_config tls_conf; + + os_memset(&tls_conf, 0, sizeof(tls_conf)); + tls_conf.event_cb = radius_tls_event_cb; + radius->tls_ctx = tls_init(&tls_conf); + if (!radius->tls_ctx) { + radius_client_deinit(radius); + return NULL; + } + } +#endif /* CONFIG_RADIUS_TLS */ + + return radius; } @@ -1535,14 +1899,21 @@ void radius_client_deinit(struct radius_client_data *radius) if (!radius) return; - radius_close_auth_sockets(radius); - radius_close_acct_sockets(radius); + radius_close_auth_socket(radius); + radius_close_acct_socket(radius); eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL); radius_client_flush(radius, 0); os_free(radius->auth_handlers); os_free(radius->acct_handlers); +#ifdef CONFIG_RADIUS_TLS + if (radius->tls_ctx) { + tls_connection_deinit(radius->tls_ctx, radius->auth_tls_conn); + tls_connection_deinit(radius->tls_ctx, radius->acct_tls_conn); + tls_deinit(radius->tls_ctx); + } +#endif /* CONFIG_RADIUS_TLS */ os_free(radius); } @@ -1566,7 +1937,7 @@ void radius_client_flush_auth(struct radius_client_data *radius, entry = radius->msgs; while (entry) { if (entry->msg_type == RADIUS_AUTH && - os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { + ether_addr_equal(entry->addr, addr)) { hostapd_logger(radius->ctx, addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, diff --git a/wpa_supplicant-2.9_standard/src/radius/radius_client.h b/wpa_supplicant-2.9_standard/src/radius/radius_client.h index 687cd81aed915be03be4fcbe2011380a11c8940c..db40637ea03bbef4f1c52797237a4fc368d64fba 100644 --- a/wpa_supplicant-2.9_standard/src/radius/radius_client.h +++ b/wpa_supplicant-2.9_standard/src/radius/radius_client.h @@ -1,6 +1,6 @@ /* * RADIUS client - * Copyright (c) 2002-2009, Jouni Malinen + * Copyright (c) 2002-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -35,6 +35,11 @@ struct hostapd_radius_server { */ int port; + /** + * tls - Whether to use RADIUS/TLS instead of RADIUS/UDP + */ + bool tls; + /** * shared_secret - Shared secret for authenticating RADIUS messages */ @@ -45,6 +50,26 @@ struct hostapd_radius_server { */ size_t shared_secret_len; + /** + * ca_cert - Path to trusted CA certificate(s) for RADIUS/TLS + */ + char *ca_cert; + + /** + * client_cert - Path to client certificate for RADIUS/TLS + */ + char *client_cert; + + /** + * private_key - Path to clienbt private key for RADIUS/TLS + */ + char *private_key; + + /** + * private_key_passwd - Password for the private key for RADIUS/TLS + */ + char *private_key_passwd; + /* Dynamic (not from configuration file) MIB data */ /** diff --git a/wpa_supplicant-2.9_standard/src/radius/radius_das.c b/wpa_supplicant-2.9_standard/src/radius/radius_das.c index aaa3fc26723ad16d3b492c3ceb8d61720bb9676c..8d7c9b4c4566bdaed1caa4e921751c7e57c7d9d9 100644 --- a/wpa_supplicant-2.9_standard/src/radius/radius_das.c +++ b/wpa_supplicant-2.9_standard/src/radius/radius_das.c @@ -177,6 +177,11 @@ fail: if (reply == NULL) return NULL; + if (!radius_msg_add_msg_auth(reply)) { + radius_msg_free(reply); + return NULL; + } + if (error) { if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, error)) { @@ -368,6 +373,11 @@ fail: if (!reply) return NULL; + if (!radius_msg_add_msg_auth(reply)) { + radius_msg_free(reply); + return NULL; + } + if (error && !radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, error)) { radius_msg_free(reply); diff --git a/wpa_supplicant-2.9_standard/src/radius/radius_server.c b/wpa_supplicant-2.9_standard/src/radius/radius_server.c index e96ed7d7578a011fe1d5a427c449cf0a425b74bb..66224758e27eefb122c1ee6c3e5fbbe57724d8c4 100644 --- a/wpa_supplicant-2.9_standard/src/radius/radius_server.c +++ b/wpa_supplicant-2.9_standard/src/radius/radius_server.c @@ -920,6 +920,11 @@ radius_server_encapsulate_eap(struct radius_server_data *data, return NULL; } + if (!radius_msg_add_msg_auth(msg)) { + radius_msg_free(msg); + return NULL; + } + sess_id = htonl(sess->sess_id); if (code == RADIUS_CODE_ACCESS_CHALLENGE && !radius_msg_add_attr(msg, RADIUS_ATTR_STATE, @@ -1204,6 +1209,11 @@ radius_server_macacl(struct radius_server_data *data, return NULL; } + if (!radius_msg_add_msg_auth(msg)) { + radius_msg_free(msg); + return NULL; + } + if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); radius_msg_free(msg); @@ -1253,6 +1263,11 @@ static int radius_server_reject(struct radius_server_data *data, return -1; } + if (!radius_msg_add_msg_auth(msg)) { + radius_msg_free(msg); + return -1; + } + os_memset(&eapfail, 0, sizeof(eapfail)); eapfail.code = EAP_CODE_FAILURE; eapfail.identifier = 0; @@ -1614,9 +1629,9 @@ static void radius_server_receive_coa_resp(struct radius_server_data *data, return; } - RADIUS_DEBUG("CoA-%s received for " MACSTR_SEC, + RADIUS_DEBUG("CoA-%s received for " MACSTR, ack ? "ACK" : "NAK", - MAC2STR_SEC(client->pending_dac_coa_addr)); + MAC2STR(client->pending_dac_coa_addr)); radius_msg_free(msg); radius_msg_free(client->pending_dac_coa_req); diff --git a/wpa_supplicant-2.9_standard/src/rsn_supp/pmksa_cache.c b/wpa_supplicant-2.9_standard/src/rsn_supp/pmksa_cache.c index 2cf26f86a338367bb501e6cb976885c96174bc50..dd81faa28e1ea85c7b4ba8ecf4663c59801b0a1a 100644 --- a/wpa_supplicant-2.9_standard/src/rsn_supp/pmksa_cache.c +++ b/wpa_supplicant-2.9_standard/src/rsn_supp/pmksa_cache.c @@ -28,6 +28,7 @@ struct rsn_pmksa_cache { enum pmksa_free_reason reason); bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx); + void (*notify_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx); void *ctx; }; @@ -45,16 +46,46 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, struct rsn_pmksa_cache_entry *entry, enum pmksa_free_reason reason) { - wpa_sm_remove_pmkid(pmksa->sm, entry->network_ctx, entry->aa, - entry->pmkid, - entry->fils_cache_id_set ? entry->fils_cache_id : - NULL); + if (pmksa->sm) + wpa_sm_remove_pmkid(pmksa->sm, entry->network_ctx, entry->aa, + entry->pmkid, + entry->fils_cache_id_set ? + entry->fils_cache_id : NULL); pmksa->pmksa_count--; - pmksa->free_cb(entry, pmksa->ctx, reason); + if (pmksa->free_cb) + pmksa->free_cb(entry, pmksa->ctx, reason); _pmksa_cache_free_entry(entry); } +void pmksa_cache_remove(struct rsn_pmksa_cache *pmksa, + struct rsn_pmksa_cache_entry *entry) +{ + struct rsn_pmksa_cache_entry *e; + + e = pmksa->pmksa; + while (e) { + if (e == entry) { + pmksa->pmksa = entry->next; + break; + } + if (e->next == entry) { + e->next = entry->next; + break; + } + } + + if (!e) { + wpa_printf(MSG_DEBUG, + "RSN: Could not remove PMKSA cache entry %p since it is not in the list", + entry); + return; + } + + pmksa_cache_free_entry(pmksa, entry, PMKSA_FREE); +} + + static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) { struct rsn_pmksa_cache *pmksa = eloop_ctx; @@ -64,7 +95,7 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) os_get_reltime(&now); while (entry && entry->expiration <= now.sec) { - if (wpa_key_mgmt_sae(entry->akmp) && + if (wpa_key_mgmt_sae(entry->akmp) && pmksa->is_current_cb && pmksa->is_current_cb(entry, pmksa->ctx)) { /* Do not expire the currently used PMKSA entry for SAE * since there is no convenient mechanism for @@ -97,6 +128,27 @@ static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx) static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx) { struct rsn_pmksa_cache *pmksa = eloop_ctx; + + if (!pmksa->sm) + return; + + if (pmksa->sm->driver_bss_selection) { + struct rsn_pmksa_cache_entry *entry; + + entry = pmksa->sm->cur_pmksa ? + pmksa->sm->cur_pmksa : + pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, + NULL, 0); + if (entry && wpa_key_mgmt_sae(entry->akmp)) { + wpa_printf(MSG_DEBUG, + "RSN: remove reauth threshold passed PMKSA from the driver for SAE"); + entry->sae_reauth_scheduled = true; + wpa_sm_remove_pmkid(pmksa->sm, entry->network_ctx, + entry->aa, entry->pmkid, NULL); + return; + } + } + pmksa->sm->cur_pmksa = NULL; eapol_sm_request_reauth(pmksa->sm->eapol); } @@ -117,6 +169,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) if (sec < 0) { sec = 0; if (wpa_key_mgmt_sae(pmksa->pmksa->akmp) && + pmksa->is_current_cb && pmksa->is_current_cb(pmksa->pmksa, pmksa->ctx)) { /* Do not continue polling for the current PMKSA entry * from SAE to expire every second. Use the expiration @@ -137,9 +190,15 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa) } eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL); + if (!pmksa->sm) + return; + entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa : - pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, 0); - if (entry && !wpa_key_mgmt_sae(entry->akmp)) { + pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL, NULL, 0); + if (entry && + (!wpa_key_mgmt_sae(entry->akmp) || + (pmksa->sm->driver_bss_selection && + !entry->sae_reauth_scheduled))) { sec = pmksa->pmksa->reauth_time - now.sec; if (sec < 0) sec = 0; @@ -177,10 +236,15 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, { struct rsn_pmksa_cache_entry *entry; struct os_reltime now; + unsigned int pmk_lifetime = 43200; + unsigned int pmk_reauth_threshold = 70; if (pmk_len > PMK_LEN_MAX) return NULL; + if (kck_len > WPA_KCK_MAX_LEN) + return NULL; + if (wpa_key_mgmt_suite_b(akmp) && !kck) return NULL; @@ -189,6 +253,9 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, return NULL; os_memcpy(entry->pmk, pmk, pmk_len); entry->pmk_len = pmk_len; + if (kck_len > 0) + os_memcpy(entry->kck, kck, kck_len); + entry->kck_len = kck_len; if (pmkid) os_memcpy(entry->pmkid, pmkid, PMKID_LEN); else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) @@ -198,15 +265,21 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, else rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, akmp); os_get_reltime(&now); - entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime; - entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime * - pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100; + if (pmksa->sm) { + pmk_lifetime = pmksa->sm->dot11RSNAConfigPMKLifetime; + pmk_reauth_threshold = + pmksa->sm->dot11RSNAConfigPMKReauthThreshold; + } + entry->expiration = now.sec + pmk_lifetime; + entry->reauth_time = now.sec + + pmk_lifetime * pmk_reauth_threshold / 100; entry->akmp = akmp; if (cache_id) { entry->fils_cache_id_set = 1; os_memcpy(entry->fils_cache_id, cache_id, FILS_CACHE_ID_LEN); } os_memcpy(entry->aa, aa, ETH_ALEN); + os_memcpy(entry->spa, spa, ETH_ALEN); entry->network_ctx = network_ctx; return pmksa_cache_add_entry(pmksa, entry); @@ -224,7 +297,8 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa, pos = pmksa->pmksa; prev = NULL; while (pos) { - if (os_memcmp(entry->aa, pos->aa, ETH_ALEN) == 0) { + if (ether_addr_equal(entry->aa, pos->aa) && + ether_addr_equal(entry->spa, pos->spa)) { if (pos->pmk_len == entry->pmk_len && os_memcmp_const(pos->pmk, entry->pmk, entry->pmk_len) == 0 && @@ -267,7 +341,7 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa, /* Remove the oldest entry to make room for the new entry */ pos = pmksa->pmksa; - if (pos == pmksa->sm->cur_pmksa) { + if (pmksa->sm && pos == pmksa->sm->cur_pmksa) { /* * Never remove the current PMKSA cache entry, since * it's in use, and removing it triggers a needless @@ -306,8 +380,16 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa, } pmksa->pmksa_count++; wpa_printf(MSG_EXCESSIVE, "RSN: Added PMKSA cache entry for " MACSTR_SEC - " network_ctx=%p akmp=0x%x", MAC2STR_SEC(entry->aa), + " spa=" MACSTR_SEC " network_ctx=%p akmp=0x%x", + MAC2STR_SEC(entry->aa), MAC2STR_SEC(entry->spa), entry->network_ctx, entry->akmp); + + if (!pmksa->sm) + return entry; + + if (pmksa->notify_cb) + pmksa->notify_cb(entry, pmksa->ctx); + wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa, entry->pmkid, entry->fils_cache_id_set ? entry->fils_cache_id : NULL, entry->pmk, entry->pmk_len, @@ -395,13 +477,15 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) * Returns: Pointer to PMKSA cache entry or %NULL if no match was found */ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, - const u8 *aa, const u8 *pmkid, + const u8 *aa, const u8 *spa, + const u8 *pmkid, const void *network_ctx, int akmp) { struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; while (entry) { - if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && + if ((aa == NULL || ether_addr_equal(entry->aa, aa)) && + (!spa || ether_addr_equal(entry->spa, spa)) && (pmkid == NULL || os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && (!akmp || akmp == entry->akmp) && @@ -423,11 +507,14 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, os_time_t old_reauth_time = old_entry->reauth_time; const u8 *pmkid = NULL; + if (!pmksa->sm) + return NULL; + if (wpa_key_mgmt_sae(old_entry->akmp) || wpa_key_mgmt_fils(old_entry->akmp)) pmkid = old_entry->pmkid; new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, - pmkid, NULL, 0, + pmkid, old_entry->kck, old_entry->kck_len, aa, pmksa->sm->own_addr, old_entry->network_ctx, old_entry->akmp, old_entry->fils_cache_id_set ? @@ -550,12 +637,13 @@ void pmksa_cache_clear_current(struct wpa_sm *sm) * @network_ctx: Network configuration context * @try_opportunistic: Whether to allow opportunistic PMKSA caching * @fils_cache_id: Pointer to FILS Cache Identifier or %NULL if not used + * @associated: Whether the device is associated * Returns: 0 if PMKSA was found or -1 if no matching entry was found */ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, const u8 *bssid, void *network_ctx, int try_opportunistic, const u8 *fils_cache_id, - int akmp) + int akmp, bool associated) { struct rsn_pmksa_cache *pmksa = sm->pmksa; wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p " @@ -574,11 +662,11 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, sm->cur_pmksa = NULL; if (pmkid) - sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid, - network_ctx, akmp); + sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, sm->own_addr, + pmkid, network_ctx, akmp); if (sm->cur_pmksa == NULL && bssid) - sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, - network_ctx, akmp); + sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, sm->own_addr, + NULL, network_ctx, akmp); if (sm->cur_pmksa == NULL && try_opportunistic && bssid) sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, network_ctx, @@ -593,13 +681,29 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, if (wpa_key_mgmt_sae(sm->cur_pmksa->akmp) && os_get_reltime(&now) == 0 && sm->cur_pmksa->reauth_time < now.sec) { - wpa_printf(MSG_DEBUG, - "RSN: Do not allow PMKSA cache entry for " - MACSTR_SEC - " to be used for SAE since its reauth threshold has passed", - MAC2STR_SEC(sm->cur_pmksa->aa)); - sm->cur_pmksa = NULL; - return -1; + /* Driver-based roaming might have used a PMKSA entry + * that is already past the reauthentication threshold. + * Remove the related PMKID from the driver to avoid + * further uses for this PMKSA, but allow the + * association to continue since the PMKSA has not yet + * expired. */ + wpa_sm_remove_pmkid(sm, sm->cur_pmksa->network_ctx, + sm->cur_pmksa->aa, + sm->cur_pmksa->pmkid, NULL); + if (associated) { + wpa_printf(MSG_DEBUG, + "RSN: Associated with " MACSTR_SEC + " using reauth threshold passed PMKSA cache entry", + MAC2STR_SEC(sm->cur_pmksa->aa)); + } else { + wpa_printf(MSG_DEBUG, + "RSN: Do not allow PMKSA cache entry for " + MACSTR_SEC + " to be used for SAE since its reauth threshold has passed", + MAC2STR_SEC(sm->cur_pmksa->aa)); + sm->cur_pmksa = NULL; + return -1; + } } wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", @@ -697,6 +801,8 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, enum pmksa_free_reason reason), bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx), + void (*notify_cb)(struct rsn_pmksa_cache_entry *entry, + void *ctx), void *ctx, struct wpa_sm *sm) { struct rsn_pmksa_cache *pmksa; @@ -705,6 +811,7 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, if (pmksa) { pmksa->free_cb = free_cb; pmksa->is_current_cb = is_current_cb; + pmksa->notify_cb = notify_cb; pmksa->ctx = ctx; pmksa->sm = sm; } @@ -745,4 +852,99 @@ void pmksa_cache_reconfig(struct rsn_pmksa_cache *pmksa) } } +#else /* IEEE8021X_EAPOL */ + +struct rsn_pmksa_cache * +pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, + void *ctx, enum pmksa_free_reason reason), + bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry, + void *ctx), + void (*notify_cb)(struct rsn_pmksa_cache_entry *entry, + void *ctx), + void *ctx, struct wpa_sm *sm) +{ + return (void *) -1; +} + + +void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) +{ +} + + +struct rsn_pmksa_cache_entry * +pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa, + const u8 *pmkid, const void *network_ctx, int akmp) +{ + return NULL; +} + + +struct rsn_pmksa_cache_entry * +pmksa_cache_get_current(struct wpa_sm *sm) +{ + return NULL; +} + + +int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) +{ + return -1; +} + + +struct rsn_pmksa_cache_entry * +pmksa_cache_head(struct rsn_pmksa_cache *pmksa) +{ + return NULL; +} + + +struct rsn_pmksa_cache_entry * +pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa, + struct rsn_pmksa_cache_entry *entry) +{ + return NULL; +} + + +struct rsn_pmksa_cache_entry * +pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, + const u8 *pmkid, const u8 *kck, size_t kck_len, + const u8 *aa, const u8 *spa, void *network_ctx, int akmp, + const u8 *cache_id) +{ + return NULL; +} + + +void pmksa_cache_clear_current(struct wpa_sm *sm) +{ +} + + +int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, const u8 *bssid, + void *network_ctx, int try_opportunistic, + const u8 *fils_cache_id, int akmp, bool associated) +{ + return -1; +} + + +void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, + const u8 *pmk, size_t pmk_len, bool external_only) +{ +} + + +void pmksa_cache_remove(struct rsn_pmksa_cache *pmksa, + struct rsn_pmksa_cache_entry *entry) +{ +} + + +void pmksa_cache_reconfig(struct rsn_pmksa_cache *pmksa) +{ +} + #endif /* IEEE8021X_EAPOL */ diff --git a/wpa_supplicant-2.9_standard/src/rsn_supp/pmksa_cache.h b/wpa_supplicant-2.9_standard/src/rsn_supp/pmksa_cache.h index b801268599a9ba5b8874320500e103f1ecaaa3df..b1203ad2f0b38be30ce6fae5e815a7e04c91e0b6 100644 --- a/wpa_supplicant-2.9_standard/src/rsn_supp/pmksa_cache.h +++ b/wpa_supplicant-2.9_standard/src/rsn_supp/pmksa_cache.h @@ -17,9 +17,12 @@ struct rsn_pmksa_cache_entry { u8 pmkid[PMKID_LEN]; u8 pmk[PMK_LEN_MAX]; size_t pmk_len; + u8 kck[WPA_KCK_MAX_LEN]; + size_t kck_len; os_time_t expiration; int akmp; /* WPA_KEY_MGMT_* */ u8 aa[ETH_ALEN]; + u8 spa[ETH_ALEN]; /* * If FILS Cache Identifier is included (fils_cache_id_set), this PMKSA @@ -44,6 +47,13 @@ struct rsn_pmksa_cache_entry { void *network_ctx; int opportunistic; bool external; + + /** + * This field is used to avoid duplicate pmksa_cache_reauth() calls for + * every 10 minutes during the periodic expiration check of the current + * PMKSA for SAE. + */ + bool sae_reauth_scheduled; }; struct rsn_pmksa_cache; @@ -54,17 +64,18 @@ enum pmksa_free_reason { PMKSA_EXPIRE, }; -#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA) - struct rsn_pmksa_cache * pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, enum pmksa_free_reason reason), bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx), + void (*notify_cb)(struct rsn_pmksa_cache_entry *entry, + void *ctx), void *ctx, struct wpa_sm *sm); void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, - const u8 *aa, const u8 *pmkid, + const u8 *aa, const u8 *spa, + const u8 *pmkid, const void *network_ctx, int akmp); int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); @@ -82,96 +93,14 @@ void pmksa_cache_clear_current(struct wpa_sm *sm); int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, const u8 *bssid, void *network_ctx, int try_opportunistic, const u8 *fils_cache_id, - int akmp); + int akmp, bool associated); struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, const u8 *aa, int akmp); void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, const u8 *pmk, size_t pmk_len, bool external_only); +void pmksa_cache_remove(struct rsn_pmksa_cache *pmksa, + struct rsn_pmksa_cache_entry *entry); void pmksa_cache_reconfig(struct rsn_pmksa_cache *pmksa); -#else /* IEEE8021X_EAPOL */ - -static inline struct rsn_pmksa_cache * -pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, - void *ctx, enum pmksa_free_reason reason), - bool (*is_current_cb)(struct rsn_pmksa_cache_entry *entry, - void *ctx), - void *ctx, struct wpa_sm *sm) -{ - return (void *) -1; -} - -static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) -{ -} - -static inline struct rsn_pmksa_cache_entry * -pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid, - const void *network_ctx, int akmp) -{ - return NULL; -} - -static inline struct rsn_pmksa_cache_entry * -pmksa_cache_get_current(struct wpa_sm *sm) -{ - return NULL; -} - -static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, - size_t len) -{ - return -1; -} - -static inline struct rsn_pmksa_cache_entry * -pmksa_cache_head(struct rsn_pmksa_cache *pmksa) -{ - return NULL; -} - -static inline struct rsn_pmksa_cache_entry * -pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa, - struct rsn_pmksa_cache_entry *entry) -{ - return NULL; -} - -static inline struct rsn_pmksa_cache_entry * -pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, - const u8 *pmkid, const u8 *kck, size_t kck_len, - const u8 *aa, const u8 *spa, void *network_ctx, int akmp, - const u8 *cache_id) -{ - return NULL; -} - -static inline void pmksa_cache_clear_current(struct wpa_sm *sm) -{ -} - -static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, - const u8 *bssid, - void *network_ctx, - int try_opportunistic, - const u8 *fils_cache_id, - int akmp) -{ - return -1; -} - -static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, - void *network_ctx, - const u8 *pmk, size_t pmk_len, - bool external_only) -{ -} - -static inline void pmksa_cache_reconfig(struct rsn_pmksa_cache *pmksa) -{ -} - -#endif /* IEEE8021X_EAPOL */ - #endif /* PMKSA_CACHE_H */ diff --git a/wpa_supplicant-2.9_standard/src/rsn_supp/preauth.c b/wpa_supplicant-2.9_standard/src/rsn_supp/preauth.c index 4e95fb99072692444c45474129a576e78c486b04..94ba749550e517b1e9e34532708f95c4221ebc5a 100644 --- a/wpa_supplicant-2.9_standard/src/rsn_supp/preauth.c +++ b/wpa_supplicant-2.9_standard/src/rsn_supp/preauth.c @@ -54,7 +54,8 @@ static int rsn_preauth_key_mgmt(int akmp) return !!(akmp & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_IEEE8021X_SHA256 | WPA_KEY_MGMT_IEEE8021X_SUITE_B | - WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)); + WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 | + WPA_KEY_MGMT_IEEE8021X_SHA384)); } @@ -68,14 +69,15 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr, if (sm->preauth_eapol == NULL || is_zero_ether_addr(sm->preauth_bssid) || - os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) { + !ether_addr_equal(sm->preauth_bssid, src_addr)) { wpa_printf(MSG_WARNING, "RSN pre-auth frame received from " "unexpected source " MACSTR_SEC " - dropped", MAC2STR_SEC(src_addr)); return; } - eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len); + eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len, + FRAME_ENCRYPTION_UNKNOWN); } @@ -336,8 +338,9 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm) dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates, struct rsn_pmksa_candidate, list) { struct rsn_pmksa_cache_entry *p = NULL; - p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL, 0); - if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 && + p = pmksa_cache_get(sm->pmksa, candidate->bssid, sm->own_addr, + NULL, NULL, 0); + if (!ether_addr_equal(sm->bssid, candidate->bssid) && (p == NULL || p->opportunistic)) { wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA " "candidate " MACSTR @@ -406,7 +409,7 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid, cand = NULL; dl_list_for_each(pos, &sm->pmksa_candidates, struct rsn_pmksa_candidate, list) { - if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) { + if (ether_addr_equal(pos->bssid, bssid)) { cand = pos; break; } @@ -500,13 +503,13 @@ void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0) return; /* Not for the current SSID */ - if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0) + if (ether_addr_equal(bssid, sm->bssid)) return; /* Ignore current AP */ if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie)) return; - pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL, 0); + pmksa = pmksa_cache_get(sm->pmksa, bssid, sm->own_addr, NULL, NULL, 0); if (pmksa && (!pmksa->opportunistic || !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) return; diff --git a/wpa_supplicant-2.9_standard/src/rsn_supp/tdls.c b/wpa_supplicant-2.9_standard/src/rsn_supp/tdls.c index 50897f853f7cb63de3c516c616bf1cfa69301507..97dedf8417feadb828fc0858a847c8428d1165d1 100644 --- a/wpa_supplicant-2.9_standard/src/rsn_supp/tdls.c +++ b/wpa_supplicant-2.9_standard/src/rsn_supp/tdls.c @@ -139,6 +139,8 @@ struct wpa_tdls_peer { struct ieee80211_he_capabilities *he_capabilities; size_t he_capab_len; struct ieee80211_he_6ghz_band_cap *he_6ghz_band_capabilities; + struct ieee80211_eht_capabilities *eht_capabilities; + size_t eht_capab_len; u8 qos_info; @@ -157,9 +159,21 @@ struct wpa_tdls_peer { /* channel switch currently enabled */ int chan_switch_enabled; + + int mld_link_id; + bool disc_resp_rcvd; + bool setup_req_rcvd; }; +static const u8 * wpa_tdls_get_link_bssid(struct wpa_sm *sm, int link_id) +{ + if (link_id >= 0) + return sm->mlo.links[link_id].bssid; + return sm->bssid; +} + + static int wpa_tdls_get_privacy(struct wpa_sm *sm) { /* @@ -180,11 +194,7 @@ static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) { -#ifdef CONFIG_MLD_PATCH if (wpa_sm_set_key(sm, -1, WPA_ALG_NONE, peer->addr, -#else - if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr, -#endif 0, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE) < 0) { wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from " "the driver"); @@ -234,11 +244,7 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR_SEC, MAC2STR_SEC(peer->addr)); -#ifdef CONFIG_MLD_PATCH if (wpa_sm_set_key(sm, -1, alg, peer->addr, 0, 1, rsc, sizeof(rsc), -#else - if (wpa_sm_set_key(sm, alg, peer->addr, 0, 1, rsc, sizeof(rsc), -#endif peer->tpk.tk, key_len, KEY_FLAG_PAIRWISE_RX_TX) < 0) { wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the " @@ -253,17 +259,19 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, - int initiator, const u8 *buf, size_t len) + int initiator, const u8 *buf, size_t len, + int link_id) { return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token, status_code, peer_capab, initiator, buf, - len); + len, link_id); } static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, - int initiator, const u8 *msg, size_t msg_len) + int initiator, const u8 *msg, size_t msg_len, + int link_id) { struct wpa_tdls_peer *peer; @@ -275,7 +283,7 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, status_code, peer_capab, initiator, msg, - msg_len)) { + msg_len, link_id)) { wpa_printf(MSG_INFO, "TDLS: Failed to send message " "(action_code=%u)", action_code); return -1; @@ -288,7 +296,7 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, return 0; /* No retries */ for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, dest, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, dest)) break; } @@ -372,7 +380,7 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) peer->sm_tmr.peer_capab, peer->initiator, peer->sm_tmr.buf, - peer->sm_tmr.buf_len)) { + peer->sm_tmr.buf_len, -1)) { wpa_printf(MSG_INFO, "TDLS: Failed to retry " "transmission"); } @@ -473,23 +481,26 @@ static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer, * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC * @kck: TPK-KCK * @lnkid: Pointer to the beginning of Link Identifier IE - * @rsnie: Pointer to the beginning of RSN IE used for handshake + * @rsne: Pointer to the beginning of RSNE used for handshake + * @rsne_len: Length of RSNE in octets * @timeoutie: Pointer to the beginning of Timeout IE used for handshake - * @ftie: Pointer to the beginning of FT IE + * @fte: Pointer to the beginning of FTE + * @fre_len: Length of FTE in octets * @mic: Pointer for writing MIC * * Calculate MIC for TDLS frame. */ static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid, - const u8 *rsnie, const u8 *timeoutie, - const u8 *ftie, u8 *mic) + const u8 *rsne, size_t rsne_len, + const u8 *timeoutie, + const u8 *fte, size_t fte_len, u8 *mic) { u8 *buf, *pos; struct wpa_tdls_ftie *_ftie; const struct wpa_tdls_lnkid *_lnkid; int ret; - int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] + - 2 + timeoutie[1] + 2 + ftie[1]; + int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + rsne_len + + 2 + timeoutie[1] + fte_len; buf = os_zalloc(len); if (!buf) { wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); @@ -510,16 +521,16 @@ static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid, os_memcpy(pos, lnkid, 2 + lnkid[1]); pos += 2 + lnkid[1]; /* 5) RSN IE */ - os_memcpy(pos, rsnie, 2 + rsnie[1]); - pos += 2 + rsnie[1]; + os_memcpy(pos, rsne, rsne_len); + pos += rsne_len; /* 6) Timeout Interval IE */ os_memcpy(pos, timeoutie, 2 + timeoutie[1]); pos += 2 + timeoutie[1]; /* 7) FTIE, with the MIC field of the FTIE set to 0 */ - os_memcpy(pos, ftie, 2 + ftie[1]); + os_memcpy(pos, fte, fte_len); _ftie = (struct wpa_tdls_ftie *) pos; os_memset(_ftie->mic, 0, TDLS_MIC_LEN); - pos += 2 + ftie[1]; + pos += fte_len; wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); @@ -537,14 +548,15 @@ static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid, * @rcode: Reason code for Teardown * @dtoken: Dialog Token used for that particular link * @lnkid: Pointer to the beginning of Link Identifier IE - * @ftie: Pointer to the beginning of FT IE + * @fte: Pointer to the beginning of FTE + * @fre_len: Length of FTE in octets * @mic: Pointer for writing MIC * * Calculate MIC for TDLS frame. */ static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode, u8 dtoken, const u8 *lnkid, - const u8 *ftie, u8 *mic) + const u8 *fte, size_t fte_len, u8 *mic) { u8 *buf, *pos; struct wpa_tdls_ftie *_ftie; @@ -555,7 +567,7 @@ static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode, return -1; len = 2 + lnkid[1] + sizeof(rcode) + sizeof(dtoken) + - sizeof(trans_seq) + 2 + ftie[1]; + sizeof(trans_seq) + fte_len; buf = os_zalloc(len); if (!buf) { @@ -575,10 +587,10 @@ static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode, /* 4) Transaction Sequence number */ *pos++ = trans_seq; /* 7) FTIE, with the MIC field of the FTIE set to 0 */ - os_memcpy(pos, ftie, 2 + ftie[1]); + os_memcpy(pos, fte, fte_len); _ftie = (struct wpa_tdls_ftie *) pos; os_memset(_ftie->mic, 0, TDLS_MIC_LEN); - pos += 2 + ftie[1]; + pos += fte_len; wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); @@ -592,14 +604,15 @@ static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode, static int wpa_supplicant_verify_tdls_mic(u8 trans_seq, struct wpa_tdls_peer *peer, const u8 *lnkid, const u8 *timeoutie, - const struct wpa_tdls_ftie *ftie) + const struct wpa_tdls_ftie *ftie, + size_t fte_len) { u8 mic[16]; if (peer->tpk_set) { wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid, - peer->rsnie_p, timeoutie, (u8 *) ftie, - mic); + peer->rsnie_p, peer->rsnie_p_len, timeoutie, + (const u8 *) ftie, fte_len, mic); if (os_memcmp_const(mic, ftie->mic, 16) != 0) { wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - " "dropping packet"); @@ -620,13 +633,14 @@ static int wpa_supplicant_verify_tdls_mic(u8 trans_seq, static int wpa_supplicant_verify_tdls_mic_teardown( u8 trans_seq, u16 rcode, u8 dtoken, struct wpa_tdls_peer *peer, - const u8 *lnkid, const struct wpa_tdls_ftie *ftie) + const u8 *lnkid, const struct wpa_tdls_ftie *ftie, size_t fte_len) { u8 mic[16]; if (peer->tpk_set) { wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode, - dtoken, lnkid, (u8 *) ftie, mic); + dtoken, lnkid, (const u8 *) ftie, + fte_len, mic); if (os_memcmp_const(mic, ftie->mic, 16) != 0) { wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - " "dropping packet"); @@ -718,6 +732,8 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer) peer->he_capabilities = NULL; os_free(peer->he_6ghz_band_capabilities); peer->he_6ghz_band_capabilities = NULL; + os_free(peer->eht_capabilities); + peer->eht_capabilities = NULL; os_free(peer->ext_capab); peer->ext_capab = NULL; os_free(peer->supp_channels); @@ -733,6 +749,7 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer) os_memset(&peer->tpk, 0, sizeof(peer->tpk)); os_memset(peer->inonce, 0, WPA_NONCE_LEN); os_memset(peer->rnonce, 0, WPA_NONCE_LEN); + peer->mld_link_id = -1; } @@ -749,7 +766,8 @@ static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer, { lnkid->ie_type = WLAN_EID_LINK_ID; lnkid->ie_len = 3 * ETH_ALEN; - os_memcpy(lnkid->bssid, sm->bssid, ETH_ALEN); + os_memcpy(lnkid->bssid, wpa_tdls_get_link_bssid(sm, peer->mld_link_id), + ETH_ALEN); if (peer->initiator) { os_memcpy(lnkid->init_sta, sm->own_addr, ETH_ALEN); os_memcpy(lnkid->resp_sta, peer->addr, ETH_ALEN); @@ -775,7 +793,7 @@ static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, /* Find the node and free from the list */ for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, addr)) break; } @@ -838,7 +856,8 @@ static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, /* compute MIC before sending */ wpa_tdls_linkid(sm, peer, &lnkid); wpa_tdls_key_mic_teardown(peer->tpk.kck, 4, reason_code, - dialog_token, (u8 *) &lnkid, (u8 *) ftie, + dialog_token, (const u8 *) &lnkid, + (const u8 *) ftie, 2 + ftie->ie_len, ftie->mic); skip_ies: @@ -847,7 +866,8 @@ skip_ies: /* request driver to send Teardown using this FTIE */ wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0, - reason_code, 0, peer->initiator, rbuf, pos - rbuf); + reason_code, 0, peer->initiator, rbuf, pos - rbuf, + -1); os_free(rbuf); return 0; @@ -862,7 +882,7 @@ int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code) return -1; for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, addr)) break; } @@ -895,7 +915,7 @@ void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr) struct wpa_tdls_peer *peer; for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, addr)) break; } @@ -931,7 +951,7 @@ const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr) return "disabled"; for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, addr)) break; } @@ -958,7 +978,7 @@ static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr, /* Find the node and free from the list */ for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, src_addr)) break; } @@ -1008,7 +1028,8 @@ static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr, /* Process MIC check to see if TDLS Teardown is right */ if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code, peer->dtoken, peer, - (u8 *) lnkid, ftie) < 0) { + (const u8 *) lnkid, + ftie, kde.ftie_len) < 0) { wpa_printf(MSG_DEBUG, "TDLS: MIC failure for TDLS " "Teardown Request from " MACSTR_SEC, MAC2STR_SEC(src_addr)); return -1; @@ -1041,7 +1062,7 @@ static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst, " (action=%u status=%u)", MAC2STR_SEC(dst), tdls_action, status); return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status, - 0, initiator, NULL, 0); + 0, initiator, NULL, 0, -1); } @@ -1053,7 +1074,7 @@ wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing) if (existing) *existing = 0; for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) { + if (ether_addr_equal(peer->addr, addr)) { if (existing) *existing = 1; return peer; /* re-use existing entry */ @@ -1068,6 +1089,7 @@ wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing) return NULL; os_memcpy(peer->addr, addr, ETH_ALEN); + peer->mld_link_id = -1; peer->next = sm->tdls; sm->tdls = peer; @@ -1249,7 +1271,8 @@ skip_ies: MAC2STR_SEC(peer->addr)); status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, - 1, 0, 0, peer->initiator, rbuf, pos - rbuf); + 1, 0, 0, peer->initiator, rbuf, pos - rbuf, + -1); os_free(rbuf); return status; @@ -1328,8 +1351,9 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm, lifetime); /* compute MIC before sending */ - wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p, - (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); + wpa_tdls_ftie_mic(peer->tpk.kck, 2, (const u8 *) lnkid, peer->rsnie_p, + peer->rsnie_p_len, (const u8 *) &timeoutie, + (const u8 *) ftie, 2 + ftie->ie_len, ftie->mic); #ifdef CONFIG_TDLS_TESTING if (tdls_testing & TDLS_TESTING_WRONG_MIC) { wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong MIC"); @@ -1340,7 +1364,7 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm, skip_ies: status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0, 0, peer->initiator, rbuf, - pos - rbuf); + pos - rbuf, -1); os_free(rbuf); return status; @@ -1418,8 +1442,9 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm, lifetime); /* compute MIC before sending */ - wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p, - (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); + wpa_tdls_ftie_mic(peer->tpk.kck, 3, (const u8 *) lnkid, peer->rsnie_p, + peer->rsnie_p_len, (const u8 *) &timeoutie, + (const u8 *) ftie, 2 + ftie->ie_len, ftie->mic); #ifdef CONFIG_TDLS_TESTING if (tdls_testing & TDLS_TESTING_WRONG_MIC) { wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong MIC"); @@ -1440,7 +1465,7 @@ skip_ies: status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0, peer_capab, peer->initiator, - rbuf, pos - rbuf); + rbuf, pos - rbuf, -1); os_free(rbuf); return status; @@ -1449,7 +1474,7 @@ skip_ies: static int wpa_tdls_send_discovery_response(struct wpa_sm *sm, struct wpa_tdls_peer *peer, - u8 dialog_token) + u8 dialog_token, int link_id) { size_t buf_len = 0; struct wpa_tdls_timeoutie timeoutie; @@ -1526,13 +1551,45 @@ skip_rsn_ies: wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime); skip_ies: status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE, - dialog_token, 0, 0, 0, rbuf, pos - rbuf); + dialog_token, 0, 0, 0, rbuf, pos - rbuf, + link_id); os_free(rbuf); return status; } +static bool wpa_tdls_is_lnkid_bss_valid(struct wpa_sm *sm, + const struct wpa_tdls_lnkid *lnkid, + int *link_id) +{ + *link_id = -1; + + if (!sm->mlo.valid_links) { + if (!ether_addr_equal(sm->bssid, lnkid->bssid)) + return false; + } else { + int i; + + for_each_link(sm->mlo.valid_links, i) { + if (ether_addr_equal(lnkid->bssid, + sm->mlo.links[i].bssid)) { + *link_id = i; + break; + } + } + if (*link_id < 0) { + wpa_printf(MSG_DEBUG, + "TDLS: MLD link not found for linkid BSS " + MACSTR, MAC2STR(lnkid->bssid)); + return false; + } + } + + return true; +} + + static int wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr, const u8 *buf, size_t len) @@ -1543,6 +1600,7 @@ wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr, size_t min_req_len = sizeof(struct wpa_tdls_frame) + 1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid); u8 dialog_token; + int link_id = -1; wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR_SEC, MAC2STR_SEC(addr)); @@ -1575,17 +1633,19 @@ wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr, lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid; - if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different " - " BSS " MACSTR_SEC, MAC2STR_SEC(lnkid->bssid)); - return -1; + if (!wpa_tdls_is_lnkid_bss_valid(sm, lnkid, &link_id)) { + wpa_printf(MSG_DEBUG, + "TDLS: Discovery Request from different BSS " + MACSTR_SEC, MAC2STR_SEC(lnkid->bssid)); + return -1; } peer = wpa_tdls_add_peer(sm, addr, NULL); if (peer == NULL) return -1; - return wpa_tdls_send_discovery_response(sm, peer, dialog_token); + return wpa_tdls_send_discovery_response(sm, peer, dialog_token, + link_id); } @@ -1597,7 +1657,7 @@ int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr) wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer " MACSTR_SEC, MAC2STR_SEC(addr)); return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST, - 1, 0, 0, 1, NULL, 0); + 1, 0, 0, 1, NULL, 0, -1); } @@ -1743,6 +1803,29 @@ static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde, } +static int copy_peer_eht_capab(const struct wpa_eapol_ie_parse *kde, + struct wpa_tdls_peer *peer) +{ + if (!kde->eht_capabilities) { + wpa_printf(MSG_DEBUG, "TDLS: No EHT capabilities received"); + return 0; + } + + os_free(peer->eht_capabilities); + peer->eht_capab_len = 0; + peer->eht_capabilities = os_memdup(kde->eht_capabilities, + kde->eht_capab_len); + if (!peer->eht_capabilities) + return -1; + + peer->eht_capab_len = kde->eht_capab_len; + wpa_hexdump(MSG_DEBUG, "TDLS: Peer EHT capabilities", + peer->eht_capabilities, peer->eht_capab_len); + + return 0; +} + + static int copy_peer_wmm_capab(const struct wpa_eapol_ie_parse *kde, struct wpa_tdls_peer *peer) { @@ -1836,7 +1919,10 @@ static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer, peer->supp_channels, peer->supp_channels_len, peer->supp_oper_classes, - peer->supp_oper_classes_len); + peer->supp_oper_classes_len, + peer->eht_capabilities, + peer->eht_capab_len, + peer->mld_link_id); } @@ -1876,6 +1962,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE; int tdls_prohibited = sm->tdls_prohibited; int existing_peer = 0; + int link_id = -1; if (len < 3 + 3) return -1; @@ -1951,12 +2038,15 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M1", kde.lnkid, kde.lnkid_len); lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; - if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS"); + + if (!wpa_tdls_is_lnkid_bss_valid(sm, lnkid, &link_id)) { + wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS " + MACSTR_SEC, MAC2STR_SEC(lnkid->bssid)); status = WLAN_STATUS_REQUEST_DECLINED; goto error; } + peer->mld_link_id = link_id; wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR_SEC, MAC2STR_SEC(src_addr)); @@ -1971,6 +2061,9 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, copy_peer_he_6ghz_band_capab(&kde, peer) < 0) goto error; + if (copy_peer_eht_capab(&kde, peer) < 0) + goto error; + if (copy_peer_ext_capab(&kde, peer) < 0) goto error; @@ -1998,7 +2091,7 @@ 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, NULL, 0, NULL, 0, 0, NULL, 0, - NULL, 0, NULL, 0); + NULL, 0, NULL, 0, NULL, 0, link_id); if (wpa_tdls_send_tpk_m1(sm, peer) == -2) { peer = NULL; goto error; @@ -2179,7 +2272,11 @@ skip_rsn: peer->lifetime = lifetime; - wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); + if (peer->mld_link_id >= 0) + wpa_printf(MSG_DEBUG, "TDLS: Use link ID %u for TPK derivation", + peer->mld_link_id); + wpa_tdls_generate_tpk(peer, sm->own_addr, + wpa_tdls_get_link_bssid(sm, peer->mld_link_id)); skip_rsn_check: #ifdef CONFIG_TDLS_TESTING @@ -2275,7 +2372,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 " "(Peer " MACSTR_SEC ")", MAC2STR_SEC(src_addr)); for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, src_addr)) break; } if (peer == NULL) { @@ -2364,7 +2461,8 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, kde.lnkid, kde.lnkid_len); lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; - if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { + if (!ether_addr_equal(sm->bssid, + wpa_tdls_get_link_bssid(sm, peer->mld_link_id))) { wpa_printf(MSG_INFO, "TDLS: TPK M2 from different BSS"); status = WLAN_STATUS_NOT_IN_SAME_BSS; goto error; @@ -2381,6 +2479,9 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, copy_peer_he_6ghz_band_capab(&kde, peer) < 0) goto error; + if (copy_peer_eht_capab(&kde, peer) < 0) + goto error; + if (copy_peer_ext_capab(&kde, peer) < 0) goto error; @@ -2488,11 +2589,16 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, goto error; } - wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); + if (peer->mld_link_id >= 0) + wpa_printf(MSG_DEBUG, "TDLS: Use link ID %u for TPK derivation", + peer->mld_link_id); + wpa_tdls_generate_tpk(peer, sm->own_addr, + wpa_tdls_get_link_bssid(sm, peer->mld_link_id)); /* Process MIC check to see if TPK M2 is right */ - if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid, - (u8 *) timeoutie, ftie) < 0) { + if (wpa_supplicant_verify_tdls_mic(2, peer, (const u8 *) lnkid, + (const u8 *) timeoutie, ftie, + kde.ftie_len) < 0) { /* Discard the frame */ wpa_tdls_del_key(sm, peer); wpa_tdls_disable_peer_link(sm, peer); @@ -2563,7 +2669,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 " "(Peer " MACSTR_SEC ")", MAC2STR_SEC(src_addr)); for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, src_addr)) break; } if (peer == NULL) { @@ -2608,7 +2714,8 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, (u8 *) kde.lnkid, kde.lnkid_len); lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; - if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { + if (!ether_addr_equal(wpa_tdls_get_link_bssid(sm, peer->mld_link_id), + lnkid->bssid)) { wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS"); goto error; } @@ -2665,8 +2772,9 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, goto error; } - if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid, - (u8 *) timeoutie, ftie) < 0) { + if (wpa_supplicant_verify_tdls_mic(3, peer, (const u8 *) lnkid, + (const u8 *) timeoutie, ftie, + kde.ftie_len) < 0) { wpa_tdls_del_key(sm, peer); goto error; } @@ -2761,12 +2869,18 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) return 0; } + if (sm->mlo.valid_links && !peer->disc_resp_rcvd) { + wpa_printf(MSG_DEBUG, + "TDLS: MLO STA connection - defer the setup request since Discovery Resp not yet received"); + peer->setup_req_rcvd = true; + return 0; + } peer->initiator = 1; /* add the peer to the driver as a "setup in progress" peer */ if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, NULL, 0, NULL, 0, 0, NULL, 0, NULL, 0, - NULL, 0)) { + NULL, 0, NULL, 0, peer->mld_link_id)) { wpa_tdls_disable_peer_link(sm, peer); return -1; } @@ -2792,7 +2906,7 @@ void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr) return; for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, addr)) break; } @@ -2830,7 +2944,7 @@ static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr, return; } - if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) { + if (ether_addr_equal(src_addr, sm->own_addr)) { wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message"); return; } @@ -3076,6 +3190,70 @@ int wpa_tdls_is_external_setup(struct wpa_sm *sm) } +int wpa_tdls_process_discovery_response(struct wpa_sm *sm, const u8 *addr, + const u8 *buf, size_t len) +{ + struct ieee802_11_elems elems; + const struct wpa_tdls_lnkid *lnkid; + struct wpa_tdls_peer *peer; + size_t min_req_len = 1 /* Dialog Token */ + 2 /* Capability */ + + sizeof(struct wpa_tdls_lnkid); + int link_id = -1; + + wpa_printf(MSG_DEBUG, "TDLS: Process Discovery Response from " MACSTR, + MAC2STR(addr)); + + if (len < min_req_len) { + wpa_printf(MSG_DEBUG, "TDLS Discovery Resp is too short: %zu", + len); + return -1; + } + + /* Elements start after the three octets of fixed field (one octet for + * the Dialog Token field and two octets for the Capability field. */ + if (ieee802_11_parse_elems(buf + 3, len - 3, &elems, 1) == + ParseFailed) { + wpa_printf(MSG_DEBUG, + "TDLS: Failed to parse IEs in Discovery Response"); + return -1; + } + + if (!elems.link_id) { + wpa_printf(MSG_DEBUG, + "TDLS: Link Identifier element not found in Discovery Response"); + return -1; + } + + lnkid = (const struct wpa_tdls_lnkid *) (elems.link_id - 2); + + if (!wpa_tdls_is_lnkid_bss_valid(sm, lnkid, &link_id)) { + wpa_printf(MSG_DEBUG, + "TDLS: Discovery Response from different BSS " + MACSTR, MAC2STR(lnkid->bssid)); + return -1; + } + + peer = wpa_tdls_add_peer(sm, addr, NULL); + if (!peer) { + wpa_printf(MSG_DEBUG, "TDLS: Could not add peer entry"); + return -1; + } + + peer->mld_link_id = link_id; + wpa_printf(MSG_DEBUG, "TDLS: Link identifier BSS: " MACSTR + " , link id: %u", MAC2STR(lnkid->bssid), link_id); + + peer->disc_resp_rcvd = true; + if (peer->setup_req_rcvd) { + peer->setup_req_rcvd = false; + wpa_printf(MSG_DEBUG, "TDLS: Process the deferred TDLS start"); + return wpa_tdls_start(sm, addr); + } + + return 0; +} + + int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr, u8 oper_class, struct hostapd_freq_params *freq_params) @@ -3099,7 +3277,7 @@ int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr, } for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, addr)) break; } @@ -3133,7 +3311,7 @@ int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr) return -1; for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(peer->addr, addr)) break; } diff --git a/wpa_supplicant-2.9_standard/src/rsn_supp/wpa.c b/wpa_supplicant-2.9_standard/src/rsn_supp/wpa.c index 626dd49d715f7854d659f41f533be4233fd0f293..e510a0831a6932e8a4f576c51e79013df5b0e2ce 100644 --- a/wpa_supplicant-2.9_standard/src/rsn_supp/wpa.c +++ b/wpa_supplicant-2.9_standard/src/rsn_supp/wpa.c @@ -45,7 +45,7 @@ static const u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; -#ifdef CONFIG_MLD_PATCH + static void _wpa_hexdump_link(int level, u8 link_id, const char *title, const void *buf, size_t len, bool key) { @@ -83,7 +83,7 @@ static void wpa_hexdump_link_key(int level, u8 link_id, const char *title, { _wpa_hexdump_link(level, link_id, title, buf, len, true); } -#endif + /** * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message @@ -234,16 +234,22 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) size_t mic_len, hdrlen, rlen; struct wpa_eapol_key *reply; int key_info, ver; - u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic; + u8 *rbuf, *key_mic, *mic; if (pairwise && sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id && - wpa_sm_get_state(sm) == WPA_COMPLETED) { + wpa_sm_get_state(sm) == WPA_COMPLETED && !error) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: PTK0 rekey not allowed, reconnecting"); wpa_sm_reconnect(sm); return; } + if (!sm->ptk_set) { + wpa_printf(MSG_INFO, + "WPA: No PTK derived yet - cannot send EAPOL-Key Request"); + return; + } + if (wpa_use_akm_defined(sm->key_mgmt)) ver = WPA_KEY_INFO_TYPE_AKM_DEFINED; else if (wpa_key_mgmt_ft(sm->key_mgmt) || @@ -254,12 +260,6 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) else ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; - if (wpa_sm_get_bssid(sm, bssid) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "Failed to read BSSID for EAPOL-Key request"); - return; - } - mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len); hdrlen = sizeof(*reply) + mic_len + 2; rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, @@ -271,10 +271,11 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) sm->proto == WPA_PROTO_OSEN) ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; key_info = WPA_KEY_INFO_REQUEST | ver; - if (sm->ptk_set) - key_info |= WPA_KEY_INFO_SECURE; - if (sm->ptk_set && mic_len) + key_info |= WPA_KEY_INFO_SECURE; + if (mic_len) key_info |= WPA_KEY_INFO_MIC; + else + key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; if (error) key_info |= WPA_KEY_INFO_ERROR; if (pairwise) @@ -296,8 +297,8 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) "WPA: Sending EAPOL-Key Request (error=%d " "pairwise=%d ptk_set=%d len=%lu)", error, pairwise, sm->ptk_set, (unsigned long) rlen); - wpa_eapol_key_send(sm, &sm->ptk, ver, bssid, ETH_P_EAPOL, rbuf, rlen, - key_mic); + wpa_eapol_key_send(sm, &sm->ptk, ver, wpa_sm_get_auth_addr(sm), + ETH_P_EAPOL, rbuf, rlen, key_mic); } @@ -330,7 +331,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, * not have enough time to get the association information * event before receiving this 1/4 message, so try to find a * matching PMKSA cache entry here. */ - sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid, + sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, + sm->own_addr, pmkid, NULL, 0); if (sm->cur_pmksa) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, @@ -352,7 +354,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, #ifdef CONFIG_IEEE80211R sm->xxkey_len = 0; #ifdef CONFIG_SAE - if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE && + if ((sm->key_mgmt == WPA_KEY_MGMT_FT_SAE || + sm->key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) && sm->pmk_len == PMK_LEN) { /* Need to allow FT key derivation to proceed with * PMK from SAE being used as the XXKey in cases where @@ -445,8 +448,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, fils_cache_id); } if (!sm->cur_pmksa && pmkid && - pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL, - 0)) { + pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr, + pmkid, NULL, 0)) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: the new PMK matches with the " "PMKID"); @@ -537,11 +540,14 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ptk *ptk) { - size_t mic_len, hdrlen, rlen; + size_t mic_len, hdrlen, rlen, extra_len = 0; struct wpa_eapol_key *reply; u8 *rbuf, *key_mic; u8 *rsn_ie_buf = NULL; u16 key_info; +#ifdef CONFIG_TESTING_OPTIONS + size_t pad_len = 0; +#endif /* CONFIG_TESTING_OPTIONS */ if (wpa_ie == NULL) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - " @@ -565,7 +571,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, return -1; os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len); res = wpa_insert_pmkid(rsn_ie_buf, &wpa_ie_len, - sm->pmk_r1_name); + sm->pmk_r1_name, !sm->ft_prepend_pmkid); if (res < 0) { os_free(rsn_ie_buf); return -1; @@ -589,10 +595,21 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len); +#ifdef CONFIG_TESTING_OPTIONS + if (sm->test_eapol_m2_elems) + extra_len = wpabuf_len(sm->test_eapol_m2_elems); + if (sm->encrypt_eapol_m2) { + pad_len = (wpa_ie_len + extra_len) % 8; + if (pad_len) + pad_len = 8 - pad_len; + extra_len += pad_len + 8; + } +#endif /* CONFIG_TESTING_OPTIONS */ + mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len); hdrlen = sizeof(*reply) + mic_len + 2; rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, - NULL, hdrlen + wpa_ie_len, + NULL, hdrlen + wpa_ie_len + extra_len, &rlen, (void *) &reply); if (rbuf == NULL) { os_free(rsn_ie_buf); @@ -603,10 +620,16 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, sm->proto == WPA_PROTO_OSEN) ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; key_info = ver | WPA_KEY_INFO_KEY_TYPE; + if (sm->ptk_set && sm->proto != WPA_PROTO_WPA) + key_info |= WPA_KEY_INFO_SECURE; if (mic_len) key_info |= WPA_KEY_INFO_MIC; else key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; +#ifdef CONFIG_TESTING_OPTIONS + if (sm->encrypt_eapol_m2) + key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; +#endif /* CONFIG_TESTING_OPTIONS */ WPA_PUT_BE16(reply->key_info, key_info); if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) WPA_PUT_BE16(reply->key_length, 0); @@ -618,9 +641,48 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, WPA_REPLAY_COUNTER_LEN); key_mic = (u8 *) (reply + 1); - WPA_PUT_BE16(key_mic + mic_len, wpa_ie_len); /* Key Data Length */ + /* Key Data Length */ + WPA_PUT_BE16(key_mic + mic_len, wpa_ie_len + extra_len); os_memcpy(key_mic + mic_len + 2, wpa_ie, wpa_ie_len); /* Key Data */ os_free(rsn_ie_buf); +#ifdef CONFIG_TESTING_OPTIONS + if (sm->test_eapol_m2_elems) { + os_memcpy(key_mic + mic_len + 2 + wpa_ie_len, + wpabuf_head(sm->test_eapol_m2_elems), + wpabuf_len(sm->test_eapol_m2_elems)); + } + + if (sm->encrypt_eapol_m2) { + u8 *plain; + size_t plain_len; + + if (sm->test_eapol_m2_elems) + extra_len = wpabuf_len(sm->test_eapol_m2_elems); + else + extra_len = 0; + plain_len = wpa_ie_len + extra_len + pad_len; + plain = os_memdup(key_mic + mic_len + 2, plain_len); + if (!plain) { + os_free(rbuf); + return -1; + } + if (pad_len) + plain[plain_len - pad_len] = 0xdd; + + wpa_hexdump_key(MSG_DEBUG, "RSN: AES-WRAP using KEK", + ptk->kek, ptk->kek_len); + if (aes_wrap(ptk->kek, ptk->kek_len, plain_len / 8, plain, + key_mic + mic_len + 2)) { + os_free(plain); + os_free(rbuf); + return -1; + } + wpa_hexdump(MSG_DEBUG, + "RSN: Encrypted Key Data from AES-WRAP", + key_mic + mic_len + 2, plain_len + 8); + os_free(plain); + } +#endif /* CONFIG_TESTING_OPTIONS */ os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); @@ -633,6 +695,7 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, struct wpa_ptk *ptk) { + int ret; const u8 *z = NULL; size_t z_len = 0, kdk_len; int akmp; @@ -666,17 +729,23 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, else kdk_len = 0; - return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", - sm->own_addr, -#ifdef CONFIG_MLD_PATCH - wpa_sm_get_auth_addr(sm), -#else - sm->bssid, -#endif - sm->snonce, - key->key_nonce, ptk, akmp, - sm->pairwise_cipher, z, z_len, - kdk_len); + ret = wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", + sm->own_addr, wpa_sm_get_auth_addr(sm), sm->snonce, + key->key_nonce, ptk, akmp, + sm->pairwise_cipher, z, z_len, + kdk_len); + if (ret) { + wpa_printf(MSG_ERROR, "WPA: PTK derivation failed"); + return ret; + } + +#ifdef CONFIG_PASN + if (sm->secure_ltf && + ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) + ret = wpa_ltf_keyseed(ptk, akmp, sm->pairwise_cipher); +#endif /* CONFIG_PASN */ + + return ret; } @@ -724,7 +793,7 @@ static int wpa_handle_ext_key_id(struct wpa_sm *sm, return 0; } -#ifdef CONFIG_MLD_PATCH + static u8 * rsn_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len) { *pos++ = WLAN_EID_VENDOR_SPECIFIC; @@ -737,13 +806,14 @@ static u8 * rsn_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len) return pos; } + static size_t wpa_mlo_link_kde_len(struct wpa_sm *sm) { int i; unsigned int num_links = 0; - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (sm->mlo.assoc_link_id != i && (sm->mlo.req_links & BIT(i))) + for_each_link(sm->mlo.req_links, i) { + if (sm->mlo.assoc_link_id != i) num_links++; } @@ -756,8 +826,8 @@ static u8 * wpa_mlo_link_kde(struct wpa_sm *sm, u8 *pos) int i; u8 hdr[1 + ETH_ALEN]; - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (sm->mlo.assoc_link_id == i || !(sm->mlo.req_links & BIT(i))) + for_each_link(sm->mlo.req_links, i) { + if (sm->mlo.assoc_link_id == i) continue; wpa_printf(MSG_DEBUG, @@ -774,25 +844,110 @@ static u8 * wpa_mlo_link_kde(struct wpa_sm *sm, u8 *pos) static bool is_valid_ap_mld_mac_kde(struct wpa_sm *sm, const u8 *mac_kde) { return mac_kde && - os_memcmp(mac_kde, sm->mlo.ap_mld_addr, ETH_ALEN) == 0; + ether_addr_equal(mac_kde, sm->mlo.ap_mld_addr); +} + + +static void wpas_swap_tkip_mic_keys(struct wpa_ptk *ptk) +{ + u8 buf[8]; + + /* Supplicant: swap tx/rx Mic keys */ + os_memcpy(buf, &ptk->tk[16], 8); + os_memcpy(&ptk->tk[16], &ptk->tk[24], 8); + os_memcpy(&ptk->tk[24], buf, 8); + forced_memzero(buf, sizeof(buf)); +} + + +static void wpa_supplicant_process_1_of_4_wpa(struct wpa_sm *sm, + const unsigned char *src_addr, + const struct wpa_eapol_key *key, + u16 ver, const u8 *key_data, + size_t key_data_len, + enum frame_encryption encrypted) +{ + struct wpa_eapol_ie_parse ie; + struct wpa_ptk *ptk; + int res; + + if (wpa_sm_get_network_ctx(sm) == NULL) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: No SSID info found (msg 1 of 4)"); + return; + } + + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: RX message 1 of 4-Way Handshake from " MACSTR + " (ver=%d)", MAC2STR(src_addr), ver); + + os_memset(&ie, 0, sizeof(ie)); + + res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid); + if (res == -2) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: Do not reply to msg 1/4 - requesting full EAP authentication"); + return; + } + if (res) + goto failed; + + wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); + + if (sm->renew_snonce) { + if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Failed to get random data for SNonce"); + goto failed; + } + sm->renew_snonce = 0; + wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce", + sm->snonce, WPA_NONCE_LEN); + } + + /* Calculate PTK which will be stored as a temporary PTK until it has + * been verified when processing message 3/4. */ + ptk = &sm->tptk; + if (wpa_derive_ptk(sm, src_addr, key, ptk) < 0) + goto failed; + if (sm->pairwise_cipher == WPA_CIPHER_TKIP) + wpas_swap_tkip_mic_keys(ptk); + sm->tptk_set = 1; + + if (wpa_supplicant_send_2_of_4(sm, wpa_sm_get_auth_addr(sm), key, ver, + sm->snonce, sm->assoc_wpa_ie, + sm->assoc_wpa_ie_len, ptk) < 0) + goto failed; + + os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN); + return; + +failed: + wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); } -#endif + static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, u16 ver, const u8 *key_data, - size_t key_data_len) + size_t key_data_len, + enum frame_encryption encrypted) { struct wpa_eapol_ie_parse ie; struct wpa_ptk *ptk; int res; u8 *kde, *kde_buf = NULL; size_t kde_len; - -#ifdef CONFIG_MLD_PATCH size_t mlo_kde_len = 0; -#endif + + if (encrypted == FRAME_NOT_ENCRYPTED && sm->tk_set && + wpa_sm_pmf_enabled(sm)) { + wpa_printf(MSG_DEBUG, + "RSN: Discard unencrypted EAPOL-Key msg 1/4 when TK is set and PMF is enabled"); + return; + } + if (wpa_sm_get_network_ctx(sm) == NULL) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info " "found (msg 1 of 4)"); @@ -807,7 +962,6 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, return; } - wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_p2p_state(sm->ctx->ctx, P2P_INTERFACE_STATE_4WAY_HANDSHAKE_1, P2P_CHR_DEFAULT_REASON_CODE, P2P_CHR_DEFAULT_REASON_CODE); @@ -819,28 +973,23 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, os_memset(&ie, 0, sizeof(ie)); -#ifndef CONFIG_MLD_PATCH - if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) { -#endif - /* RSN: msg 1/4 should contain PMKID for the selected PMK */ - wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", - key_data, key_data_len); - if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) - goto failed; - if (ie.pmkid) { - wpa_hexdump(MSG_DEBUG, "RSN: PMKID from " - "Authenticator", ie.pmkid, PMKID_LEN); - } -#ifdef CONFIG_MLD_PATCH - if (sm->mlo.valid_links && !is_valid_ap_mld_mac_kde(sm, ie.mac_addr)) { - wpa_printf(MSG_INFO, - "RSN: Discard EAPOL-Key msg 1/4 with invalid AP MLD MAC address KDE"); - return; - } -#endif -#ifndef CONFIG_MLD_PATCH + /* RSN: msg 1/4 should contain PMKID for the selected PMK */ + wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", key_data, key_data_len); + if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) { + wpa_printf(MSG_DEBUG, + "RSN: Discard EAPOL-Key msg 1/4 with invalid IEs/KDEs"); + return; + } + if (ie.pmkid) { + wpa_hexdump(MSG_DEBUG, "RSN: PMKID from Authenticator", + ie.pmkid, PMKID_LEN); + } + + if (sm->mlo.valid_links && !is_valid_ap_mld_mac_kde(sm, ie.mac_addr)) { + wpa_printf(MSG_INFO, + "RSN: Discard EAPOL-Key msg 1/4 with invalid AP MLD MAC address KDE"); + return; } -#endif res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid); if (res == -2) { @@ -851,6 +1000,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, if (res) goto failed; + wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); + if (sm->renew_snonce) { if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, @@ -867,21 +1018,14 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, ptk = &sm->tptk; if (wpa_derive_ptk(sm, src_addr, key, ptk) < 0) goto failed; - if (sm->pairwise_cipher == WPA_CIPHER_TKIP) { - u8 buf[8]; - /* Supplicant: swap tx/rx Mic keys */ - os_memcpy(buf, &ptk->tk[16], 8); - os_memcpy(&ptk->tk[16], &ptk->tk[24], 8); - os_memcpy(&ptk->tk[24], buf, 8); - forced_memzero(buf, sizeof(buf)); - } + if (sm->pairwise_cipher == WPA_CIPHER_TKIP) + wpas_swap_tkip_mic_keys(ptk); sm->tptk_set = 1; -#ifdef CONFIG_MLD_PATCH /* Add MLO Link KDE and MAC KDE in M2 for ML connection */ if (sm->mlo.valid_links) - mlo_kde_len = wpa_mlo_link_kde_len(sm) + RSN_SELECTOR_LEN + ETH_ALEN + 2; -#endif + mlo_kde_len = wpa_mlo_link_kde_len(sm) + + RSN_SELECTOR_LEN + ETH_ALEN + 2; kde = sm->assoc_wpa_ie; kde_len = sm->assoc_wpa_ie_len; @@ -889,11 +1033,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, 2 + RSN_SELECTOR_LEN + 3 + sm->assoc_rsnxe_len + 2 + RSN_SELECTOR_LEN + 1 + - 2 + RSN_SELECTOR_LEN + 2 -#ifdef CONFIG_MLD_PATCH - + mlo_kde_len -#endif - ); + 2 + RSN_SELECTOR_LEN + 2 + mlo_kde_len); + if (!kde_buf) goto failed; os_memcpy(kde_buf, kde, kde_len); @@ -967,32 +1108,24 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, } #endif /* CONFIG_DPP2 */ -#ifdef CONFIG_MLD_PATCH if (sm->mlo.valid_links) { u8 *pos; /* Add MAC KDE */ wpa_printf(MSG_DEBUG, "MLO: Add MAC KDE into EAPOL-Key 2/4"); pos = kde + kde_len; - pos = rsn_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->own_addr, ETH_ALEN); + pos = rsn_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->own_addr, + ETH_ALEN); /* Add MLO Link KDE */ wpa_printf(MSG_DEBUG, "Add MLO Link KDE(s) into EAPOL-Key 2/4"); pos = wpa_mlo_link_kde(sm, pos); kde_len = pos - kde; } -#endif - if (wpa_supplicant_send_2_of_4(sm, -#ifdef CONFIG_MLD_PATCH - wpa_sm_get_auth_addr(sm), -#else - sm->bssid, -#endif - key, ver, sm->snonce, - kde, kde_len, ptk) < 0) { + if (wpa_supplicant_send_2_of_4(sm, wpa_sm_get_auth_addr(sm), key, ver, + sm->snonce, kde, kde_len, ptk) < 0) goto failed; - } #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_p2p_state(sm->ctx->ctx, P2P_INTERFACE_STATE_4WAY_HANDSHAKE_2, P2P_CHR_DEFAULT_REASON_CODE, P2P_CHR_DEFAULT_REASON_CODE); @@ -1122,15 +1255,10 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, key_rsc = key->key_rsc; wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen); } -#ifdef CONFIG_MLD_PATCH + if (wpa_sm_set_key(sm, -1, alg, wpa_sm_get_auth_addr(sm), sm->keyidx_active, 1, key_rsc, rsclen, sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE | key_flag) < 0) { -#else - if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1, key_rsc, - rsclen, sm->ptk.tk, keylen, - KEY_FLAG_PAIRWISE | key_flag) < 0) { -#endif wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to set PTK to the driver (alg=%d keylen=%d bssid=" MACSTR " idx=%d key_flag=0x%x)", @@ -1143,6 +1271,20 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, return -1; } +#ifdef CONFIG_PASN + if (sm->secure_ltf && + ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) && + wpa_sm_set_ltf_keyseed(sm, sm->own_addr, sm->bssid, + sm->ptk.ltf_keyseed_len, + sm->ptk.ltf_keyseed) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Failed to set LTF keyseed to the driver (keylen=%zu bssid=" + MACSTR ")", sm->ptk.ltf_keyseed_len, + MAC2STR(sm->bssid)); + return -1; + } +#endif /* CONFIG_PASN */ + wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher, sm->dot11RSNAConfigPMKLifetime, &sm->ptk); @@ -1150,6 +1292,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN); sm->ptk.tk_len = 0; sm->ptk.installed = 1; + sm->tk_set = true; if (sm->wpa_ptk_rekey) { eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL); @@ -1163,23 +1306,20 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, static int wpa_supplicant_activate_ptk(struct wpa_sm *sm) { wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: Activate PTK (idx=%d bssid=" MACSTR ")", - sm->keyidx_active, MAC2STR(sm->bssid)); - wpa_printf(MSG_DEBUG, "WPA: Activate PTK (idx=%d bssid=" MACSTR_SEC ")", - sm->keyidx_active, MAC2STR_SEC(sm->bssid)); -#ifdef CONFIG_MLD_PATCH + "WPA: Activate PTK (idx=%d auth_addr=" MACSTR ")", + sm->keyidx_active, MAC2STR(wpa_sm_get_auth_addr(sm))); + wpa_printf(MSG_DEBUG, "WPA: Activate PTK (idx=%d auth_addr=" MACSTR_SEC ")", + sm->keyidx_active, MAC2STR_SEC(wpa_sm_get_auth_addr(sm))); + if (wpa_sm_set_key(sm, -1, 0, wpa_sm_get_auth_addr(sm), sm->keyidx_active, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE_RX_TX_MODIFY) < 0) { -#else - if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active, 0, NULL, 0, - NULL, 0, KEY_FLAG_PAIRWISE_RX_TX_MODIFY) < 0) { -#endif wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to activate PTK for TX (idx=%d bssid=" - MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid)); - wpa_printf(MSG_WARNING, "WPA: Failed to activate PTK for TX (idx=%d bssid=" - MACSTR_SEC ")", sm->keyidx_active, MAC2STR_SEC(sm->bssid)); + "WPA: Failed to activate PTK for TX (idx=%d auth_addr=" + MACSTR ")", sm->keyidx_active, + MAC2STR(wpa_sm_get_auth_addr(sm))); + wpa_printf(MSG_WARNING, "WPA: Failed to activate PTK for TX (idx=%d auth_addr=" + MACSTR_SEC ")", sm->keyidx_active, MAC2STR_SEC(wpa_sm_get_auth_addr(sm))); return -1; } return 0; @@ -1254,11 +1394,7 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, _gtk = gtk_buf; } if (sm->pairwise_cipher == WPA_CIPHER_NONE) { -#ifdef CONFIG_MLD_PATCH if (wpa_sm_set_key(sm, -1, gd->alg, NULL, -#else - if (wpa_sm_set_key(sm, gd->alg, NULL, -#endif gd->keyidx, 1, key_rsc, gd->key_rsc_len, _gtk, gd->gtk_len, KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0) { @@ -1268,11 +1404,7 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, forced_memzero(gtk_buf, sizeof(gtk_buf)); return -1; } -#ifdef CONFIG_MLD_PATCH } else if (wpa_sm_set_key(sm, -1, gd->alg, broadcast_ether_addr, -#else - } else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr, -#endif gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len, _gtk, gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, @@ -1295,12 +1427,14 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, return 0; } -#ifdef CONFIG_MLD_PATCH + + static int wpa_supplicant_install_mlo_gtk(struct wpa_sm *sm, u8 link_id, const struct wpa_gtk_data *gd, const u8 *key_rsc, int wnm_sleep) { const u8 *gtk = gd->gtk; + u8 gtk_buf[32]; /* Detect possible key reinstallation */ if ((sm->mlo.links[link_id].gtk.gtk_len == (size_t) gd->gtk_len && @@ -1323,15 +1457,23 @@ static int wpa_supplicant_install_mlo_gtk(struct wpa_sm *sm, u8 link_id, link_id, gd->keyidx, gd->tx, gd->gtk_len); wpa_hexdump_link(MSG_DEBUG, link_id, "RSN: RSC", key_rsc, gd->key_rsc_len); - + if (sm->group_cipher == WPA_CIPHER_TKIP) { + /* Swap Tx/Rx keys for Michael MIC */ + os_memcpy(gtk_buf, gd->gtk, 16); + os_memcpy(gtk_buf + 16, gd->gtk + 24, 8); + os_memcpy(gtk_buf + 24, gd->gtk + 16, 8); + gtk = gtk_buf; + } if (wpa_sm_set_key(sm, link_id, gd->alg, broadcast_ether_addr, gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len, gtk, gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "RSN: Failed to set GTK to the driver (link_id=%d alg=%d keylen=%d keyidx=%d)", link_id, gd->alg, gd->gtk_len, gd->keyidx); + forced_memzero(gtk_buf, sizeof(gtk_buf)); return -1; } + forced_memzero(gtk_buf, sizeof(gtk_buf)); if (wnm_sleep) { sm->mlo.links[link_id].gtk_wnm_sleep.gtk_len = gd->gtk_len; @@ -1345,7 +1487,8 @@ static int wpa_supplicant_install_mlo_gtk(struct wpa_sm *sm, u8 link_id, return 0; } -#endif + + static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm, int tx) { @@ -1393,7 +1536,7 @@ static int wpa_supplicant_rsc_relaxation(const struct wpa_sm *sm, return 0; } -#ifdef CONFIG_MLD_PATCH + static int wpa_supplicant_mlo_gtk(struct wpa_sm *sm, u8 link_id, const u8 *gtk, size_t gtk_len, int key_info) { @@ -1453,9 +1596,7 @@ static int wpa_supplicant_pairwise_mlo_gtk(struct wpa_sm *sm, { u8 i; - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(sm->mlo.valid_links & BIT(i))) - continue; + for_each_link(sm->mlo.valid_links, i) { if (!ie->mlo_gtk[i]) { wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, "MLO RSN: GTK not found for link ID %u", i); @@ -1469,7 +1610,7 @@ static int wpa_supplicant_pairwise_mlo_gtk(struct wpa_sm *sm, return 0; } -#endif + static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm, const struct wpa_eapol_key *key, @@ -1553,11 +1694,7 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm, "WPA: Invalid IGTK KeyID %d", keyidx); return -1; } -#ifdef CONFIG_MLD_PATCH if (wpa_sm_set_key(sm, -1, wpa_cipher_to_alg(sm->mgmt_group_cipher), -#else - if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), -#endif broadcast_ether_addr, keyidx, 0, igtk->pn, sizeof(igtk->pn), igtk->igtk, len, KEY_FLAG_GROUP_RX) < 0) { @@ -1628,11 +1765,7 @@ static int wpa_supplicant_install_bigtk(struct wpa_sm *sm, "WPA: Invalid BIGTK KeyID %d", keyidx); return -1; } -#ifdef CONFIG_MLD_PATCH if (wpa_sm_set_key(sm, -1, wpa_cipher_to_alg(sm->mgmt_group_cipher), -#else - if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), -#endif broadcast_ether_addr, keyidx, 0, bigtk->pn, sizeof(bigtk->pn), bigtk->bigtk, len, KEY_FLAG_GROUP_RX) < 0) { @@ -1652,7 +1785,8 @@ static int wpa_supplicant_install_bigtk(struct wpa_sm *sm, return 0; } -#ifdef CONFIG_MLD_PATCH + + static int wpa_supplicant_install_mlo_igtk(struct wpa_sm *sm, u8 link_id, const struct rsn_mlo_igtk_kde *igtk, int wnm_sleep) @@ -1815,16 +1949,15 @@ static int mlo_ieee80211w_set_keys(struct wpa_sm *sm, sm->mgmt_group_cipher == WPA_CIPHER_GTK_NOT_USED) return 0; - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(sm->mlo.valid_links & BIT(i))) - continue; + for_each_link(sm->mlo.valid_links, i) { if (_mlo_ieee80211w_set_keys(sm, i, ie)) return -1; } return 0; } -#endif + + static int ieee80211w_set_keys(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie) { @@ -2133,30 +2266,165 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm, return 0; } -#ifdef CONFIG_MLD_PATCH -static int wpa_supplicant_validate_link_kde(struct wpa_sm *sm, u8 link_id, - const u8 *link_kde, - size_t link_kde_len) + + +/** + * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake + * @sm: Pointer to WPA state machine data from wpa_sm_init() + * @dst: Destination address for the frame + * @key: Pointer to the EAPOL-Key frame header + * @ver: Version bits from EAPOL-Key Key Info + * @key_info: Key Info + * @ptk: PTK to use for keyed hash and encryption + * Returns: >= 0 on success, < 0 on failure + */ +int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, + const struct wpa_eapol_key *key, + u16 ver, u16 key_info, + struct wpa_ptk *ptk) { - size_t rsne_len = 0, rsnxe_len = 0; - const u8 *rsne = NULL, *rsnxe = NULL; + size_t mic_len, hdrlen, rlen; + struct wpa_eapol_key *reply; + u8 *rbuf, *key_mic; + u8 *kde = NULL; + size_t kde_len = 0, extra_len = 0; +#ifdef CONFIG_TESTING_OPTIONS + size_t pad_len = 0; +#endif /* CONFIG_TESTING_OPTIONS */ - if (!link_kde || - link_kde_len < RSN_MLO_LINK_KDE_LINK_MAC_INDEX + ETH_ALEN) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: MLO Link KDE is not found for link ID %d", - link_id); - return -1; + if (sm->mlo.valid_links) { + u8 *pos; + + kde = os_malloc(RSN_SELECTOR_LEN + ETH_ALEN + 2); + if (!kde) + return -1; + + /* Add MAC KDE */ + wpa_printf(MSG_DEBUG, "MLO: Add MAC KDE into EAPOL-Key 4/4"); + pos = kde; + pos = rsn_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->own_addr, + ETH_ALEN); + kde_len = pos - kde; } - if (os_memcmp(sm->mlo.links[link_id].bssid, - &link_kde[RSN_MLO_LINK_KDE_LINK_MAC_INDEX], ETH_ALEN) != 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: MLO Link %u MAC address (" MACSTR - ") not matching association response (" MACSTR ")", - link_id, - MAC2STR(&link_kde[RSN_MLO_LINK_KDE_LINK_MAC_INDEX]), - MAC2STR(sm->mlo.links[link_id].bssid)); +#ifdef CONFIG_TESTING_OPTIONS + if (sm->test_eapol_m4_elems) + extra_len = wpabuf_len(sm->test_eapol_m4_elems); + if (sm->encrypt_eapol_m4) { + pad_len = (kde_len + extra_len) % 8; + if (pad_len) + pad_len = 8 - pad_len; + extra_len += pad_len + 8; + } +#endif /* CONFIG_TESTING_OPTIONS */ + + mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len); + hdrlen = sizeof(*reply) + mic_len + 2; + rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, + hdrlen + kde_len + extra_len, &rlen, + (void *) &reply); + if (!rbuf) { + os_free(kde); + return -1; + } + + reply->type = (sm->proto == WPA_PROTO_RSN || + sm->proto == WPA_PROTO_OSEN) ? + EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; + key_info &= WPA_KEY_INFO_SECURE; + key_info |= ver | WPA_KEY_INFO_KEY_TYPE; + if (mic_len) + key_info |= WPA_KEY_INFO_MIC; + else + key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; +#ifdef CONFIG_TESTING_OPTIONS + if (sm->encrypt_eapol_m4) + key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; +#endif /* CONFIG_TESTING_OPTIONS */ + WPA_PUT_BE16(reply->key_info, key_info); + if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) + WPA_PUT_BE16(reply->key_length, 0); + else + os_memcpy(reply->key_length, key->key_length, 2); + os_memcpy(reply->replay_counter, key->replay_counter, + WPA_REPLAY_COUNTER_LEN); + + key_mic = (u8 *) (reply + 1); + /* Key Data length */ + WPA_PUT_BE16(key_mic + mic_len, kde_len + extra_len); + if (kde) { + os_memcpy(key_mic + mic_len + 2, kde, kde_len); /* Key Data */ + os_free(kde); + } + +#ifdef CONFIG_TESTING_OPTIONS + if (sm->test_eapol_m4_elems) { + os_memcpy(key_mic + mic_len + 2 + kde_len, + wpabuf_head(sm->test_eapol_m4_elems), + wpabuf_len(sm->test_eapol_m4_elems)); + } + + if (sm->encrypt_eapol_m4) { + u8 *plain; + size_t plain_len; + + if (sm->test_eapol_m4_elems) + extra_len = wpabuf_len(sm->test_eapol_m4_elems); + else + extra_len = 0; + plain_len = kde_len + extra_len + pad_len; + plain = os_memdup(key_mic + mic_len + 2, plain_len); + if (!plain) { + os_free(rbuf); + return -1; + } + if (pad_len) + plain[plain_len - pad_len] = 0xdd; + + wpa_hexdump_key(MSG_DEBUG, "RSN: AES-WRAP using KEK", + ptk->kek, ptk->kek_len); + if (aes_wrap(ptk->kek, ptk->kek_len, plain_len / 8, plain, + key_mic + mic_len + 2)) { + os_free(plain); + os_free(rbuf); + return -1; + } + wpa_hexdump(MSG_DEBUG, + "RSN: Encrypted Key Data from AES-WRAP", + key_mic + mic_len + 2, plain_len + 8); + os_free(plain); + } +#endif /* CONFIG_TESTING_OPTIONS */ + + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4"); + return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen, + key_mic); +} + + +static int wpa_supplicant_validate_link_kde(struct wpa_sm *sm, u8 link_id, + const u8 *link_kde, + size_t link_kde_len) +{ + size_t rsne_len = 0, rsnxe_len = 0; + const u8 *rsne = NULL, *rsnxe = NULL; + + if (!link_kde || + link_kde_len < RSN_MLO_LINK_KDE_LINK_MAC_INDEX + ETH_ALEN) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: MLO Link KDE is not found for link ID %d", + link_id); + return -1; + } + + if (!ether_addr_equal(sm->mlo.links[link_id].bssid, + &link_kde[RSN_MLO_LINK_KDE_LINK_MAC_INDEX])) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: MLO Link %u MAC address (" MACSTR + ") not matching association response (" MACSTR ")", + link_id, + MAC2STR(&link_kde[RSN_MLO_LINK_KDE_LINK_MAC_INDEX]), + MAC2STR(sm->mlo.links[link_id].bssid)); return -1; } @@ -2231,6 +2499,7 @@ static int wpa_supplicant_validate_link_kde(struct wpa_sm *sm, u8 link_id, return 0; } + static int wpa_validate_mlo_ieee80211w_kdes(struct wpa_sm *sm, u8 link_id, struct wpa_eapol_ie_parse *ie) @@ -2258,83 +2527,75 @@ static int wpa_validate_mlo_ieee80211w_kdes(struct wpa_sm *sm, return 0; } -#endif -#ifdef CONFIG_MLD_PATCH -/** - * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @dst: Destination address for the frame - * @key: Pointer to the EAPOL-Key frame header - * @ver: Version bits from EAPOL-Key Key Info - * @key_info: Key Info - * @ptk: PTK to use for keyed hash and encryption - * Returns: >= 0 on success, < 0 on failure - */ -int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, - const struct wpa_eapol_key *key, - u16 ver, u16 key_info, - struct wpa_ptk *ptk) + + +static void wpa_supplicant_process_3_of_4_wpa(struct wpa_sm *sm, + const struct wpa_eapol_key *key, + u16 ver, const u8 *key_data, + size_t key_data_len) { - size_t mic_len, hdrlen, rlen; - struct wpa_eapol_key *reply; - u8 *rbuf, *key_mic; - u8 *kde = NULL; - size_t kde_len = 0; + u16 key_info, keylen; + struct wpa_eapol_ie_parse ie; - if (sm->mlo.valid_links) { - u8 *pos; + wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: RX message 3 of 4-Way Handshake from " MACSTR + " (ver=%d)", MAC2STR(sm->bssid), ver); - kde = os_malloc(RSN_SELECTOR_LEN + ETH_ALEN + 2); - if (!kde) - return -1; + key_info = WPA_GET_BE16(key->key_info); - /* Add MAC KDE */ - wpa_printf(MSG_DEBUG, "MLO: Add MAC KDE into EAPOL-Key 4/4"); - pos = kde; - pos = rsn_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->own_addr, - ETH_ALEN); - kde_len = pos - kde; + wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", key_data, key_data_len); + if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) + goto failed; + + if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) + goto failed; + + if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: ANonce from message 1 of 4-Way Handshake differs from 3 of 4-Way Handshake - drop packet (src=" + MACSTR ")", MAC2STR(sm->bssid)); + goto failed; } - mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len); - hdrlen = sizeof(*reply) + mic_len + 2; - rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - hdrlen + kde_len, &rlen, (void *) &reply); - if (!rbuf) { - os_free(kde); - return -1; + keylen = WPA_GET_BE16(key->key_length); + if (keylen != wpa_cipher_key_len(sm->pairwise_cipher)) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Invalid %s key length %d (src=" MACSTR ")", + wpa_cipher_txt(sm->pairwise_cipher), keylen, + MAC2STR(sm->bssid)); + goto failed; } - reply->type = (sm->proto == WPA_PROTO_RSN || - sm->proto == WPA_PROTO_OSEN) ? - EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; - key_info &= WPA_KEY_INFO_SECURE; - key_info |= ver | WPA_KEY_INFO_KEY_TYPE; - if (mic_len) - key_info |= WPA_KEY_INFO_MIC; - else - key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; - WPA_PUT_BE16(reply->key_info, key_info); - if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) - WPA_PUT_BE16(reply->key_length, 0); - else - os_memcpy(reply->key_length, key->key_length, 2); - os_memcpy(reply->replay_counter, key->replay_counter, - WPA_REPLAY_COUNTER_LEN); + if (wpa_supplicant_send_4_of_4(sm, wpa_sm_get_auth_addr(sm), key, ver, + key_info, &sm->ptk) < 0) + goto failed; - key_mic = (u8 *) (reply + 1); - /* Key Data length */ - WPA_PUT_BE16(key_mic + mic_len, kde_len); - if (kde) { - os_memcpy(key_mic + mic_len + 2, kde, kde_len); /* Key Data */ - os_free(kde); + /* SNonce was successfully used in msg 3/4, so mark it to be renewed + * for the next 4-Way Handshake. If msg 3 is received again, the old + * SNonce will still be used to avoid changing PTK. */ + sm->renew_snonce = 1; + + if ((key_info & WPA_KEY_INFO_INSTALL) && + wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX_TX)) + goto failed; + + if (key_info & WPA_KEY_INFO_SECURE) { + wpa_sm_mlme_setprotection( + sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX, + MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); + eapol_sm_notify_portValid(sm->eapol, true); } + wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4"); - return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen, - key_mic); + sm->msg_3_of_4_ok = 1; + return; + +failed: + wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); } + static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, const struct wpa_eapol_key *key, u16 ver, const u8 *key_data, @@ -2357,9 +2618,28 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, key_info = WPA_GET_BE16(key->key_info); wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", key_data, key_data_len); - if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) { - + if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) goto failed; + + if (sm->ssid_protection) { + if (!ie.ssid) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: No SSID included in EAPOL-Key msg 3/4"); + goto failed; + } + + if (ie.ssid_len != sm->ssid_len || + os_memcmp(ie.ssid, sm->ssid, sm->ssid_len) != 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: SSID mismatch in EAPOL-Key msg 3/4"); + wpa_hexdump_ascii(MSG_DEBUG, "RSN: Received SSID", + ie.ssid, ie.ssid_len); + wpa_hexdump_ascii(MSG_DEBUG, "RSN: Expected SSID", + sm->ssid, sm->ssid_len); + goto failed; + } + + wpa_sm_ssid_verified(sm); } if (mlo && !ie.valid_mlo_gtks) { @@ -2407,6 +2687,12 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, goto failed; } +#ifdef CONFIG_IEEE80211R + if (mlo && wpa_key_mgmt_ft(sm->key_mgmt) && + wpa_supplicant_validate_ie_ft(sm, sm->bssid, &ie) < 0) + goto failed; +#endif /* CONFIG_IEEE80211R */ + if (!mlo && ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: GTK IE in unencrypted key data"); @@ -2532,7 +2818,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, P2P_CHR_DEFAULT_REASON_CODE, P2P_CHR_DEFAULT_REASON_CODE); #endif if (mlo) { - if (wpa_supplicant_pairwise_mlo_gtk(sm, key, &ie, key_info) < 0) { + if (wpa_supplicant_pairwise_mlo_gtk(sm, key, &ie, + key_info) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "MLO RSN: Failed to configure MLO GTKs"); goto failed; @@ -2590,38 +2877,41 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, failed: wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); } -#else /* CONFIG_MLD_PATCH */ -/** - * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @dst: Destination address for the frame - * @key: Pointer to the EAPOL-Key frame header - * @ver: Version bits from EAPOL-Key Key Info - * @key_info: Key Info - * @ptk: PTK to use for keyed hash and encryption - * Returns: >= 0 on success, < 0 on failure - */ -int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, - const struct wpa_eapol_key *key, - u16 ver, u16 key_info, - struct wpa_ptk *ptk) + + +static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, + const struct wpa_eapol_key *key, + int ver, u16 key_info) { size_t mic_len, hdrlen, rlen; struct wpa_eapol_key *reply; u8 *rbuf, *key_mic; + size_t kde_len = 0; + +#ifdef CONFIG_TESTING_OPTIONS + if (sm->disable_eapol_g2_tx) { + wpa_printf(MSG_INFO, "TEST: Disable sending EAPOL-Key 2/2"); + return 0; + } +#endif /* CONFIG_TESTING_OPTIONS */ + +#ifdef CONFIG_OCV + if (wpa_sm_ocv_enabled(sm)) + kde_len = OCV_OCI_KDE_LEN; +#endif /* CONFIG_OCV */ mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len); hdrlen = sizeof(*reply) + mic_len + 2; rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - hdrlen, &rlen, (void *) &reply); + hdrlen + kde_len, &rlen, (void *) &reply); if (rbuf == NULL) return -1; reply->type = (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) ? EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; - key_info &= WPA_KEY_INFO_SECURE; - key_info |= ver | WPA_KEY_INFO_KEY_TYPE; + key_info &= WPA_KEY_INFO_KEY_INDEX_MASK; + key_info |= ver | WPA_KEY_INFO_SECURE; if (mic_len) key_info |= WPA_KEY_INFO_MIC; else @@ -2635,433 +2925,12 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, WPA_REPLAY_COUNTER_LEN); key_mic = (u8 *) (reply + 1); - WPA_PUT_BE16(key_mic + mic_len, 0); - - wpa_dbg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Sending EAPOL-Key 4/4"); - return wpa_eapol_key_send(sm, ptk, ver, dst, ETH_P_EAPOL, rbuf, rlen, - key_mic); -} - -static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, - const struct wpa_eapol_key *key, - u16 ver, const u8 *key_data, - size_t key_data_len) -{ - u16 key_info, keylen; - struct wpa_eapol_ie_parse ie; + WPA_PUT_BE16(key_mic + mic_len, kde_len); /* Key Data Length */ - wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); -#ifdef CONFIG_P2P_CHR - wpa_supplicant_upload_p2p_state(sm->ctx->ctx, P2P_INTERFACE_STATE_4WAY_HANDSHAKE_3, - P2P_CHR_DEFAULT_REASON_CODE, P2P_CHR_DEFAULT_REASON_CODE); -#endif - wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 3 of 4-Way " - "Handshake from " MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver); - wpa_printf(MSG_DEBUG, "WPA: RX message 3 of 4-Way " - "Handshake from " MACSTR_SEC " (ver=%d)", MAC2STR_SEC(sm->bssid), ver); - - key_info = WPA_GET_BE16(key->key_info); - - wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", key_data, key_data_len); - if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) - goto failed; - if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: GTK IE in unencrypted key data"); - goto failed; - } - if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: IGTK KDE in unencrypted key data"); - goto failed; - } - - 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)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Invalid IGTK KDE length %lu", - (unsigned long) ie.igtk_len); - goto failed; - } - - if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) - goto failed; - - if (wpa_handle_ext_key_id(sm, &ie)) - goto failed; - - if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { - wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: ANonce from message 1 of 4-Way Handshake " - "differs from 3 of 4-Way Handshake - drop packet (src=" - MACSTR ")", MAC2STR(sm->bssid)); - wpa_printf(MSG_WARNING, "WPA: ANonce from message 1 of 4-Way Handshake " - "differs from 3 of 4-Way Handshake - drop packet (src=" - MACSTR_SEC ")", MAC2STR_SEC(sm->bssid)); - goto failed; - } - - keylen = WPA_GET_BE16(key->key_length); - if (keylen != wpa_cipher_key_len(sm->pairwise_cipher)) { - wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Invalid %s key length %d (src=" MACSTR - ")", wpa_cipher_txt(sm->pairwise_cipher), keylen, - MAC2STR(sm->bssid)); - wpa_printf(MSG_WARNING, "WPA: Invalid %s key length %d (src=" MACSTR_SEC - ")", wpa_cipher_txt(sm->pairwise_cipher), keylen, - MAC2STR_SEC(sm->bssid)); - goto failed; - } - -#ifdef CONFIG_P2P - if (ie.ip_addr_alloc) { - os_memcpy(sm->p2p_ip_addr, ie.ip_addr_alloc, 3 * 4); - wpa_hexdump(MSG_DEBUG, "P2P: IP address info", - sm->p2p_ip_addr, sizeof(sm->p2p_ip_addr)); - } -#endif /* CONFIG_P2P */ - -#ifdef CONFIG_OCV - if (wpa_sm_ocv_enabled(sm)) { - struct wpa_channel_info ci; - - if (wpa_sm_channel_info(sm, &ci) != 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "Failed to get channel info to validate received OCI in EAPOL-Key 3/4"); - return; - } - - if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci, - channel_width_to_int(ci.chanwidth), - 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; - } - } -#endif /* CONFIG_OCV */ - -#ifdef CONFIG_DPP2 - if (DPP_VERSION > 1 && ie.dpp_kde) { - wpa_printf(MSG_DEBUG, - "DPP: peer Protocol Version %u Flags 0x%x", - ie.dpp_kde[0], ie.dpp_kde[1]); - if (sm->key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_pfs != 2 && - (ie.dpp_kde[1] & DPP_KDE_PFS_ALLOWED) && !sm->dpp_z) { - wpa_printf(MSG_INFO, - "DPP: Peer indicated it supports PFS and local configuration allows this, but PFS was not negotiated for the association"); - goto failed; - } - } -#endif /* CONFIG_DPP2 */ - - if (sm->use_ext_key_id && - wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX)) - goto failed; - - if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, - &sm->ptk) < 0) { - goto failed; - } - - /* SNonce was successfully used in msg 3/4, so mark it to be renewed - * for the next 4-Way Handshake. If msg 3 is received again, the old - * SNonce will still be used to avoid changing PTK. */ - sm->renew_snonce = 1; - - if (key_info & WPA_KEY_INFO_INSTALL) { - int res; - - if (sm->use_ext_key_id) - res = wpa_supplicant_activate_ptk(sm); - else - res = wpa_supplicant_install_ptk(sm, key, - KEY_FLAG_RX_TX); - if (res) - goto failed; - } - - if (key_info & WPA_KEY_INFO_SECURE) { - wpa_sm_mlme_setprotection( - sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX, - MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); - eapol_sm_notify_portValid(sm->eapol, true); - } - wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); -#ifdef CONFIG_P2P_CHR - wpa_supplicant_upload_p2p_state(sm->ctx->ctx, P2P_INTERFACE_STATE_GROUP_HANDSHAKE, - P2P_CHR_DEFAULT_REASON_CODE, P2P_CHR_DEFAULT_REASON_CODE); -#endif - if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) { - /* No GTK to be set to the driver */ - } else if (!ie.gtk && sm->proto == WPA_PROTO_RSN) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: No GTK KDE included in EAPOL-Key msg 3/4"); - goto failed; - } else if (ie.gtk && - wpa_supplicant_pairwise_gtk(sm, key, - ie.gtk, ie.gtk_len, key_info) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: Failed to configure GTK"); - goto failed; - } - - if (ieee80211w_set_keys(sm, &ie) < 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "RSN: Failed to configure IGTK"); - goto failed; - } - - if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED || ie.gtk) - wpa_supplicant_key_neg_complete(sm, sm->bssid, - key_info & WPA_KEY_INFO_SECURE); - - if (ie.gtk) - wpa_sm_set_rekey_offload(sm); - - /* Add PMKSA cache entry for Suite B AKMs here since PMKID can be - * calculated only after KCK has been derived. Though, do not replace an - * existing PMKSA entry after each 4-way handshake (i.e., new KCK/PMKID) - * to avoid unnecessary changes of PMKID while continuing to use the - * same PMK. */ - if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt) && - !sm->cur_pmksa) { - struct rsn_pmksa_cache_entry *sa; - - sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, NULL, - sm->ptk.kck, sm->ptk.kck_len, - sm->bssid, sm->own_addr, - sm->network_ctx, sm->key_mgmt, NULL); - if (!sm->cur_pmksa) - sm->cur_pmksa = sa; - } - - if (ie.transition_disable) - wpa_sm_transition_disable(sm, ie.transition_disable[0]); - sm->msg_3_of_4_ok = 1; - return; - -failed: - wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); -} -#endif /* end CONFIG_MLD_PATCH */ - -static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm, - const u8 *keydata, - size_t keydatalen, - u16 key_info, - struct wpa_gtk_data *gd) -{ - int maxkeylen; - struct wpa_eapol_ie_parse ie; - u16 gtk_len; - - wpa_hexdump_key(MSG_DEBUG, "RSN: msg 1/2 key data", - keydata, keydatalen); - if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0) - return -1; - if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: GTK IE in unencrypted key data"); - return -1; - } - if (ie.gtk == NULL) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: No GTK IE in Group Key msg 1/2"); - return -1; - } - 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)) { - struct wpa_channel_info ci; - - if (wpa_sm_channel_info(sm, &ci) != 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "Failed to get channel info to validate received OCI in EAPOL-Key group msg 1/2"); - return -1; - } - - if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci, - channel_width_to_int(ci.chanwidth), - 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, - 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, 2 + gtk_len); - gd->keyidx = ie.gtk[0] & 0x3; - gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm, - !!(ie.gtk[0] & BIT(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, - "RSN: Failed to configure IGTK"); - - return 0; -} - - -static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, - const struct wpa_eapol_key *key, - const u8 *key_data, - size_t key_data_len, u16 key_info, - u16 ver, struct wpa_gtk_data *gd) -{ - size_t maxkeylen; - u16 gtk_len; - - gtk_len = WPA_GET_BE16(key->key_length); - maxkeylen = key_data_len; - if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { - if (maxkeylen < 8) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Too short maxkeylen (%lu)", - (unsigned long) maxkeylen); - return -1; - } - maxkeylen -= 8; - } - - if (gtk_len > maxkeylen || - wpa_supplicant_check_group_cipher(sm, sm->group_cipher, - gtk_len, maxkeylen, - &gd->key_rsc_len, &gd->alg)) - return -1; - - gd->gtk_len = gtk_len; - gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> - WPA_KEY_INFO_KEY_INDEX_SHIFT; - if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) { -#ifdef CONFIG_NO_RC4 - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: RC4 not supported in the build"); - return -1; -#else /* CONFIG_NO_RC4 */ - u8 ek[32]; - if (key_data_len > sizeof(gd->gtk)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: RC4 key data too long (%lu)", - (unsigned long) key_data_len); - return -1; - } - os_memcpy(ek, key->key_iv, 16); - os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len); - os_memcpy(gd->gtk, key_data, key_data_len); - if (rc4_skip(ek, 32, 256, gd->gtk, key_data_len)) { - forced_memzero(ek, sizeof(ek)); - wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, - "WPA: RC4 failed"); - return -1; - } - forced_memzero(ek, sizeof(ek)); -#endif /* CONFIG_NO_RC4 */ - } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { - if (maxkeylen % 8) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Unsupported AES-WRAP len %lu", - (unsigned long) maxkeylen); - return -1; - } - if (maxkeylen > sizeof(gd->gtk)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: AES-WRAP key data " - "too long (keydatalen=%lu maxkeylen=%lu)", - (unsigned long) key_data_len, - (unsigned long) maxkeylen); - return -1; - } - if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, maxkeylen / 8, - key_data, gd->gtk)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: AES unwrap failed - could not decrypt " - "GTK"); - return -1; - } - } else { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Unsupported key_info type %d", ver); - return -1; - } - gd->tx = wpa_supplicant_gtk_tx_bit_workaround( - sm, !!(key_info & WPA_KEY_INFO_TXRX)); - return 0; -} - - -static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, - const struct wpa_eapol_key *key, - int ver, u16 key_info) -{ - size_t mic_len, hdrlen, rlen; - struct wpa_eapol_key *reply; - u8 *rbuf, *key_mic; - size_t kde_len = 0; - -#ifdef CONFIG_OCV - if (wpa_sm_ocv_enabled(sm)) - kde_len = OCV_OCI_KDE_LEN; -#endif /* CONFIG_OCV */ - - mic_len = wpa_mic_len(sm->key_mgmt, sm->pmk_len); - hdrlen = sizeof(*reply) + mic_len + 2; - rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - hdrlen + kde_len, &rlen, (void *) &reply); - if (rbuf == NULL) - return -1; - - reply->type = (sm->proto == WPA_PROTO_RSN || - sm->proto == WPA_PROTO_OSEN) ? - EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA; - key_info &= WPA_KEY_INFO_KEY_INDEX_MASK; - key_info |= ver | WPA_KEY_INFO_SECURE; - if (mic_len) - key_info |= WPA_KEY_INFO_MIC; - else - key_info |= WPA_KEY_INFO_ENCR_KEY_DATA; - WPA_PUT_BE16(reply->key_info, key_info); - if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) - WPA_PUT_BE16(reply->key_length, 0); - else - os_memcpy(reply->key_length, key->key_length, 2); - os_memcpy(reply->replay_counter, key->replay_counter, - WPA_REPLAY_COUNTER_LEN); - - key_mic = (u8 *) (reply + 1); - WPA_PUT_BE16(key_mic + mic_len, kde_len); /* Key Data Length */ - -#ifdef CONFIG_OCV - if (wpa_sm_ocv_enabled(sm)) { - struct wpa_channel_info ci; - u8 *pos; +#ifdef CONFIG_OCV + if (wpa_sm_ocv_enabled(sm)) { + struct wpa_channel_info ci; + u8 *pos; if (wpa_sm_channel_info(sm, &ci) != 0) { wpa_printf(MSG_WARNING, @@ -3088,11 +2957,11 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, #endif /* CONFIG_OCV */ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2"); - return wpa_eapol_key_send(sm, &sm->ptk, ver, sm->bssid, ETH_P_EAPOL, - rbuf, rlen, key_mic); + return wpa_eapol_key_send(sm, &sm->ptk, ver, wpa_sm_get_auth_addr(sm), + ETH_P_EAPOL, rbuf, rlen, key_mic); } -#ifdef CONFIG_MLD_PATCH + static void wpa_supplicant_process_mlo_1_of_2(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, @@ -3159,9 +3028,7 @@ static void wpa_supplicant_process_mlo_1_of_2(struct wpa_sm *sm, wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "MLO RSN: Failed to configure MLO IGTK"); - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(sm->mlo.valid_links & BIT(i))) - continue; + for_each_link(sm->mlo.valid_links, i) { /* * AP may send group keys for subset of the all links during * rekey @@ -3190,7 +3057,144 @@ static void wpa_supplicant_process_mlo_1_of_2(struct wpa_sm *sm, failed: wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); } -#endif + + +static void wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, + const unsigned char *src_addr, + const struct wpa_eapol_key *key, + const u8 *key_data, + size_t key_data_len, u16 ver) +{ + u16 key_info; + int rekey; + struct wpa_gtk_data gd; + const u8 *key_rsc; + size_t maxkeylen; + u16 gtk_len; + + if (!sm->msg_3_of_4_ok) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: Group Key Handshake started prior to completion of 4-way handshake"); + goto failed; + } + + os_memset(&gd, 0, sizeof(gd)); + + rekey = wpa_sm_get_state(sm) == WPA_COMPLETED; + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: RX message 1 of Group Key Handshake from " MACSTR + " (ver=%d)", MAC2STR(src_addr), ver); + + key_info = WPA_GET_BE16(key->key_info); + + gtk_len = WPA_GET_BE16(key->key_length); + maxkeylen = key_data_len; + if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + if (maxkeylen < 8) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: Too short maxkeylen (%lu)", + (unsigned long) maxkeylen); + goto failed; + } + maxkeylen -= 8; + } + + if (gtk_len > maxkeylen || + wpa_supplicant_check_group_cipher(sm, sm->group_cipher, + gtk_len, maxkeylen, + &gd.key_rsc_len, &gd.alg)) + goto failed; + + wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); + + gd.gtk_len = gtk_len; + gd.keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> + WPA_KEY_INFO_KEY_INDEX_SHIFT; + if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) { +#if defined(CONFIG_NO_RC4) || defined(CONFIG_FIPS) + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: RC4 not supported in the build"); + goto failed; +#else /* CONFIG_NO_RC4 || CONFIG_FIPS */ + u8 ek[32]; + if (key_data_len > sizeof(gd.gtk)) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: RC4 key data too long (%lu)", + (unsigned long) key_data_len); + goto failed; + } + os_memcpy(ek, key->key_iv, 16); + os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len); + os_memcpy(gd.gtk, key_data, key_data_len); + if (rc4_skip(ek, 32, 256, gd.gtk, key_data_len)) { + forced_memzero(ek, sizeof(ek)); + wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, + "WPA: RC4 failed"); + goto failed; + } + forced_memzero(ek, sizeof(ek)); +#endif /* CONFIG_NO_RC4 || CONFIG_FIPS */ + } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + if (maxkeylen % 8) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Unsupported AES-WRAP len %lu", + (unsigned long) maxkeylen); + goto failed; + } + if (maxkeylen > sizeof(gd.gtk)) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: AES-WRAP key data " + "too long (keydatalen=%lu maxkeylen=%lu)", + (unsigned long) key_data_len, + (unsigned long) maxkeylen); + goto failed; + } + if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, maxkeylen / 8, + key_data, gd.gtk)) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: AES unwrap failed - could not decrypt " + "GTK"); + goto failed; + } + } else { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Unsupported key_info type %d", ver); + goto failed; + } + gd.tx = wpa_supplicant_gtk_tx_bit_workaround( + sm, !!(key_info & WPA_KEY_INFO_TXRX)); + + key_rsc = key->key_rsc; + if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc)) + key_rsc = null_rsc; + + if (wpa_supplicant_install_gtk(sm, &gd, key_rsc, 0) || + wpa_supplicant_send_2_of_2(sm, key, ver, key_info) < 0) + goto failed; + forced_memzero(&gd, sizeof(gd)); + + if (rekey) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: Group rekeying completed with " MACSTR + " [GTK=%s]", + MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher)); + wpa_sm_cancel_auth_timeout(sm); + wpa_sm_set_state(sm, WPA_COMPLETED); + } else { + wpa_supplicant_key_neg_complete(sm, sm->bssid, + key_info & WPA_KEY_INFO_SECURE); + } + + wpa_sm_set_rekey_offload(sm); + + return; + +failed: + forced_memzero(&gd, sizeof(gd)); + wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED); +} + + static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, @@ -3198,19 +3202,20 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, size_t key_data_len, u16 ver) { u16 key_info; - int rekey, ret; struct wpa_gtk_data gd; const u8 *key_rsc; + int maxkeylen; + struct wpa_eapol_ie_parse ie; + u16 gtk_len; if (!sm->msg_3_of_4_ok && !wpa_fils_is_completed(sm)) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Group Key Handshake started prior to completion of 4-way handshake"); + "RSN: Group Key Handshake started prior to completion of 4-way handshake"); goto failed; } os_memset(&gd, 0, sizeof(gd)); - rekey = wpa_sm_get_state(sm) == WPA_COMPLETED; wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of Group Key " "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); wpa_printf(MSG_DEBUG, "WPA: RX message 1 of Group Key " @@ -3218,21 +3223,75 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, key_info = WPA_GET_BE16(key->key_info); - if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) { - ret = wpa_supplicant_process_1_of_2_rsn(sm, key_data, - key_data_len, key_info, - &gd); - } else { - ret = wpa_supplicant_process_1_of_2_wpa(sm, key, key_data, - key_data_len, - key_info, ver, &gd); - } + wpa_hexdump_key(MSG_DEBUG, "RSN: msg 1/2 key data", + key_data, key_data_len); + if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) + goto failed; wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); - if (ret) + if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "RSN: GTK KDE in unencrypted key data"); + goto failed; + } + if (!ie.gtk) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: No GTK KDE in Group Key msg 1/2"); + goto failed; + } + 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); + goto failed; + } + 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); + goto failed; + } + maxkeylen = gd.gtk_len = gtk_len; + +#ifdef CONFIG_OCV + if (wpa_sm_ocv_enabled(sm)) { + struct wpa_channel_info ci; + + if (wpa_sm_channel_info(sm, &ci) != 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "Failed to get channel info to validate received OCI in EAPOL-Key group msg 1/2"); + goto failed; + } + + if (ocv_verify_tx_params(ie.oci, ie.oci_len, &ci, + channel_width_to_int(ci.chanwidth), + 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); + goto failed; + } + } +#endif /* CONFIG_OCV */ + + if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher, + gtk_len, maxkeylen, + &gd.key_rsc_len, &gd.alg)) goto failed; + wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in group key handshake", + 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))); + os_memcpy(gd.gtk, ie.gtk + 2, gtk_len); + + if (ieee80211w_set_keys(sm, &ie) < 0) + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: Failed to configure IGTK"); + key_rsc = key->key_rsc; if (wpa_supplicant_rsc_relaxation(sm, key->key_rsc)) key_rsc = null_rsc; @@ -3242,20 +3301,14 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, goto failed; forced_memzero(&gd, sizeof(gd)); - if (rekey) { - wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying " - "completed with " MACSTR " [GTK=%s]", - MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher)); - wpa_printf(MSG_INFO, "WPA: Group rekeying " - "completed with " MACSTR_SEC " [GTK=%s]", - MAC2STR_SEC(sm->bssid), wpa_cipher_txt(sm->group_cipher)); - wpa_sm_cancel_auth_timeout(sm); - wpa_sm_set_state(sm, WPA_COMPLETED); - } else { - wpa_supplicant_key_neg_complete(sm, sm->bssid, - key_info & - WPA_KEY_INFO_SECURE); - } + wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying " + "completed with " MACSTR " [GTK=%s]", + MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher)); + wpa_printf(MSG_INFO, "WPA: Group rekeying " + "completed with " MACSTR_SEC " [GTK=%s]", + MAC2STR_SEC(sm->bssid), wpa_cipher_txt(sm->group_cipher)); + wpa_sm_cancel_auth_timeout(sm); + wpa_sm_set_state(sm, WPA_COMPLETED); wpa_sm_set_rekey_offload(sm); @@ -3365,11 +3418,11 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, /* Decrypt key data here so that this operation does not need * to be implemented separately for each message type. */ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) { -#ifdef CONFIG_NO_RC4 +#if defined(CONFIG_NO_RC4) || defined(CONFIG_FIPS) wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: RC4 not supported in the build"); return -1; -#else /* CONFIG_NO_RC4 */ +#else /* CONFIG_NO_RC4 || CONFIG_FIPS */ u8 ek[32]; wpa_printf(MSG_DEBUG, "WPA: Decrypt Key Data using RC4"); @@ -3382,7 +3435,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, return -1; } forced_memzero(ek, sizeof(ek)); -#endif /* CONFIG_NO_RC4 */ +#endif /* CONFIG_NO_RC4 || CONFIG_FIPS */ } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || ver == WPA_KEY_INFO_TYPE_AES_128_CMAC || wpa_use_aes_key_wrap(sm->key_mgmt)) { @@ -3568,12 +3621,95 @@ static int wpa_supp_aead_decrypt(struct wpa_sm *sm, u8 *buf, size_t buf_len, #endif /* CONFIG_FILS */ +static int wpa_sm_rx_eapol_wpa(struct wpa_sm *sm, const u8 *src_addr, + struct wpa_eapol_key *key, + enum frame_encryption encrypted, + const u8 *tmp, size_t data_len, + u8 *key_data, size_t key_data_len) +{ + u16 key_info, ver; + + key_info = WPA_GET_BE16(key->key_info); + + if (key->type != EAPOL_KEY_TYPE_WPA) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: Unsupported EAPOL-Key type %d", key->type); + return -1; + } + + ver = key_info & WPA_KEY_INFO_TYPE_MASK; + if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && + ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: Unsupported EAPOL-Key descriptor version %d", + ver); + return -1; + } + + if (sm->pairwise_cipher == WPA_CIPHER_CCMP && + ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: CCMP is used, but EAPOL-Key descriptor version (%d) is not 2", + ver); + if (sm->group_cipher != WPA_CIPHER_CCMP && + !(key_info & WPA_KEY_INFO_KEY_TYPE)) { + /* Earlier versions of IEEE 802.11i did not explicitly + * require version 2 descriptor for all EAPOL-Key + * packets, so allow group keys to use version 1 if + * CCMP is not used for them. */ + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: Backwards compatibility: allow invalid version for non-CCMP group keys"); + } else + return -1; + } + + if ((key_info & WPA_KEY_INFO_MIC) && + wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len)) + return -1; + + if (key_info & WPA_KEY_INFO_KEY_TYPE) { + if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Ignored EAPOL-Key (Pairwise) with non-zero key index"); + return -1; + } + if (key_info & (WPA_KEY_INFO_MIC | + WPA_KEY_INFO_ENCR_KEY_DATA)) { + /* 3/4 4-Way Handshake */ + wpa_supplicant_process_3_of_4_wpa(sm, key, ver, + key_data, + key_data_len); + } else { + /* 1/4 4-Way Handshake */ + wpa_supplicant_process_1_of_4_wpa(sm, src_addr, key, + ver, key_data, + key_data_len, + encrypted); + } + } else { + if (key_info & WPA_KEY_INFO_MIC) { + /* 1/2 Group Key Handshake */ + wpa_supplicant_process_1_of_2_wpa(sm, src_addr, key, + key_data, + key_data_len, + ver); + } else { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: EAPOL-Key (Group) without Mic/Encr bit - dropped"); + } + } + + return 1; +} + + /** * wpa_sm_rx_eapol - Process received WPA EAPOL frames * @sm: Pointer to WPA state machine data from wpa_sm_init() * @src_addr: Source MAC address of the EAPOL packet * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) * @len: Length of the EAPOL frame + * @encrypted: Whether the frame was encrypted * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure * * This function is called for each received EAPOL frame. Other than EAPOL-Key @@ -3585,7 +3721,7 @@ static int wpa_supp_aead_decrypt(struct wpa_sm *sm, u8 *buf, size_t buf_len, * successful key handshake. */ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) + const u8 *buf, size_t len, enum frame_encryption encrypted) { size_t plen, data_len, key_data_len; const struct ieee802_1x_hdr *hdr; @@ -3678,19 +3814,77 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, goto out; } + if (sm->rx_replay_counter_set && + os_memcmp(key->replay_counter, sm->rx_replay_counter, + WPA_REPLAY_COUNTER_LEN) <= 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: EAPOL-Key Replay Counter did not increase - dropping packet"); + goto out; + } + eapol_sm_notify_lower_layer_success(sm->eapol, 0); + key_info = WPA_GET_BE16(key->key_info); + + if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: Unsupported SMK bit in key_info"); + goto out; + } + + if (!(key_info & WPA_KEY_INFO_ACK)) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: No Ack bit in key_info"); + goto out; + } + + if (key_info & WPA_KEY_INFO_REQUEST) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: EAPOL-Key with Request bit - dropped"); + goto out; + } + + if (sm->proto == WPA_PROTO_WPA) { + ret = wpa_sm_rx_eapol_wpa(sm, src_addr, key, encrypted, + tmp, data_len, + key_data, key_data_len); + goto out; + } + + if (key->type != EAPOL_KEY_TYPE_RSN) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: Unsupported EAPOL-Key type %d", key->type); + goto out; + } + ver = key_info & WPA_KEY_INFO_TYPE_MASK; if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES && !wpa_use_akm_defined(sm->key_mgmt)) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Unsupported EAPOL-Key descriptor version %d", + "RSN: Unsupported EAPOL-Key descriptor version %d", + ver); + goto out; + } + + if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && + sm->pairwise_cipher != WPA_CIPHER_TKIP) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: EAPOL-Key descriptor version %d not allowed without TKIP as the pairwise cipher", ver); goto out; } + if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES && + (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X && + sm->key_mgmt != WPA_KEY_MGMT_PSK)) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: EAPOL-Key descriptor version %d not allowed due to negotiated AKM (0x%x)", + ver, sm->key_mgmt); + goto out; + } + if (wpa_use_akm_defined(sm->key_mgmt) && ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, @@ -3714,63 +3908,28 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC && !wpa_use_akm_defined(sm->key_mgmt)) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: AP did not use the " - "negotiated AES-128-CMAC"); + "RSN: AP did not use the negotiated AES-128-CMAC"); goto out; } } else if (sm->pairwise_cipher == WPA_CIPHER_CCMP && !wpa_use_akm_defined(sm->key_mgmt) && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: CCMP is used, but EAPOL-Key " - "descriptor version (%d) is not 2", ver); - if (sm->group_cipher != WPA_CIPHER_CCMP && - !(key_info & WPA_KEY_INFO_KEY_TYPE)) { - /* Earlier versions of IEEE 802.11i did not explicitly - * require version 2 descriptor for all EAPOL-Key - * packets, so allow group keys to use version 1 if - * CCMP is not used for them. */ + "RSN: CCMP is used, but EAPOL-Key descriptor version (%d) is not 2", ver); + if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Backwards compatibility: allow invalid " - "version for non-CCMP group keys"); - } else if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) { + "RSN: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger (is AES-128-CMAC), descriptor version to be used"); + } else { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger (is AES-128-CMAC), descriptor version to be used"); - } else + "RSN: Unexpected descriptor version %u", ver); goto out; + } } else if (sm->pairwise_cipher == WPA_CIPHER_GCMP && !wpa_use_akm_defined(sm->key_mgmt) && ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: GCMP is used, but EAPOL-Key " - "descriptor version (%d) is not 2", ver); - goto out; - } - - if (sm->rx_replay_counter_set && - os_memcmp(key->replay_counter, sm->rx_replay_counter, - WPA_REPLAY_COUNTER_LEN) <= 0) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: EAPOL-Key Replay Counter did not increase - " - "dropping packet"); - goto out; - } - - if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Unsupported SMK bit in key_info"); - goto out; - } - - if (!(key_info & WPA_KEY_INFO_ACK)) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: No Ack bit in key_info"); - goto out; - } - - if (key_info & WPA_KEY_INFO_REQUEST) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: EAPOL-Key with Request bit - dropped"); + "RSN: GCMP is used, but EAPOL-Key descriptor version (%d) is not 2", + ver); goto out; } @@ -3807,8 +3966,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, if (key_info & WPA_KEY_INFO_KEY_TYPE) { if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Ignored EAPOL-Key (Pairwise) with " - "non-zero key index"); + "RSN: Ignored EAPOL-Key (Pairwise) with non-zero key index"); goto out; } if (key_info & (WPA_KEY_INFO_MIC | @@ -3820,29 +3978,26 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, /* 1/4 4-Way Handshake */ wpa_supplicant_process_1_of_4(sm, src_addr, key, ver, key_data, - key_data_len); + key_data_len, + encrypted); } } else { if ((mic_len && (key_info & WPA_KEY_INFO_MIC)) || (!mic_len && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA))) { /* 1/2 Group Key Handshake */ -#ifdef CONFIG_MLD_PATCH - if (sm->mlo.valid_links) { + if (sm->mlo.valid_links) wpa_supplicant_process_mlo_1_of_2(sm, src_addr, key, key_data, key_data_len, ver); - } else -#endif - { - wpa_supplicant_process_1_of_2(sm, src_addr, key, - key_data, key_data_len, - ver); - } + else + wpa_supplicant_process_1_of_2(sm, src_addr, key, + key_data, + key_data_len, + ver); } else { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: EAPOL-Key (Group) without Mic/Encr bit - " - "dropped"); + "RSN: EAPOL-Key (Group) without Mic/Encr bit - dropped"); } } @@ -3887,6 +4042,8 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm) return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B; case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192: return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192; + case WPA_KEY_MGMT_IEEE8021X_SHA384: + return RSN_AUTH_KEY_MGMT_802_1X_SHA384; default: return 0; } @@ -4030,6 +4187,15 @@ static bool wpa_sm_pmksa_is_current_cb(struct rsn_pmksa_cache_entry *entry, } +static void wpa_sm_pmksa_notify_cb(struct rsn_pmksa_cache_entry *entry, + void *ctx) +{ + struct wpa_sm *sm = ctx; + + wpa_sm_notify_pmksa_cache_entry(sm, entry); +} + + /** * wpa_sm_init - Initialize WPA state machine * @ctx: Context pointer for callbacks; this needs to be an allocated buffer @@ -4057,7 +4223,8 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) #endif sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, - wpa_sm_pmksa_is_current_cb, sm, sm); + wpa_sm_pmksa_is_current_cb, + wpa_sm_pmksa_notify_cb, sm, sm); if (sm->pmksa == NULL) { wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, "RSN: PMKSA cache initialization failed"); @@ -4075,6 +4242,8 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) */ void wpa_sm_deinit(struct wpa_sm *sm) { + int i; + if (sm == NULL) return; pmksa_cache_deinit(sm->pmksa); @@ -4085,13 +4254,10 @@ void wpa_sm_deinit(struct wpa_sm *sm) os_free(sm->ap_wpa_ie); os_free(sm->ap_rsn_ie); os_free(sm->ap_rsnxe); -#ifdef CONFIG_MLD_PATCH - int i; for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { os_free(sm->mlo.links[i].ap_rsne); os_free(sm->mlo.links[i].ap_rsnxe); } -#endif wpa_sm_drop_sa(sm); os_free(sm->ctx); #ifdef CONFIG_IEEE80211R @@ -4099,6 +4265,8 @@ void wpa_sm_deinit(struct wpa_sm *sm) #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_TESTING_OPTIONS wpabuf_free(sm->test_assoc_ie); + wpabuf_free(sm->test_eapol_m2_elems); + wpabuf_free(sm->test_eapol_m4_elems); #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_FILS_SK_PFS crypto_ecdh_deinit(sm->fils_ecdh); @@ -4115,11 +4283,11 @@ void wpa_sm_deinit(struct wpa_sm *sm) os_free(sm); } + static void wpa_sm_clear_ptk(struct wpa_sm *sm) { -#ifdef CONFIG_MLD_PATCH int i; -#endif + sm->ptk_set = 0; os_memset(&sm->ptk, 0, sizeof(sm->ptk)); sm->tptk_set = 0; @@ -4130,7 +4298,7 @@ static void wpa_sm_clear_ptk(struct wpa_sm *sm) os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep)); os_memset(&sm->bigtk, 0, sizeof(sm->bigtk)); os_memset(&sm->bigtk_wnm_sleep, 0, sizeof(sm->bigtk_wnm_sleep)); -#ifdef CONFIG_MLD_PATCH + sm->tk_set = false; for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { os_memset(&sm->mlo.links[i].gtk, 0, sizeof(sm->mlo.links[i].gtk)); @@ -4145,9 +4313,9 @@ static void wpa_sm_clear_ptk(struct wpa_sm *sm) os_memset(&sm->mlo.links[i].bigtk_wnm_sleep, 0, sizeof(sm->mlo.links[i].bigtk_wnm_sleep)); } -#endif } + /** * wpa_sm_notify_assoc - Notify WPA state machine about association * @sm: Pointer to WPA state machine data from wpa_sm_init() @@ -4169,7 +4337,7 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN); sm->rx_replay_counter_set = 0; sm->renew_snonce = 1; - if (os_memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0) + if (ether_addr_equal(sm->preauth_bssid, bssid)) rsn_preauth_deinit(sm); #ifdef CONFIG_IEEE80211R @@ -4404,7 +4572,20 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) } -#ifdef CONFIG_MLD_PATCH +void wpa_sm_set_ssid(struct wpa_sm *sm, const u8 *ssid, size_t ssid_len) +{ + if (!sm) + return; + + if (ssid) { + os_memcpy(sm->ssid, ssid, ssid_len); + sm->ssid_len = ssid_len; + } else { + sm->ssid_len = 0; + } +} + + int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo) { int i; @@ -4422,6 +4603,15 @@ int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo) size_t len; if (sm->mlo.req_links & BIT(i)) { + if (!mlo->links[i].ap_rsne || + mlo->links[i].ap_rsne_len == 0) { + wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: No RSNE for AP MLO link %d with BSSID " + MACSTR, + i, MAC2STR(mlo->links[i].bssid)); + return -1; + + } os_memcpy(sm->mlo.links[i].addr, mlo->links[i].addr, ETH_ALEN); os_memcpy(sm->mlo.links[i].bssid, mlo->links[i].bssid, @@ -4433,7 +4623,7 @@ int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo) os_free(sm->mlo.links[i].ap_rsne); if (!ie || len == 0) { if (sm->mlo.links[i].ap_rsne) - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Clearing MLO link[%u] AP RSNE", i); sm->mlo.links[i].ap_rsne = NULL; @@ -4473,7 +4663,7 @@ int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo) return 0; } -#endif + /** * wpa_sm_set_own_addr - Set own MAC address @@ -4604,12 +4794,30 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, case WPA_PARAM_OCI_FREQ_FILS_ASSOC: sm->oci_freq_override_fils_assoc = value; break; + case WPA_PARAM_DISABLE_EAPOL_G2_TX: + sm->disable_eapol_g2_tx = value; + break; + case WPA_PARAM_ENCRYPT_EAPOL_M2: + sm->encrypt_eapol_m2 = value; + break; + case WPA_PARAM_ENCRYPT_EAPOL_M4: + sm->encrypt_eapol_m4 = value; + break; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_DPP2 case WPA_PARAM_DPP_PFS: sm->dpp_pfs = value; break; #endif /* CONFIG_DPP2 */ + case WPA_PARAM_WMM_ENABLED: + sm->wmm_enabled = value; + break; + case WPA_PARAM_FT_PREPEND_PMKID: + sm->ft_prepend_pmkid = value; + break; + case WPA_PARAM_SSID_PROTECTION: + sm->ssid_protection = value; + break; default: break; } @@ -4881,6 +5089,14 @@ int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len) sm->assoc_rsnxe_len = len; } + if (sm->ssid_protection && + !ieee802_11_rsnx_capab(sm->assoc_rsnxe, + WLAN_RSNX_CAPAB_SSID_PROTECTION)) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "RSN: Disabling SSID protection based on own RSNXE update"); + sm->ssid_protection = 0; + } + return 0; } @@ -5050,10 +5266,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, +int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid, const u8 *own_addr, const void *network_ctx) { - return pmksa_cache_get(sm->pmksa, bssid, NULL, network_ctx, 0) != NULL; + return pmksa_cache_get(sm->pmksa, bssid, own_addr, NULL, network_ctx, + 0) != NULL; } @@ -5063,23 +5280,25 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm, const void *network_ctx, int akmp) { - return pmksa_cache_get(sm->pmksa, aa, pmkid, network_ctx, akmp); + return pmksa_cache_get(sm->pmksa, aa, sm->own_addr, pmkid, network_ctx, + akmp); +} + + +void wpa_sm_pmksa_cache_remove(struct wpa_sm *sm, + struct rsn_pmksa_cache_entry *entry) +{ + if (sm && sm->pmksa) + pmksa_cache_remove(sm->pmksa, entry); } void wpa_sm_drop_sa(struct wpa_sm *sm) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK"); - sm->ptk_set = 0; - sm->tptk_set = 0; + wpa_sm_clear_ptk(sm); sm->pmk_len = 0; os_memset(sm->pmk, 0, sizeof(sm->pmk)); - os_memset(&sm->ptk, 0, sizeof(sm->ptk)); - os_memset(&sm->tptk, 0, sizeof(sm->tptk)); - os_memset(&sm->gtk, 0, sizeof(sm->gtk)); - os_memset(&sm->gtk_wnm_sleep, 0, sizeof(sm->gtk_wnm_sleep)); - os_memset(&sm->igtk, 0, sizeof(sm->igtk)); - os_memset(&sm->igtk_wnm_sleep, 0, sizeof(sm->igtk_wnm_sleep)); #ifdef CONFIG_IEEE80211R os_memset(sm->xxkey, 0, sizeof(sm->xxkey)); sm->xxkey_len = 0; @@ -5096,19 +5315,28 @@ void wpa_sm_drop_sa(struct wpa_sm *sm) } -int wpa_sm_has_ptk(struct wpa_sm *sm) +#ifdef CONFIG_IEEE80211R +bool wpa_sm_has_ft_keys(struct wpa_sm *sm, const u8 *md) { - if (sm == NULL) - return 0; + if (!sm) + return false; + if (!wpa_key_mgmt_ft(sm->key_mgmt) || + os_memcmp(md, sm->key_mobility_domain, + MOBILITY_DOMAIN_ID_LEN) != 0) { + /* Do not allow FT protocol to be used even if we were to have + * an PTK since the mobility domain has changed. */ + return false; + } return sm->ptk_set; } +#endif /* CONFIG_IEEE80211R */ int wpa_sm_has_ptk_installed(struct wpa_sm *sm) { if (!sm) return 0; - return sm->ptk.installed; + return sm->tk_set || sm->ptk.installed; } @@ -5247,6 +5475,20 @@ void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf) } +void wpa_sm_set_test_eapol_m2_elems(struct wpa_sm *sm, struct wpabuf *buf) +{ + wpabuf_free(sm->test_eapol_m2_elems); + sm->test_eapol_m2_elems = buf; +} + + +void wpa_sm_set_test_eapol_m4_elems(struct wpa_sm *sm, struct wpabuf *buf) +{ + wpabuf_free(sm->test_eapol_m4_elems); + sm->test_eapol_m4_elems = buf; +} + + const u8 * wpa_sm_get_anonce(struct wpa_sm *sm) { return sm->anonce; @@ -5259,12 +5501,14 @@ unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm) { return sm->key_mgmt; } -#ifdef CONFIG_MLD_PATCH + + const u8 * wpa_sm_get_auth_addr(struct wpa_sm *sm) { return sm->mlo.valid_links ? sm->mlo.ap_mld_addr : sm->bssid; } -#endif + + #ifdef CONFIG_FILS struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md) @@ -5414,6 +5658,11 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, const u8 *g_ap = NULL; size_t g_ap_len = 0, kdk_len; struct wpabuf *pub = NULL; +#ifdef CONFIG_IEEE80211R + struct wpa_ft_ies parse; + + os_memset(&parse, 0, sizeof(parse)); +#endif /* CONFIG_IEEE80211R */ os_memcpy(sm->bssid, bssid, ETH_ALEN); @@ -5492,15 +5741,13 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, #ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->key_mgmt)) { - struct wpa_ft_ies parse; - if (!elems.mdie || !elems.ftie) { wpa_printf(MSG_DEBUG, "FILS+FT: No MDE or FTE"); goto fail; } if (wpa_ft_parse_ies(pos, end - pos, &parse, - wpa_key_mgmt_sha384(sm->key_mgmt)) < 0) { + sm->key_mgmt, false) < 0) { wpa_printf(MSG_DEBUG, "FILS+FT: Failed to parse IEs"); goto fail; } @@ -5648,11 +5895,7 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, kdk_len = 0; if (fils_pmk_to_ptk(sm->pmk, sm->pmk_len, sm->own_addr, -#ifdef CONFIG_MLD_PATCH wpa_sm_get_auth_addr(sm), -#else - sm->bssid, -#endif sm->fils_nonce, sm->fils_anonce, dh_ss ? wpabuf_head(dh_ss) : NULL, dh_ss ? wpabuf_len(dh_ss) : 0, @@ -5664,6 +5907,15 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, goto fail; } +#ifdef CONFIG_PASN + if (sm->secure_ltf && + ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) && + wpa_ltf_keyseed(&sm->ptk, sm->key_mgmt, sm->pairwise_cipher)) { + wpa_printf(MSG_DEBUG, "FILS: Failed to derive LTF keyseed"); + goto fail; + } +#endif /* CONFIG_PASN */ + wpabuf_clear_free(dh_ss); dh_ss = NULL; @@ -5699,10 +5951,16 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, &sm->fils_key_auth_len); wpabuf_free(pub); forced_memzero(ick, sizeof(ick)); +#ifdef CONFIG_IEEE80211R + wpa_ft_parse_ies_free(&parse); +#endif /* CONFIG_IEEE80211R */ return res; fail: wpabuf_free(pub); wpabuf_clear_free(dh_ss); +#ifdef CONFIG_IEEE80211R + wpa_ft_parse_ies_free(&parse); +#endif /* CONFIG_IEEE80211R */ return -1; } @@ -5785,21 +6043,27 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf) if (wpa_derive_pmk_r0(sm->fils_ft, sm->fils_ft_len, sm->ssid, sm->ssid_len, sm->mobility_domain, sm->r0kh_id, sm->r0kh_id_len, sm->own_addr, - sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0) { + sm->pmk_r0, sm->pmk_r0_name, sm->key_mgmt) < 0) { wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMK-R0"); return -1; } - sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; + if (wpa_key_mgmt_sae_ext_key(sm->key_mgmt)) + sm->pmk_r0_len = sm->fils_ft_len; + else + sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; wpa_printf(MSG_DEBUG, "FILS+FT: R1KH-ID: " MACSTR_SEC, MAC2STR_SEC(sm->r1kh_id)); pos = wpabuf_put(buf, WPA_PMK_NAME_LEN); if (wpa_derive_pmk_r1_name(sm->pmk_r0_name, sm->r1kh_id, sm->own_addr, - sm->pmk_r1_name, use_sha384) < 0) { + sm->pmk_r1_name, sm->fils_ft_len) < 0) { wpa_printf(MSG_WARNING, "FILS+FT: Could not derive PMKR1Name"); return -1; } os_memcpy(pos, sm->pmk_r1_name, WPA_PMK_NAME_LEN); + os_memcpy(sm->key_mobility_domain, sm->mobility_domain, + MOBILITY_DOMAIN_ID_LEN); + if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { /* Management Group Cipher Suite */ pos = wpabuf_put(buf, RSN_SELECTOR_LEN); @@ -6205,19 +6469,16 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len) rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher); wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver", sm->ptk.tk, keylen); -#ifdef CONFIG_MLD_PATCH - if (wpa_sm_set_key(sm, -1, alg, wpa_sm_get_auth_addr(sm), 0, 1, null_rsc, rsclen, -#else - if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen, -#endif + if (wpa_sm_set_key(sm, -1, alg, wpa_sm_get_auth_addr(sm), 0, 1, + null_rsc, rsclen, sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) { wpa_msg_only_for_cb(sm->ctx->msg_ctx, MSG_WARNING, - "FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid=" + "FILS: Failed to set PTK to the driver (alg=%d keylen=%d auth_addr=" MACSTR ")", - alg, keylen, MAC2STR(sm->bssid)); - wpa_printf(MSG_WARNING, "FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid=" + alg, keylen, MAC2STR(wpa_sm_get_auth_addr(sm))); + wpa_printf(MSG_WARNING, "FILS: Failed to set PTK to the driver (alg=%d keylen=%d auth_addr=" MACSTR_SEC ")", - alg, keylen, MAC2STR_SEC(sm->bssid)); + alg, keylen, MAC2STR_SEC(wpa_sm_get_auth_addr(sm))); goto fail; } @@ -6230,6 +6491,7 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len) os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN); sm->ptk.tk_len = 0; sm->ptk.installed = 1; + sm->tk_set = true; /* FILS HLP Container */ fils_process_hlp_container(sm, ie_start, end - ie_start); @@ -6499,13 +6761,17 @@ void wpa_sm_set_dpp_z(struct wpa_sm *sm, const struct wpabuf *z) #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) + +void wpa_pasn_sm_set_caps(struct wpa_sm *sm, unsigned int flags2) { - sm->cur_pmksa = pmksa_cache_add(sm->pmksa, pmk, pmk_len, pmkid, NULL, 0, - bssid, sm->own_addr, NULL, - key_mgmt, 0); + if (flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) + sm->secure_ltf = 1; + if (flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_STA) + sm->secure_rtt = 1; + if (flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA) + sm->prot_range_neg = 1; } + #endif /* CONFIG_PASN */ @@ -6514,3 +6780,25 @@ void wpa_sm_pmksa_cache_reconfig(struct wpa_sm *sm) if (sm) pmksa_cache_reconfig(sm->pmksa); } + + +struct rsn_pmksa_cache * wpa_sm_get_pmksa_cache(struct wpa_sm *sm) +{ + return sm ? sm->pmksa : NULL; +} + + +void wpa_sm_set_cur_pmksa(struct wpa_sm *sm, + struct rsn_pmksa_cache_entry *entry) +{ + if (sm) + sm->cur_pmksa = entry; +} + + +void wpa_sm_set_driver_bss_selection(struct wpa_sm *sm, + bool driver_bss_selection) +{ + if (sm) + sm->driver_bss_selection = driver_bss_selection; +} diff --git a/wpa_supplicant-2.9_standard/src/rsn_supp/wpa.h b/wpa_supplicant-2.9_standard/src/rsn_supp/wpa.h index 14864182c941cc5b3fb117f2da395fbdf1bf4caf..13b7d176935bc21bcecb1b49b967fa3ed8640c50 100644 --- a/wpa_supplicant-2.9_standard/src/rsn_supp/wpa.h +++ b/wpa_supplicant-2.9_standard/src/rsn_supp/wpa.h @@ -19,6 +19,8 @@ struct eapol_sm; struct wpa_config_blob; struct hostapd_freq_params; struct wpa_channel_info; +struct rsn_pmksa_cache_entry; +enum frame_encryption; struct wpa_sm_ctx { void *ctx; /* pointer to arbitrary upper level context */ @@ -28,11 +30,7 @@ struct wpa_sm_ctx { enum wpa_states (*get_state)(void *ctx); void (*deauthenticate)(void * ctx, u16 reason_code); void (*reconnect)(void *ctx); -#ifdef CONFIG_MLD_PATCH int (*set_key)(void *ctx, int link_id, enum wpa_alg alg, -#else - int (*set_key)(void *ctx, enum wpa_alg alg, -#endif const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len, enum key_flag key_flag); @@ -66,7 +64,8 @@ struct wpa_sm_ctx { int (*send_tdls_mgmt)(void *ctx, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, - int initiator, const u8 *buf, size_t len); + int initiator, const u8 *buf, size_t len, + int link_id); int (*tdls_oper)(void *ctx, int oper, const u8 *peer); int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid, u16 capability, const u8 *supp_rates, @@ -80,7 +79,9 @@ struct wpa_sm_ctx { size_t ext_capab_len, const u8 *supp_channels, size_t supp_channels_len, const u8 *supp_oper_classes, - size_t supp_oper_classes_len); + size_t supp_oper_classes_len, + const struct ieee80211_eht_capabilities *eht_capab, + size_t eht_capab_len, int mld_link_id); int (*tdls_enable_channel_switch)( void *ctx, const u8 *addr, u8 oper_class, const struct hostapd_freq_params *params); @@ -94,8 +95,16 @@ 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, + void (*store_ptk)(void *ctx, const u8 *addr, int cipher, u32 life_time, const struct wpa_ptk *ptk); +#ifdef CONFIG_PASN + int (*set_ltf_keyseed)(void *ctx, const u8 *own_addr, + const u8 *peer_addr, size_t ltf_keyseed_len, + const u8 *ltf_keyseed); +#endif /* CONFIG_PASN */ + void (*notify_pmksa_cache_entry)(void *ctx, + struct rsn_pmksa_cache_entry *entry); + void (*ssid_verified)(void *ctx); }; @@ -118,10 +127,16 @@ enum wpa_sm_conf_params { WPA_PARAM_USE_EXT_KEY_ID, WPA_PARAM_FT_RSNXE_USED, WPA_PARAM_DPP_PFS, + WPA_PARAM_WMM_ENABLED, WPA_PARAM_OCI_FREQ_EAPOL, WPA_PARAM_OCI_FREQ_EAPOL_G2, WPA_PARAM_OCI_FREQ_FT_ASSOC, WPA_PARAM_OCI_FREQ_FILS_ASSOC, + WPA_PARAM_DISABLE_EAPOL_G2_TX, + WPA_PARAM_ENCRYPT_EAPOL_M2, + WPA_PARAM_ENCRYPT_EAPOL_M4, + WPA_PARAM_FT_PREPEND_PMKID, + WPA_PARAM_SSID_PROTECTION, }; struct rsn_supp_config { @@ -141,7 +156,7 @@ struct rsn_supp_config { int beacon_prot; bool force_kdk_derivation; }; -#ifdef CONFIG_MLD_PATCH + struct wpa_sm_link { u8 addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; @@ -162,7 +177,7 @@ struct wpa_sm_mlo { u16 req_links; /* bitmap of requested links */ struct wpa_sm_link links[MAX_NUM_MLD_LINKS]; }; -#endif + #ifndef CONFIG_NO_WPA struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx); @@ -175,6 +190,7 @@ void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm); void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth); void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx); void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config); +void wpa_sm_set_ssid(struct wpa_sm *sm, const u8 *ssid, size_t ssid_len); void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr); void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname, const char *bridge_ifname); @@ -211,7 +227,7 @@ int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, void wpa_sm_aborted_cached(struct wpa_sm *sm); void wpa_sm_aborted_external_cached(struct wpa_sm *sm); int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len); + const u8 *buf, size_t len, enum frame_encryption encrypted); int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data); int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len); struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_head(struct wpa_sm *sm); @@ -221,7 +237,7 @@ wpa_sm_pmksa_cache_add_entry(struct wpa_sm *sm, void wpa_sm_pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len, const u8 *pmkid, const u8 *bssid, const u8 *fils_cache_id); -int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid, +int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid, const u8 *own_addr, 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, @@ -229,7 +245,9 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm, const u8 *pmkid, const void *network_ctx, int akmp); -int wpa_sm_has_ptk(struct wpa_sm *sm); +void wpa_sm_pmksa_cache_remove(struct wpa_sm *sm, + struct rsn_pmksa_cache_entry *entry); +bool wpa_sm_has_ft_keys(struct wpa_sm *sm, const u8 *md); int wpa_sm_has_ptk_installed(struct wpa_sm *sm); void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr); @@ -245,9 +263,8 @@ void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kek, size_t ptk_kek_len); int wpa_fils_is_completed(struct wpa_sm *sm); void wpa_sm_pmksa_cache_reconfig(struct wpa_sm *sm); -#ifdef CONFIG_MLD_PATCH int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo); -#endif + #else /* CONFIG_NO_WPA */ static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx) @@ -399,7 +416,8 @@ static inline void wpa_sm_aborted_external_cached(struct wpa_sm *sm) } static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) + const u8 *buf, size_t len, + enum frame_encryption encrypted) { return -1; } @@ -466,13 +484,13 @@ static inline int wpa_fils_is_completed(struct wpa_sm *sm) static inline void wpa_sm_pmksa_cache_reconfig(struct wpa_sm *sm) { } -#ifdef CONFIG_MLD_PATCH + static inline int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo) { return 0; } -#endif + #endif /* CONFIG_NO_WPA */ #ifdef CONFIG_IEEE80211R @@ -490,7 +508,7 @@ void wpa_reset_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); + const u8 *mdie, bool force); #ifdef CONFIG_PASN @@ -544,8 +562,9 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len, #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) +static inline 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; } @@ -573,6 +592,8 @@ int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr, u8 oper_class, struct hostapd_freq_params *freq_params); int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr); +int wpa_tdls_process_discovery_response(struct wpa_sm *sm, const u8 *addr, + const u8 *buf, size_t len); #ifdef CONFIG_TDLS_TESTING extern unsigned int tdls_testing; #endif /* CONFIG_TDLS_TESTING */ @@ -580,6 +601,8 @@ extern unsigned int tdls_testing; int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf); void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf); +void wpa_sm_set_test_eapol_m2_elems(struct wpa_sm *sm, struct wpabuf *buf); +void wpa_sm_set_test_eapol_m4_elems(struct wpa_sm *sm, struct wpabuf *buf); const u8 * wpa_sm_get_anonce(struct wpa_sm *sm); unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm); @@ -600,9 +623,13 @@ 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); -#ifdef CONFIG_MLD_PATCH +void wpa_pasn_sm_set_caps(struct wpa_sm *sm, unsigned int flags2); +struct rsn_pmksa_cache * wpa_sm_get_pmksa_cache(struct wpa_sm *sm); + +void wpa_sm_set_cur_pmksa(struct wpa_sm *sm, + struct rsn_pmksa_cache_entry *entry); const u8 * wpa_sm_get_auth_addr(struct wpa_sm *sm); -#endif +void wpa_sm_set_driver_bss_selection(struct wpa_sm *sm, + bool driver_bss_selection); + #endif /* WPA_H */ diff --git a/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_ft.c b/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_ft.c index 3ce6a218cb681d2bb1aab7699403727f3ab420cb..cf8a226a210f85df76c186a9a19e6b8841ef7d65 100644 --- a/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_ft.c +++ b/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_ft.c @@ -11,6 +11,7 @@ #include "common.h" #include "crypto/aes_wrap.h" #include "crypto/sha384.h" +#include "crypto/sha512.h" #include "crypto/random.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" @@ -41,6 +42,7 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt); const u8 *mpmk; size_t mpmk_len, kdk_len; + int ret = 0; if (sm->xxkey_len > 0) { mpmk = sm->xxkey; @@ -54,11 +56,14 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, return -1; } - sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; + if (wpa_key_mgmt_sae_ext_key(sm->key_mgmt)) + sm->pmk_r0_len = mpmk_len; + else + sm->pmk_r0_len = use_sha384 ? SHA384_MAC_LEN : PMK_LEN; if (wpa_derive_pmk_r0(mpmk, mpmk_len, sm->ssid, sm->ssid_len, sm->mobility_domain, sm->r0kh_id, sm->r0kh_id_len, sm->own_addr, - sm->pmk_r0, sm->pmk_r0_name, use_sha384) < 0) + sm->pmk_r0, sm->pmk_r0_name, sm->key_mgmt) < 0) return -1; sm->pmk_r1_len = sm->pmk_r0_len; if (wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_len, sm->pmk_r0_name, @@ -75,14 +80,25 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, else kdk_len = 0; - return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, anonce, -#ifdef CONFIG_MLD_PATCH - sm->own_addr, wpa_sm_get_auth_addr(sm), sm->pmk_r1_name, ptk, -#else - sm->own_addr, sm->bssid, sm->pmk_r1_name, ptk, -#endif - ptk_name, sm->key_mgmt, sm->pairwise_cipher, - kdk_len); + ret = wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, + anonce, sm->own_addr, wpa_sm_get_auth_addr(sm), + sm->pmk_r1_name, ptk, ptk_name, sm->key_mgmt, + sm->pairwise_cipher, kdk_len); + if (ret) { + wpa_printf(MSG_ERROR, "FT: PTK derivation failed"); + return ret; + } + + os_memcpy(sm->key_mobility_domain, sm->mobility_domain, + MOBILITY_DOMAIN_ID_LEN); + +#ifdef CONFIG_PASN + if (sm->secure_ltf && + ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) + ret = wpa_ltf_keyseed(ptk, sm->key_mgmt, sm->pairwise_cipher); +#endif /* CONFIG_PASN */ + + return ret; } @@ -96,7 +112,6 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) { struct wpa_ft_ies ft; - int use_sha384; if (sm == NULL) return 0; @@ -112,12 +127,13 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) return 0; } - use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt); - if (wpa_ft_parse_ies(ies, ies_len, &ft, use_sha384) < 0) + if (wpa_ft_parse_ies(ies, ies_len, &ft, sm->key_mgmt, false) < 0) return -1; - if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) + if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) { + wpa_ft_parse_ies_free(&ft); return -1; + } wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", ft.mdie, MOBILITY_DOMAIN_ID_LEN); @@ -165,6 +181,7 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) sm->assoc_resp_ies, sm->assoc_resp_ies_len); } + wpa_ft_parse_ies_free(&ft); return 0; } @@ -175,7 +192,7 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) * @len: Buffer for returning the length of the IEs * @anonce: ANonce or %NULL if not yet available * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List - * @kck: 128-bit KCK for MIC or %NULL if no MIC is used + * @kck: KCK for MIC or %NULL if no MIC is used * @kck_len: KCK length in octets * @target_ap: Target AP address * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL @@ -202,12 +219,13 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, size_t rsnxe_len; int rsnxe_used; int res; + u8 mic_control; sm->ft_completed = 0; sm->ft_reassoc_completed = 0; buf_len = 2 + sizeof(struct rsn_mdie) + 2 + - sizeof(struct rsn_ftie_sha384) + + sizeof(struct rsn_ftie_sha512) + 2 + sm->r0kh_id_len + ric_ies_len + 100; buf = os_zalloc(buf_len); if (buf == NULL) @@ -261,6 +279,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE) RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); + else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY); #ifdef CONFIG_FILS else if (sm->key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256) RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256); @@ -323,7 +343,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, *pos++ = WLAN_EID_FAST_BSS_TRANSITION; ftie_len = pos++; rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) && anonce && - (sm->sae_pwe == 1 || sm->sae_pwe == 2); + (sm->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || + sm->sae_pwe == SAE_PWE_BOTH); #ifdef CONFIG_TESTING_OPTIONS if (anonce && sm->ft_rsnxe_used) { rsnxe_used = sm->ft_rsnxe_used == 1; @@ -331,11 +352,28 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, rsnxe_used); } #endif /* CONFIG_TESTING_OPTIONS */ - if (wpa_key_mgmt_sha384(sm->key_mgmt)) { + mic_control = rsnxe_used ? FTE_MIC_CTRL_RSNXE_USED : 0; + if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + sm->pmk_r0_len == SHA512_MAC_LEN) { + struct rsn_ftie_sha512 *ftie; + + ftie = (struct rsn_ftie_sha512 *) pos; + mic_control |= FTE_MIC_LEN_32 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + ftie->mic_control[0] = mic_control; + fte_mic = ftie->mic; + elem_count = &ftie->mic_control[1]; + pos += sizeof(*ftie); + os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN); + if (anonce) + os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN); + } else if ((sm->key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + sm->pmk_r0_len == SHA384_MAC_LEN) || + wpa_key_mgmt_sha384(sm->key_mgmt)) { struct rsn_ftie_sha384 *ftie; ftie = (struct rsn_ftie_sha384 *) pos; - ftie->mic_control[0] = !!rsnxe_used; + mic_control |= FTE_MIC_LEN_24 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + ftie->mic_control[0] = mic_control; fte_mic = ftie->mic; elem_count = &ftie->mic_control[1]; pos += sizeof(*ftie); @@ -346,7 +384,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, struct rsn_ftie *ftie; ftie = (struct rsn_ftie *) pos; - ftie->mic_control[0] = !!rsnxe_used; + mic_control |= FTE_MIC_LEN_16 << FTE_MIC_CTRL_MIC_LEN_SHIFT; + ftie->mic_control[0] = mic_control; fte_mic = ftie->mic; elem_count = &ftie->mic_control[1]; pos += sizeof(*ftie); @@ -430,11 +469,13 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, *elem_count = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len); if (rsnxe_len) *elem_count += 1; - if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5, + if (wpa_ft_mic(sm->key_mgmt, kck, kck_len, + sm->own_addr, target_ap, 5, ((u8 *) mdie) - 2, 2 + sizeof(*mdie), ftie_pos, 2 + *ftie_len, (u8 *) rsnie, 2 + rsnie->len, ric_ies, ric_ies_len, rsnxe_len ? rsnxe : NULL, rsnxe_len, + NULL, fte_mic) < 0) { wpa_printf(MSG_INFO, "FT: Failed to calculate MIC"); os_free(buf); @@ -465,18 +506,16 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) alg = wpa_cipher_to_alg(sm->pairwise_cipher); keylen = wpa_cipher_key_len(sm->pairwise_cipher); -#ifdef CONFIG_MLD_PATCH + /* TODO: AP MLD address for MLO */ if (wpa_sm_set_key(sm, -1, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc), -#else - if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc), -#endif (u8 *) sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) { wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver"); return -1; } + sm->tk_set = true; - wpa_sm_store_ptk(sm, sm->bssid, sm->pairwise_cipher, + wpa_sm_store_ptk(sm, bssid, sm->pairwise_cipher, sm->dot11RSNAConfigPMKLifetime, &sm->ptk); return 0; } @@ -551,12 +590,12 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, struct wpa_ft_ies parse; struct rsn_mdie *mdie; u8 ptk_name[WPA_PMK_NAME_LEN]; - int ret; + int ret = -1, res; const u8 *bssid; const u8 *kck; size_t kck_len, kdk_len; - int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt); - const u8 *anonce, *snonce; + + os_memset(&parse, 0, sizeof(parse)); wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len); @@ -565,26 +604,27 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, if (!sm->over_the_ds_in_progress) { wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " "- drop FT Action Response"); - return -1; + goto fail; } - if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) { + if (!ether_addr_equal(target_ap, sm->target_ap)) { wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress " "with this Target AP - drop FT Action " "Response"); - return -1; + goto fail; } } if (!wpa_key_mgmt_ft(sm->key_mgmt)) { wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " "enabled for this connection"); - return -1; + goto fail; } - if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, sm->key_mgmt, + !ft_action) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); - return -1; + goto fail; } mdie = (struct rsn_mdie *) parse.mdie; @@ -592,45 +632,26 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, os_memcmp(mdie->mobility_domain, sm->mobility_domain, MOBILITY_DOMAIN_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); - return -1; + goto fail; } - if (use_sha384) { - struct rsn_ftie_sha384 *ftie; - - ftie = (struct rsn_ftie_sha384 *) parse.ftie; - if (!ftie || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return -1; - } - - anonce = ftie->anonce; - snonce = ftie->snonce; - } else { - struct rsn_ftie *ftie; - - ftie = (struct rsn_ftie *) parse.ftie; - if (!ftie || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return -1; - } - - anonce = ftie->anonce; - snonce = ftie->snonce; + if (!parse.ftie || !parse.fte_anonce || !parse.fte_snonce) { + wpa_printf(MSG_DEBUG, "FT: Invalid FTE"); + goto fail; } - if (os_memcmp(snonce, sm->snonce, WPA_NONCE_LEN) != 0) { + if (os_memcmp(parse.fte_snonce, sm->snonce, WPA_NONCE_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", - snonce, WPA_NONCE_LEN); + parse.fte_snonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", sm->snonce, WPA_NONCE_LEN); - return -1; + goto fail; } if (parse.r0kh_id == NULL) { wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); - return -1; + goto fail; } if (parse.r0kh_id_len != sm->r0kh_id_len || @@ -642,12 +663,12 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, parse.r0kh_id, parse.r0kh_id_len); wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", sm->r0kh_id, sm->r0kh_id_len); - return -1; + goto fail; } if (parse.r1kh_id == NULL) { wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); - return -1; + goto fail; } if (parse.rsn_pmkid == NULL || @@ -655,24 +676,24 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, { wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in " "RSNIE"); - return -1; + goto fail; } if (sm->mfp == 2 && !(parse.rsn_capab & WPA_CAPABILITY_MFPC)) { wpa_printf(MSG_INFO, "FT: Target AP does not support PMF, but local configuration requires that"); - return -1; + goto fail; } os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN); wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN); wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "FT: ANonce", anonce, WPA_NONCE_LEN); - os_memcpy(sm->anonce, anonce, WPA_NONCE_LEN); + wpa_hexdump(MSG_DEBUG, "FT: ANonce", parse.fte_anonce, WPA_NONCE_LEN); + os_memcpy(sm->anonce, parse.fte_anonce, WPA_NONCE_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; + goto fail; sm->pmk_r1_len = sm->pmk_r0_len; bssid = target_ap; @@ -686,12 +707,25 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, else kdk_len = 0; + /* TODO: AP MLD address for MLO */ if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len, sm->snonce, - anonce, sm->own_addr, bssid, + parse.fte_anonce, sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk, ptk_name, sm->key_mgmt, sm->pairwise_cipher, kdk_len) < 0) - return -1; + goto fail; + + os_memcpy(sm->key_mobility_domain, sm->mobility_domain, + MOBILITY_DOMAIN_ID_LEN); + +#ifdef CONFIG_PASN + if (sm->secure_ltf && + ieee802_11_rsnx_capab(sm->ap_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF) && + wpa_ltf_keyseed(&sm->ptk, sm->key_mgmt, sm->pairwise_cipher)) { + wpa_printf(MSG_DEBUG, "FT: Failed to derive LTF keyseed"); + goto fail; + } +#endif /* CONFIG_PASN */ if (wpa_key_mgmt_fils(sm->key_mgmt)) { kck = sm->ptk.kck2; @@ -700,7 +734,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, kck = sm->ptk.kck; kck_len = sm->ptk.kck_len; } - ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, anonce, + ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, parse.fte_anonce, sm->pmk_r1_name, kck, kck_len, bssid, ric_ies, ric_ies_len, @@ -713,8 +747,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, } wpa_sm_mark_authenticated(sm, bssid); - ret = wpa_ft_install_ptk(sm, bssid); - if (ret) { + res = wpa_ft_install_ptk(sm, bssid); + if (res) { /* * Some drivers do not support key configuration when we are * not associated with the target AP. Work around this by @@ -736,7 +770,10 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, os_memcpy(sm->bssid, target_ap, ETH_ALEN); } - return 0; + ret = 0; +fail: + wpa_ft_parse_ies_free(&parse); + return ret; } @@ -831,11 +868,7 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, os_memcpy(gtk + 16, gtk + 24, 8); os_memcpy(gtk + 24, tmp, 8); } -#ifdef CONFIG_MLD_PATCH if (wpa_sm_set_key(sm, -1, alg, broadcast_ether_addr, keyidx, 0, -#else - if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0, -#endif gtk_elem + 3, rsc_len, gtk, keylen, KEY_FLAG_GROUP_RX) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the " @@ -902,11 +935,7 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk, igtk_len); -#ifdef CONFIG_MLD_PATCH if (wpa_sm_set_key(sm, -1, wpa_cipher_to_alg(sm->mgmt_group_cipher), -#else - if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), -#endif broadcast_ether_addr, keyidx, 0, igtk_elem + 2, 6, igtk, igtk_len, KEY_FLAG_GROUP_RX) < 0) { @@ -974,11 +1003,7 @@ static int wpa_ft_process_bigtk_subelem(struct wpa_sm *sm, const u8 *bigtk_elem, wpa_hexdump_key(MSG_DEBUG, "FT: BIGTK from Reassoc Resp", bigtk, bigtk_len); -#ifdef CONFIG_MLD_PATCH if (wpa_sm_set_key(sm, -1, wpa_cipher_to_alg(sm->mgmt_group_cipher), -#else - if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), -#endif broadcast_ether_addr, keyidx, 0, bigtk_elem + 2, 6, bigtk, bigtk_len, KEY_FLAG_GROUP_RX) < 0) { @@ -1002,17 +1027,18 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN]; const u8 *kck; size_t kck_len; - int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt); - const u8 *anonce, *snonce, *fte_mic; - u8 fte_elem_count; - int own_rsnxe_used, rsnxe_used; + int own_rsnxe_used; + size_t mic_len; + int ret = -1; + + os_memset(&parse, 0, sizeof(parse)); wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); if (!wpa_key_mgmt_ft(sm->key_mgmt)) { wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not " "enabled for this connection"); - return -1; + goto fail; } if (sm->ft_reassoc_completed) { @@ -1020,9 +1046,9 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, return 0; } - if (wpa_ft_parse_ies(ies, ies_len, &parse, use_sha384) < 0) { + if (wpa_ft_parse_ies(ies, ies_len, &parse, sm->key_mgmt, true) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs"); - return -1; + goto fail; } mdie = (struct rsn_mdie *) parse.mdie; @@ -1030,60 +1056,48 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, os_memcmp(mdie->mobility_domain, sm->mobility_domain, MOBILITY_DOMAIN_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); - return -1; + goto fail; } - if (use_sha384) { - struct rsn_ftie_sha384 *ftie; - - ftie = (struct rsn_ftie_sha384 *) parse.ftie; - if (!ftie || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return -1; - } - - anonce = ftie->anonce; - snonce = ftie->snonce; - rsnxe_used = ftie->mic_control[0] & 0x01; - fte_elem_count = ftie->mic_control[1]; - fte_mic = ftie->mic; - } else { - struct rsn_ftie *ftie; - - ftie = (struct rsn_ftie *) parse.ftie; - if (!ftie || parse.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_DEBUG, "FT: Invalid FTIE"); - return -1; - } + if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + sm->pmk_r1_len == SHA512_MAC_LEN) + mic_len = 32; + else if ((sm->key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY && + sm->pmk_r1_len == SHA384_MAC_LEN) || + wpa_key_mgmt_sha384(sm->key_mgmt)) + mic_len = 24; + else + mic_len = 16; - anonce = ftie->anonce; - snonce = ftie->snonce; - rsnxe_used = ftie->mic_control[0] & 0x01; - fte_elem_count = ftie->mic_control[1]; - fte_mic = ftie->mic; + if (!parse.ftie || !parse.fte_anonce || !parse.fte_snonce || + parse.fte_mic_len != mic_len) { + wpa_printf(MSG_DEBUG, + "FT: Invalid FTE (fte_mic_len=%zu mic_len=%zu)", + parse.fte_mic_len, mic_len); + goto fail; } - if (os_memcmp(snonce, sm->snonce, WPA_NONCE_LEN) != 0) { + if (os_memcmp(parse.fte_snonce, sm->snonce, WPA_NONCE_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE"); wpa_hexdump(MSG_DEBUG, "FT: Received SNonce", - snonce, WPA_NONCE_LEN); + parse.fte_snonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce", sm->snonce, WPA_NONCE_LEN); - return -1; + goto fail; } - if (os_memcmp(anonce, sm->anonce, WPA_NONCE_LEN) != 0) { + if (os_memcmp(parse.fte_anonce, sm->anonce, WPA_NONCE_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE"); wpa_hexdump(MSG_DEBUG, "FT: Received ANonce", - anonce, WPA_NONCE_LEN); + parse.fte_anonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce", sm->anonce, WPA_NONCE_LEN); - return -1; + goto fail; } if (parse.r0kh_id == NULL) { wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE"); - return -1; + goto fail; } if (parse.r0kh_id_len != sm->r0kh_id_len || @@ -1095,18 +1109,18 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, parse.r0kh_id, parse.r0kh_id_len); wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID", sm->r0kh_id, sm->r0kh_id_len); - return -1; + goto fail; } if (parse.r1kh_id == NULL) { wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE"); - return -1; + goto fail; } if (os_memcmp_const(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " "ReassocResp"); - return -1; + goto fail; } if (parse.rsn_pmkid == NULL || @@ -1114,7 +1128,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, { wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); - return -1; + goto fail; } count = 3; @@ -1122,11 +1136,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, count += ieee802_11_ie_count(parse.ric, parse.ric_len); if (parse.rsnxe) count++; - if (fte_elem_count != count) { + if (parse.fte_elem_count != count) { wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC " "Control: received %u expected %u", - fte_elem_count, count); - return -1; + parse.fte_elem_count, count); + goto fail; } if (wpa_key_mgmt_fils(sm->key_mgmt)) { @@ -1137,29 +1151,31 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, kck_len = sm->ptk.kck_len; } - if (wpa_ft_mic(kck, kck_len, sm->own_addr, src_addr, 6, + if (wpa_ft_mic(sm->key_mgmt, kck, kck_len, sm->own_addr, src_addr, 6, parse.mdie - 2, parse.mdie_len + 2, parse.ftie - 2, parse.ftie_len + 2, parse.rsn - 2, parse.rsn_len + 2, parse.ric, parse.ric_len, parse.rsnxe ? parse.rsnxe - 2 : NULL, parse.rsnxe ? parse.rsnxe_len + 2 : 0, + NULL, mic) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); - return -1; + goto fail; } - if (os_memcmp_const(mic, fte_mic, 16) != 0) { + if (os_memcmp_const(mic, parse.fte_mic, mic_len) != 0) { wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); - wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", fte_mic, 16); - wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16); - return -1; + wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", + parse.fte_mic, mic_len); + wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len); + goto fail; } - if (rsnxe_used && !sm->ap_rsnxe) { + if (parse.fte_rsnxe_used && !sm->ap_rsnxe) { wpa_printf(MSG_INFO, "FT: FTE indicated that AP uses RSNXE, but RSNXE was not included in Beacon/Probe Response frames"); - return -1; + goto fail; } if (!sm->ap_rsn_ie) { @@ -1168,7 +1184,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, if (wpa_sm_get_beacon_ie(sm) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "FT: Could not find AP from the scan results"); - return -1; + goto fail; } wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: Found the current AP from updated scan results"); @@ -1186,11 +1202,12 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, "RSNE in FT protocol Reassociation Response frame", parse.rsn ? parse.rsn - 2 : NULL, parse.rsn ? parse.rsn_len + 2 : 0); - return -1; + goto fail; } own_rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) && - (sm->sae_pwe == 1 || sm->sae_pwe == 2); + (sm->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || + sm->sae_pwe == SAE_PWE_BOTH); if ((sm->ap_rsnxe && !parse.rsnxe && own_rsnxe_used) || (!sm->ap_rsnxe && parse.rsnxe) || (sm->ap_rsnxe && parse.rsnxe && @@ -1205,7 +1222,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, "RSNXE in FT protocol Reassociation Response frame", parse.rsnxe ? parse.rsnxe - 2 : NULL, parse.rsnxe ? parse.rsnxe_len + 2 : 0); - return -1; + goto fail; } #ifdef CONFIG_OCV @@ -1215,7 +1232,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, if (wpa_sm_channel_info(sm, &ci) != 0) { wpa_printf(MSG_WARNING, "Failed to get channel info to validate received OCI in (Re)Assoc Response"); - return -1; + goto fail; } if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci, @@ -1224,7 +1241,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, wpa_msg(sm->ctx->msg_ctx, MSG_INFO, OCV_FAILURE "addr=" MACSTR " frame=ft-assoc error=%s", MAC2STR(src_addr), ocv_errorstr); - return -1; + goto fail; } } #endif /* CONFIG_OCV */ @@ -1234,13 +1251,13 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0 || wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0 || wpa_ft_process_bigtk_subelem(sm, parse.bigtk, parse.bigtk_len) < 0) - return -1; + goto fail; if (sm->set_ptk_after_assoc) { wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we " "are associated"); if (wpa_ft_install_ptk(sm, src_addr) < 0) - return -1; + goto fail; sm->set_ptk_after_assoc = 0; } @@ -1253,7 +1270,10 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, wpa_printf(MSG_DEBUG, "FT: Completed successfully"); - return 0; + ret = 0; +fail: + wpa_ft_parse_ies_free(&parse); + return ret; } @@ -1262,14 +1282,24 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, * @sm: Pointer to WPA state machine data from wpa_sm_init() * @target_ap: Target AP Address * @mdie: Mobility Domain IE from the target AP + * @force: Whether to force the request and ignore mobility domain differences + * (only for testing purposes) * Returns: 0 on success, -1 on failure */ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, - const u8 *mdie) + const u8 *mdie, bool force) { u8 *ft_ies; size_t ft_ies_len; + if (!force && + (!mdie || mdie[1] < 3 || !wpa_sm_has_ft_keys(sm, mdie + 2))) { + wpa_printf(MSG_DEBUG, "FT: Cannot use over-the DS with " MACSTR_SEC + " - no keys matching the mobility domain", + MAC2STR_SEC(target_ap)); + return -1; + } + wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR_SEC, MAC2STR_SEC(target_ap)); @@ -1300,7 +1330,7 @@ static struct pasn_ft_r1kh * wpa_ft_pasn_get_r1kh(struct wpa_sm *sm, size_t i; for (i = 0; i < sm->n_pasn_r1kh; i++) - if (os_memcmp(sm->pasn_r1kh[i].bssid, bssid, ETH_ALEN) == 0) + if (ether_addr_equal(sm->pasn_r1kh[i].bssid, bssid)) return &sm->pasn_r1kh[i]; return NULL; diff --git a/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_i.h b/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_i.h index 072320f0df1218fe34d49ed337aa76bf98334ff7..c1d9a1e019b6211d45347de3aa07715d8a28d539 100644 --- a/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_i.h +++ b/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_i.h @@ -27,6 +27,7 @@ struct wpa_sm { size_t pmk_len; struct wpa_ptk ptk, tptk; int ptk_set, tptk_set; + bool tk_set; /* Whether any TK is configured to the driver */ unsigned int msg_3_of_4_ok:1; u8 snonce[WPA_NONCE_LEN]; u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */ @@ -105,12 +106,13 @@ struct wpa_sm { int rsn_enabled; /* Whether RSN is enabled in configuration */ int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */ int ocv; /* Operating Channel Validation */ - int sae_pwe; /* SAE PWE generation options */ + enum sae_pwe 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; + unsigned int ssid_protection:1; u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */ size_t assoc_wpa_ie_len; @@ -152,6 +154,7 @@ struct wpa_sm { size_t pmk_r1_len; u8 pmk_r1_name[WPA_PMK_NAME_LEN]; u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; + u8 key_mobility_domain[MOBILITY_DOMAIN_ID_LEN]; u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; size_t r0kh_id_len; u8 r1kh_id[FT_R1KH_ID_LEN]; @@ -183,11 +186,16 @@ struct wpa_sm { #ifdef CONFIG_TESTING_OPTIONS struct wpabuf *test_assoc_ie; + struct wpabuf *test_eapol_m2_elems; + struct wpabuf *test_eapol_m4_elems; 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; + unsigned int disable_eapol_g2_tx; + bool encrypt_eapol_m2; + bool encrypt_eapol_m4; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_FILS @@ -219,9 +227,11 @@ struct wpa_sm { struct wpabuf *dpp_z; int dpp_pfs; #endif /* CONFIG_DPP2 */ -#ifdef CONFIG_MLD_PATCH struct wpa_sm_mlo mlo; -#endif + + bool wmm_enabled; + bool driver_bss_selection; + bool ft_prepend_pmkid; }; @@ -242,23 +252,16 @@ static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, u16 reason_code) WPA_ASSERT(sm->ctx->deauthenticate); sm->ctx->deauthenticate(sm->ctx->ctx, reason_code); } -#ifdef CONFIG_MLD_PATCH -static inline int wpa_sm_set_key(struct wpa_sm *sm, int link_id, enum wpa_alg alg, -#else -static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg, -#endif - const u8 *addr, int key_idx, int set_tx, - const u8 *seq, size_t seq_len, + +static inline int wpa_sm_set_key(struct wpa_sm *sm, int link_id, + enum wpa_alg alg, const u8 *addr, int key_idx, + int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len, enum key_flag key_flag) { WPA_ASSERT(sm->ctx->set_key); -#ifdef CONFIG_MLD_PATCH - return sm->ctx->set_key(sm->ctx->ctx, link_id, alg, addr, key_idx, set_tx, -#else - return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx, -#endif - seq, seq_len, key, key_len, key_flag); + return sm->ctx->set_key(sm->ctx->ctx, link_id, alg, addr, key_idx, + set_tx, seq, seq_len, key, key_len, key_flag); } static inline void wpa_sm_reconnect(struct wpa_sm *sm) @@ -387,13 +390,13 @@ static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, int initiator, const u8 *buf, - size_t len) + size_t len, int link_id) { if (sm->ctx->send_tdls_mgmt) return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code, dialog_token, status_code, peer_capab, initiator, buf, - len); + len, link_id); return -1; } @@ -417,7 +420,9 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add, u8 qosinfo, int wmm, const u8 *ext_capab, size_t ext_capab_len, const u8 *supp_channels, size_t supp_channels_len, const u8 *supp_oper_classes, - size_t supp_oper_classes_len) + size_t supp_oper_classes_len, + const struct ieee80211_eht_capabilities *eht_capab, + size_t eht_capab_len, int mld_link_id) { if (sm->ctx->tdls_peer_addset) return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add, @@ -430,7 +435,9 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add, supp_channels, supp_channels_len, supp_oper_classes, - supp_oper_classes_len); + supp_oper_classes_len, + eht_capab, eht_capab_len, + mld_link_id); return -1; } @@ -486,7 +493,7 @@ static inline void wpa_sm_transition_disable(struct wpa_sm *sm, u8 bitmap) } static inline void wpa_sm_store_ptk(struct wpa_sm *sm, - u8 *addr, int cipher, + const u8 *addr, int cipher, u32 life_time, struct wpa_ptk *ptk) { if (sm->ctx->store_ptk) @@ -494,6 +501,32 @@ static inline void wpa_sm_store_ptk(struct wpa_sm *sm, ptk); } +#ifdef CONFIG_PASN +static inline int wpa_sm_set_ltf_keyseed(struct wpa_sm *sm, const u8 *own_addr, + const u8 *peer_addr, + size_t ltf_keyseed_len, + const u8 *ltf_keyseed) +{ + WPA_ASSERT(sm->ctx->set_ltf_keyseed); + return sm->ctx->set_ltf_keyseed(sm->ctx->ctx, own_addr, peer_addr, + ltf_keyseed_len, ltf_keyseed); +} +#endif /* CONFIG_PASN */ + +static inline void +wpa_sm_notify_pmksa_cache_entry(struct wpa_sm *sm, + struct rsn_pmksa_cache_entry *entry) +{ + if (sm->ctx->notify_pmksa_cache_entry) + sm->ctx->notify_pmksa_cache_entry(sm->ctx->ctx, entry); +} + +static inline void wpa_sm_ssid_verified(struct wpa_sm *sm) +{ + if (sm->ctx->ssid_verified) + sm->ctx->ssid_verified(sm->ctx->ctx); +} + int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk, int ver, const u8 *dest, u16 proto, u8 *msg, size_t msg_len, u8 *key_mic); diff --git a/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_ie.c b/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_ie.c index b61c6767cbeb4e72cd2ce87182b9494cc5c285df..1023b39f2a5f2fe349d44b512fba0085e9ca00f0 100644 --- a/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_ie.c +++ b/wpa_supplicant-2.9_standard/src/rsn_supp/wpa_ie.c @@ -115,6 +115,10 @@ u16 rsn_supp_capab(struct wpa_sm *sm) { u16 capab = 0; + if (sm->wmm_enabled) { + /* Advertise 16 PTKSA replay counters when using WMM */ + capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; + } if (sm->mfp) capab |= WPA_CAPABILITY_MFPC; if (sm->mfp == 2) @@ -201,6 +205,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY); } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); + } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE_EXT_KEY) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY); #endif /* CONFIG_SAE */ } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192); @@ -230,6 +236,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, } else if (key_mgmt & WPA_KEY_MGMT_OSEN) { RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN); #endif /* CONFIG_HS20 */ +#ifdef CONFIG_SHA384 + } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA384) { + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA384); +#endif /* CONFIG_SHA384 */ } else { wpa_printf(MSG_WARNING, "Invalid key management type (%d).", key_mgmt); @@ -362,11 +372,12 @@ 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; + u32 capab = 0, tmp; size_t flen; if (wpa_key_mgmt_sae(sm->key_mgmt) && - (sm->sae_pwe == 1 || sm->sae_pwe == 2 || sm->sae_pk)) { + (sm->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || + sm->sae_pwe == SAE_PWE_BOTH || sm->sae_pk)) { capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); #ifdef CONFIG_SAE_PK if (sm->sae_pk) @@ -379,21 +390,28 @@ int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len) if (sm->secure_rtt) capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT); if (sm->prot_range_neg) - capab |= BIT(WLAN_RSNX_CAPAB_PROT_RANGE_NEG); + capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR); + if (sm->ssid_protection) + capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION); - flen = (capab & 0xff00) ? 2 : 1; if (!capab) return 0; /* no supported extended RSN capabilities */ + tmp = capab; + flen = 0; + while (tmp) { + flen++; + tmp >>= 8; + } if (rsnxe_len < 2 + flen) return -1; capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */ *pos++ = WLAN_EID_RSNX; *pos++ = flen; - *pos++ = capab & 0x00ff; - capab >>= 8; - if (capab) - *pos++ = capab; + while (capab) { + *pos++ = capab & 0xff; + capab >>= 8; + } return pos - rsnxe; } diff --git a/wpa_supplicant-2.9_standard/src/tls/libtommath.c b/wpa_supplicant-2.9_standard/src/tls/libtommath.c index 715674424324d9bad5621e24ebedadffeb0c5c83..ed595bd62d72de786914c742be210829e14fbf10 100644 --- a/wpa_supplicant-2.9_standard/src/tls/libtommath.c +++ b/wpa_supplicant-2.9_standard/src/tls/libtommath.c @@ -59,14 +59,6 @@ /* from tommath.h */ -#ifndef MIN - #define MIN(x,y) ((x)<(y)?(x):(y)) -#endif - -#ifndef MAX - #define MAX(x,y) ((x)>(y)?(x):(y)) -#endif - #define OPT_CAST(x) #ifdef __x86_64__ diff --git a/wpa_supplicant-2.9_standard/src/tls/pkcs1.c b/wpa_supplicant-2.9_standard/src/tls/pkcs1.c index 49e439d0276897c692927b4cbfce77c41b48c77f..7ea9cc7f32b09fdbf1cd82fb989eed4efab0730c 100755 --- a/wpa_supplicant-2.9_standard/src/tls/pkcs1.c +++ b/wpa_supplicant-2.9_standard/src/tls/pkcs1.c @@ -322,8 +322,6 @@ int pkcs1_v15_sig_ver(struct crypto_public_key *pk, return -1; } - os_free(decrypted); - if (hdr.payload + hdr.length != decrypted + decrypted_len) { wpa_printf(MSG_INFO, "PKCS #1: Extra data after signature - reject"); @@ -332,8 +330,12 @@ int pkcs1_v15_sig_ver(struct crypto_public_key *pk, hdr.payload + hdr.length, decrypted + decrypted_len - hdr.payload - hdr.length); + + os_free(decrypted); return -1; } + os_free(decrypted); + return 0; } diff --git a/wpa_supplicant-2.9_standard/src/tls/tlsv1_client_read.c b/wpa_supplicant-2.9_standard/src/tls/tlsv1_client_read.c index 3825a7380dd5eae6b6221e3441b89138634167e0..9df56c257b317392d2e3b2b9a653723f9de42095 100644 --- a/wpa_supplicant-2.9_standard/src/tls/tlsv1_client_read.c +++ b/wpa_supplicant-2.9_standard/src/tls/tlsv1_client_read.c @@ -771,7 +771,8 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, hlen = tls_key_x_server_params_hash( conn->rl.tls_version, conn->client_random, conn->server_random, server_params, - server_params_end - server_params, hash); + server_params_end - server_params, hash, + sizeof(hash)); } if (hlen < 0) diff --git a/wpa_supplicant-2.9_standard/src/tls/tlsv1_common.c b/wpa_supplicant-2.9_standard/src/tls/tlsv1_common.c index e178915a454d79c096dfc5c1be53fa384136ac75..0dd8e279994f3d13be9298a34d14721c26fb7e63 100644 --- a/wpa_supplicant-2.9_standard/src/tls/tlsv1_common.c +++ b/wpa_supplicant-2.9_standard/src/tls/tlsv1_common.c @@ -378,7 +378,7 @@ int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_alg, int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random, const u8 *server_random, const u8 *server_params, - size_t server_params_len, u8 *hash) + size_t server_params_len, u8 *hash, size_t hsz) { u8 *hpos; size_t hlen; @@ -393,6 +393,8 @@ int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random, crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN); crypto_hash_update(ctx, server_params, server_params_len); hlen = MD5_MAC_LEN; + if (hsz < hlen) + return -1; if (crypto_hash_finish(ctx, hash, &hlen) < 0) return -1; hpos += hlen; @@ -403,7 +405,7 @@ int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random, crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN); crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN); crypto_hash_update(ctx, server_params, server_params_len); - hlen = hash + sizeof(hash) - hpos; + hlen = hsz - hlen; if (crypto_hash_finish(ctx, hpos, &hlen) < 0) return -1; hpos += hlen; diff --git a/wpa_supplicant-2.9_standard/src/tls/tlsv1_common.h b/wpa_supplicant-2.9_standard/src/tls/tlsv1_common.h index e30b15a030a801c8cc72e808d16588f48dca19a3..4cfdc2d551590e8bc25b92b5da318227f2a2336f 100644 --- a/wpa_supplicant-2.9_standard/src/tls/tlsv1_common.h +++ b/wpa_supplicant-2.9_standard/src/tls/tlsv1_common.h @@ -267,7 +267,8 @@ int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_Alg, int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random, const u8 *server_random, const u8 *server_params, - size_t server_params_len, u8 *hash); + size_t server_params_len, + u8 *hash, size_t hsz); int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk, const u8 *data, size_t data_len, const u8 *pos, size_t len, u8 *alert); diff --git a/wpa_supplicant-2.9_standard/src/tls/tlsv1_server_write.c b/wpa_supplicant-2.9_standard/src/tls/tlsv1_server_write.c index 8d36cf1353910bba9e6fff71fd02a9ef8fb9f71c..545abae2ba845b51624da98a60863836bc59b952 100644 --- a/wpa_supplicant-2.9_standard/src/tls/tlsv1_server_write.c +++ b/wpa_supplicant-2.9_standard/src/tls/tlsv1_server_write.c @@ -620,7 +620,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, hlen = tls_key_x_server_params_hash( conn->rl.tls_version, conn->client_random, conn->server_random, server_params, - pos - server_params, hash); + pos - server_params, hash, sizeof(hash)); } if (hlen < 0) { diff --git a/wpa_supplicant-2.9_standard/src/tls/x509v3.c b/wpa_supplicant-2.9_standard/src/tls/x509v3.c index f07affc52dc6f071eb29076435bfc5a4fb6a165a..b006e99fd53839481a64f605a140d917e19d381d 100755 --- a/wpa_supplicant-2.9_standard/src/tls/x509v3.c +++ b/wpa_supplicant-2.9_standard/src/tls/x509v3.c @@ -1903,8 +1903,6 @@ int x509_check_signature(struct x509_certificate *issuer, } wpa_hexdump(MSG_MSGDUMP, "X509: DigestInfo", hdr.payload, hdr.length); - wpa_hexdump(MSG_MSGDUMP, "X509: DigestInfo", hdr.payload, hdr.length); - pos = hdr.payload; end = pos + hdr.length; diff --git a/wpa_supplicant-2.9_standard/src/utils/browser.c b/wpa_supplicant-2.9_standard/src/utils/browser.c index c0f4380c4e3844dd427528f2b9b695522a55e7f3..b5d5ba78f26475dd7d73727642d5301f8e82b92d 100644 --- a/wpa_supplicant-2.9_standard/src/utils/browser.c +++ b/wpa_supplicant-2.9_standard/src/utils/browser.c @@ -370,11 +370,21 @@ int hs20_web_browser(const char *url, int ignore_tls) #ifdef USE_WEBKIT2 if (ignore_tls) { +#if WEBKIT_CHECK_VERSION(2, 32, 0) + WebKitWebContext *wkctx; + WebKitWebsiteDataManager *wkmgr; + + wkctx = webkit_web_context_get_default(); + wkmgr = webkit_web_context_get_website_data_manager(wkctx); + webkit_website_data_manager_set_tls_errors_policy( + wkmgr, WEBKIT_TLS_ERRORS_POLICY_IGNORE); +#else WebKitWebContext *wkctx; wkctx = webkit_web_context_get_default(); webkit_web_context_set_tls_errors_policy( wkctx, WEBKIT_TLS_ERRORS_POLICY_IGNORE); +#endif } #endif /* USE_WEBKIT2 */ diff --git a/wpa_supplicant-2.9_standard/src/utils/common.c b/wpa_supplicant-2.9_standard/src/utils/common.c index cc455a70873407c476c72337d0d7514df4a5e3b6..0817f1fe5c71553c0bcdfa07745964d48a258ccb 100644 --- a/wpa_supplicant-2.9_standard/src/utils/common.c +++ b/wpa_supplicant-2.9_standard/src/utils/common.c @@ -15,7 +15,7 @@ #include "securec.h" #define GAP_SIZE 2 #endif -static int hex2num(char c) +int hex2num(char c) { if (c >= '0' && c <= '9') return c - '0'; @@ -1031,6 +1031,19 @@ void int_array_add_unique(int **res, int a) } +bool int_array_includes(int *arr, int val) +{ + int i; + + for (i = 0; arr && arr[i]; i++) { + if (val == arr[i]) + return true; + } + + return false; +} + + void str_clear_free(char *str) { if (str) { @@ -1164,7 +1177,7 @@ size_t utf8_unescape(const char *inp, size_t in_size, return 0; in_size--; inp++; - /* fall through */ + __attribute__((fallthrough)); default: *outp++ = *inp++; @@ -1204,7 +1217,7 @@ size_t utf8_escape(const char *inp, size_t in_size, if (res_size++ >= out_size) return 0; *outp++ = '\\'; - /* fall through */ + __attribute__((fallthrough)); default: *outp++ = *inp++; diff --git a/wpa_supplicant-2.9_standard/src/utils/common.h b/wpa_supplicant-2.9_standard/src/utils/common.h index 75d9ee0f5424d3a71af95d4df2bd261e6d6d7200..53081fe38d19f74d092a5ab7a2a0035491bcf175 100644 --- a/wpa_supplicant-2.9_standard/src/utils/common.h +++ b/wpa_supplicant-2.9_standard/src/utils/common.h @@ -261,6 +261,18 @@ static inline void WPA_PUT_BE24(u8 *a, u32 val) a[2] = val & 0xff; } +static inline u32 WPA_GET_LE24(const u8 *a) +{ + return (a[2] << 16) | (a[1] << 8) | a[0]; +} + +static inline void WPA_PUT_LE24(u8 *a, u32 val) +{ + a[2] = (val >> 16) & 0xff; + a[1] = (val >> 8) & 0xff; + a[0] = val & 0xff; +} + static inline u32 WPA_GET_BE32(const u8 *a) { return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]; @@ -453,6 +465,13 @@ void perror(const char *s); #define BIT(x) (1U << (x)) #endif +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + /* * Definitions for sparse validation * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) @@ -501,6 +520,7 @@ int hwaddr_aton(const char *txt, u8 *addr); int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable); int hwaddr_compact_aton(const char *txt, u8 *addr); int hwaddr_aton2(const char *txt, u8 *addr); +int hex2num(char c); int hex2byte(const char *hex); int hexstr2bin(const char *hex, u8 *buf, size_t len); #ifdef CONFIG_EAP_AUTH @@ -557,6 +577,11 @@ static inline int is_multicast_ether_addr(const u8 *a) return a[0] & 0x01; } +static inline bool ether_addr_equal(const u8 *a, const u8 *b) +{ + return os_memcmp(a, b, ETH_ALEN) == 0; +} + #define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" #include "wpa_debug.h" @@ -579,6 +604,7 @@ size_t int_array_len(const int *a); void int_array_concat(int **res, const int *a); void int_array_sort_unique(int *a); void int_array_add_unique(int **res, int a); +bool int_array_includes(int *arr, int val); #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) @@ -600,7 +626,7 @@ int str_starts(const char *str, const char *start); u8 rssi_to_rcpi(int rssi); char * get_param(const char *cmd, const char *param); -#ifdef CONFIG_MLD_PATCH + #define for_each_link(__links, __i) \ for ((__i) = 0; (__i) < MAX_NUM_MLD_LINKS; (__i)++) \ if ((__links) & BIT(__i)) @@ -612,7 +638,7 @@ char * get_param(const char *cmd, const char *param); (!(_links) && (_i) == (_def_idx)); \ (_i)++) \ if (!(_links) || (_links) & BIT(_i)) -#endif + void forced_memzero(void *ptr, size_t len); const char *mac_to_str(const u8 *addr); diff --git a/wpa_supplicant-2.9_standard/src/utils/crc32.c b/wpa_supplicant-2.9_standard/src/utils/crc32.c index 12d9e2a7008ed96c4b47fffa1147533bc4a80211..3712549945dc4c60040573c5fde3fde2ed76818a 100644 --- a/wpa_supplicant-2.9_standard/src/utils/crc32.c +++ b/wpa_supplicant-2.9_standard/src/utils/crc32.c @@ -72,7 +72,7 @@ static const u32 crc32_table[256] = { }; -u32 crc32(const u8 *frame, size_t frame_len) +u32 ieee80211_crc32(const u8 *frame, size_t frame_len) { size_t i; u32 crc; diff --git a/wpa_supplicant-2.9_standard/src/utils/crc32.h b/wpa_supplicant-2.9_standard/src/utils/crc32.h index dc31399beb638e65858a287e3adb29413a8873c6..71a19dc5fcc3293f1e85fa1909c40409486c4956 100644 --- a/wpa_supplicant-2.9_standard/src/utils/crc32.h +++ b/wpa_supplicant-2.9_standard/src/utils/crc32.h @@ -9,6 +9,6 @@ #ifndef CRC32_H #define CRC32_H -u32 crc32(const u8 *frame, size_t frame_len); +u32 ieee80211_crc32(const u8 *frame, size_t frame_len); #endif /* CRC32_H */ diff --git a/wpa_supplicant-2.9_standard/src/utils/eloop.c b/wpa_supplicant-2.9_standard/src/utils/eloop.c index acc6b456ff2ffe379d9cece7cf1eb9ad85290195..9523011bc8080dbc87d791e3b017ff0c917296d7 100644 --- a/wpa_supplicant-2.9_standard/src/utils/eloop.c +++ b/wpa_supplicant-2.9_standard/src/utils/eloop.c @@ -1171,19 +1171,6 @@ int eloop_register_signal_reconfig(eloop_signal_handler handler, #endif /* CONFIG_NATIVE_WINDOWS */ } -long select_start_time; - -long select_end_time; - -long get_select_start_time(void) -{ - return select_start_time; -} - -long get_select_end_time(void) -{ - return select_end_time; -} void eloop_run(void) { @@ -1263,10 +1250,8 @@ void eloop_run(void) eloop_sock_table_set_fds(&eloop.readers, rfds); eloop_sock_table_set_fds(&eloop.writers, wfds); eloop_sock_table_set_fds(&eloop.exceptions, efds); - select_start_time = get_realtime_microsecond(); res = select(eloop.max_sock + 1, rfds, wfds, efds, timeout ? &_tv : NULL); - select_end_time = get_realtime_microsecond(); #endif /* CONFIG_ELOOP_SELECT */ #ifdef CONFIG_ELOOP_EPOLL if (eloop.count == 0) { diff --git a/wpa_supplicant-2.9_standard/src/utils/eloop.h b/wpa_supplicant-2.9_standard/src/utils/eloop.h index b40f87572b40010524eb0078c5ba31054c794a2f..04ee6d1837b63e92ceef4448975eceeaa5fb073c 100644 --- a/wpa_supplicant-2.9_standard/src/utils/eloop.h +++ b/wpa_supplicant-2.9_standard/src/utils/eloop.h @@ -364,15 +364,4 @@ int eloop_terminated(void); */ void eloop_wait_for_read_sock(int sock); -/** - * get_select_start_time - get time of select start time - * @return eloop run select start time - */ -long get_select_start_time(void); - -/** - * get_select_start_time - get time of select end time - * @return eloop run select end time - */ -long get_select_end_time(void); #endif /* ELOOP_H */ diff --git a/wpa_supplicant-2.9_standard/src/utils/http-utils.h b/wpa_supplicant-2.9_standard/src/utils/http-utils.h index d9fc925a2bce1ea56b7baec43c2276dfbea8ee80..23e9ecd9bb638bae99cbf7b5d32c1614982355a3 100644 --- a/wpa_supplicant-2.9_standard/src/utils/http-utils.h +++ b/wpa_supplicant-2.9_standard/src/utils/http-utils.h @@ -33,6 +33,7 @@ struct http_cert { size_t num_othername; struct http_logo *logo; size_t num_logo; + const char *url; }; int soap_init_client(struct http_ctx *ctx, const char *address, diff --git a/wpa_supplicant-2.9_standard/src/utils/http_curl.c b/wpa_supplicant-2.9_standard/src/utils/http_curl.c index e62fbf96bcb32ff548167e79362283c178986598..a09e8d49e9085d01017c091d55516c9559ff0709 100644 --- a/wpa_supplicant-2.9_standard/src/utils/http_curl.c +++ b/wpa_supplicant-2.9_standard/src/utils/http_curl.c @@ -64,6 +64,7 @@ struct http_ctx { X509 *peer_issuer_issuer; const char *last_err; + const char *url; }; @@ -432,28 +433,6 @@ ASN1_SEQUENCE(LogotypeExtn) = { IMPLEMENT_ASN1_FUNCTIONS(LogotypeExtn); -#ifdef OPENSSL_IS_BORINGSSL -#define sk_LogotypeInfo_num(st) \ -sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeInfo) *, (st))) -#define sk_LogotypeInfo_value(st, i) (LogotypeInfo *) \ -sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeInfo) *, (st)), (i)) -#define sk_LogotypeImage_num(st) \ -sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeImage) *, (st))) -#define sk_LogotypeImage_value(st, i) (LogotypeImage *) \ -sk_value(CHECKED_CAST(_STACK *, const STACK_OF(LogotypeImage) *, (st)), (i)) -#define sk_LogotypeAudio_num(st) \ -sk_num(CHECKED_CAST(_STACK *, STACK_OF(LogotypeAudio) *, (st))) -#define sk_LogotypeAudio_value(st, i) (LogotypeAudio *) \ -sk_value(CHECK_CAST(_STACK *, const STACK_OF(LogotypeAudio) *, (st)), (i)) -#define sk_HashAlgAndValue_num(st) \ -sk_num(CHECKED_CAST(_STACK *, STACK_OF(HashAlgAndValue) *, (st))) -#define sk_HashAlgAndValue_value(st, i) (HashAlgAndValue *) \ -sk_value(CHECKED_CAST(_STACK *, const STACK_OF(HashAlgAndValue) *, (st)), (i)) -#define sk_ASN1_IA5STRING_num(st) \ -sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_IA5STRING) *, (st))) -#define sk_ASN1_IA5STRING_value(st, i) (ASN1_IA5STRING *) \ -sk_value(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_IA5STRING) *, (st)), (i)) -#else /* OPENSSL_IS_BORINGSSL */ #if OPENSSL_VERSION_NUMBER < 0x10100000L #define sk_LogotypeInfo_num(st) SKM_sk_num(LogotypeInfo, (st)) #define sk_LogotypeInfo_value(st, i) SKM_sk_value(LogotypeInfo, (st), (i)) @@ -472,7 +451,6 @@ DEFINE_STACK_OF(LogotypeAudio) DEFINE_STACK_OF(HashAlgAndValue) DEFINE_STACK_OF(ASN1_IA5STRING) #endif -#endif /* OPENSSL_IS_BORINGSSL */ static void add_logo(struct http_ctx *ctx, struct http_cert *hcert, @@ -871,6 +849,7 @@ static void parse_cert(struct http_ctx *ctx, struct http_cert *hcert, X509 *cert, GENERAL_NAMES **names) { os_memset(hcert, 0, sizeof(*hcert)); + hcert->url = ctx->url ? ctx->url : ctx->svc_address; *names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (*names) @@ -1357,8 +1336,7 @@ static CURL * setup_curl_post(struct http_ctx *ctx, const char *address, const char *extra = ""; #endif /* EAP_TLS_OPENSSL */ - wpa_printf(MSG_DEBUG, "Start HTTP client: address=%s ca_fname=%s " - "username=%s%s", address, ca_fname, username, extra); + wpa_printf(MSG_DEBUG, "Start HTTP client: ca_fname=%s ", ca_fname); curl = curl_easy_init(); if (curl == NULL) @@ -1617,23 +1595,23 @@ int http_download_file(struct http_ctx *ctx, const char *url, const char *fname, const char *ca_fname) { CURL *curl; - FILE *f; + FILE *f = NULL; CURLcode res; long http = 0; + int ret = -1; ctx->last_err = NULL; + ctx->url = url; wpa_printf(MSG_DEBUG, "curl: Download file from %s to %s (ca=%s)", url, fname, ca_fname); curl = curl_easy_init(); if (curl == NULL) - return -1; + goto fail; f = fopen(fname, "wb"); - if (f == NULL) { - curl_easy_cleanup(curl); - return -1; - } + if (!f) + goto fail; curl_easy_setopt(curl, CURLOPT_URL, url); if (ca_fname) { @@ -1655,9 +1633,7 @@ int http_download_file(struct http_ctx *ctx, const char *url, ctx->last_err = curl_easy_strerror(res); wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", ctx->last_err); - curl_easy_cleanup(curl); - fclose(f); - return -1; + goto fail; } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); @@ -1665,15 +1641,19 @@ int http_download_file(struct http_ctx *ctx, const char *url, if (http != 200) { ctx->last_err = "HTTP download failed"; wpa_printf(MSG_INFO, "HTTP download failed - code %ld", http); - curl_easy_cleanup(curl); - fclose(f); - return -1; + goto fail; } - curl_easy_cleanup(curl); - fclose(f); + ret = 0; - return 0; +fail: + ctx->url = NULL; + if (curl) + curl_easy_cleanup(curl); + if (f) + fclose(f); + + return ret; } @@ -1686,16 +1666,17 @@ char * http_post(struct http_ctx *ctx, const char *url, const char *data, { long http = 0; CURLcode res; - char *ret; + char *ret = NULL; CURL *curl; struct curl_slist *curl_hdr = NULL; ctx->last_err = NULL; + ctx->url = url; wpa_printf(MSG_DEBUG, "curl: HTTP POST to %s", url); curl = setup_curl_post(ctx, url, ca_fname, username, password, client_cert, client_key); if (curl == NULL) - return NULL; + goto fail; if (content_type) { char ct[200]; @@ -1715,8 +1696,7 @@ char * http_post(struct http_ctx *ctx, const char *url, const char *data, ctx->last_err = curl_easy_strerror(res); wpa_printf(MSG_ERROR, "curl_easy_perform() failed: %s", ctx->last_err); - free_curl_buf(ctx); - return NULL; + goto fail; } curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http); @@ -1724,12 +1704,11 @@ char * http_post(struct http_ctx *ctx, const char *url, const char *data, if (http != 200) { ctx->last_err = "HTTP POST failed"; wpa_printf(MSG_INFO, "HTTP POST failed - code %ld", http); - free_curl_buf(ctx); - return NULL; + goto fail; } if (ctx->curl_buf == NULL) - return NULL; + goto fail; ret = ctx->curl_buf; if (resp_len) @@ -1739,6 +1718,9 @@ char * http_post(struct http_ctx *ctx, const char *url, const char *data, wpa_printf(MSG_MSGDUMP, "Server response:\n%s", ret); +fail: + free_curl_buf(ctx); + ctx->url = NULL; return ret; } diff --git a/wpa_supplicant-2.9_standard/src/utils/ip_addr.c b/wpa_supplicant-2.9_standard/src/utils/ip_addr.c index 92a3590390331c8ef16b9df75e97f764e73874fa..a971f72e26afb52e111e04ae21b36f567752dcb8 100644 --- a/wpa_supplicant-2.9_standard/src/utils/ip_addr.c +++ b/wpa_supplicant-2.9_standard/src/utils/ip_addr.c @@ -51,3 +51,22 @@ int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr) return -1; } + + +bool hostapd_ip_equal(const struct hostapd_ip_addr *a, + const struct hostapd_ip_addr *b) +{ + if (a->af != b->af) + return false; + + if (a->af == AF_INET && a->u.v4.s_addr == b->u.v4.s_addr) + return true; + +#ifdef CONFIG_IPV6 + if (a->af == AF_INET6 && + os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) == 0) + return true; +#endif /* CONFIG_IPV6 */ + + return false; +} diff --git a/wpa_supplicant-2.9_standard/src/utils/ip_addr.h b/wpa_supplicant-2.9_standard/src/utils/ip_addr.h index e572277d1a68413ee1afb95dc7f358d30f70fed8..2250470cb7c811cefbb61a7322edad47f3140584 100644 --- a/wpa_supplicant-2.9_standard/src/utils/ip_addr.h +++ b/wpa_supplicant-2.9_standard/src/utils/ip_addr.h @@ -26,5 +26,7 @@ struct hostapd_ip_addr { const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf, size_t buflen); int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr); +bool hostapd_ip_equal(const struct hostapd_ip_addr *a, + const struct hostapd_ip_addr *b); #endif /* IP_ADDR_H */ diff --git a/wpa_supplicant-2.9_standard/src/utils/os.h b/wpa_supplicant-2.9_standard/src/utils/os.h index 11d3315f51411dea38354efbf8372fa97e42e250..bdbf6c5a5b880180565f4650e3ebed542fa52b01 100644 --- a/wpa_supplicant-2.9_standard/src/utils/os.h +++ b/wpa_supplicant-2.9_standard/src/utils/os.h @@ -9,6 +9,7 @@ #ifndef OS_H #define OS_H #include +#include typedef long os_time_t; @@ -109,6 +110,26 @@ static inline int os_reltime_expired(struct os_reltime *now, } +static inline void os_reltime_add_ms(struct os_reltime *ts, int ms) +{ + ts->usec += ms * 1000; + while (ts->usec >= 1000000) { + ts->sec++; + ts->usec -= 1000000; + } + while (ts->usec < 0) { + ts->sec--; + ts->usec += 1000000; + } +} + + +static inline int os_reltime_in_ms(struct os_reltime *ts) +{ + return ts->sec * 1000 + ts->usec / 1000; +} + + static inline int os_reltime_initialized(struct os_reltime *t) { return t->sec != 0 || t->usec != 0; @@ -668,14 +689,24 @@ int os_exec(const char *program, const char *arg, int wait_completion); #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) -#define TEST_FAIL() testing_test_fail() -int testing_test_fail(void); -extern char wpa_trace_fail_func[256]; -extern unsigned int wpa_trace_fail_after; -extern char wpa_trace_test_fail_func[256]; -extern unsigned int wpa_trace_test_fail_after; +#define TEST_FAIL() testing_test_fail(NULL, false) +#define TEST_FAIL_TAG(tag) testing_test_fail(tag, false) +int testing_test_fail(const char *tag, bool is_alloc); +int testing_set_fail_pattern(bool is_alloc, char *patterns); +int testing_get_fail_pattern(bool is_alloc, char *buf, size_t buflen); #else #define TEST_FAIL() 0 +#define TEST_FAIL_TAG(tag) 0 +static inline int testing_set_fail_pattern(bool is_alloc, char *patterns) +{ + return -1; +} + +static inline int testing_get_fail_pattern(bool is_alloc, char *buf, + size_t buflen) +{ + return -1; +} #endif #endif /* OS_H */ diff --git a/wpa_supplicant-2.9_standard/src/utils/os_unix.c b/wpa_supplicant-2.9_standard/src/utils/os_unix.c index 3cbab909c42764dc6d0f9c6d1eccc7ea22901f98..73035d19d70d91f76f6a1feabe0b5d1131530d3f 100644 --- a/wpa_supplicant-2.9_standard/src/utils/os_unix.c +++ b/wpa_supplicant-2.9_standard/src/utils/os_unix.c @@ -540,44 +540,65 @@ void * os_memdup(const void *src, size_t len) #ifdef WPA_TRACE #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) -char wpa_trace_fail_func[256] = { 0 }; -unsigned int wpa_trace_fail_after; +struct wpa_trace_test_fail { + unsigned int fail_after; + char pattern[256]; +} wpa_trace_test_fail[5][2]; -static int testing_fail_alloc(void) +int testing_test_fail(const char *tag, bool is_alloc) { + const char *ignore_list[] = { + "os_malloc", "os_zalloc", "os_calloc", "os_realloc", + "os_realloc_array", "os_strdup", "os_memdup" + }; const char *func[WPA_TRACE_LEN]; - size_t i, res, len; + size_t i, j, res, len, idx; char *pos, *next; int match; - if (!wpa_trace_fail_after) + is_alloc = !!is_alloc; + + for (idx = 0; idx < ARRAY_SIZE(wpa_trace_test_fail[is_alloc]); idx++) { + if (wpa_trace_test_fail[is_alloc][idx].fail_after != 0) + break; + } + if (idx >= ARRAY_SIZE(wpa_trace_test_fail[is_alloc])) return 0; res = wpa_trace_calling_func(func, WPA_TRACE_LEN); i = 0; - if (i < res && os_strcmp(func[i], __func__) == 0) - i++; - if (i < res && os_strcmp(func[i], "os_malloc") == 0) - i++; - if (i < res && os_strcmp(func[i], "os_zalloc") == 0) - i++; - if (i < res && os_strcmp(func[i], "os_calloc") == 0) - i++; - if (i < res && os_strcmp(func[i], "os_realloc") == 0) - i++; - if (i < res && os_strcmp(func[i], "os_realloc_array") == 0) - i++; - if (i < res && os_strcmp(func[i], "os_strdup") == 0) - i++; - if (i < res && os_strcmp(func[i], "os_memdup") == 0) + + if (is_alloc) { + /* Skip our own stack frame */ i++; - pos = wpa_trace_fail_func; + /* Skip allocation helpers */ + for (j = 0; j < ARRAY_SIZE(ignore_list) && i < res; j++) { + if (os_strcmp(func[i], ignore_list[j]) == 0) + i++; + } + } else { + /* Not allocation, we might have a tag, if so, replace our + * own stack frame with the tag, otherwise skip it. + */ + if (tag) + func[0] = tag; + else + i++; + } + + pos = wpa_trace_test_fail[is_alloc][idx].pattern; + + /* The prefixes mean: + * - '=': The function needs to be next in the backtrace + * - '?': The function is optionally present in the backtrace + */ match = 0; while (i < res) { int allow_skip = 1; int maybe = 0; + bool prefix = false; if (*pos == '=') { allow_skip = 0; @@ -591,7 +612,12 @@ static int testing_fail_alloc(void) len = next - pos; else len = os_strlen(pos); - if (os_memcmp(pos, func[i], len) != 0) { + if (len >= 1 && pos[len - 1] == '*') { + prefix = true; + len -= 1; + } + if (os_strncmp(pos, func[i], len) != 0 || + (!prefix && func[i][len] != '\0')) { if (maybe && next) { pos = next + 1; continue; @@ -612,10 +638,10 @@ static int testing_fail_alloc(void) if (!match) return 0; - wpa_trace_fail_after--; - if (wpa_trace_fail_after == 0) { - wpa_printf(MSG_INFO, "TESTING: fail allocation at %s", - wpa_trace_fail_func); + wpa_trace_test_fail[is_alloc][idx].fail_after--; + if (wpa_trace_test_fail[is_alloc][idx].fail_after == 0) { + wpa_printf(MSG_INFO, "TESTING: fail at %s", + wpa_trace_test_fail[is_alloc][idx].pattern); for (i = 0; i < res; i++) wpa_printf(MSG_INFO, "backtrace[%d] = %s", (int) i, func[i]); @@ -626,90 +652,83 @@ static int testing_fail_alloc(void) } -char wpa_trace_test_fail_func[256] = { 0 }; -unsigned int wpa_trace_test_fail_after; - -int testing_test_fail(void) +int testing_set_fail_pattern(bool is_alloc, char *patterns) { - const char *func[WPA_TRACE_LEN]; - size_t i, res, len; - char *pos, *next; - int match; +#ifdef WPA_TRACE_BFD + char *token, *context = NULL; + size_t idx; + + is_alloc = !!is_alloc; + + os_memset(wpa_trace_test_fail[is_alloc], 0, + sizeof(wpa_trace_test_fail[is_alloc])); + + idx = 0; + while ((token = str_token(patterns, " \n\r\t", &context)) && + idx < ARRAY_SIZE(wpa_trace_test_fail[is_alloc])) { + wpa_trace_test_fail[is_alloc][idx].fail_after = atoi(token); + token = os_strchr(token, ':'); + if (!token) { + os_memset(wpa_trace_test_fail[is_alloc], 0, + sizeof(wpa_trace_test_fail[is_alloc])); + return -1; + } - if (!wpa_trace_test_fail_after) - return 0; + os_strlcpy(wpa_trace_test_fail[is_alloc][idx].pattern, + token + 1, + sizeof(wpa_trace_test_fail[is_alloc][0].pattern)); + idx++; + } - res = wpa_trace_calling_func(func, WPA_TRACE_LEN); - i = 0; - if (i < res && os_strcmp(func[i], __func__) == 0) - i++; + return 0; +#else /* WPA_TRACE_BFD */ + return -1; +#endif /* WPA_TRACE_BFD */ +} - pos = wpa_trace_test_fail_func; - match = 0; - while (i < res) { - int allow_skip = 1; - int maybe = 0; +int testing_get_fail_pattern(bool is_alloc, char *buf, size_t buflen) +{ +#ifdef WPA_TRACE_BFD + size_t idx, ret; + char *pos = buf; + char *end = buf + buflen; - if (*pos == '=') { - allow_skip = 0; - pos++; - } else if (*pos == '?') { - maybe = 1; - pos++; - } - next = os_strchr(pos, ';'); - if (next) - len = next - pos; - else - len = os_strlen(pos); - if (os_memcmp(pos, func[i], len) != 0) { - if (maybe && next) { - pos = next + 1; - continue; - } - if (allow_skip) { - i++; - continue; - } - return 0; - } - if (!next) { - match = 1; + is_alloc = !!is_alloc; + + for (idx = 0; idx < ARRAY_SIZE(wpa_trace_test_fail[is_alloc]); idx++) { + if (wpa_trace_test_fail[is_alloc][idx].pattern[0] == '\0') break; - } - pos = next + 1; - i++; - } - if (!match) - return 0; - wpa_trace_test_fail_after--; - if (wpa_trace_test_fail_after == 0) { - wpa_printf(MSG_INFO, "TESTING: fail at %s", - wpa_trace_test_fail_func); - for (i = 0; i < res; i++) - wpa_printf(MSG_INFO, "backtrace[%d] = %s", - (int) i, func[i]); - return 1; + ret = os_snprintf(pos, end - pos, "%s%u:%s", + pos == buf ? "" : " ", + wpa_trace_test_fail[is_alloc][idx].fail_after, + wpa_trace_test_fail[is_alloc][idx].pattern); + if (os_snprintf_error(end - pos, ret)) + break; + pos += ret; } - return 0; + return pos - buf; +#else /* WPA_TRACE_BFD */ + return -1; +#endif /* WPA_TRACE_BFD */ } -#else +#else /* defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) */ -static inline int testing_fail_alloc(void) +static inline int testing_test_fail(const char *tag, bool is_alloc) { return 0; } + #endif void * os_malloc(size_t size) { struct os_alloc_trace *a; - if (testing_fail_alloc()) + if (testing_test_fail(NULL, true)) return NULL; a = malloc(sizeof(*a) + size); diff --git a/wpa_supplicant-2.9_standard/src/utils/trace.c b/wpa_supplicant-2.9_standard/src/utils/trace.c index 8f12da87bb1ba21bdfea1d723c35322c9087bd77..7c9a17ff8f7cbee02c90b52e748c3a3f12b28727 100644 --- a/wpa_supplicant-2.9_standard/src/utils/trace.c +++ b/wpa_supplicant-2.9_standard/src/utils/trace.c @@ -197,7 +197,7 @@ static void wpa_trace_bfd_addr(void *pc) if (abfd == NULL) return; - data.pc = (bfd_hostptr_t) ((u8 *) pc - start_offset); + data.pc = (uintptr_t) ((u8 *) pc - start_offset); data.found = FALSE; bfd_map_over_sections(abfd, find_addr_sect, &data); @@ -238,7 +238,7 @@ static const char * wpa_trace_bfd_addr2func(void *pc) if (abfd == NULL) return NULL; - data.pc = (bfd_hostptr_t) ((u8 *) pc - start_offset); + data.pc = (uintptr_t) ((u8 *) pc - start_offset); data.found = FALSE; bfd_map_over_sections(abfd, find_addr_sect, &data); @@ -310,7 +310,7 @@ size_t wpa_trace_calling_func(const char *buf[], size_t len) for (i = 0; i < btrace_num; i++) { struct bfd_data data; - data.pc = (bfd_hostptr_t) ((u8 *) btrace_res[i] - start_offset); + data.pc = (uintptr_t) ((u8 *) btrace_res[i] - start_offset); data.found = FALSE; bfd_map_over_sections(abfd, find_addr_sect, &data); diff --git a/wpa_supplicant-2.9_standard/src/utils/utils_module_tests.c b/wpa_supplicant-2.9_standard/src/utils/utils_module_tests.c index 365f21fb11c63b35b0f483dfa4bfc87724196813..8a80164019882ae7a06e11c64c1e52d60a2311c5 100644 --- a/wpa_supplicant-2.9_standard/src/utils/utils_module_tests.c +++ b/wpa_supplicant-2.9_standard/src/utils/utils_module_tests.c @@ -682,8 +682,7 @@ static void reopen_pipefd2(struct test_eloop *t) } wpa_printf(MSG_INFO, - "re-register pipefd2 with new sockets %d,%d", - t->pipefd2[0], t->pipefd2[1]); + "re-register pipefd2 with new sockets"); eloop_register_read_sock(t->pipefd2[0], eloop_test_read_2_wrong, t, NULL); } diff --git a/wpa_supplicant-2.9_standard/src/utils/wpa_debug.c b/wpa_supplicant-2.9_standard/src/utils/wpa_debug.c index 45a01f69ab731d2390626bc0f886bb81b7e29dbc..0af881431bb08e856572caec0ecede4ba8650ec5 100644 --- a/wpa_supplicant-2.9_standard/src/utils/wpa_debug.c +++ b/wpa_supplicant-2.9_standard/src/utils/wpa_debug.c @@ -254,8 +254,9 @@ static int is_symbol_logical(char *for_check, size_t i) const int macIndexSix = 6; const int macIndexNine = 9; const int macIndexTwelve = 12; - if ((':' == *(for_check + i)) && (':' == *(for_check + i + macIndexThr)) && (':' == *(for_check + i + macIndexSix)) - && (':' == *(for_check + i + macIndexNine)) && (':' == *(for_check + i + macIndexTwelve))) { + if ((':' == *(for_check + i)) && (':' == *(for_check + i + macIndexThr)) + && (':' == *(for_check + i + macIndexSix)) && (':' == *(for_check + i + macIndexNine)) + && (':' == *(for_check + i + macIndexTwelve))) { return 1; } return 0; @@ -1061,13 +1062,21 @@ int wpa_debug_open_file(const char *path) } -void wpa_debug_close_file(void) +void wpa_debug_stop_log(void) { #ifdef CONFIG_DEBUG_FILE if (!out_file) return; fclose(out_file); out_file = NULL; +#endif /* CONFIG_DEBUG_FILE */ +} + + +void wpa_debug_close_file(void) +{ +#ifdef CONFIG_DEBUG_FILE + wpa_debug_stop_log(); os_free(last_path); last_path = NULL; #endif /* CONFIG_DEBUG_FILE */ @@ -1346,7 +1355,7 @@ void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, hostapd_logger_cb(ctx, addr, module, level, buf, len); else if (addr) wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR_SEC " - %s", - MAC2STR_SEC(addr), get_anonymized_result_setnetwork_for_bssid(buf)); + MAC2STR_SEC(addr), get_anonymized_result_setnetwork_for_bssid(buf)); else wpa_printf(MSG_DEBUG, "hostapd_logger: %s", get_anonymized_result_setnetwork_for_bssid(buf)); bin_clear_free(buf, buflen); diff --git a/wpa_supplicant-2.9_standard/src/utils/wpa_debug.h b/wpa_supplicant-2.9_standard/src/utils/wpa_debug.h index b25f2cc5275e4bd8a62e5601ab143716a32545a5..0cd27af8768fb24bcd552ed8c6e57931f35cc89e 100644 --- a/wpa_supplicant-2.9_standard/src/utils/wpa_debug.h +++ b/wpa_supplicant-2.9_standard/src/utils/wpa_debug.h @@ -49,6 +49,7 @@ int wpa_debug_open_file(const char *path); int wpa_debug_reopen_file(void); void wpa_debug_close_file(void); void wpa_debug_setup_stdout(void); +void wpa_debug_stop_log(void); /** * wpa_debug_printf_timestamp - Print timestamp for debug output diff --git a/wpa_supplicant-2.9_standard/src/utils/wpabuf.h b/wpa_supplicant-2.9_standard/src/utils/wpabuf.h index eb1db80912a06b651b567ee207d33e4813c4b478..88d72bd685e5c86cd319a3a806052002b177a898 100644 --- a/wpa_supplicant-2.9_standard/src/utils/wpabuf.h +++ b/wpa_supplicant-2.9_standard/src/utils/wpabuf.h @@ -127,6 +127,12 @@ static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) WPA_PUT_LE16(pos, data); } +static inline void wpabuf_put_le24(struct wpabuf *buf, u32 data) +{ + u8 *pos = (u8 *) wpabuf_put(buf, 3); + WPA_PUT_LE24(pos, data); +} + static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data) { u8 *pos = (u8 *) wpabuf_put(buf, 4); diff --git a/wpa_supplicant-2.9_standard/src/wps/ndef.c b/wpa_supplicant-2.9_standard/src/wps/ndef.c index bb3c055486c027ca994054440aa13c4a8df63f53..63f0d527d5874e3e5636d7c4d7108d4dba158b10 100644 --- a/wpa_supplicant-2.9_standard/src/wps/ndef.c +++ b/wpa_supplicant-2.9_standard/src/wps/ndef.c @@ -63,12 +63,18 @@ static int ndef_parse_record(const u8 *data, u32 size, } else record->id_length = 0; + if (record->type_length > data + size - pos) + return -1; record->type = record->type_length == 0 ? NULL : pos; pos += record->type_length; + if (record->id_length > data + size - pos) + return -1; record->id = record->id_length == 0 ? NULL : pos; pos += record->id_length; + if (record->payload_length > (size_t) (data + size - pos)) + return -1; record->payload = record->payload_length == 0 ? NULL : pos; pos += record->payload_length; diff --git a/wpa_supplicant-2.9_standard/src/wps/wps.c b/wpa_supplicant-2.9_standard/src/wps/wps.c index 5d459e81d5ae06ef24cd70ad8d2dc12cbae17d10..4c5f317ea223a465dc8ba09bd36266057d9299af 100644 --- a/wpa_supplicant-2.9_standard/src/wps/wps.c +++ b/wpa_supplicant-2.9_standard/src/wps/wps.c @@ -145,6 +145,7 @@ struct wps_data * wps_init(const struct wps_config *cfg) } data->multi_ap_backhaul_sta = cfg->multi_ap_backhaul_sta; + data->multi_ap_profile = cfg->multi_ap_profile; return data; } @@ -342,9 +343,9 @@ int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr, pos = attr.authorized_macs; for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) { - if (os_memcmp(pos, addr, ETH_ALEN) == 0) + if (ether_addr_equal(pos, addr)) return 2; - if (os_memcmp(pos, bcast, ETH_ALEN) == 0) + if (ether_addr_equal(pos, bcast)) return 1; pos += ETH_ALEN; } diff --git a/wpa_supplicant-2.9_standard/src/wps/wps.h b/wpa_supplicant-2.9_standard/src/wps/wps.h index e29f985d4ad7c9a1381b66040ff435768459f12f..c21f3fcd1fd20dd11b2d955931d2f1c3478c18ac 100644 --- a/wpa_supplicant-2.9_standard/src/wps/wps.h +++ b/wpa_supplicant-2.9_standard/src/wps/wps.h @@ -195,6 +195,11 @@ struct wps_config { * enrollee */ int multi_ap_backhaul_sta; + + /* + * multi_ap_profile - Get the Multi-AP Profile + */ + int multi_ap_profile; }; struct wps_data * wps_init(const struct wps_config *cfg); diff --git a/wpa_supplicant-2.9_standard/src/wps/wps_attr_parse.c b/wpa_supplicant-2.9_standard/src/wps/wps_attr_parse.c index fd51635158ac5c646bf8772e0d83200972e9c595..d36443008d9aa87ffe349899a372627951939b8b 100644 --- a/wpa_supplicant-2.9_standard/src/wps/wps_attr_parse.c +++ b/wpa_supplicant-2.9_standard/src/wps/wps_attr_parse.c @@ -599,10 +599,15 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr) u16 type, len; #ifdef WPS_WORKAROUNDS u16 prev_type = 0; + size_t last_nonzero = 0; + const u8 *start; #endif /* WPS_WORKAROUNDS */ os_memset(attr, 0, sizeof(*attr)); pos = wpabuf_head(msg); +#ifdef WPS_WORKAROUNDS + start = pos; +#endif /* WPS_WORKAROUNDS */ end = pos + wpabuf_len(msg); while (pos < end) { @@ -649,9 +654,15 @@ int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr) * end of M1. Skip those to avoid interop issues. */ int i; + + if (last_nonzero > (size_t) (pos - start)) + continue; + for (i = 0; i < end - pos; i++) { - if (pos[i]) + if (pos[i]) { + last_nonzero = pos - start + i; break; + } } if (i == end - pos) { wpa_printf(MSG_DEBUG, "WPS: Workaround - skip " diff --git a/wpa_supplicant-2.9_standard/src/wps/wps_attr_process.c b/wpa_supplicant-2.9_standard/src/wps/wps_attr_process.c index f43ae9b84246c720d426a3798ef03044f1dc3e29..f208e2d6141e2bb840d5bc0087891ee9dbcf2ac4 100644 --- a/wpa_supplicant-2.9_standard/src/wps/wps_attr_process.c +++ b/wpa_supplicant-2.9_standard/src/wps/wps_attr_process.c @@ -201,7 +201,7 @@ static int wps_process_cred_mac_addr(struct wps_credential *cred, return -1; } - wpa_printf(MSG_EXCESSIVE, "WPS: MAC Address " MACSTR_SEC, MAC2STR_SEC(mac_addr)); + wpa_printf(MSG_EXCESSIVE, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr)); os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN); return 0; diff --git a/wpa_supplicant-2.9_standard/src/wps/wps_enrollee.c b/wpa_supplicant-2.9_standard/src/wps/wps_enrollee.c index 57495979711303c6909218572f02e2945170d3e7..96b11399402ba1145bc52d9bce08da3ce771479b 100644 --- a/wpa_supplicant-2.9_standard/src/wps/wps_enrollee.c +++ b/wpa_supplicant-2.9_standard/src/wps/wps_enrollee.c @@ -112,7 +112,7 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps) wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce", wps->nonce_e, WPS_NONCE_LEN); - wpa_printf(MSG_WARNING, "WPS: Building Message M1"); + wpa_printf(MSG_EXCESSIVE, "WPS: Building Message M1"); msg = wpabuf_alloc(1000); if (msg == NULL) return NULL; @@ -715,8 +715,7 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred, wps_process_cred(&attr, &wps->cred)) return -1; - if (os_memcmp(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) != - 0) { + if (!ether_addr_equal(wps->cred.mac_addr, wps->wps->dev.mac_addr)) { wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential (" MACSTR_SEC ") does not match with own address (" MACSTR_SEC ")", MAC2STR_SEC(wps->cred.mac_addr), @@ -815,8 +814,7 @@ static int wps_process_ap_settings_e(struct wps_data *wps, wpa_printf(MSG_INFO, "WPS: Received new AP configuration from " "Registrar"); - if (os_memcmp(cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) != - 0) { + if (!ether_addr_equal(cred.mac_addr, wps->wps->dev.mac_addr)) { wpa_printf(MSG_DEBUG, "WPS: MAC Address in the AP Settings (" MACSTR_SEC ") does not match with own address (" MACSTR_SEC ")", MAC2STR_SEC(cred.mac_addr), @@ -1213,7 +1211,7 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps, struct wpabuf *decrypted; struct wps_parse_attr eattr; - wpa_printf(MSG_WARNING, "WPS: Received M8"); + wpa_printf(MSG_EXCESSIVE, "WPS: Received M8"); if (wps->state != RECV_M8) { wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for " diff --git a/wpa_supplicant-2.9_standard/src/wps/wps_er.c b/wpa_supplicant-2.9_standard/src/wps/wps_er.c index 541a9838e71bc6acaf058a67fba6e29996fff8a4..36dc897a7a590d03d3e4ed489f455f9cd5d3f6bf 100644 --- a/wpa_supplicant-2.9_standard/src/wps/wps_er.c +++ b/wpa_supplicant-2.9_standard/src/wps/wps_er.c @@ -62,7 +62,7 @@ static struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr, struct wps_er_sta *sta; dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) { if ((addr == NULL || - os_memcmp(sta->addr, addr, ETH_ALEN) == 0) && + ether_addr_equal(sta->addr, addr)) && (uuid == NULL || os_memcmp(uuid, sta->uuid, WPS_UUID_LEN) == 0)) return sta; @@ -106,7 +106,7 @@ static struct wps_er_ap * wps_er_ap_get(struct wps_er *er, (uuid == NULL || os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0) && (mac_addr == NULL || - os_memcmp(mac_addr, ap->mac_addr, ETH_ALEN) == 0)) + ether_addr_equal(mac_addr, ap->mac_addr))) return ap; } return NULL; @@ -181,7 +181,7 @@ static void wps_er_ap_free(struct wps_er_ap *ap) static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap) { wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from AP %s (%s)", - inet_ntoa(ap->addr), ap->location); + anonymize_ip(inet_ntoa(ap->addr)), ap->location); dl_list_del(&ap->list); wps_er_ap_free(ap); @@ -334,7 +334,7 @@ static int wps_er_ap_use_cached_settings(struct wps_er *er, static void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap) { wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)", - inet_ntoa(ap->addr), ap->location); + anonymize_ip(inet_ntoa(ap->addr)), ap->location); eloop_cancel_timeout(wps_er_ap_timeout, er, ap); wps_er_sta_remove_all(ap); wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_REMOVE); @@ -370,7 +370,7 @@ static int wps_er_get_sid(struct wps_er_ap *ap, char *sid) if (!sid) { wpa_printf(MSG_DEBUG, "WPS ER: No SID received from %s (%s)", - inet_ntoa(ap->addr), ap->location); + anonymize_ip(inet_ntoa(ap->addr)), ap->location); return -1; } @@ -392,7 +392,7 @@ static int wps_er_get_sid(struct wps_er_ap *ap, char *sid) uuid_bin2str(ap->sid, txt, sizeof(txt)); wpa_printf(MSG_DEBUG, "WPS ER: SID for subscription with %s (%s): %s", - inet_ntoa(ap->addr), ap->location, txt); + anonymize_ip(inet_ntoa(ap->addr)), ap->location, txt); return 0; } @@ -665,7 +665,7 @@ void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr, eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap); wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)", - inet_ntoa(ap->addr), ap->location); + anonymize_ip(inet_ntoa(ap->addr)), ap->location); /* Fetch device description */ ap->http = http_client_url(ap->location, NULL, 10000, @@ -1220,7 +1220,7 @@ static void wps_er_http_req(void *ctx, struct http_request *req) wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from " "%s:%d", http_request_get_uri(req), type, - inet_ntoa(cli->sin_addr), ntohs(cli->sin_port)); + anonymize_ip(inet_ntoa(cli->sin_addr)), ntohs(cli->sin_port)); switch (type) { case HTTPREAD_HDR_TYPE_NOTIFY: @@ -1321,7 +1321,7 @@ wps_er_init(struct wps_context *wps, const char *ifname, const char *filter) er->http_port = http_server_get_port(er->http_srv); wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s)", - er->ifname, er->ip_addr_text); + er->ifname, anonymize_ip(er->ip_addr_text)); return er; } @@ -1354,7 +1354,7 @@ static void wps_er_deinit_finish(void *eloop_data, void *user_ctx) dl_list_for_each_safe(ap, tmp, &er->ap_unsubscribing, struct wps_er_ap, list) { wpa_printf(MSG_DEBUG, "WPS ER: AP entry for %s (%s) still in ap_unsubscribing list - free it", - inet_ntoa(ap->addr), ap->location); + anonymize_ip(inet_ntoa(ap->addr)), ap->location); dl_list_del(&ap->list); wps_er_ap_free(ap); } diff --git a/wpa_supplicant-2.9_standard/src/wps/wps_i.h b/wpa_supplicant-2.9_standard/src/wps/wps_i.h index 2cf22d4b7a636890e8a262de9531cef70d8e73fe..5486e2a1c2ea9fa58402d174915649b8e93290d2 100644 --- a/wpa_supplicant-2.9_standard/src/wps/wps_i.h +++ b/wpa_supplicant-2.9_standard/src/wps/wps_i.h @@ -127,6 +127,7 @@ struct wps_data { struct wps_nfc_pw_token *nfc_pw_token; int multi_ap_backhaul_sta; + int multi_ap_profile; }; diff --git a/wpa_supplicant-2.9_standard/src/wps/wps_registrar.c b/wpa_supplicant-2.9_standard/src/wps/wps_registrar.c index 7057ce48bc0dc3a997ef5ed0722dea7667868b9f..c5283ab9a90b2fa9cd0ba9b58a4b3ae629227113 100644 --- a/wpa_supplicant-2.9_standard/src/wps/wps_registrar.c +++ b/wpa_supplicant-2.9_standard/src/wps/wps_registrar.c @@ -231,7 +231,7 @@ static void wps_registrar_remove_pin(struct wps_registrar *reg, struct wps_uuid_pin *pin); #ifdef HARMONY_CONNECTIVITY_PATCH static void wps_registrar_wsc_done_timeout(void *eloop_ctx, void *timeout_ctx); -#endif /* CONFIG_WPS_SKIP_WSC_DONE */ +#endif static void wps_registrar_add_authorized_mac(struct wps_registrar *reg, const u8 *addr) @@ -240,7 +240,7 @@ static void wps_registrar_add_authorized_mac(struct wps_registrar *reg, wpa_printf(MSG_DEBUG, "WPS: Add authorized MAC " MACSTR_SEC, MAC2STR_SEC(addr)); for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) - if (os_memcmp(reg->authorized_macs[i], addr, ETH_ALEN) == 0) { + if (ether_addr_equal(reg->authorized_macs[i], addr)) { wpa_printf(MSG_DEBUG, "WPS: Authorized MAC was " "already in the list"); return; /* already in list */ @@ -261,7 +261,7 @@ static void wps_registrar_remove_authorized_mac(struct wps_registrar *reg, wpa_printf(MSG_DEBUG, "WPS: Remove authorized MAC " MACSTR_SEC, MAC2STR_SEC(addr)); for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) { - if (os_memcmp(reg->authorized_macs, addr, ETH_ALEN) == 0) + if (ether_addr_equal(reg->authorized_macs[i], addr)) break; } if (i == WPS_MAX_AUTHORIZED_MACS) { @@ -298,7 +298,7 @@ static struct wps_registrar_device * wps_device_get(struct wps_registrar *reg, struct wps_registrar_device *dev; for (dev = reg->devices; dev; dev = dev->next) { - if (os_memcmp(dev->dev.mac_addr, addr, ETH_ALEN) == 0) + if (ether_addr_equal(dev->dev.mac_addr, addr)) return dev; } return NULL; @@ -355,7 +355,7 @@ static void wps_registrar_add_pbc_session(struct wps_registrar *reg, pbc = reg->pbc_sessions; while (pbc) { - if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 && + if (ether_addr_equal(pbc->addr, addr) && os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) { if (prev) prev->next = pbc->next; @@ -407,8 +407,7 @@ static void wps_registrar_remove_pbc_session(struct wps_registrar *reg, while (pbc) { if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 || (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) && - os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) == - 0)) { + ether_addr_equal(reg->p2p_dev_addr, p2p_dev_addr))) { if (prev) prev->next = pbc->next; else @@ -2622,7 +2621,7 @@ static int wps_registrar_p2p_dev_addr_match(struct wps_data *wps) if (is_zero_ether_addr(reg->p2p_dev_addr)) return 1; /* no filtering in use */ - if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(reg->p2p_dev_addr, wps->p2p_dev_addr)) { wpa_printf(MSG_DEBUG, "WPS: No match on P2P Device Address " "filtering for PBC: expected " MACSTR_SEC " was " MACSTR_SEC " - indicate PBC session overlap", @@ -2643,7 +2642,7 @@ static int wps_registrar_skip_overlap(struct wps_data *wps) if (is_zero_ether_addr(reg->p2p_dev_addr)) return 0; /* no specific Enrollee selected */ - if (os_memcmp(reg->p2p_dev_addr, wps->p2p_dev_addr, ETH_ALEN) == 0) { + if (ether_addr_equal(reg->p2p_dev_addr, wps->p2p_dev_addr)) { wpa_printf(MSG_DEBUG, "WPS: Skip PBC overlap due to selected " "Enrollee match"); return 1; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/.config b/wpa_supplicant-2.9_standard/wpa_supplicant/.config index d2c8efb0834bb0dcd697171c744d329864ca8d8b..a2087e53b2fa5af86aa3a571377d08a10741cec1 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/.config +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/.config @@ -1,625 +1,625 @@ -# Example wpa_supplicant build time configuration -# -# This file lists the configuration options that are used when building the -# wpa_supplicant binary. All lines starting with # are ignored. Configuration -# option lines must be commented out complete, if they are not to be included, -# i.e., just setting VARIABLE=n is not disabling that variable. -# -# This file is included in Makefile, so variables like CFLAGS and LIBS can also -# be modified from here. In most cases, these lines should use += in order not -# to override previous values of the variables. - - -# Uncomment following two lines and fix the paths if you have installed OpenSSL -# or GnuTLS in non-default location -#CFLAGS += -I/usr/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/include -#LIBS += -L/usr1/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/lib -lssl -lcrypto - -# Some Red Hat versions seem to include kerberos header files from OpenSSL, but -# the kerberos files are not in the default include path. Following line can be -# used to fix build issues on such systems (krb5.h not found). -#CFLAGS += -I/usr/include/kerberos - -# Driver interface for generic Linux wireless extensions -# Note: WEXT is deprecated in the current Linux kernel version and no new -# functionality is added to it. nl80211-based interface is the new -# replacement for WEXT and its use allows wpa_supplicant to properly control -# the driver to improve existing functionality like roaming and to support new -# functionality. -#CONFIG_DRIVER_WEXT=y - -# Driver interface for Linux drivers using the nl80211 kernel interface -#CONFIG_DRIVER_NL80211=y - -# QCA vendor extensions to nl80211 -#CONFIG_DRIVER_NL80211_QCA=y - -# driver_nl80211.c requires libnl. If you are compiling it yourself -# you may need to point hostapd to your version of libnl. -# -#CFLAGS += -I$ -#LIBS += -L$ - -# Use libnl v2.0 (or 3.0) libraries. -#CONFIG_LIBNL20=y - -# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored) -#CONFIG_LIBNL32=y - - -# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) -#CONFIG_DRIVER_BSD=y -#CFLAGS += -I/usr1/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/include -#LIBS += -L/usr1/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/lib -lssl -lcrypto -#LIBS_p += -L/usr1/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/lib -#LIBS_c += -L/usr1/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/lib - -# Driver interface for Windows NDIS -#CONFIG_DRIVER_NDIS=y -#CFLAGS += -I/usr/include/w32api/ddk -#LIBS += -L/usr/local/lib -# For native build using mingw -#CONFIG_NATIVE_WINDOWS=y -# Additional directories for cross-compilation on Linux host for mingw target -#CFLAGS += -I/opt/mingw/mingw32/include/ddk -#LIBS += -L/opt/mingw/mingw32/lib -# By default, driver_ndis uses WinPcap for low-level operations. This can be -# replaced with the following option which replaces WinPcap calls with NDISUIO. -# However, this requires that WZC is disabled (net stop wzcsvc) before starting -# wpa_supplicant. -# CONFIG_USE_NDISUIO=y - -# Driver interface for wired Ethernet drivers -#CONFIG_DRIVER_WIRED=y - -# Driver interface for MACsec capable Qualcomm Atheros drivers -#CONFIG_DRIVER_MACSEC_QCA=y - -# Driver interface for Linux MACsec drivers -#CONFIG_DRIVER_MACSEC_LINUX=y - -# Driver interface for the Broadcom RoboSwitch family -#CONFIG_DRIVER_ROBOSWITCH=y - -# Driver interface for no driver (e.g., WPS ER only) -#CONFIG_DRIVER_NONE=y - -# Solaris libraries -#LIBS += -lsocket -ldlpi -lnsl -#LIBS_c += -lsocket - -# Enable IEEE 802.1X Supplicant (automatically included if any EAP method or -# MACsec is included) -CONFIG_IEEE8021X_EAPOL=y - -# EAP-MD5 -# CONFIG_EAP_MD5=y - -# EAP-MSCHAPv2 -# CONFIG_EAP_MSCHAPV2=y - -# EAP-TLS -# CONFIG_EAP_TLS=y - -# EAL-PEAP -# CONFIG_EAP_PEAP=y - -# EAP-TTLS -# CONFIG_EAP_TTLS=y - -# EAP-FAST -#CONFIG_EAP_FAST=y - -# EAP-TEAP -# Note: The current EAP-TEAP implementation is experimental and should not be -# enabled for production use. The IETF RFC 7170 that defines EAP-TEAP has number -# of conflicting statements and missing details and the implementation has -# vendor specific workarounds for those and as such, may not interoperate with -# any other implementation. This should not be used for anything else than -# experimentation and interoperability testing until those issues has been -# resolved. -#CONFIG_EAP_TEAP=y - -# EAP-GTC -# CONFIG_EAP_GTC=y - -# EAP-OTP -# CONFIG_EAP_OTP=y - -# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used) -#CONFIG_EAP_SIM=y - -# Enable SIM simulator (Milenage) for EAP-SIM -#CONFIG_SIM_SIMULATOR=y - -# EAP-PSK (experimental; this is _not_ needed for WPA-PSK) -#CONFIG_EAP_PSK=y - -# EAP-pwd (secure authentication using only a password) -#CONFIG_EAP_PWD=y - -# EAP-PAX -#CONFIG_EAP_PAX=y - -# LEAP -# CONFIG_EAP_LEAP=y - -# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used) -#CONFIG_EAP_AKA=y - -# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used). -# This requires CONFIG_EAP_AKA to be enabled, too. -#CONFIG_EAP_AKA_PRIME=y - -# Enable USIM simulator (Milenage) for EAP-AKA -#CONFIG_USIM_SIMULATOR=y - -# EAP-SAKE -#CONFIG_EAP_SAKE=y - -# EAP-GPSK -#CONFIG_EAP_GPSK=y -# Include support for optional SHA256 cipher suite in EAP-GPSK -#CONFIG_EAP_GPSK_SHA256=y - -# EAP-TNC and related Trusted Network Connect support (experimental) -#CONFIG_EAP_TNC=y - -# Wi-Fi Protected Setup (WPS) -#CONFIG_WPS=y -# Enable WPS external registrar functionality -#CONFIG_WPS_ER=y -# Disable credentials for an open network by default when acting as a WPS -# registrar. -#CONFIG_WPS_REG_DISABLE_OPEN=y -# Enable WPS support with NFC config method -#CONFIG_WPS_NFC=y - -# EAP-IKEv2 -#CONFIG_EAP_IKEV2=y - -# EAP-EKE -#CONFIG_EAP_EKE=y - -# MACsec -#CONFIG_MACSEC=y - -# PKCS#12 (PFX) support (used to read private key and certificate file from -# a file that usually has extension .p12 or .pfx) -#CONFIG_PKCS12=y - -# Smartcard support (i.e., private key on a smartcard), e.g., with openssl -# engine. -#CONFIG_SMARTCARD=y - -# PC/SC interface for smartcards (USIM, GSM SIM) -# Enable this if EAP-SIM or EAP-AKA is included -#CONFIG_PCSC=y - -# Support HT overrides (disable HT/HT40, mask MCS rates, etc.) -#CONFIG_HT_OVERRIDES=y - -# Support VHT overrides (disable VHT, mask MCS rates, etc.) -#CONFIG_VHT_OVERRIDES=y - -# Development testing -#CONFIG_EAPOL_TEST=y - -# Select control interface backend for external programs, e.g, wpa_cli: -# unix = UNIX domain sockets (default for Linux/*BSD) -# udp = UDP sockets using localhost (127.0.0.1) -# udp6 = UDP IPv6 sockets using localhost (::1) -# named_pipe = Windows Named Pipe (default for Windows) -# udp-remote = UDP sockets with remote access (only for tests systems/purpose) -# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose) -# y = use default (backwards compatibility) -# If this option is commented out, control interface is not included in the -# build. -CONFIG_CTRL_IFACE=udp - -# Include support for GNU Readline and History Libraries in wpa_cli. -# When building a wpa_cli binary for distribution, please note that these -# libraries are licensed under GPL and as such, BSD license may not apply for -# the resulting binary. -#CONFIG_READLINE=y - -# Include internal line edit mode in wpa_cli. This can be used as a replacement -# for GNU Readline to provide limited command line editing and history support. -#CONFIG_WPA_CLI_EDIT=y - -# Remove debugging code that is printing out debug message to stdout. -# This can be used to reduce the size of the wpa_supplicant considerably -# if debugging code is not needed. The size reduction can be around 35% -# (e.g., 90 kB). -#CONFIG_NO_STDOUT_DEBUG=y - -# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save -# 35-50 kB in code size. -#CONFIG_NO_WPA=y - -# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support -# This option can be used to reduce code size by removing support for -# converting ASCII passphrases into PSK. If this functionality is removed, the -# PSK can only be configured as the 64-octet hexstring (e.g., from -# wpa_passphrase). This saves about 0.5 kB in code size. -#CONFIG_NO_WPA_PASSPHRASE=y - -# Simultaneous Authentication of Equals (SAE), WPA3-Personal -#CONFIG_SAE=y - -# Disable scan result processing (ap_mode=1) to save code size by about 1 kB. -# This can be used if ap_scan=1 mode is never enabled. -#CONFIG_NO_SCAN_PROCESSING=y - -# Select configuration backend: -# file = text file (e.g., wpa_supplicant.conf; note: the configuration file -# path is given on command line, not here; this option is just used to -# select the backend that allows configuration files to be used) -# winreg = Windows registry (see win_example.reg for an example) -CONFIG_BACKEND=file - -# Remove configuration write functionality (i.e., to allow the configuration -# file to be updated based on runtime configuration changes). The runtime -# configuration can still be changed, the changes are just not going to be -# persistent over restarts. This option can be used to reduce code size by -# about 3.5 kB. -#CONFIG_NO_CONFIG_WRITE=y - -# Remove support for configuration blobs to reduce code size by about 1.5 kB. -#CONFIG_NO_CONFIG_BLOBS=y - -# Select program entry point implementation: -# main = UNIX/POSIX like main() function (default) -# main_winsvc = Windows service (read parameters from registry) -# main_none = Very basic example (development use only) -#CONFIG_MAIN=main - -# Select wrapper for operating system and C library specific functions -# unix = UNIX/POSIX like systems (default) -# win32 = Windows systems -# none = Empty template -CONFIG_OS=unix - -# Select event loop implementation -# eloop = select() loop (default) -# eloop_win = Windows events and WaitForMultipleObject() loop -#CONFIG_ELOOP=eloop - -# Should we use poll instead of select? Select is used by default. -#CONFIG_ELOOP_POLL=y - -# Should we use epoll instead of select? Select is used by default. -#CONFIG_ELOOP_EPOLL=y - -# Should we use kqueue instead of select? Select is used by default. -#CONFIG_ELOOP_KQUEUE=y - -# Select layer 2 packet implementation -# linux = Linux packet socket (default) -# pcap = libpcap/libdnet/WinPcap -# freebsd = FreeBSD libpcap -# winpcap = WinPcap with receive thread -# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y) -# none = Empty template - -# Disable Linux packet socket workaround applicable for station interface -# in a bridge for EAPOL frames. This should be uncommented only if the kernel -# is known to not have the regression issue in packet socket behavior with -# bridge interfaces (commit 'bridge: respect RFC2863 operational state')'). -#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y - -# IEEE 802.11w (management frame protection), also known as PMF -# Driver support is also needed for IEEE 802.11w. -CONFIG_IEEE80211W=y - -# Support Operating Channel Validation -#CONFIG_OCV=y - -# Select TLS implementation -# openssl = OpenSSL (default) -# gnutls = GnuTLS -# internal = Internal TLSv1 implementation (experimental) -# linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental) -# none = Empty template -CONFIG_TLS=internal - -# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1) -# can be enabled to get a stronger construction of messages when block ciphers -# are used. It should be noted that some existing TLS v1.0 -based -# implementation may not be compatible with TLS v1.1 message (ClientHello is -# sent prior to negotiating which version will be used) -#CONFIG_TLSV11=y - -# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2) -# can be enabled to enable use of stronger crypto algorithms. It should be -# noted that some existing TLS v1.0 -based implementation may not be compatible -# with TLS v1.2 message (ClientHello is sent prior to negotiating which version -# will be used) -#CONFIG_TLSV12=y - -# Select which ciphers to use by default with OpenSSL if the user does not -# specify them. -#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW" - -# If CONFIG_TLS=internal is used, additional library and include paths are -# needed for LibTomMath. Alternatively, an integrated, minimal version of -# LibTomMath can be used. See beginning of libtommath.c for details on benefits -# and drawbacks of this option. -CONFIG_INTERNAL_LIBTOMMATH=y -ifndef CONFIG_INTERNAL_LIBTOMMATH -LTM_PATH=/usr/src/libtommath-0.39 -CFLAGS += -I$(LTM_PATH) -LIBS += -L$(LTM_PATH) -LIBS_p += -L$(LTM_PATH) -endif -# At the cost of about 4 kB of additional binary size, the internal LibTomMath -# can be configured to include faster routines for exptmod, sqr, and div to -# speed up DH and RSA calculation considerably -#CONFIG_INTERNAL_LIBTOMMATH_FAST=y - -# Include NDIS event processing through WMI into wpa_supplicant/wpasvc. -# This is only for Windows builds and requires WMI-related header files and -# WbemUuid.Lib from Platform SDK even when building with MinGW. -#CONFIG_NDIS_EVENTS_INTEGRATED=y -#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib" - -# Add support for new DBus control interface -# (fi.w1.hostap.wpa_supplicant1) -#CONFIG_CTRL_IFACE_DBUS_NEW=y - -# Add introspection support for new DBus control interface -#CONFIG_CTRL_IFACE_DBUS_INTRO=y - -# Add support for loading EAP methods dynamically as shared libraries. -# When this option is enabled, each EAP method can be either included -# statically (CONFIG_EAP_=y) or dynamically (CONFIG_EAP_=dyn). -# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to -# be loaded in the beginning of the wpa_supplicant configuration file -# (see load_dynamic_eap parameter in the example file) before being used in -# the network blocks. -# -# Note that some shared parts of EAP methods are included in the main program -# and in order to be able to use dynamic EAP methods using these parts, the -# main program must have been build with the EAP method enabled (=y or =dyn). -# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries -# unless at least one of them was included in the main build to force inclusion -# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included -# in the main build to be able to load these methods dynamically. -# -# Please also note that using dynamic libraries will increase the total binary -# size. Thus, it may not be the best option for targets that have limited -# amount of memory/flash. -#CONFIG_DYNAMIC_EAP_METHODS=y - -# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode -#CONFIG_IEEE80211R=y - -# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt) -#CONFIG_DEBUG_FILE=y - -# Send debug messages to syslog instead of stdout -#CONFIG_DEBUG_SYSLOG=y -# Set syslog facility for debug messages -#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON - -# Add support for sending all debug messages (regardless of debug verbosity) -# to the Linux kernel tracing facility. This helps debug the entire stack by -# making it easy to record everything happening from the driver up into the -# same file, e.g., using trace-cmd. -#CONFIG_DEBUG_LINUX_TRACING=y - -# Add support for writing debug log to Android logcat instead of standard -# output -#CONFIG_ANDROID_LOG=y - -# Enable privilege separation (see README 'Privilege separation' for details) -#CONFIG_PRIVSEP=y - -# Enable mitigation against certain attacks against TKIP by delaying Michael -# MIC error reports by a random amount of time between 0 and 60 seconds -#CONFIG_DELAYED_MIC_ERROR_REPORT=y - -# Enable tracing code for developer debugging -# This tracks use of memory allocations and other registrations and reports -# incorrect use with a backtrace of call (or allocation) location. -#CONFIG_WPA_TRACE=y -# For BSD, uncomment these. -#LIBS += -lexecinfo -#LIBS_p += -lexecinfo -#LIBS_c += -lexecinfo - -# Use libbfd to get more details for developer debugging -# This enables use of libbfd to get more detailed symbols for the backtraces -# generated by CONFIG_WPA_TRACE=y. -#CONFIG_WPA_TRACE_BFD=y -# For BSD, uncomment these. -#LIBS += -lbfd -liberty -lz -#LIBS_p += -lbfd -liberty -lz -#LIBS_c += -lbfd -liberty -lz - -# wpa_supplicant depends on strong random number generation being available -# from the operating system. os_get_random() function is used to fetch random -# data when needed, e.g., for key generation. On Linux and BSD systems, this -# works by reading /dev/urandom. It should be noted that the OS entropy pool -# needs to be properly initialized before wpa_supplicant is started. This is -# important especially on embedded devices that do not have a hardware random -# number generator and may by default start up with minimal entropy available -# for random number generation. -# -# As a safety net, wpa_supplicant is by default trying to internally collect -# additional entropy for generating random data to mix in with the data fetched -# from the OS. This by itself is not considered to be very strong, but it may -# help in cases where the system pool is not initialized properly. However, it -# is very strongly recommended that the system pool is initialized with enough -# entropy either by using hardware assisted random number generator or by -# storing state over device reboots. -# -# wpa_supplicant can be configured to maintain its own entropy store over -# restarts to enhance random number generation. This is not perfect, but it is -# much more secure than using the same sequence of random numbers after every -# reboot. This can be enabled with -e command line option. The -# specified file needs to be readable and writable by wpa_supplicant. -# -# If the os_get_random() is known to provide strong random data (e.g., on -# Linux/BSD, the board in question is known to have reliable source of random -# data from /dev/urandom), the internal wpa_supplicant random pool can be -# disabled. This will save some in binary size and CPU use. However, this -# should only be considered for builds that are known to be used on devices -# that meet the requirements described above. -#CONFIG_NO_RANDOM_POOL=y - -# Should we attempt to use the getrandom(2) call that provides more reliable -# yet secure randomness source than /dev/random on Linux 3.17 and newer. -# Requires glibc 2.25 to build, falls back to /dev/random if unavailable. - -# IEEE 802.11n (High Throughput) support (mainly for AP mode) -CONFIG_IEEE80211N=y - -# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode) -# (depends on CONFIG_IEEE80211N) -#CONFIG_IEEE80211AC=y - -# Wireless Network Management (IEEE Std 802.11v-2011) -# Note: This is experimental and not complete implementation. -#CONFIG_WNM=y - -# Interworking (IEEE 802.11u) -# This can be used to enable functionality to improve interworking with -# external networks (GAS/ANQP to learn more about the networks and network -# selection based on available credentials). -#CONFIG_INTERWORKING=y - -# Hotspot 2.0 -#CONFIG_HS20=y - -# Enable interface matching in wpa_supplicant -#CONFIG_MATCH_IFACE=y - -# Disable roaming in wpa_supplicant -#CONFIG_NO_ROAMING=y - -# AP mode operations with wpa_supplicant -# This can be used for controlling AP mode operations with wpa_supplicant. It -# should be noted that this is mainly aimed at simple cases like -# WPA2-Personal while more complex configurations like WPA2-Enterprise with an -# external RADIUS server can be supported with hostapd. -#CONFIG_AP=y - -# P2P (Wi-Fi Direct) -# This can be used to enable P2P support in wpa_supplicant. See README-P2P for -# more information on P2P operations. -#CONFIG_P2P=y - -# Enable TDLS support -#CONFIG_TDLS=y - -# Wi-Fi Display -# This can be used to enable Wi-Fi Display extensions for P2P using an external -# program to control the additional information exchanges in the messages. -#CONFIG_WIFI_DISPLAY=y - -# Autoscan -# This can be used to enable automatic scan support in wpa_supplicant. -# See wpa_supplicant.conf for more information on autoscan usage. -# -# Enabling directly a module will enable autoscan support. -# For exponential module: -#CONFIG_AUTOSCAN_EXPONENTIAL=y -# For periodic module: -#CONFIG_AUTOSCAN_PERIODIC=y - -# Password (and passphrase, etc.) backend for external storage -# These optional mechanisms can be used to add support for storing passwords -# and other secrets in external (to wpa_supplicant) location. This allows, for -# example, operating system specific key storage to be used -# -# External password backend for testing purposes (developer use) -#CONFIG_EXT_PASSWORD_TEST=y - -# Enable Fast Session Transfer (FST) -#CONFIG_FST=y - -# Enable CLI commands for FST testing -#CONFIG_FST_TEST=y - -# OS X builds. This is only for building eapol_test. -#CONFIG_OSX=y - -# Automatic Channel Selection -# This will allow wpa_supplicant to pick the channel automatically when channel -# is set to "0". -# -# TODO: Extend parser to be able to parse "channel=acs_survey" as an alternative -# to "channel=0". This would enable us to eventually add other ACS algorithms in -# similar way. -# -# Automatic selection is currently only done through initialization, later on -# we hope to do background checks to keep us moving to more ideal channels as -# time goes by. ACS is currently only supported through the nl80211 driver and -# your driver must have survey dump capability that is filled by the driver -# during scanning. -# -# TODO: In analogy to hostapd be able to customize the ACS survey algorithm with -# a newly to create wpa_supplicant.conf variable acs_num_scans. -# -# Supported ACS drivers: -# * ath9k -# * ath5k -# * ath10k -# -# For more details refer to: -# http://wireless.kernel.org/en/users/Documentation/acs -#CONFIG_ACS=y - -# Support Multi Band Operation -#CONFIG_MBO=y - -# Fast Initial Link Setup (FILS) (IEEE 802.11ai) -#CONFIG_FILS=y -# FILS shared key authentication with PFS -#CONFIG_FILS_SK_PFS=y - -# Support RSN on IBSS networks -# This is needed to be able to use mode=1 network profile with proto=RSN and -# key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None). -CONFIG_IBSS_RSN=y - -# External PMKSA cache control -# This can be used to enable control interface commands that allow the current -# PMKSA cache entries to be fetched and new entries to be added. -#CONFIG_PMKSA_CACHE_EXTERNAL=y - -# Mesh Networking (IEEE 802.11s) -#CONFIG_MESH=y - -# Background scanning modules -# These can be used to request wpa_supplicant to perform background scanning -# operations for roaming within an ESS (same SSID). See the bgscan parameter in -# the wpa_supplicant.conf file for more details. -# Periodic background scans based on signal strength -#CONFIG_BGSCAN_SIMPLE=y -# Learn channels used by the network and try to avoid bgscans on other -# channels (experimental) -#CONFIG_BGSCAN_LEARN=y - -# Opportunistic Wireless Encryption (OWE) -# Experimental implementation of draft-harkins-owe-07.txt -#CONFIG_OWE=y - -# Device Provisioning Protocol (DPP) -# This requires CONFIG_IEEE80211W=y to be enabled, too. (see -# wpa_supplicant/README-DPP for details) -#CONFIG_DPP=y -CONFIG_TEST_RANDOM=y -CONFIG_DRIVER_HDF=y -CONFIG_L2_PACKET=rtos -CONFIG_GETRANDOM=y -CONFIG_SHA256=y -CONFIG_NO_RADIUS=y -CONFIG_CRYPTO_INTERNAL=y -HISI_CODE_CROP=y -HISI_WPA_KEY_MGMT_CROP=y -CONFIG_NO_RANDOM_POOL=y -CONFIG_NO_STDOUT_DEBUG=y -CONFIG_NO_CONFIG_BLOBS=y +# Example wpa_supplicant build time configuration +# +# This file lists the configuration options that are used when building the +# wpa_supplicant binary. All lines starting with # are ignored. Configuration +# option lines must be commented out complete, if they are not to be included, +# i.e., just setting VARIABLE=n is not disabling that variable. +# +# This file is included in Makefile, so variables like CFLAGS and LIBS can also +# be modified from here. In most cases, these lines should use += in order not +# to override previous values of the variables. + + +# Uncomment following two lines and fix the paths if you have installed OpenSSL +# or GnuTLS in non-default location +#CFLAGS += -I/usr/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/include +#LIBS += -L/usr1/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/lib -lssl -lcrypto + +# Some Red Hat versions seem to include kerberos header files from OpenSSL, but +# the kerberos files are not in the default include path. Following line can be +# used to fix build issues on such systems (krb5.h not found). +#CFLAGS += -I/usr/include/kerberos + +# Driver interface for generic Linux wireless extensions +# Note: WEXT is deprecated in the current Linux kernel version and no new +# functionality is added to it. nl80211-based interface is the new +# replacement for WEXT and its use allows wpa_supplicant to properly control +# the driver to improve existing functionality like roaming and to support new +# functionality. +#CONFIG_DRIVER_WEXT=y + +# Driver interface for Linux drivers using the nl80211 kernel interface +#CONFIG_DRIVER_NL80211=y + +# QCA vendor extensions to nl80211 +#CONFIG_DRIVER_NL80211_QCA=y + +# driver_nl80211.c requires libnl. If you are compiling it yourself +# you may need to point hostapd to your version of libnl. +# +#CFLAGS += -I$ +#LIBS += -L$ + +# Use libnl v2.0 (or 3.0) libraries. +#CONFIG_LIBNL20=y + +# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored) +#CONFIG_LIBNL32=y + + +# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) +#CONFIG_DRIVER_BSD=y +#CFLAGS += -I/usr1/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/include +#LIBS += -L/usr1/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/lib -lssl -lcrypto +#LIBS_p += -L/usr1/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/lib +#LIBS_c += -L/usr1/w00371129/code/wpa_supplicant-2.9/openssl-OpenSSL_1_1_1d/install/lib + +# Driver interface for Windows NDIS +#CONFIG_DRIVER_NDIS=y +#CFLAGS += -I/usr/include/w32api/ddk +#LIBS += -L/usr/local/lib +# For native build using mingw +#CONFIG_NATIVE_WINDOWS=y +# Additional directories for cross-compilation on Linux host for mingw target +#CFLAGS += -I/opt/mingw/mingw32/include/ddk +#LIBS += -L/opt/mingw/mingw32/lib +# By default, driver_ndis uses WinPcap for low-level operations. This can be +# replaced with the following option which replaces WinPcap calls with NDISUIO. +# However, this requires that WZC is disabled (net stop wzcsvc) before starting +# wpa_supplicant. +# CONFIG_USE_NDISUIO=y + +# Driver interface for wired Ethernet drivers +#CONFIG_DRIVER_WIRED=y + +# Driver interface for MACsec capable Qualcomm Atheros drivers +#CONFIG_DRIVER_MACSEC_QCA=y + +# Driver interface for Linux MACsec drivers +#CONFIG_DRIVER_MACSEC_LINUX=y + +# Driver interface for the Broadcom RoboSwitch family +#CONFIG_DRIVER_ROBOSWITCH=y + +# Driver interface for no driver (e.g., WPS ER only) +#CONFIG_DRIVER_NONE=y + +# Solaris libraries +#LIBS += -lsocket -ldlpi -lnsl +#LIBS_c += -lsocket + +# Enable IEEE 802.1X Supplicant (automatically included if any EAP method or +# MACsec is included) +CONFIG_IEEE8021X_EAPOL=y + +# EAP-MD5 +# CONFIG_EAP_MD5=y + +# EAP-MSCHAPv2 +# CONFIG_EAP_MSCHAPV2=y + +# EAP-TLS +# CONFIG_EAP_TLS=y + +# EAL-PEAP +# CONFIG_EAP_PEAP=y + +# EAP-TTLS +# CONFIG_EAP_TTLS=y + +# EAP-FAST +#CONFIG_EAP_FAST=y + +# EAP-TEAP +# Note: The current EAP-TEAP implementation is experimental and should not be +# enabled for production use. The IETF RFC 7170 that defines EAP-TEAP has number +# of conflicting statements and missing details and the implementation has +# vendor specific workarounds for those and as such, may not interoperate with +# any other implementation. This should not be used for anything else than +# experimentation and interoperability testing until those issues has been +# resolved. +#CONFIG_EAP_TEAP=y + +# EAP-GTC +# CONFIG_EAP_GTC=y + +# EAP-OTP +# CONFIG_EAP_OTP=y + +# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used) +#CONFIG_EAP_SIM=y + +# Enable SIM simulator (Milenage) for EAP-SIM +#CONFIG_SIM_SIMULATOR=y + +# EAP-PSK (experimental; this is _not_ needed for WPA-PSK) +#CONFIG_EAP_PSK=y + +# EAP-pwd (secure authentication using only a password) +#CONFIG_EAP_PWD=y + +# EAP-PAX +#CONFIG_EAP_PAX=y + +# LEAP +# CONFIG_EAP_LEAP=y + +# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used) +#CONFIG_EAP_AKA=y + +# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used). +# This requires CONFIG_EAP_AKA to be enabled, too. +#CONFIG_EAP_AKA_PRIME=y + +# Enable USIM simulator (Milenage) for EAP-AKA +#CONFIG_USIM_SIMULATOR=y + +# EAP-SAKE +#CONFIG_EAP_SAKE=y + +# EAP-GPSK +#CONFIG_EAP_GPSK=y +# Include support for optional SHA256 cipher suite in EAP-GPSK +#CONFIG_EAP_GPSK_SHA256=y + +# EAP-TNC and related Trusted Network Connect support (experimental) +#CONFIG_EAP_TNC=y + +# Wi-Fi Protected Setup (WPS) +#CONFIG_WPS=y +# Enable WPS external registrar functionality +#CONFIG_WPS_ER=y +# Disable credentials for an open network by default when acting as a WPS +# registrar. +#CONFIG_WPS_REG_DISABLE_OPEN=y +# Enable WPS support with NFC config method +#CONFIG_WPS_NFC=y + +# EAP-IKEv2 +#CONFIG_EAP_IKEV2=y + +# EAP-EKE +#CONFIG_EAP_EKE=y + +# MACsec +#CONFIG_MACSEC=y + +# PKCS#12 (PFX) support (used to read private key and certificate file from +# a file that usually has extension .p12 or .pfx) +#CONFIG_PKCS12=y + +# Smartcard support (i.e., private key on a smartcard), e.g., with openssl +# engine. +#CONFIG_SMARTCARD=y + +# PC/SC interface for smartcards (USIM, GSM SIM) +# Enable this if EAP-SIM or EAP-AKA is included +#CONFIG_PCSC=y + +# Support HT overrides (disable HT/HT40, mask MCS rates, etc.) +#CONFIG_HT_OVERRIDES=y + +# Support VHT overrides (disable VHT, mask MCS rates, etc.) +#CONFIG_VHT_OVERRIDES=y + +# Development testing +#CONFIG_EAPOL_TEST=y + +# Select control interface backend for external programs, e.g, wpa_cli: +# unix = UNIX domain sockets (default for Linux/*BSD) +# udp = UDP sockets using localhost (127.0.0.1) +# udp6 = UDP IPv6 sockets using localhost (::1) +# named_pipe = Windows Named Pipe (default for Windows) +# udp-remote = UDP sockets with remote access (only for tests systems/purpose) +# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose) +# y = use default (backwards compatibility) +# If this option is commented out, control interface is not included in the +# build. +CONFIG_CTRL_IFACE=udp + +# Include support for GNU Readline and History Libraries in wpa_cli. +# When building a wpa_cli binary for distribution, please note that these +# libraries are licensed under GPL and as such, BSD license may not apply for +# the resulting binary. +#CONFIG_READLINE=y + +# Include internal line edit mode in wpa_cli. This can be used as a replacement +# for GNU Readline to provide limited command line editing and history support. +#CONFIG_WPA_CLI_EDIT=y + +# Remove debugging code that is printing out debug message to stdout. +# This can be used to reduce the size of the wpa_supplicant considerably +# if debugging code is not needed. The size reduction can be around 35% +# (e.g., 90 kB). +#CONFIG_NO_STDOUT_DEBUG=y + +# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save +# 35-50 kB in code size. +#CONFIG_NO_WPA=y + +# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support +# This option can be used to reduce code size by removing support for +# converting ASCII passphrases into PSK. If this functionality is removed, the +# PSK can only be configured as the 64-octet hexstring (e.g., from +# wpa_passphrase). This saves about 0.5 kB in code size. +#CONFIG_NO_WPA_PASSPHRASE=y + +# Simultaneous Authentication of Equals (SAE), WPA3-Personal +#CONFIG_SAE=y + +# Disable scan result processing (ap_mode=1) to save code size by about 1 kB. +# This can be used if ap_scan=1 mode is never enabled. +#CONFIG_NO_SCAN_PROCESSING=y + +# Select configuration backend: +# file = text file (e.g., wpa_supplicant.conf; note: the configuration file +# path is given on command line, not here; this option is just used to +# select the backend that allows configuration files to be used) +# winreg = Windows registry (see win_example.reg for an example) +CONFIG_BACKEND=file + +# Remove configuration write functionality (i.e., to allow the configuration +# file to be updated based on runtime configuration changes). The runtime +# configuration can still be changed, the changes are just not going to be +# persistent over restarts. This option can be used to reduce code size by +# about 3.5 kB. +#CONFIG_NO_CONFIG_WRITE=y + +# Remove support for configuration blobs to reduce code size by about 1.5 kB. +#CONFIG_NO_CONFIG_BLOBS=y + +# Select program entry point implementation: +# main = UNIX/POSIX like main() function (default) +# main_winsvc = Windows service (read parameters from registry) +# main_none = Very basic example (development use only) +#CONFIG_MAIN=main + +# Select wrapper for operating system and C library specific functions +# unix = UNIX/POSIX like systems (default) +# win32 = Windows systems +# none = Empty template +CONFIG_OS=unix + +# Select event loop implementation +# eloop = select() loop (default) +# eloop_win = Windows events and WaitForMultipleObject() loop +#CONFIG_ELOOP=eloop + +# Should we use poll instead of select? Select is used by default. +#CONFIG_ELOOP_POLL=y + +# Should we use epoll instead of select? Select is used by default. +#CONFIG_ELOOP_EPOLL=y + +# Should we use kqueue instead of select? Select is used by default. +#CONFIG_ELOOP_KQUEUE=y + +# Select layer 2 packet implementation +# linux = Linux packet socket (default) +# pcap = libpcap/libdnet/WinPcap +# freebsd = FreeBSD libpcap +# winpcap = WinPcap with receive thread +# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y) +# none = Empty template + +# Disable Linux packet socket workaround applicable for station interface +# in a bridge for EAPOL frames. This should be uncommented only if the kernel +# is known to not have the regression issue in packet socket behavior with +# bridge interfaces (commit 'bridge: respect RFC2863 operational state')'). +#CONFIG_NO_LINUX_PACKET_SOCKET_WAR=y + +# IEEE 802.11w (management frame protection), also known as PMF +# Driver support is also needed for IEEE 802.11w. +CONFIG_IEEE80211W=y + +# Support Operating Channel Validation +#CONFIG_OCV=y + +# Select TLS implementation +# openssl = OpenSSL (default) +# gnutls = GnuTLS +# internal = Internal TLSv1 implementation (experimental) +# linux = Linux kernel AF_ALG and internal TLSv1 implementation (experimental) +# none = Empty template +CONFIG_TLS=internal + +# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1) +# can be enabled to get a stronger construction of messages when block ciphers +# are used. It should be noted that some existing TLS v1.0 -based +# implementation may not be compatible with TLS v1.1 message (ClientHello is +# sent prior to negotiating which version will be used) +#CONFIG_TLSV11=y + +# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2) +# can be enabled to enable use of stronger crypto algorithms. It should be +# noted that some existing TLS v1.0 -based implementation may not be compatible +# with TLS v1.2 message (ClientHello is sent prior to negotiating which version +# will be used) +#CONFIG_TLSV12=y + +# Select which ciphers to use by default with OpenSSL if the user does not +# specify them. +#CONFIG_TLS_DEFAULT_CIPHERS="DEFAULT:!EXP:!LOW" + +# If CONFIG_TLS=internal is used, additional library and include paths are +# needed for LibTomMath. Alternatively, an integrated, minimal version of +# LibTomMath can be used. See beginning of libtommath.c for details on benefits +# and drawbacks of this option. +CONFIG_INTERNAL_LIBTOMMATH=y +ifndef CONFIG_INTERNAL_LIBTOMMATH +LTM_PATH=/usr/src/libtommath-0.39 +CFLAGS += -I$(LTM_PATH) +LIBS += -L$(LTM_PATH) +LIBS_p += -L$(LTM_PATH) +endif +# At the cost of about 4 kB of additional binary size, the internal LibTomMath +# can be configured to include faster routines for exptmod, sqr, and div to +# speed up DH and RSA calculation considerably +#CONFIG_INTERNAL_LIBTOMMATH_FAST=y + +# Include NDIS event processing through WMI into wpa_supplicant/wpasvc. +# This is only for Windows builds and requires WMI-related header files and +# WbemUuid.Lib from Platform SDK even when building with MinGW. +#CONFIG_NDIS_EVENTS_INTEGRATED=y +#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib" + +# Add support for new DBus control interface +# (fi.w1.hostap.wpa_supplicant1) +#CONFIG_CTRL_IFACE_DBUS_NEW=y + +# Add introspection support for new DBus control interface +#CONFIG_CTRL_IFACE_DBUS_INTRO=y + +# Add support for loading EAP methods dynamically as shared libraries. +# When this option is enabled, each EAP method can be either included +# statically (CONFIG_EAP_=y) or dynamically (CONFIG_EAP_=dyn). +# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to +# be loaded in the beginning of the wpa_supplicant configuration file +# (see load_dynamic_eap parameter in the example file) before being used in +# the network blocks. +# +# Note that some shared parts of EAP methods are included in the main program +# and in order to be able to use dynamic EAP methods using these parts, the +# main program must have been build with the EAP method enabled (=y or =dyn). +# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries +# unless at least one of them was included in the main build to force inclusion +# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included +# in the main build to be able to load these methods dynamically. +# +# Please also note that using dynamic libraries will increase the total binary +# size. Thus, it may not be the best option for targets that have limited +# amount of memory/flash. +#CONFIG_DYNAMIC_EAP_METHODS=y + +# IEEE Std 802.11r-2008 (Fast BSS Transition) for station mode +#CONFIG_IEEE80211R=y + +# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt) +#CONFIG_DEBUG_FILE=y + +# Send debug messages to syslog instead of stdout +#CONFIG_DEBUG_SYSLOG=y +# Set syslog facility for debug messages +#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON + +# Add support for sending all debug messages (regardless of debug verbosity) +# to the Linux kernel tracing facility. This helps debug the entire stack by +# making it easy to record everything happening from the driver up into the +# same file, e.g., using trace-cmd. +#CONFIG_DEBUG_LINUX_TRACING=y + +# Add support for writing debug log to Android logcat instead of standard +# output +#CONFIG_ANDROID_LOG=y + +# Enable privilege separation (see README 'Privilege separation' for details) +#CONFIG_PRIVSEP=y + +# Enable mitigation against certain attacks against TKIP by delaying Michael +# MIC error reports by a random amount of time between 0 and 60 seconds +#CONFIG_DELAYED_MIC_ERROR_REPORT=y + +# Enable tracing code for developer debugging +# This tracks use of memory allocations and other registrations and reports +# incorrect use with a backtrace of call (or allocation) location. +#CONFIG_WPA_TRACE=y +# For BSD, uncomment these. +#LIBS += -lexecinfo +#LIBS_p += -lexecinfo +#LIBS_c += -lexecinfo + +# Use libbfd to get more details for developer debugging +# This enables use of libbfd to get more detailed symbols for the backtraces +# generated by CONFIG_WPA_TRACE=y. +#CONFIG_WPA_TRACE_BFD=y +# For BSD, uncomment these. +#LIBS += -lbfd -liberty -lz +#LIBS_p += -lbfd -liberty -lz +#LIBS_c += -lbfd -liberty -lz + +# wpa_supplicant depends on strong random number generation being available +# from the operating system. os_get_random() function is used to fetch random +# data when needed, e.g., for key generation. On Linux and BSD systems, this +# works by reading /dev/urandom. It should be noted that the OS entropy pool +# needs to be properly initialized before wpa_supplicant is started. This is +# important especially on embedded devices that do not have a hardware random +# number generator and may by default start up with minimal entropy available +# for random number generation. +# +# As a safety net, wpa_supplicant is by default trying to internally collect +# additional entropy for generating random data to mix in with the data fetched +# from the OS. This by itself is not considered to be very strong, but it may +# help in cases where the system pool is not initialized properly. However, it +# is very strongly recommended that the system pool is initialized with enough +# entropy either by using hardware assisted random number generator or by +# storing state over device reboots. +# +# wpa_supplicant can be configured to maintain its own entropy store over +# restarts to enhance random number generation. This is not perfect, but it is +# much more secure than using the same sequence of random numbers after every +# reboot. This can be enabled with -e command line option. The +# specified file needs to be readable and writable by wpa_supplicant. +# +# If the os_get_random() is known to provide strong random data (e.g., on +# Linux/BSD, the board in question is known to have reliable source of random +# data from /dev/urandom), the internal wpa_supplicant random pool can be +# disabled. This will save some in binary size and CPU use. However, this +# should only be considered for builds that are known to be used on devices +# that meet the requirements described above. +#CONFIG_NO_RANDOM_POOL=y + +# Should we attempt to use the getrandom(2) call that provides more reliable +# yet secure randomness source than /dev/random on Linux 3.17 and newer. +# Requires glibc 2.25 to build, falls back to /dev/random if unavailable. + +# IEEE 802.11n (High Throughput) support (mainly for AP mode) +CONFIG_IEEE80211N=y + +# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode) +# (depends on CONFIG_IEEE80211N) +#CONFIG_IEEE80211AC=y + +# Wireless Network Management (IEEE Std 802.11v-2011) +# Note: This is experimental and not complete implementation. +#CONFIG_WNM=y + +# Interworking (IEEE 802.11u) +# This can be used to enable functionality to improve interworking with +# external networks (GAS/ANQP to learn more about the networks and network +# selection based on available credentials). +#CONFIG_INTERWORKING=y + +# Hotspot 2.0 +#CONFIG_HS20=y + +# Enable interface matching in wpa_supplicant +#CONFIG_MATCH_IFACE=y + +# Disable roaming in wpa_supplicant +#CONFIG_NO_ROAMING=y + +# AP mode operations with wpa_supplicant +# This can be used for controlling AP mode operations with wpa_supplicant. It +# should be noted that this is mainly aimed at simple cases like +# WPA2-Personal while more complex configurations like WPA2-Enterprise with an +# external RADIUS server can be supported with hostapd. +#CONFIG_AP=y + +# P2P (Wi-Fi Direct) +# This can be used to enable P2P support in wpa_supplicant. See README-P2P for +# more information on P2P operations. +#CONFIG_P2P=y + +# Enable TDLS support +#CONFIG_TDLS=y + +# Wi-Fi Display +# This can be used to enable Wi-Fi Display extensions for P2P using an external +# program to control the additional information exchanges in the messages. +#CONFIG_WIFI_DISPLAY=y + +# Autoscan +# This can be used to enable automatic scan support in wpa_supplicant. +# See wpa_supplicant.conf for more information on autoscan usage. +# +# Enabling directly a module will enable autoscan support. +# For exponential module: +#CONFIG_AUTOSCAN_EXPONENTIAL=y +# For periodic module: +#CONFIG_AUTOSCAN_PERIODIC=y + +# Password (and passphrase, etc.) backend for external storage +# These optional mechanisms can be used to add support for storing passwords +# and other secrets in external (to wpa_supplicant) location. This allows, for +# example, operating system specific key storage to be used +# +# External password backend for testing purposes (developer use) +#CONFIG_EXT_PASSWORD_TEST=y + +# Enable Fast Session Transfer (FST) +#CONFIG_FST=y + +# Enable CLI commands for FST testing +#CONFIG_FST_TEST=y + +# OS X builds. This is only for building eapol_test. +#CONFIG_OSX=y + +# Automatic Channel Selection +# This will allow wpa_supplicant to pick the channel automatically when channel +# is set to "0". +# +# TODO: Extend parser to be able to parse "channel=acs_survey" as an alternative +# to "channel=0". This would enable us to eventually add other ACS algorithms in +# similar way. +# +# Automatic selection is currently only done through initialization, later on +# we hope to do background checks to keep us moving to more ideal channels as +# time goes by. ACS is currently only supported through the nl80211 driver and +# your driver must have survey dump capability that is filled by the driver +# during scanning. +# +# TODO: In analogy to hostapd be able to customize the ACS survey algorithm with +# a newly to create wpa_supplicant.conf variable acs_num_scans. +# +# Supported ACS drivers: +# * ath9k +# * ath5k +# * ath10k +# +# For more details refer to: +# http://wireless.kernel.org/en/users/Documentation/acs +#CONFIG_ACS=y + +# Support Multi Band Operation +#CONFIG_MBO=y + +# Fast Initial Link Setup (FILS) (IEEE 802.11ai) +#CONFIG_FILS=y +# FILS shared key authentication with PFS +#CONFIG_FILS_SK_PFS=y + +# Support RSN on IBSS networks +# This is needed to be able to use mode=1 network profile with proto=RSN and +# key_mgmt=WPA-PSK (i.e., full key management instead of WPA-None). +CONFIG_IBSS_RSN=y + +# External PMKSA cache control +# This can be used to enable control interface commands that allow the current +# PMKSA cache entries to be fetched and new entries to be added. +#CONFIG_PMKSA_CACHE_EXTERNAL=y + +# Mesh Networking (IEEE 802.11s) +#CONFIG_MESH=y + +# Background scanning modules +# These can be used to request wpa_supplicant to perform background scanning +# operations for roaming within an ESS (same SSID). See the bgscan parameter in +# the wpa_supplicant.conf file for more details. +# Periodic background scans based on signal strength +#CONFIG_BGSCAN_SIMPLE=y +# Learn channels used by the network and try to avoid bgscans on other +# channels (experimental) +#CONFIG_BGSCAN_LEARN=y + +# Opportunistic Wireless Encryption (OWE) +# Experimental implementation of draft-harkins-owe-07.txt +#CONFIG_OWE=y + +# Device Provisioning Protocol (DPP) +# This requires CONFIG_IEEE80211W=y to be enabled, too. (see +# wpa_supplicant/README-DPP for details) +#CONFIG_DPP=y +CONFIG_TEST_RANDOM=y +CONFIG_DRIVER_HDF=y +CONFIG_L2_PACKET=rtos +CONFIG_GETRANDOM=y +CONFIG_SHA256=y +CONFIG_NO_RADIUS=y +CONFIG_CRYPTO_INTERNAL=y +HISI_CODE_CROP=y +HISI_WPA_KEY_MGMT_CROP=y +CONFIG_NO_RANDOM_POOL=y +CONFIG_NO_STDOUT_DEBUG=y +CONFIG_NO_CONFIG_BLOBS=y CONFIG_NO_CONFIG_WRITE=y \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/Android.mk b/wpa_supplicant-2.9_standard/wpa_supplicant/Android.mk index 7e597f396a079c221e461082010a73948ff2eaf2..3aadcb2bb9216d5854c06f4fad6bb24361e3f805 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/Android.mk +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/Android.mk @@ -75,6 +75,7 @@ INCLUDES += $(LOCAL_PATH)/src/rsn_supp INCLUDES += $(LOCAL_PATH)/src/tls INCLUDES += $(LOCAL_PATH)/src/utils INCLUDES += $(LOCAL_PATH)/src/wps +INCLUDES += $(LOCAL_PATH)/src/pasn INCLUDES += system/security/keystore/include ifdef CONFIG_DRIVER_NL80211 ifneq ($(wildcard external/libnl),) @@ -86,7 +87,6 @@ endif ifdef CONFIG_FIPS CONFIG_NO_RANDOM_POOL= -CONFIG_OPENSSL_CMAC=y endif OBJS = config.c @@ -100,11 +100,9 @@ OBJS += src/utils/wpabuf.c OBJS += src/utils/bitfield.c OBJS += src/utils/ip_addr.c OBJS += src/utils/crc32.c -OBJS += wmm_ac.c -OBJS += op_classes.c -OBJS += rrm.c +OBJS += src/common/ptksa_cache.c +OBJS += src/rsn_supp/pmksa_cache.c OBJS += twt.c -OBJS += robust_av.c OBJS_p = wpa_passphrase.c OBJS_p += src/utils/common.c OBJS_p += src/utils/wpa_debug.c @@ -244,6 +242,7 @@ L_CFLAGS += -DCONFIG_SAE OBJS += src/common/sae.c ifdef CONFIG_SAE_PK L_CFLAGS += -DCONFIG_SAE_PK +NEED_AES_SIV=y OBJS += src/common/sae_pk.c endif NEED_ECC=y @@ -284,6 +283,12 @@ L_CFLAGS += -DCONFIG_DPP3 endif endif +ifdef CONFIG_NAN_USD +OBJS += src/common/nan_de.c +OBJS += nan_usd.c +L_CFLAGS += -DCONFIG_NAN_USD +endif + ifdef CONFIG_OWE L_CFLAGS += -DCONFIG_OWE NEED_ECC=y @@ -308,6 +313,10 @@ ifdef CONFIG_MBO CONFIG_WNM=y endif +ifdef CONFIG_BGSCAN_SIMPLE +CONFIG_WNM=y +endif + ifdef CONFIG_WNM L_CFLAGS += -DCONFIG_WNM OBJS += wnm_sta.c @@ -329,7 +338,6 @@ endif ifndef CONFIG_NO_WPA OBJS += src/rsn_supp/wpa.c OBJS += src/rsn_supp/preauth.c -OBJS += src/rsn_supp/pmksa_cache.c OBJS += src/rsn_supp/wpa_ie.c OBJS += src/common/wpa_common.c NEED_AES=y @@ -382,7 +390,8 @@ NEED_HMAC_SHA256_KDF=y NEED_HMAC_SHA384_KDF=y NEED_SHA256=y NEED_SHA384=y -OBJS += src/common/ptksa_cache.c +OBJS += src/pasn/pasn_initiator.c +OBJS += src/pasn/pasn_common.c OBJS += pasn_supplicant.c endif @@ -421,6 +430,28 @@ ifdef CONFIG_NO_TKIP L_CFLAGS += -DCONFIG_NO_TKIP endif +ifdef CONFIG_NO_RRM +L_CFLAGS += -DCONFIG_NO_RRM +else +OBJS += rrm.c +ifdef CONFIG_AP +OBJS += src/ap/rrm.c +endif +OBJS += op_classes.c +endif + +ifdef CONFIG_NO_WMM_AC +L_CFLAGS += -DCONFIG_NO_WMM_AC +else +OBJS += wmm_ac.c +endif + +ifdef CONFIG_NO_ROBUST_AV +L_CFLAGS += -DCONFIG_NO_ROBUST_AV +else +OBJS += robust_av.c +endif + include $(LOCAL_PATH)/src/drivers/drivers.mk @@ -478,6 +509,9 @@ OBJS += src/eap_peer/eap_tls.c endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y +ifdef CONFIG_EAP_TLSV1_3 +L_CFLAGS += -DEAP_TLSV1_3 +endif endif ifdef CONFIG_EAP_UNAUTH_TLS @@ -738,6 +772,7 @@ OBJS += src/eap_peer/eap_pwd.c src/eap_common/eap_pwd_common.c CONFIG_IEEE8021X_EAPOL=y NEED_ECC=y NEED_DRAGONFLY=y +MS_FUNCS=y endif ifdef CONFIG_EAP_EKE @@ -900,7 +935,6 @@ OBJS += src/ap/beacon.c OBJS += src/ap/bss_load.c OBJS += src/ap/eap_user_db.c OBJS += src/ap/neighbor_db.c -OBJS += src/ap/rrm.c OBJS += src/ap/ieee802_11_ht.c ifdef CONFIG_IEEE80211AC OBJS += src/ap/ieee802_11_vht.c @@ -908,6 +942,9 @@ endif ifdef CONFIG_IEEE80211AX OBJS += src/ap/ieee802_11_he.c endif +ifdef CONFIG_IEEE80211BE +OBJS += src/ap/ieee802_11_eht.c +endif ifdef CONFIG_WNM_AP L_CFLAGS += -DCONFIG_WNM_AP OBJS += src/ap/wnm_ap.c @@ -930,6 +967,10 @@ OBJS += src/eap_server/eap_server_methods.c ifdef CONFIG_IEEE80211AC L_CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_IEEE80211BE +CONFIG_IEEE80211AX=y +L_CFLAGS += -DCONFIG_IEEE80211BE +endif ifdef CONFIG_IEEE80211AX L_CFLAGS += -DCONFIG_IEEE80211AX endif @@ -937,6 +978,8 @@ endif ifdef NEED_AP_MLME OBJS += src/ap/wmm.c OBJS += src/ap/ap_list.c +OBJS += src/ap/comeback_token.c +OBJS += src/pasn/pasn_responder.c OBJS += src/ap/ieee802_11.c OBJS += src/ap/hw_features.c OBJS += src/ap/dfs.c @@ -952,6 +995,9 @@ OBJS += src/ap/dpp_hostapd.c OBJS += src/ap/gas_query_ap.c NEED_AP_GAS_SERV=y endif +ifdef CONFIG_NAN_USD +OBJS += src/ap/nan_usd_ap.c +endif ifdef CONFIG_INTERWORKING NEED_AP_GAS_SERV=y endif @@ -970,6 +1016,7 @@ endif ifdef CONFIG_TESTING_OPTIONS L_CFLAGS += -DCONFIG_TESTING_OPTIONS +NEED_AES_WRAP=y endif ifdef NEED_RSN_AUTHENTICATOR @@ -1061,6 +1108,7 @@ L_CFLAGS += -DCONFIG_TLSV12 endif ifeq ($(CONFIG_TLS), openssl) +L_CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 ifdef TLS_FUNCS L_CFLAGS += -DEAP_TLS_OPENSSL OBJS += src/crypto/tls_openssl.c @@ -1265,9 +1313,7 @@ ifdef NEED_AES_ENCBLOCK AESOBJS += src/crypto/aes-encblock.c endif NEED_AES_ENC=y -ifdef CONFIG_OPENSSL_CMAC -L_CFLAGS += -DCONFIG_OPENSSL_CMAC -else +ifneq ($(CONFIG_TLS), openssl) AESOBJS += src/crypto/aes-omac1.c endif ifdef NEED_AES_WRAP @@ -1361,6 +1407,17 @@ endif endif endif +ifdef CONFIG_SAE +ifdef NEED_SHA384 +# Need to add HMAC-SHA384 KDF as well, if SHA384 was enabled. +NEED_HMAC_SHA384_KDF=y +endif +ifdef NEED_SHA512 +# Need to add HMAC-SHA512 KDF as well, if SHA512 was enabled. +NEED_HMAC_SHA512_KDF=y +endif +endif + SHA256OBJS = # none by default L_CFLAGS += -DCONFIG_SHA256 ifneq ($(CONFIG_TLS), openssl) @@ -1698,6 +1755,144 @@ ifndef LDO LDO=$(CC) endif +PASNOBJS = +PASNOBJS += src/utils/$(CONFIG_ELOOP).c +PASNOBJS += src/utils/wpa_debug.c +PASNOBJS += src/utils/wpabuf.c +PASNOBJS += src/utils/os_$(CONFIG_OS).c +PASNOBJS += src/utils/config.c +PASNOBJS += src/utils/common.c + +ifdef NEED_BASE64 +PASNOBJS += src/utils/base64.c +endif + +ifdef CONFIG_WPA_TRACE +PASNOBJS += src/utils/trace.c +endif + +ifdef CONFIG_EXT_PASSWORD_FILE +PASNOBJS += src/utils/ext_password_file.c +endif + +ifdef CONFIG_EXT_PASSWORD_TEST +PASNOBJS += src/utils/ext_password_test.c +endif + +ifdef NEED_EXT_PASSWORD +PASNOBJS += src/utils/ext_password.c +endif + +ifdef CONFIG_SAE +PASNOBJS += src/common/sae.c +endif + +ifdef CONFIG_SAE_PK +PASNOBJS += src/common/sae_pk.c +endif + +ifndef CONFIG_NO_WPA +PASNOBJS += src/common/wpa_common.c +endif + +PASNOBJS += src/common/ieee802_11_common.c + +ifdef NEED_DRAGONFLY +PASNOBJS += src/common/dragonfly.c +endif + +PASNOBJS += src/common/ptksa_cache.c + +PASNOBJS += src/rsn_supp/pmksa_cache.c + +ifndef CONFIG_NO_WPA +PASNOBJS += src/rsn_supp/wpa_ie.c +endif + +PASNOBJS += src/ap/comeback_token.c +PASNOBJS += src/ap/pmksa_cache_auth.c + +ifdef NEED_EAP_COMMON +PASNOBJS += src/eap_common/eap_common.c +endif + +ifdef CHAP +PASNOBJS += src/eap_common/chap.c +endif + +ifdef CONFIG_IEEE8021X_EAPOL +PASNOBJS += src/eap_peer/eap.c +PASNOBJS += src/eap_peer/eap_methods.c +PASNOBJS += src/eapol_supp/eapol_supp_sm.c +endif + +ifeq ($(CONFIG_TLS), openssl) +PASNOBJS += src/crypto/crypto_openssl.c +ifdef TLS_FUNCS +PASNOBJS += src/crypto/tls_openssl.c +PASNOBJS += -lssl -lcrypto +NEED_TLS_PRF_SHA256=y +endif +endif + +ifeq ($(CONFIG_TLS), gnutls) +PASNOBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c +ifdef TLS_FUNCS +PASNOBJS += src/crypto/tls_gnutls.c +PASNOBJS += -lgnutls -lgpg-error +PASNOBJS += -lgcrypt +endif +endif + +ifdef NEED_TLS_PRF_SHA256 +PASNOBJS += src/crypto/sha256-tlsprf.c +endif + +ifdef NEED_SHA512 +PASNOBJS += src/crypto/sha512-prf.c +endif + +ifdef NEED_SHA384 +PASNOBJS += src/crypto/sha384-prf.c +endif + +PASNOBJS += src/crypto/sha256-prf.c + +ifdef NEED_HMAC_SHA512_KDF +PASNOBJS += src/crypto/sha512-kdf.c +endif + +ifdef NEED_HMAC_SHA384_KDF +PASNOBJS += src/crypto/sha384-kdf.c +endif + +ifdef NEED_HMAC_SHA256_KDF +PASNOBJS += src/crypto/sha256-kdf.c +endif + +ifdef NEED_DH_GROUPS +PASNOBJS += src/crypto/dh_groups.c +endif + +ifdef NEED_AES_SIV +PASNOBJS += src/crypto/aes-siv.c +endif + +ifdef NEED_AES_CTR +PASNOBJS += src/crypto/aes-ctr.c +endif + +ifdef NEED_SHA1 +PASNOBJS += src/crypto/sha1-prf.c +ifdef NEED_TLS_PRF +PASNOBJS += src/crypto/sha1-tlsprf.c +endif +endif + +PASNOBJS += src/pasn/pasn_initiator.c +PASNOBJS += src/pasn/pasn_responder.c +PASNOBJS += src/pasn/pasn_common.c + ######################## include $(CLEAR_VARS) @@ -1825,3 +2020,14 @@ LOCAL_STATIC_LIBRARIES := libwpa_binder_interface include $(BUILD_STATIC_LIBRARY) endif # BINDER == y + +include $(CLEAR_VARS) +LOCAL_MODULE = libpasn +LOCAL_CFLAGS = $(L_CFLAGS) +LOCAL_SRC_FILES = $(PASNOBJS) +LOCAL_C_INCLUDES = $(INCLUDES) +LOCAL_SHARED_LIBRARIES := libc libcutils liblog +ifeq ($(CONFIG_TLS), openssl) +LOCAL_SHARED_LIBRARIES := libcrypto libssl +endif +include $(BUILD_SHARED_LIBRARY) diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/ChangeLog b/wpa_supplicant-2.9_standard/wpa_supplicant/ChangeLog index efcc6cd9c9ba31b541807d0a6023b7fd56a60b98..3f4162eb0b866ff2d162c34a15972b3b77116fae 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/ChangeLog +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/ChangeLog @@ -1,5 +1,55 @@ ChangeLog for wpa_supplicant +2024-07-20 - v2.11 + * Wi-Fi Easy Connect + - add support for DPP release 3 + - allow Configurator parameters to be provided during config exchange + * MACsec + - add support for GCM-AES-256 cipher suite + - remove incorrect EAP Session-Id length constraint + - add hardware offload support for additional drivers + * HE/IEEE 802.11ax/Wi-Fi 6 + - support BSS color updates + - various fixes + * EHT/IEEE 802.11be/Wi-Fi 7 + - add preliminary support + * support OpenSSL 3.0 API changes + * improve EAP-TLS support for TLSv1.3 + * EAP-SIM/AKA: support IMSI privacy + * improve mitigation against DoS attacks when PMF is used + * improve 4-way handshake operations + - discard unencrypted EAPOL frames in additional cases + - use Secure=1 in message 2 during PTK rekeying + * OCV: do not check Frequency Segment 1 Channel Number for 160 MHz cases + to avoid interoperability issues + * support new SAE AKM suites with variable length keys + * support new AKM for 802.1X/EAP with SHA384 + * improve cross-AKM roaming with driver-based SME/BSS selection + * PASN + - extend support for secure ranging + - allow PASN implementation to be used with external programs for + Wi-Fi Aware + * FT: Use SHA256 to derive PMKID for AKM 00-0F-AC:3 (FT-EAP) + - this is based on additional details being added in the IEEE 802.11 + standard + - the new implementation is not backwards compatible, but PMKSA + caching with FT-EAP was, and still is, disabled by default + * support a pregenerated MAC (mac_addr=3) as an alternative mechanism + for using per-network random MAC addresses + * EAP-PEAP: require Phase 2 authentication by default (phase2_auth=1) + to improve security for still unfortunately common invalid + configurations that do not set ca_cert + * extend SCS support for QoS Characteristics + * extend MSCS support + * support unsynchronized service discovery (USD) + * add support for explicit SSID protection in 4-way handshake + (a mitigation for CVE-2023-52424; disabled by default for now, can be + enabled with ssid_protection=1) + - in addition, verify SSID after key setup when beacon protection is + used + * fix SAE H2E rejected groups validation to avoid downgrade attacks + * a large number of other fixes, cleanup, and extensions + 2022-01-16 - v2.10 * SAE changes - improved protection against side channel attacks diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/Makefile b/wpa_supplicant-2.9_standard/wpa_supplicant/Makefile index 676208e6192090ad4e1da1c074bdf2707a537f69..743c8acd683f7028ada9e1b98a091d37fb2b7635 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/Makefile +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/Makefile @@ -1,30 +1,33 @@ -ifeq ($(KERNEL_TYPE), linux) -CC=arm-himix410-linux-gcc -LD=arm-himix410-linux-ld -else -CC=../../../../prebuilts/gcc/linux-x86/arm/arm-linux-ohoseabi-gcc/bin/arm-linux-ohoseabi-gcc -endif +BINALL=wpa_supplicant wpa_cli -ifndef CFLAGS -ifeq ($(LIB_TYPE),$(KERNEL_TYPE), 1,linux) -CFLAGS = -fvisibility=hidden -MMD -O2 -g -w -fsigned-char -else ifeq ($(LIB_TYPE), 1) -CFLAGS = -fvisibility=hidden -flto -MMD -O2 -g -w -fsigned-char -else -CFLAGS = -MMD -O2 -g -w -fsigned-char -endif -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 + +EXTRA_TARGETS=dynamic_eap_methods + +CONFIG_FILE=.config +include ../src/build.rules -ifeq ($(MAKECMDGOALS), libwpa_client.so) -ifeq ($(LIB_TYPE),$(KERNEL_TYPE), 1,linux) -CFLAGS = -MMD -O2 -g -w -fsigned-char -else ifeq ($(LIB_TYPE), 1) -CFLAGS = -flto -MMD -O2 -g -w -fsigned-char +ifdef CONFIG_BUILD_PASN_SO +# add the dependency this way to allow CONFIG_BUILD_PASN_SO +# being set in the config which is read by build.rules +_all: libpasn.so endif + +ifdef CONFIG_BUILD_WPA_CLIENT_SO +# add the dependency this way to allow CONFIG_BUILD_WPA_CLIENT_SO +# being set in the config which is read by build.rules +_all: libwpa_client.so endif -ifeq ($(MAKECMDGOALS), libwpa_client.a) -CFLAGS = -MMD -O2 -g -w -fsigned-char +ifndef CONFIG_NO_WPA_PASSPHRASE +# add the dependency this way to allow CONFIG_NO_WPA_PASSPHRASE +# being set in the config which is read by build.rules +_all: wpa_passphrase endif ifdef LIBS @@ -46,32 +49,6 @@ PKG_CONFIG ?= pkg-config CFLAGS += $(EXTRA_CFLAGS) CFLAGS += -I$(abspath ../src) CFLAGS += -I$(abspath ../src/utils) -CFLAGS += -I$(abspath ../src/drivers) -CFLAGS += -I$(abspath ./) -CFLAGS += -I$(abspath ../os_dep/include) -CFLAGS += -I$(abspath ../../../../drivers/framework/include) -CFLAGS += -I$(abspath ../../../../drivers/framework/include/utils) -CFLAGS += -I$(abspath ../../../../drivers/framework/utils/include) -CFLAGS += -I$(abspath ../../../../drivers/framework/include/osal) -CFLAGS += -I$(abspath ../../../../drivers/framework/ability/sbuf/include) -CFLAGS += -I$(abspath ../../../../drivers/framework/core/shared/include) -CFLAGS += -I$(abspath ../../../../drivers/framework/include/core) -CFLAGS += -I$(abspath ../../../../drivers/framework/core/adapter/syscall/include) -CFLAGS += -I$(abspath ../../../../third_party/bounds_checking_function/include) -CFLAGS += -I$(abspath ../../../../drivers/peripheral/wlan/client/include) -CFLAGS += -I$(abspath ../build/include) -CFLAGS += -shared -fPIC -CFLAGS += -DUSERSPACE_CLIENT_SUPPORT -CFLAGS += -fstack-protector-all -LIBS += -L$(DEPDIR) -lsec_shared -lhilog_shared -lwifi_driver_client -ifeq ($(COMPILER_TYPE), clang) -SYSROOT_PATH ?= ../../../../sysroot -ARCH_CFLAGS ?= --target=arm-liteos-ohos -march=armv7-a -mfloat-abi=softfp -CC := $(COMPILER_DIR)/bin/clang -CFLAGS += --sysroot=$(SYSROOT_PATH) $(ARCH_CFLAGS) -LDFLAGS += --sysroot=$(SYSROOT_PATH) $(ARCH_CFLAGS) -LDFLAGS += -lc -endif ifndef CONFIG_NO_GITVER # Add VERSION_STR postfix for builds from a git repository @@ -87,37 +64,9 @@ ifdef CONFIG_TESTING_OPTIONS CFLAGS += -DCONFIG_TESTING_OPTIONS CONFIG_WPS_TESTING=y CONFIG_TDLS_TESTING=y +NEED_AES_WRAP=y endif -COPY_OBJS = copy_objs -BINALL=$(COPY_OBJS) 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'; \ @@ -131,6 +80,14 @@ $(DESTDIR)$(BINDIR)/%: % install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL)) $(MAKE) -C ../src install +ifndef CONFIG_NO_WPA_PASSPHRASE + install -D wpa_passphrase $(DESTDIR)/$(BINDIR)/wpa_passphrase +endif + +ifdef CONFIG_BUILD_PASN_SO + install -m 0644 -D libpasn.so $(DESTDIR)/$(LIBDIR)/libpasn.so +endif + ifdef CONFIG_BUILD_WPA_CLIENT_SO install -m 0644 -D libwpa_client.so $(DESTDIR)/$(LIBDIR)/libwpa_client.so install -m 0644 -D ../src/common/wpa_ctrl.h $(DESTDIR)/$(INCDIR)/wpa_ctrl.h @@ -142,7 +99,6 @@ endif ifdef CONFIG_FIPS CONFIG_NO_RANDOM_POOL= -CONFIG_OPENSSL_CMAC=y endif OBJS = config.o @@ -156,10 +112,9 @@ OBJS += ../src/utils/wpabuf.o OBJS += ../src/utils/bitfield.o OBJS += ../src/utils/ip_addr.o OBJS += ../src/utils/crc32.o -OBJS += op_classes.o -OBJS += rrm.o +OBJS += ../src/common/ptksa_cache.o +OBJS += ../src/rsn_supp/pmksa_cache.o OBJS += twt.o -OBJS += robust_av.o OBJS_p = wpa_passphrase.o OBJS_p += ../src/utils/common.o OBJS_p += ../src/utils/wpa_debug.o @@ -168,7 +123,6 @@ OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o OBJS_c += ../src/utils/wpa_debug.o OBJS_c += ../src/utils/common.o OBJS_c += ../src/common/cli.o -OBJS += wmm_ac.o ifndef CONFIG_OS ifdef CONFIG_NATIVE_WINDOWS @@ -193,9 +147,6 @@ OBJS_p += ../src/utils/trace.o OBJS_c += ../src/utils/trace.o OBJS_priv += ../src/utils/trace.o LIBCTRL += ../src/utils/trace.o -ifeq ($(LIB_TYPE), 0) -OBJS += ../src/utils/trace.o -endif LIBCTRLSO += ../src/utils/trace.c LDFLAGS += -rdynamic CFLAGS += -funwind-tables @@ -240,7 +191,7 @@ CFLAGS += -Werror -DEAPOL_TEST endif ifdef CONFIG_CODE_COVERAGE -CFLAGS += -O0 -fprofile-arcs -ftest-coverage +CFLAGS += -O0 -fprofile-arcs -ftest-coverage -U_FORTIFY_SOURCE LIBS += -lgcov LIBS_c += -lgcov LIBS_p += -lgcov @@ -325,6 +276,7 @@ CFLAGS += -DCONFIG_SAE OBJS += ../src/common/sae.o ifdef CONFIG_SAE_PK CFLAGS += -DCONFIG_SAE_PK +NEED_AES_SIV=y OBJS += ../src/common/sae_pk.o endif NEED_ECC=y @@ -365,6 +317,12 @@ CFLAGS += -DCONFIG_DPP3 endif endif +ifdef CONFIG_NAN_USD +OBJS += ../src/common/nan_de.o +OBJS += nan_usd.o +CFLAGS += -DCONFIG_NAN_USD +endif + ifdef CONFIG_OWE CFLAGS += -DCONFIG_OWE NEED_ECC=y @@ -389,6 +347,10 @@ ifdef CONFIG_MBO CONFIG_WNM=y endif +ifdef CONFIG_BGSCAN_SIMPLE +CONFIG_WNM=y +endif + ifdef CONFIG_WNM CFLAGS += -DCONFIG_WNM OBJS += wnm_sta.o @@ -410,7 +372,6 @@ endif ifndef CONFIG_NO_WPA OBJS += ../src/rsn_supp/wpa.o OBJS += ../src/rsn_supp/preauth.o -OBJS += ../src/rsn_supp/pmksa_cache.o OBJS += ../src/rsn_supp/wpa_ie.o OBJS += ../src/common/wpa_common.o NEED_AES=y @@ -471,7 +432,8 @@ NEED_HMAC_SHA256_KDF=y NEED_HMAC_SHA384_KDF=y NEED_SHA256=y NEED_SHA384=y -OBJS += ../src/common/ptksa_cache.o +OBJS += ../src/pasn/pasn_initiator.o +OBJS += ../src/pasn/pasn_common.o OBJS += pasn_supplicant.o endif @@ -519,6 +481,28 @@ ifdef CONFIG_NO_LOAD_DYNAMIC_EAP CFLAGS += -DCONFIG_NO_LOAD_DYNAMIC_EAP endif +ifdef CONFIG_NO_RRM +CFLAGS += -DCONFIG_NO_RRM +else +OBJS += rrm.o +ifdef CONFIG_AP +OBJS += ../src/ap/rrm.o +endif +OBJS += op_classes.o +endif + +ifdef CONFIG_NO_WMM_AC +CFLAGS += -DCONFIG_NO_WMM_AC +else +OBJS += wmm_ac.o +endif + +ifdef CONFIG_NO_ROBUST_AV +CFLAGS += -DCONFIG_NO_ROBUST_AV +else +OBJS += robust_av.o +endif + include ../src/drivers/drivers.mak ifdef CONFIG_AP OBJS_d += $(DRV_BOTH_OBJS) @@ -574,6 +558,9 @@ OBJS += ../src/eap_peer/eap_tls.o endif TLS_FUNCS=y CONFIG_IEEE8021X_EAPOL=y +ifdef CONFIG_EAP_TLSV1_3 +CFLAGS += -DEAP_TLSV1_3 +endif endif ifdef CONFIG_EAP_UNAUTH_TLS @@ -840,6 +827,7 @@ OBJS += ../src/eap_peer/eap_pwd.o ../src/eap_common/eap_pwd_common.o CONFIG_IEEE8021X_EAPOL=y NEED_ECC=y NEED_DRAGONFLY=y +MS_FUNCS=y endif ifdef CONFIG_EAP_EKE @@ -1021,7 +1009,6 @@ OBJS += ../src/ap/beacon.o OBJS += ../src/ap/bss_load.o OBJS += ../src/ap/eap_user_db.o OBJS += ../src/ap/neighbor_db.o -OBJS += ../src/ap/rrm.o OBJS += ../src/ap/ieee802_11_ht.o ifdef CONFIG_IEEE80211AC OBJS += ../src/ap/ieee802_11_vht.o @@ -1029,6 +1016,9 @@ endif ifdef CONFIG_IEEE80211AX OBJS += ../src/ap/ieee802_11_he.o endif +ifdef CONFIG_IEEE80211BE +OBJS += ../src/ap/ieee802_11_eht.o +endif ifdef CONFIG_WNM_AP CFLAGS += -DCONFIG_WNM_AP OBJS += ../src/ap/wnm_ap.o @@ -1051,6 +1041,10 @@ OBJS += ../src/eap_server/eap_server_methods.o ifdef CONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC endif +ifdef CONFIG_IEEE80211BE +CONFIG_IEEE80211AX=y +CFLAGS += -DCONFIG_IEEE80211BE +endif ifdef CONFIG_IEEE80211AX CFLAGS += -DCONFIG_IEEE80211AX endif @@ -1058,6 +1052,8 @@ endif ifdef NEED_AP_MLME OBJS += ../src/ap/wmm.o OBJS += ../src/ap/ap_list.o +OBJS += ../src/ap/comeback_token.o +OBJS += ../src/pasn/pasn_responder.o OBJS += ../src/ap/ieee802_11.o OBJS += ../src/ap/hw_features.o OBJS += ../src/ap/dfs.o @@ -1073,6 +1069,9 @@ OBJS += ../src/ap/dpp_hostapd.o OBJS += ../src/ap/gas_query_ap.o NEED_AP_GAS_SERV=y endif +ifdef CONFIG_NAN_USD +OBJS += ../src/ap/nan_usd_ap.o +endif ifdef CONFIG_INTERWORKING NEED_AP_GAS_SERV=y endif @@ -1087,6 +1086,7 @@ endif ifdef CONFIG_MBO OBJS += mbo.o CFLAGS += -DCONFIG_MBO +NEED_GAS=y endif ifdef NEED_RSN_AUTHENTICATOR @@ -1105,17 +1105,20 @@ endif ifdef CONFIG_PCSC # PC/SC interface for smartcards (USIM, GSM SIM) -CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC +CFLAGS += -DPCSC_FUNCS OBJS += ../src/utils/pcsc_funcs.o ifdef CONFIG_NATIVE_WINDOWS #Once MinGW gets support for WinScard, -lwinscard could be used instead of the #dynamic symbol loading that is now used in pcsc_funcs.c #LIBS += -lwinscard +CFLAGS += -I/usr/include/PCSC else ifdef CONFIG_OSX LIBS += -framework PCSC +CFLAGS += -I/usr/include/PCSC else LIBS += $(shell $(PKG_CONFIG) --libs libpcsclite) +CFLAGS += $(shell $(PKG_CONFIG) --cflags libpcsclite) endif endif endif @@ -1181,6 +1184,10 @@ ifdef CONFIG_TLSV12 CFLAGS += -DCONFIG_TLSV12 endif +ifdef CONFIG_RADIUS_TLS +TLS_FUNCS=y +endif + ifeq ($(CONFIG_TLS), wolfssl) ifdef TLS_FUNCS CFLAGS += -DWOLFSSL_DER_LOAD @@ -1197,6 +1204,7 @@ LIBS_p += -lwolfssl -lm endif ifeq ($(CONFIG_TLS), openssl) +CFLAGS += -DCRYPTO_RSA_OAEP_SHA256 ifdef TLS_FUNCS CFLAGS += -DEAP_TLS_OPENSSL OBJS += ../src/crypto/tls_openssl.o @@ -1448,9 +1456,7 @@ ifdef NEED_AES_ENCBLOCK AESOBJS += ../src/crypto/aes-encblock.o endif NEED_AES_ENC=y -ifdef CONFIG_OPENSSL_CMAC -CFLAGS += -DCONFIG_OPENSSL_CMAC -else +ifneq ($(CONFIG_TLS), openssl) ifneq ($(CONFIG_TLS), linux) ifneq ($(CONFIG_TLS), wolfssl) AESOBJS += ../src/crypto/aes-omac1.o @@ -1564,6 +1570,17 @@ endif endif endif +ifdef CONFIG_SAE +ifdef NEED_SHA384 +# Need to add HMAC-SHA384 KDF as well, if SHA384 was enabled. +NEED_HMAC_SHA384_KDF=y +endif +ifdef NEED_SHA512 +# Need to add HMAC-SHA512 KDF as well, if SHA512 was enabled. +NEED_HMAC_SHA512_KDF=y +endif +endif + SHA256OBJS = # none by default CFLAGS += -DCONFIG_SHA256 ifneq ($(CONFIG_TLS), openssl) @@ -1677,7 +1694,6 @@ OBJS += ../src/common/ctrl_iface_common.o endif ifeq ($(CONFIG_CTRL_IFACE), udp) CFLAGS += -DCONFIG_CTRL_IFACE_UDP -CFLAGS += -DCONFIG_OPEN_HARMONY_PATCH_LITE endif ifeq ($(CONFIG_CTRL_IFACE), udp6) CONFIG_CTRL_IFACE=udp @@ -1748,9 +1764,7 @@ LIBS_p += -lcrypt32 endif endif -#ifdef CONFIG_NO_STDOUT_DEBUG -ifneq ($(DEBUG), 1) -CFLAGS += -DCONFIG_WPA_NO_LOG +ifdef CONFIG_NO_STDOUT_DEBUG CFLAGS += -DCONFIG_NO_STDOUT_DEBUG ifndef CONFIG_CTRL_IFACE CFLAGS += -DCONFIG_NO_WPA_MSG @@ -1912,6 +1926,9 @@ 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 +ifdef CONFIG_RADIUS_TLS +CFLAGS += -DCONFIG_RADIUS_TLS +endif OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o OBJS_nfc := $(OBJS) $(OBJS_l2) nfc_pw_token.o @@ -1987,13 +2004,12 @@ wpa_priv: $(BCHECK) $(OBJS_priv) _OBJS_VAR := OBJS include ../src/objs.mk -$(COPY_OBJS): $(OBJS) - cp $(OBJS) ../build/objs > /dev/null 2>&1 - -#wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs) -# $(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS) -lm -lpthread -# @$(E) " LD " $@ +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 " $@ @@ -2013,7 +2029,7 @@ wpa_passphrase: $(OBJS_p) _OBJS_VAR := OBJS_c include ../src/objs.mk wpa_cli: $(OBJS_c) - $(Q)$(LDO) --static $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c) + $(Q)$(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c) @$(E) " LD " $@ LIBCTRL += ../src/common/wpa_ctrl.o @@ -2025,23 +2041,16 @@ LIBCTRLSO += ../src/utils/os_$(CONFIG_OS).c LIBCTRLSO += ../src/utils/common.c LIBCTRLSO += ../src/utils/wpa_debug.c -ifeq ($(LIB_TYPE), 0) -OBJS += ../src/common/wpa_ctrl.o -OBJS += ../src/utils/os_$(CONFIG_OS).o -OBJS += ../src/utils/common.o -OBJS += ../src/utils/wpa_debug.o -endif - +_OBJS_VAR := LIBCTRL +include ../src/objs.mk libwpa_client.a: $(LIBCTRL) $(Q)rm -f $@ $(Q)$(AR) crs $@ $? @$(E) " AR " $@ - cp $@ ../build libwpa_client.so: $(LIBCTRLSO) @$(E) " CC $@ ($^)" $(Q)$(CC) $(LDFLAGS) -o $@ $(CFLAGS) -shared -fPIC $^ - cp $@ ../build OBJS_wpatest := libwpa_test.o _OBJS_VAR := OBJS_wpatest @@ -2165,9 +2174,161 @@ lcov-html: $(call BUILDOBJ,wpa_supplicant.gcda) lcov -c -d $(BUILDDIR) > lcov.info genhtml lcov.info --output-directory lcov-html +PASN_CFLAGS := $(CFLAGS) +PASN_CFLAGS += -DCONFIG_PASN + +LIBPASNSO := ../src/utils/$(CONFIG_ELOOP).c +LIBPASNSO += ../src/utils/wpa_debug.c +LIBPASNSO += ../src/utils/wpabuf.c +LIBPASNSO += ../src/utils/os_$(CONFIG_OS).c +LIBPASNSO += ../src/utils/config.c +LIBPASNSO += ../src/utils/common.c + +ifdef NEED_BASE64 +LIBPASNSO += ../src/utils/base64.c +endif + +ifdef CONFIG_WPA_TRACE +LIBPASNSO += ../src/utils/trace.c +endif + +ifdef CONFIG_EXT_PASSWORD_FILE +LIBPASNSO += ../src/utils/ext_password_file.c +endif + +ifdef CONFIG_EXT_PASSWORD_TEST +LIBPASNSO += ../src/utils/ext_password_test.c +endif + +ifdef NEED_EXT_PASSWORD +LIBPASNSO += ../src/utils/ext_password.c +endif + +ifdef CONFIG_SAE +LIBPASNSO += ../src/common/sae.c +endif + +ifdef CONFIG_SAE_PK +LIBPASNSO += ../src/common/sae_pk.c +endif + +ifndef CONFIG_NO_WPA +LIBPASNSO += ../src/common/wpa_common.c +endif + +LIBPASNSO += ../src/common/ieee802_11_common.c + +ifdef NEED_DRAGONFLY +LIBPASNSO += ../src/common/dragonfly.c +endif + +LIBPASNSO += ../src/common/ptksa_cache.c +LIBPASNSO += ../src/rsn_supp/pmksa_cache.c + +ifndef CONFIG_NO_WPA +LIBPASNSO += ../src/rsn_supp/wpa_ie.c +endif + +LIBPASNSO += ../src/ap/comeback_token.c +LIBPASNSO += ../src/ap/pmksa_cache_auth.c + +ifdef NEED_EAP_COMMON +LIBPASNSO += ../src/eap_common/eap_common.c +endif + +ifdef CHAP +LIBPASNSO += ../src/eap_common/chap.c +endif + +ifdef CONFIG_IEEE8021X_EAPOL +LIBPASNSO += ../src/eap_peer/eap.c +LIBPASNSO += ../src/eap_peer/eap_methods.c +LIBPASNSO += ../src/eapol_supp/eapol_supp_sm.c +endif + +ifeq ($(CONFIG_TLS), wolfssl) +LIBPASNSO += ../src/crypto/crypto_wolfssl.c +ifdef TLS_FUNCS +LIBPASNSO += ../src/crypto/tls_wolfssl.c +NEED_TLS_PRF_SHA256=y +LIBPASNSO += -lwolfssl -lm +endif +endif + +ifeq ($(CONFIG_TLS), openssl) +LIBPASNSO += ../src/crypto/crypto_openssl.c +ifdef TLS_FUNCS +LIBPASNSO += ../src/crypto/tls_openssl.c +LIBPASNSO += -lssl -lcrypto +NEED_TLS_PRF_SHA256=y +endif +endif + +ifeq ($(CONFIG_TLS), gnutls) +LIBPASNSO += ../src/crypto/crypto_$(CONFIG_CRYPTO).c +ifdef TLS_FUNCS +LIBPASNSO += ../src/crypto/tls_gnutls.c +LIBPASNSO += -lgnutls -lgpg-error +LIBPASNSO += -lgcrypt +endif +endif + +ifdef NEED_TLS_PRF_SHA256 +LIBPASNSO += ../src/crypto/sha256-tlsprf.c +endif + +ifdef NEED_SHA512 +LIBPASNSO += ../src/crypto/sha512-prf.c +endif + +ifdef NEED_SHA384 +LIBPASNSO += ../src/crypto/sha384-prf.c +endif + +LIBPASNSO += ../src/crypto/sha256-prf.c + +ifdef NEED_HMAC_SHA512_KDF +LIBPASNSO += ../src/crypto/sha512-kdf.c +endif + +ifdef NEED_HMAC_SHA384_KDF +LIBPASNSO += ../src/crypto/sha384-kdf.c +endif + +ifdef NEED_HMAC_SHA256_KDF +LIBPASNSO += ../src/crypto/sha256-kdf.c +endif + +ifdef NEED_DH_GROUPS +LIBPASNSO += ../src/crypto/dh_groups.c +endif + +ifdef NEED_AES_SIV +LIBPASNSO += ../src/crypto/aes-siv.c +endif + +ifdef NEED_AES_CTR +LIBPASNSO += ../src/crypto/aes-ctr.c +endif + +ifdef NEED_SHA1 +LIBPASNSO += ../src/crypto/sha1-prf.c +ifdef NEED_TLS_PRF +LIBPASNSO += ../src/crypto/sha1-tlsprf.c +endif +endif + +LIBPASNSO += ../src/pasn/pasn_initiator.c +LIBPASNSO += ../src/pasn/pasn_responder.c +LIBPASNSO += ../src/pasn/pasn_common.c + +libpasn.so: $(LIBPASNSO) + @$(E) " CC $@ ($^)" + $(Q)$(CC) $(LDFLAGS) -o $@ $(PASN_CFLAGS) -shared -fPIC -lcrypto $^ + clean: common-clean $(MAKE) -C ../src clean - $(MAKE) -C ./dbus clean + $(MAKE) -C dbus clean rm -f core *~ *.o *.d *.gcno *.gcda *.gcov rm -f eap_*.so $(WINALL) eapol_test preauth_test rm -f wpa_priv @@ -2175,5 +2336,7 @@ clean: common-clean rm -f lcov.info rm -rf lcov-html rm -f libwpa_client.a + rm -f libpasn.so rm -f libwpa_client.so rm -f libwpa_test1 libwpa_test2 + rm -f wpa_passphrase diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/README b/wpa_supplicant-2.9_standard/wpa_supplicant/README index c643b268470042df9a3395457885ec6263d0ea83..49e971e218b4c92d30f1dc4ac111538f592c7b81 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/README +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/README @@ -1,7 +1,7 @@ wpa_supplicant ============== -Copyright (c) 2003-2022, Jouni Malinen and contributors +Copyright (c) 2003-2024, Jouni Malinen and contributors All Rights Reserved. This program is licensed under the BSD license (the one with @@ -442,7 +442,9 @@ drivers: nl80211 = Linux nl80211/cfg80211 wext = Linux wireless extensions (generic) wired = wpa_supplicant wired Ethernet driver + macsec_linux = MACsec Ethernet driver for Linux roboswitch = wpa_supplicant Broadcom switch driver + none = no driver (RADIUS server/WPS ER only) bsd = BSD 802.11 support (Atheros, etc.) ndis = Windows NDIS driver diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/README-HS20 b/wpa_supplicant-2.9_standard/wpa_supplicant/README-HS20 index b076621db5270a9afa08e8bdd3f0914aa338a23d..7d30e23c6d664bd407afd15b170070b13746c1f8 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/README-HS20 +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/README-HS20 @@ -168,6 +168,17 @@ Credentials can be pre-configured for automatic network selection: # milenage: Milenage parameters for SIM/USIM simulator in :: # format # +# imsi_privacy_cert: IMSI privacy certificate (PEM encoded X.509v3 certificate) +# This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent +# identity (IMSI) to improve privacy. The X.509v3 certificate needs to +# include a 2048-bit RSA public key and this is from the operator who +# authenticates the SIM/USIM. +# imsi_privacy_attr: IMSI privacy attribute +# This field is used to help the EAP-SIM/AKA/AKA' server to identify +# the used certificate (and as such, the matching private key). This +# is set to an attribute in name=value format if the operator needs +# this information. +# # domain_suffix_match: Constraint for server domain name # If set, this FQDN is used as a suffix match requirement for the AAA # server certificate in SubjectAltName dNSName element(s). If a @@ -188,7 +199,26 @@ Credentials can be pre-configured for automatic network selection: # be used to configure alternative FQDNs that will be considered home # networks. # +# home_ois: Home OI(s) +# This string field contains one or more comma delimited OIs (hexdump) +# identifying the access the access points that support authentication +# with this credential. There are an alternative to the use of the realm +# parameter. When using Home OIs to match the network, the EAP parameters +# need to be pre-configured with the credentials since the NAI Realm +# information may not be available or fetched. +# A successful authentication with the access point is possible as soon +# as at least one Home OI from the list matches an OI in the Roaming +# Consortium advertised by the access point. +# (Hotspot 2.0 PerProviderSubscription//HomeSP/HomeOIList//HomeOI) +# +# required_home_ois: Required Home OI(s) +# This string field contains the set of Home OI(s) (hexdump) that are +# required to be advertised by the AP for the credential to be considered +# matching. +# (Hotspot 2.0 PerProviderSubscription//HomeSP/HomeOIList//HomeOIRequired) +# # roaming_consortium: Roaming Consortium OI +# Deprecated: use home_ois instead. # If roaming_consortium_len is non-zero, this field contains the # Roaming Consortium OI that can be used to determine which access # points support authentication with this credential. This is an @@ -198,6 +228,7 @@ Credentials can be pre-configured for automatic network selection: # may not be available or fetched. # # required_roaming_consortium: Required Roaming Consortium OI +# Deprecated: use required_home_ois instead. # If required_roaming_consortium_len is non-zero, this field contains the # Roaming Consortium OI that is required to be advertised by the AP for # the credential to be considered matching. @@ -314,7 +345,7 @@ Credentials can be pre-configured for automatic network selection: # password="password" # ca_cert="/etc/wpa_supplicant/ca.pem" # domain="example.com" -# roaming_consortium=223344 +# home_ois="223344" # roaming_consortiums="112233,4455667788,aabbcc" # eap=TTLS # phase2="auth=MSCHAPV2" diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/README-NAN-USD b/wpa_supplicant-2.9_standard/wpa_supplicant/README-NAN-USD new file mode 100644 index 0000000000000000000000000000000000000000..72c379fc976af15143580c7266ca01ac6cb414a8 --- /dev/null +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/README-NAN-USD @@ -0,0 +1,147 @@ +Wi-Fi Aware unsynchronized service discovery (NAN USD) +====================================================== + +This document descibes how the unsynchronized service discovery defined +in the Wi-Fi Aware specification v4.0 can be used with wpa_spplicant. + +More information about Wi-Fi Aware is available from this Wi-Fi +Alliance web page: +https://www.wi-fi.org/discover-wi-fi/wi-fi-aware + +Build config setup +------------------ + +The following parameters must be included in the config file used to +compile hostapd and wpa_supplicant. + +wpa_supplicant build config +--------------------------- + +Enable NAN USD in wpa_supplicant build config file + +CONFIG_NAN_USD=y + +Control interface commands and events +------------------------------------- + +Following control interface commands can be used: + +NAN_PUBLISH service_name= [ttl=] [freq=] [freq_list=] [srv_proto_type=] [ssi=] [solicited=0] [unsolicited=0] [fsd=0] + +If ttl=0 or the parameter is not included, only one Publish message is +transmitted. + +If freq is not included, the default frequency 2437 MHz (channel 6 on +the 2.4 GHz band) is used. + +If freq_list is included, publisher iterates over all the listed +channels. A special freq_list=all value can be used to generate the +channel list automatically based on the list of allowed 2.4 and 5 GHz +channels. + +srv_proto_type values are defined in the Service Protocol Types table in +the Wi-Fi Aware specification. + +This command returns the assigned publish_id value or FAIL on failure. + +This command maps to the Publish() method in the NAN Discovery Engine. + +NAN_CANCEL_PUBLISH publish_id= + +This command maps to the CancelPublish() method in the NAN Discovery +Engine. + +NAN_UPDATE_PUBLISH publish_id= [ssi=] + +This command maps to the UpdatePublish() method in the NAN Discovery +Engine. + +NAN_SUBSCRIBE service_name= [active=1] [ttl=] [freq=] [srv_proto_type=] [ssi=] + +If ttl=0 or the parameter is not included, operation is terminated once +the first matching publisher is found. + +If freq is not included, the default frequency 2437 MHz (channel 6 on +the 2.4 GHz band) is used. + +srv_proto_type values are defined in the Service Protocol Types table in +the Wi-Fi Aware specification. + +This command returns the assigned subscribe_id value or FAIL on failure. + +This command maps to the Subscribe() method in the NAN Discovery Engine. + +NAN_CANCEL_SUBSCRIBE subscribe_id= + +This command maps to the CancelSubscribe() method in the NAN Discovery Engine. + +NAN_TRANSMIT handle= req_instance_id= address= [ssi=] + +This command maps to the Transmit() method in the NAN Discovery Engine. + +Following control interface events are used: + +NAN-DISCOVERY-RESULT subscribe_id= publish_id= address= fsd=<0/1> fsd_gas=<0/1> srv_proto_type= ssi= + +This event maps to the DiscoveryResult() event in the NAN Discovery +Engine. + +NAN-REPLIED publish_id= address= subscribe_id= srv_proto_type= ssi= + +This event maps to the Replied() event in the NAN Discovery Engine. + +NAN-PUBLISH-TERMINATED publish_id= reason= + +This event maps to the PublishTerminated() event in the NAN Discovery +Engine. + +NAN-SUBSCRIBE-TERMINATED subscribe_id= reason= + +This event maps to the SubscribeTerminate() event in the NAN Discovery +Engine. + +NAN-RECEIVE id= peer_instance_id= address= ssi= + +This event maps to the Receive() event in the NAN Discovery Engine. + + +Example operation +----------------- + +Start Subscribe and Publish functions: + +dev0: NAN_SUBSCRIBE service_name=_test srv_proto_type=3 ssi=1122334455 +--> returns 7 + +dev1: NAN_PUBLISH service_name=_test srv_proto_type=3 ssi=6677 +--> returns 5 + +Subscriber notification of a discovery: + +event on dev0: <3>NAN-DISCOVERY-RESULT subscribe_id=7 publish_id=5 address=02:00:00:00:01:00 fsd=1 fsd_gas=0 srv_proto_type=3 ssi=6677 + +Publisher notification of a Follow-up message with no ssi (to enter +paused state to continue exchange with the subscriber): + +event on dev1: <3>NAN-RECEIVE id=5 peer_instance_id=7 address=02:00:00:00:00:00 ssi= + +Subscriber sending a Follow-up message: + +dev0: NAN_TRANSMIT handle=7 req_instance_id=5 address=02:00:00:00:01:00 ssi=8899 + +Publisher receiving the Follow-up message: + +event on dev1: <3>NAN-RECEIVE id=5 peer_instance_id=7 address=02:00:00:00:00:00 ssi=8899 + +Publisher sending a Follow-up message: + +dev1: NAN_TRANSMIT handle=5 req_instance_id=7 address=02:00:00:00:00:00 ssi=aabbccdd + +Subscriber receiving the Follow-up message: + +event on dev0: <3>NAN-RECEIVE id=7 peer_instance_id=5 address=02:00:00:00:01:00 ssi=aabbccdd + +Stop Subscribe and Publish functions: + +dev0: NAN_CANCEL_SUBSCRIBE subscribe_id=7 +dev1: NAN_CANCEL_PUBLIST publish_id=5 diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/README-WPS b/wpa_supplicant-2.9_standard/wpa_supplicant/README-WPS index b884f67a2435bbd838a88598821503d87b1f2e9e..e902cc8c7b46306c22c949c98da4a0596ea8767f 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/README-WPS +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/README-WPS @@ -24,8 +24,8 @@ not very secure. As such, use of WPS may not be suitable for environments that require secure network access without chance for allowing outsiders to gain access during the setup phase. -WPS uses following terms to describe the entities participating in the -network setup: +WPS uses the following terms to describe the entities participating +in the network setup: - access point: the WLAN access point - Registrar: a device that control a network and can authorize addition of new devices); this may be either in the AP ("internal @@ -55,22 +55,22 @@ wpa_supplicant configuration WPS is an optional component that needs to be enabled in wpa_supplicant build configuration (.config). Here is an example -configuration that includes WPS support and Linux nl80211 -based +configuration that includes WPS support and Linux nl80211-based driver interface: CONFIG_DRIVER_NL80211=y CONFIG_WPS=y If you want to enable WPS external registrar (ER) functionality, you -will also need to add following line: +will also need to add the following line: CONFIG_WPS_ER=y -Following parameter can be used to enable support for NFC config method: +The following parameter can be used to enable support for NFC config +method: CONFIG_WPS_NFC=y - WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for the device. This is configured in the runtime configuration for wpa_supplicant (if not set, UUID will be generated based on local MAC @@ -91,7 +91,6 @@ to allow configuration file updates: update_config=1 - External operations ------------------- @@ -118,7 +117,6 @@ entered at the Registrar to complete WPS registration. At that point, the client will be enrolled with credentials needed to connect to the AP to access the network. - If the client device does not have a display that could show the random PIN, a hardcoded PIN that is printed on a label can be used. wpa_supplicant is notified this with a control interface @@ -135,7 +133,6 @@ expiration timeout for the PIN in seconds. For example: wpa_cli wps_pin any 12345670 300 - If a random PIN is needed for a user interface, "wpa_cli wps_pin get" can be used to generate a new PIN without starting WPS negotiation. This random PIN can then be passed as an argument to another wps_pin @@ -154,7 +151,6 @@ At this point, the AP/Registrar has two minutes to complete WPS negotiation which will generate a new WPA PSK in the same way as the PIN method described above. - If the client wants to operate in the Registrar role to learn the current AP configuration and optionally, to configure an AP, wpa_supplicant is notified over the control interface, e.g., with @@ -218,7 +214,8 @@ option. When this is used, an external program is responsible for processing the credential attributes and updating wpa_supplicant configuration based on them. -Following control interface messages are sent out for external programs: +The following control interface messages are sent out for external +programs: WPS-CRED-RECEIVED For example: @@ -236,7 +233,7 @@ can be either over a wired or wireless connection). Separate wpa_supplicant process can be started for WPS ER operations. A special "none" driver can be used in such a case to indicate that no local network interface is actually controlled. For -example, following command could be used to start the ER: +example, the following command could be used to start the ER: wpa_supplicant -Dnone -c er.conf -ieth0 @@ -245,7 +242,6 @@ Sample er.conf: ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=admin device_name=WPS External Registrar - wpa_cli commands for ER functionality: wps_er_start [IP address] @@ -275,7 +271,6 @@ wps_er_config must be one of the following: OPEN WPAPSK WPA2PSK must be one of the following: NONE WEP TKIP CCMP - wps_er_pbc - accept an Enrollee PBC using External Registrar @@ -285,7 +280,6 @@ wps_er_pin [Enrollee MAC address] - if the MAC address of the enrollee is known, it should be configured to allow the AP to advertise list of authorized enrollees - WPS ER events: WPS_EVENT_ER_AP_ADD diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/README.OpenSource b/wpa_supplicant-2.9_standard/wpa_supplicant/README.OpenSource index a101014319092506346cb7566c04608241e258ae..ee5b94b2810689b4beeacac15b4c91fccc04bd82 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/README.OpenSource +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/README.OpenSource @@ -1,12 +1,12 @@ -[ - { - "Name": "WPA Supplicant", - "License": "BSD 3-Clause License", - "License File": "../COPYING", - "Version Number": "2.10", - "Owner": "maoyufeng3@huawei.com", - "Upstream URL": "https://w1.fi/releases/wpa_supplicant-2.10.tar.gz", - "Description": "wpa_supplicant is a WPA Supplicant for Linux, BSD, Mac OS X, and Windows with support for WPA and WPA2 (IEEE 802.11i / RSN). It is suitable for both desktop/laptop computers and embedded systems. Supplicant is the IEEE 802.1X/WPA component that is used in the client stations. It implements key negotiation with a WPA Authenticator and it controls the roaming and IEEE 802.11 authentication/association of the wlan driver." - } -] - +[ + { + "Name": "WPA Supplicant", + "License": "BSD 3-Clause License", + "License File": "../COPYING", + "Version Number": "2.11", + "Owner": "maoyufeng3@huawei.com", + "Upstream URL": "https://w1.fi/releases/wpa_supplicant-2.11.tar.gz", + "Description": "wpa_supplicant is a WPA Supplicant for Linux, BSD, Mac OS X, and Windows with support for WPA and WPA2 (IEEE 802.11i / RSN). It is suitable for both desktop/laptop computers and embedded systems. Supplicant is the IEEE 802.1X/WPA component that is used in the client stations. It implements key negotiation with a WPA Authenticator and it controls the roaming and IEEE 802.11 authentication/association of the wlan driver." + } +] + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/android.config b/wpa_supplicant-2.9_standard/wpa_supplicant/android.config index 283f8eb0a995518405d7affa0aa3c0adafd05a5d..5ae3808fb6632f39b2b5b2ca96d41344157ef6e2 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/android.config +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/android.config @@ -542,4 +542,19 @@ CONFIG_WIFI_DISPLAY=y # be completely removed in a future release. CONFIG_WEP=y +# Disable support for Radio Measurement (IEEE 802.11k) and supported operating +# class indication. Removing these is not recommended since they can help the +# AP manage the network and STA steering. +#CONFIG_NO_RRM=y + +# Disable support for Robust AV streaming for consumer and enterprise Wi-Fi +# applications; IEEE Std 802.11-2020, 4.3.24; SCS, MSCS, QoS Management +#CONFIG_NO_ROBUST_AV=y + +# Disable support for WMM admission control +#CONFIG_NO_WMM_AC=y + +# Wi-Fi Aware unsynchronized service discovery (NAN USD) +#CONFIG_NAN_USD=y + include $(wildcard $(LOCAL_PATH)/android_config_*.inc) diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/ap.c b/wpa_supplicant-2.9_standard/wpa_supplicant/ap.c index 0316ec9676c2b39bdbb1b06f854b7e07de5cfa6b..bb424c2aa7a050f3004f728afdeb2e2b82eaa0cd 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/ap.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/ap.c @@ -44,6 +44,7 @@ #ifdef CONFIG_P2P_CHR #include "wpa_hw_p2p_chr.h" #endif + #ifdef CONFIG_WPS static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); #endif /* CONFIG_WPS */ @@ -95,7 +96,7 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, &conf->op_class, &conf->channel); - if (hostapd_get_oper_chwidth(conf) == CHANWIDTH_80P80MHZ) { + if (hostapd_get_oper_chwidth(conf) == CONF_OPER_CHWIDTH_80P80MHZ) { ieee80211_freq_to_chan(ssid->vht_center_freq2, &freq_seg_idx); hostapd_set_oper_centr_freq_seg1_idx(conf, freq_seg_idx); @@ -117,15 +118,15 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, #ifdef CONFIG_P2P switch (hostapd_get_oper_chwidth(conf)) { - case CHANWIDTH_80MHZ: - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel, conf->op_class); wpa_printf(MSG_DEBUG, "VHT center channel %u for 80 or 80+80 MHz bandwidth", center_chan); break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: center_chan = wpas_p2p_get_vht160_center(wpa_s, mode, channel, conf->op_class); wpa_printf(MSG_DEBUG, @@ -138,7 +139,7 @@ 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. */ - hostapd_set_oper_chwidth(conf, CHANWIDTH_160MHZ); + hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_160MHZ); ieee80211_freq_to_channel_ext(ssid->frequency, 0, conf->vht_oper_chwidth, &conf->op_class, @@ -150,7 +151,7 @@ static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, "VHT center channel %u for auto-selected 160 MHz bandwidth", center_chan); } else { - hostapd_set_oper_chwidth(conf, CHANWIDTH_80MHZ); + hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_80MHZ); ieee80211_freq_to_channel_ext(ssid->frequency, 0, conf->vht_oper_chwidth, &conf->op_class, @@ -179,7 +180,10 @@ no_vht: conf->channel); hostapd_set_oper_centr_freq_seg0_idx( conf, conf->channel + conf->secondary_channel * 2); - hostapd_set_oper_chwidth(conf, CHANWIDTH_USE_HT); + hostapd_set_oper_chwidth(conf, CONF_OPER_CHWIDTH_USE_HT); + ieee80211_freq_to_channel_ext(ssid->frequency, 0, + conf->vht_oper_chwidth, + &conf->op_class, &conf->channel); } @@ -206,14 +210,14 @@ wpa_supplicant_find_hw_mode(struct wpa_supplicant *wpa_s, static int get_max_oper_chwidth_6ghz(int chwidth) { switch (chwidth) { - case CHANWIDTH_USE_HT: + case CONF_OPER_CHWIDTH_USE_HT: return 20; - case CHANWIDTH_40MHZ_6GHZ: + case CONF_OPER_CHWIDTH_40MHZ_6GHZ: return 40; - case CHANWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: return 80; - case CHANWIDTH_80P80MHZ: - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_160MHZ: return 160; default: return 0; @@ -254,8 +258,8 @@ static void wpas_conf_ap_he_6ghz(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "Secondary channel offset %d for P2P group", conf->secondary_channel); - if (ssid->max_oper_chwidth == CHANWIDTH_40MHZ_6GHZ) - ssid->max_oper_chwidth = CHANWIDTH_USE_HT; + if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_40MHZ_6GHZ) + ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_USE_HT; } if ((is_chanwidth_40_80 || is_chanwidth_160) && ssid->p2p_group && @@ -271,7 +275,7 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, struct hostapd_config *conf) { conf->hw_mode = ieee80211_freq_to_channel_ext(ssid->frequency, 0, - CHANWIDTH_USE_HT, + CONF_OPER_CHWIDTH_USE_HT, &conf->op_class, &conf->channel); if (conf->hw_mode == NUM_HOSTAPD_MODES) { @@ -316,8 +320,20 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, #ifdef CONFIG_HT_OVERRIDES if (ssid->disable_ht) ssid->ht = 0; + if (ssid->disable_ht40) + ssid->ht40 = 0; #endif /* CONFIG_HT_OVERRIDES */ +#ifdef CONFIG_VHT_OVERRIDES + if (ssid->disable_vht) + ssid->vht = 0; +#endif /* CONFIG_VHT_OVERRIDES */ + +#ifdef CONFIG_HE_OVERRIDES + if (ssid->disable_he) + ssid->he = 0; +#endif /* CONFIG_HE_OVERRIDES */ + if (!ssid->ht) { wpa_printf(MSG_DEBUG, "HT not enabled in network profile"); @@ -328,6 +344,16 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, if (mode && is_6ghz_freq(ssid->frequency) && conf->hw_mode == HOSTAPD_MODE_IEEE80211A) { + if (mode->eht_capab[wpas_mode_to_ieee80211_mode( + ssid->mode)].eht_supported && + ssid->eht) + conf->ieee80211be = 1; + + if (mode->he_capab[wpas_mode_to_ieee80211_mode( + ssid->mode)].he_supported && + ssid->he) + conf->ieee80211ax = 1; + #ifdef CONFIG_P2P wpas_conf_ap_he_6ghz(wpa_s, mode, ssid, conf); #endif /* CONFIG_P2P */ @@ -387,7 +413,7 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET; /* - * white-list capabilities that won't cause issues + * include capabilities that won't cause issues * to connecting stations, while leaving the current * capabilities intact (currently disabled SMPS). */ @@ -402,6 +428,11 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, /* 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->eht_capab[wpas_mode_to_ieee80211_mode( + ssid->mode)].eht_supported && + ssid->eht) + conf->ieee80211be = 1; + if (mode->he_capab[wpas_mode_to_ieee80211_mode( ssid->mode)].he_supported && ssid->he) @@ -415,6 +446,13 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, } } +#ifdef CONFIG_P2P + if (ssid->p2p_group && wpa_s->p2p_go_no_pri_sec_switch) { + conf->no_pri_sec_switch = 1; + return 0; + } +#endif /* CONFIG_P2P */ + if (conf->secondary_channel) { struct wpa_supplicant *iface; @@ -444,7 +482,7 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, * connection time is too long. So turn off channel switching. */ if (ssid->p2p_group) { - conf->no_pri_sec_switch = 1; + conf->no_pri_sec_switch = 1; } #endif } @@ -717,8 +755,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, bss->wpa_group_rekey = 86400; } - if (ssid->ieee80211w != MGMT_FRAME_PROTECTION_DEFAULT) + if (ssid->ieee80211w != MGMT_FRAME_PROTECTION_DEFAULT) { bss->ieee80211w = ssid->ieee80211w; + } else if (wpa_s->conf->pmf != MGMT_FRAME_PROTECTION_DEFAULT) { + if (ssid->mode == WPAS_MODE_AP) + bss->ieee80211w = wpa_s->conf->pmf; + } #ifdef CONFIG_OCV bss->ocv = ssid->ocv; @@ -855,9 +897,10 @@ static void ap_wps_event_cb(void *ctx, enum wps_event event, static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr, - int authorized, const u8 *p2p_dev_addr) + int authorized, const u8 *p2p_dev_addr, + const u8 *ip) { - wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr); + wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr, ip); } @@ -926,12 +969,18 @@ 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 /* CONFIG_ACS */ + if (acs || (wpa_s->assoc_freq && wpa_s->ap_iface->freq && + (int) 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; + } + } wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); #ifdef CONFIG_P2P_CHR @@ -1044,10 +1093,12 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, return -1; hapd_iface->owner = wpa_s; hapd_iface->drv_flags = wpa_s->drv_flags; + hapd_iface->drv_flags2 = wpa_s->drv_flags2; hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads; hapd_iface->extended_capa = wpa_s->extended_capa; hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask; hapd_iface->extended_capa_len = wpa_s->extended_capa_len; + hapd_iface->drv_max_acl_mac_addrs = wpa_s->drv_max_acl_mac_addrs; wpa_s->ap_iface->conf = conf = hostapd_config_defaults(); if (conf == NULL) { @@ -1125,6 +1176,11 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, hapd_iface->bss[i]->ext_eapol_frame_io = wpa_s->ext_eapol_frame_io; #endif /* CONFIG_TESTING_OPTIONS */ + +#ifdef CONFIG_WNM_AP + if (ssid->mode == WPAS_MODE_AP) + hapd_iface->bss[i]->conf->bss_transition = 1; +#endif /* CONFIG_WNM_AP */ } os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN); @@ -1232,6 +1288,7 @@ void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt) struct wpa_supplicant *wpa_s = ctx; struct hostapd_frame_info fi; os_memset(&fi, 0, sizeof(fi)); + fi.freq = rx_mgmt->freq; fi.datarate = rx_mgmt->datarate; fi.ssi_signal = rx_mgmt->ssi_signal; ieee802_11_mgmt(wpa_s->ap_iface->bss[0], rx_mgmt->frame, @@ -1250,9 +1307,11 @@ void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok) void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s, - const u8 *src_addr, const u8 *buf, size_t len) + const u8 *src_addr, const u8 *buf, size_t len, + enum frame_encryption encrypted) { - ieee802_1x_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len); + ieee802_1x_receive(wpa_s->ap_iface->bss[0], src_addr, buf, len, + encrypted); } @@ -1586,6 +1645,183 @@ int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf, return pos - buf; } + +#ifdef CONFIG_WNM_AP + +int ap_ctrl_iface_disassoc_imminent(struct wpa_supplicant *wpa_s, + const char *buf) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + return hostapd_ctrl_iface_disassoc_imminent(hapd, buf); +} + + +int ap_ctrl_iface_ess_disassoc(struct wpa_supplicant *wpa_s, const char *buf) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + return hostapd_ctrl_iface_ess_disassoc(hapd, buf); +} + + +int ap_ctrl_iface_bss_tm_req(struct wpa_supplicant *wpa_s, const char *buf) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + return hostapd_ctrl_iface_bss_tm_req(hapd, buf); +} + +#endif /* CONFIG_WNM_AP */ + + +int ap_ctrl_iface_acl_add_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, + const char *buf) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + hapd->conf->macaddr_acl = acl_type; + + if (acl_type == ACCEPT_UNLESS_DENIED) + return hostapd_ctrl_iface_acl_add_mac(&hapd->conf->deny_mac, + &hapd->conf->num_deny_mac, + buf); + if (acl_type == DENY_UNLESS_ACCEPTED) + return hostapd_ctrl_iface_acl_add_mac( + &hapd->conf->accept_mac, + &hapd->conf->num_accept_mac, buf); + + return -1; +} + + +int ap_ctrl_iface_acl_del_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, + const char *buf) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + hapd->conf->macaddr_acl = acl_type; + + if (acl_type == ACCEPT_UNLESS_DENIED) + return hostapd_ctrl_iface_acl_del_mac(&hapd->conf->deny_mac, + &hapd->conf->num_deny_mac, + buf); + if (acl_type == DENY_UNLESS_ACCEPTED) + return hostapd_ctrl_iface_acl_del_mac( + &hapd->conf->accept_mac, &hapd->conf->num_accept_mac, + buf); + + return -1; +} + + +int ap_ctrl_iface_acl_show_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, char *buf, + size_t buflen) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + if (acl_type == ACCEPT_UNLESS_DENIED) + return hostapd_ctrl_iface_acl_show_mac(hapd->conf->deny_mac, + hapd->conf->num_deny_mac, + buf, buflen); + if (acl_type == DENY_UNLESS_ACCEPTED) + return hostapd_ctrl_iface_acl_show_mac( + hapd->conf->accept_mac, hapd->conf->num_accept_mac, + buf, buflen); + + return -1; +} + + +void ap_ctrl_iface_acl_clear_list(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return; + + hapd->conf->macaddr_acl = acl_type; + + if (acl_type == ACCEPT_UNLESS_DENIED) + hostapd_ctrl_iface_acl_clear_list(&hapd->conf->deny_mac, + &hapd->conf->num_deny_mac); + else if (acl_type == DENY_UNLESS_ACCEPTED) + hostapd_ctrl_iface_acl_clear_list(&hapd->conf->accept_mac, + &hapd->conf->num_accept_mac); +} + + +int ap_ctrl_iface_disassoc_deny_mac(struct wpa_supplicant *wpa_s) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + return hostapd_disassoc_deny_mac(hapd); +} + + +int ap_ctrl_iface_disassoc_accept_mac(struct wpa_supplicant *wpa_s) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + return hostapd_disassoc_accept_mac(hapd); +} + + +int ap_ctrl_iface_set_acl(struct wpa_supplicant *wpa_s) +{ + struct hostapd_data *hapd; + + if (wpa_s->ap_iface) + hapd = wpa_s->ap_iface->bss[0]; + else + return -1; + + return hostapd_set_acl(hapd); +} + #endif /* CONFIG_CTRL_IFACE */ @@ -1648,13 +1884,16 @@ int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *pos) if (ret) return ret; + settings.link_id = -1; + return ap_switch_channel(wpa_s, &settings); } #endif /* CONFIG_CTRL_IFACE */ void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, - int offset, int width, int cf1, int cf2, int finished) + int offset, int width, int cf1, int cf2, + u16 punct_bitmap, int finished) { struct hostapd_iface *iface = wpa_s->ap_iface; @@ -1666,7 +1905,8 @@ void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, if (wpa_s->current_ssid) wpa_s->current_ssid->frequency = freq; hostapd_event_ch_switch(iface->bss[0], freq, ht, - offset, width, cf1, cf2, finished); + offset, width, cf1, cf2, punct_bitmap, + finished); } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/ap.h b/wpa_supplicant-2.9_standard/wpa_supplicant/ap.h index 7bc1b781e3ac4f24e7f2af0703e56d3d403d7dc4..5835ecd876bea0b4d31a5ca5b63308788b4ad9f1 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/ap.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/ap.h @@ -10,11 +10,14 @@ #ifndef AP_H #define AP_H +enum macaddr_acl; + int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s); void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s, - const u8 *src_addr, const u8 *buf, size_t len); + const u8 *src_addr, const u8 *buf, size_t len, + enum frame_encryption encrypted); int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *p2p_dev_addr); int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid, @@ -38,6 +41,22 @@ int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s, const char *txtaddr); int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen, int verbose); +int ap_ctrl_iface_disassoc_imminent(struct wpa_supplicant *wpa_s, + const char *buf); +int ap_ctrl_iface_ess_disassoc(struct wpa_supplicant *wpa_s, const char *buf); +int ap_ctrl_iface_bss_tm_req(struct wpa_supplicant *wpa_s, const char *buf); +int ap_ctrl_iface_acl_add_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, const char *buf); +int ap_ctrl_iface_acl_del_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, const char *buf); +int ap_ctrl_iface_acl_show_mac(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type, char *buf, + size_t buflen); +void ap_ctrl_iface_acl_clear_list(struct wpa_supplicant *wpa_s, + enum macaddr_acl acl_type); +int ap_ctrl_iface_disassoc_deny_mac(struct wpa_supplicant *wpa_s); +int ap_ctrl_iface_disassoc_accept_mac(struct wpa_supplicant *wpa_s); +int ap_ctrl_iface_set_acl(struct wpa_supplicant *wpa_s); void ap_tx_status(void *ctx, const u8 *addr, const u8 *buf, size_t len, int ack); void ap_eapol_tx_status(void *ctx, const u8 *dst, @@ -54,7 +73,8 @@ int ap_switch_channel(struct wpa_supplicant *wpa_s, struct csa_settings *settings); int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr); void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht, - int offset, int width, int cf1, int cf2, int finished); + int offset, int width, int cf1, int cf2, + u16 punct_bitmap, int finished); struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s, int ndef); #ifdef CONFIG_AP diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan.h b/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan.h index 3df1550a97dda529cdcec209c1bb5bffd8d16408..4388b4e062452f6c41f01fcd97dad8c51ad4807d 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan.h @@ -51,7 +51,7 @@ extern const struct bgscan_ops bgscan_learn_ops; #else /* CONFIG_BGSCAN */ static inline int bgscan_init(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid, const char name) + struct wpa_ssid *ssid, const char *name) { return 0; } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan_learn.c b/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan_learn.c index 1ee286e71df5cfbdeedab5450c940c2cc6ce76f5..fe8681d41c181895b325269d463a20bbec905ab4 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan_learn.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan_learn.c @@ -57,7 +57,7 @@ static int bssid_in_array(u8 *array, size_t array_len, const u8 *bssid) return 0; for (i = 0; i < array_len; i++) { - if (os_memcmp(array + i * ETH_ALEN, bssid, ETH_ALEN) == 0) + if (ether_addr_equal(array + i * ETH_ALEN, bssid)) return 1; } @@ -70,7 +70,7 @@ static void bgscan_learn_add_neighbor(struct bgscan_learn_bss *bss, { u8 *n; - if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) + if (ether_addr_equal(bss->bssid, bssid)) return; if (bssid_in_array(bss->neigh, bss->num_neigh, bssid)) return; @@ -91,7 +91,7 @@ static struct bgscan_learn_bss * bgscan_learn_get_bss( struct bgscan_learn_bss *bss; dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) { - if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) + if (ether_addr_equal(bss->bssid, bssid)) return bss; } return NULL; @@ -305,7 +305,7 @@ static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx) } wpa_printf(MSG_DEBUG, "bgscan learn: Request a background scan"); - if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) { + if (wpa_supplicant_trigger_scan(wpa_s, ¶ms, true, false)) { wpa_printf(MSG_DEBUG, "bgscan learn: Failed to trigger scan"); eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout, data, NULL); @@ -422,7 +422,7 @@ static void * bgscan_learn_init(struct wpa_supplicant *wpa_s, /* Poll for signal info to set initial scan interval */ struct wpa_signal_info siginfo; if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 && - siginfo.current_signal >= data->signal_threshold) + siginfo.data.signal >= data->signal_threshold) data->scan_interval = data->long_interval; } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan_simple.c b/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan_simple.c index 41a26df0d63556a94e45f888b6cd19b86145fc5b..a90cf86e5eaca4f40c0c569941b69ed9fb95c256 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan_simple.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/bgscan_simple.c @@ -15,11 +15,16 @@ #include "wpa_supplicant_i.h" #include "driver_i.h" #include "scan.h" +#include "config.h" +#include "wnm_sta.h" +#include "bss.h" #include "bgscan.h" struct bgscan_simple_data { struct wpa_supplicant *wpa_s; const struct wpa_ssid *ssid; + unsigned int use_btm_query; + unsigned int scan_action_count; int scan_interval; int signal_threshold; int short_scan_count; /* counter for scans using short scan interval */ @@ -30,12 +35,54 @@ struct bgscan_simple_data { }; +static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx); + + +static bool bgscan_simple_btm_query(struct wpa_supplicant *wpa_s, + struct bgscan_simple_data *data) +{ + unsigned int mod; + + if (!data->use_btm_query || wpa_s->conf->disable_btm || + !wpa_s->current_bss || + !wpa_bss_ext_capab(wpa_s->current_bss, + WLAN_EXT_CAPAB_BSS_TRANSITION)) + return false; + + /* Try BTM x times, scan on x + 1 */ + data->scan_action_count++; + mod = data->scan_action_count % (data->use_btm_query + 1); + if (mod >= data->use_btm_query) + return false; + + wpa_printf(MSG_DEBUG, + "bgscan simple: Send BSS transition management query %d/%d", + mod, data->use_btm_query); + if (wnm_send_bss_transition_mgmt_query( + wpa_s, WNM_TRANSITION_REASON_BETTER_AP_FOUND, NULL, 0)) { + wpa_printf(MSG_DEBUG, + "bgscan simple: Failed to send BSS transition management query"); + /* Fall through and do regular scan */ + return false; + } + + /* Start a new timeout for the next one. We don't have scan callback to + * otherwise trigger future progress when using BTM path. */ + eloop_register_timeout(data->scan_interval, 0, + bgscan_simple_timeout, data, NULL); + return true; +} + + static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx) { struct bgscan_simple_data *data = eloop_ctx; struct wpa_supplicant *wpa_s = data->wpa_s; struct wpa_driver_scan_params params; + if (bgscan_simple_btm_query(wpa_s, data)) + goto scan_ok; + os_memset(¶ms, 0, sizeof(params)); params.num_ssids = 1; params.ssids[0].ssid = data->ssid->ssid; @@ -49,11 +96,12 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx) */ wpa_printf(MSG_DEBUG, "bgscan simple: Request a background scan"); - if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) { + if (wpa_supplicant_trigger_scan(wpa_s, ¶ms, true, false)) { wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan"); eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout, data, NULL); } else { + scan_ok: if (data->scan_interval == data->short_interval) { data->short_scan_count++; if (data->short_scan_count >= data->max_short_scans) { @@ -80,6 +128,8 @@ static int bgscan_simple_get_params(struct bgscan_simple_data *data, { const char *pos; + data->use_btm_query = 0; + data->short_interval = atoi(params); pos = os_strchr(params, ':'); @@ -95,6 +145,11 @@ static int bgscan_simple_get_params(struct bgscan_simple_data *data, } pos++; data->long_interval = atoi(pos); + pos = os_strchr(pos, ':'); + if (pos) { + pos++; + data->use_btm_query = atoi(pos); + } return 0; } @@ -134,10 +189,11 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s, data->scan_interval = data->short_interval; data->max_short_scans = data->long_interval / data->short_interval + 1; if (data->signal_threshold) { + wpa_s->signal_threshold = data->signal_threshold; /* Poll for signal info to set initial scan interval */ struct wpa_signal_info siginfo; if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 && - siginfo.current_signal >= data->signal_threshold) + siginfo.data.signal >= data->signal_threshold) data->scan_interval = data->long_interval; } wpa_printf(MSG_DEBUG, "bgscan simple: Init scan interval: %d", @@ -161,8 +217,10 @@ static void bgscan_simple_deinit(void *priv) { struct bgscan_simple_data *data = priv; eloop_cancel_timeout(bgscan_simple_timeout, data, NULL); - if (data->signal_threshold) + if (data->signal_threshold) { + data->wpa_s->signal_threshold = 0; wpa_drv_signal_monitor(data->wpa_s, 0, 0); + } os_free(data); } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/.clang-format b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/.clang-format index dbfdabfc07fd6168ed1f709993d9bffb347bdeb6..ed96c918c7ff8df0e6ae3861719fb34da1ff423d 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/.clang-format +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/.clang-format @@ -1,9 +1,9 @@ -BasedOnStyle: LLVM -IndentWidth: 8 -UseTab: Always -BreakBeforeBraces: Mozilla -AllowShortIfStatementsOnASingleLine: false -IndentCaseLabels: false -AccessModifierOffset: -8 -AlignAfterOpenBracket: AlwaysBreak -SortIncludes: false +BasedOnStyle: LLVM +IndentWidth: 8 +UseTab: Always +BreakBeforeBraces: Mozilla +AllowShortIfStatementsOnASingleLine: false +IndentCaseLabels: false +AccessModifierOffset: -8 +AlignAfterOpenBracket: AlwaysBreak +SortIncludes: false diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder.cpp index 750e87818b2083018e3d7422f80bd3678311ebd2..7eee3d806d9618049c57b420914a9d8510a61daa 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder.cpp @@ -1,104 +1,104 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include -#include -#include - -#include "binder_manager.h" - -extern "C" { -#include "binder.h" -#include "binder_i.h" -#include "utils/common.h" -#include "utils/eloop.h" -#include "utils/includes.h" -} - -void wpas_binder_sock_handler(int sock, void *eloop_ctx, void *sock_ctx) -{ - struct wpa_global *global = (wpa_global *)eloop_ctx; - struct wpas_binder_priv *priv = (wpas_binder_priv *)sock_ctx; - - wpa_printf( - MSG_DEBUG, "Processing binder events on FD %d", priv->binder_fd); - android::IPCThreadState::self()->handlePolledCommands(); -} - -struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global) -{ - struct wpas_binder_priv *priv; - wpa_supplicant_binder::BinderManager *binder_manager; - - priv = (wpas_binder_priv *)os_zalloc(sizeof(*priv)); - if (!priv) - return NULL; - priv->global = global; - - android::ProcessState::self()->setThreadPoolMaxThreadCount(0); - android::IPCThreadState::self()->disableBackgroundScheduling(true); - android::IPCThreadState::self()->setupPolling(&priv->binder_fd); - wpa_printf(MSG_INFO, "Process binder events on FD %d", priv->binder_fd); - if (priv->binder_fd < 0) - goto err; - /* Look for read events from the binder socket in the eloop. */ - if (eloop_register_read_sock( - priv->binder_fd, wpas_binder_sock_handler, global, priv) < 0) - goto err; - - binder_manager = wpa_supplicant_binder::BinderManager::getInstance(); - if (!binder_manager) - goto err; - binder_manager->registerBinderService(global); - /* We may not need to store this binder manager reference in the - * global data strucure because we've made it a singleton class. */ - priv->binder_manager = (void *)binder_manager; - - return priv; - -err: - wpas_binder_deinit(priv); - return NULL; -} - -void wpas_binder_deinit(struct wpas_binder_priv *priv) -{ - if (!priv) - return; - - wpa_supplicant_binder::BinderManager::destroyInstance(); - eloop_unregister_read_sock(priv->binder_fd); - android::IPCThreadState::shutdown(); -} - -int wpas_binder_register_interface(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s->global->binder) - return 1; - - wpa_supplicant_binder::BinderManager *binder_manager = - wpa_supplicant_binder::BinderManager::getInstance(); - if (!binder_manager) - return 1; - - return binder_manager->registerInterface(wpa_s); -} - -int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s->global->binder) - return 1; - - wpa_supplicant_binder::BinderManager *binder_manager = - wpa_supplicant_binder::BinderManager::getInstance(); - if (!binder_manager) - return 1; - - return binder_manager->unregisterInterface(wpa_s); -} +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include +#include + +#include "binder_manager.h" + +extern "C" { +#include "binder.h" +#include "binder_i.h" +#include "utils/common.h" +#include "utils/eloop.h" +#include "utils/includes.h" +} + +void wpas_binder_sock_handler(int sock, void *eloop_ctx, void *sock_ctx) +{ + struct wpa_global *global = (wpa_global *)eloop_ctx; + struct wpas_binder_priv *priv = (wpas_binder_priv *)sock_ctx; + + wpa_printf( + MSG_DEBUG, "Processing binder events on FD %d", priv->binder_fd); + android::IPCThreadState::self()->handlePolledCommands(); +} + +struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global) +{ + struct wpas_binder_priv *priv; + wpa_supplicant_binder::BinderManager *binder_manager; + + priv = (wpas_binder_priv *)os_zalloc(sizeof(*priv)); + if (!priv) + return NULL; + priv->global = global; + + android::ProcessState::self()->setThreadPoolMaxThreadCount(0); + android::IPCThreadState::self()->disableBackgroundScheduling(true); + android::IPCThreadState::self()->setupPolling(&priv->binder_fd); + wpa_printf(MSG_INFO, "Process binder events on FD %d", priv->binder_fd); + if (priv->binder_fd < 0) + goto err; + /* Look for read events from the binder socket in the eloop. */ + if (eloop_register_read_sock( + priv->binder_fd, wpas_binder_sock_handler, global, priv) < 0) + goto err; + + binder_manager = wpa_supplicant_binder::BinderManager::getInstance(); + if (!binder_manager) + goto err; + binder_manager->registerBinderService(global); + /* We may not need to store this binder manager reference in the + * global data strucure because we've made it a singleton class. */ + priv->binder_manager = (void *)binder_manager; + + return priv; + +err: + wpas_binder_deinit(priv); + return NULL; +} + +void wpas_binder_deinit(struct wpas_binder_priv *priv) +{ + if (!priv) + return; + + wpa_supplicant_binder::BinderManager::destroyInstance(); + eloop_unregister_read_sock(priv->binder_fd); + android::IPCThreadState::shutdown(); +} + +int wpas_binder_register_interface(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->global->binder) + return 1; + + wpa_supplicant_binder::BinderManager *binder_manager = + wpa_supplicant_binder::BinderManager::getInstance(); + if (!binder_manager) + return 1; + + return binder_manager->registerInterface(wpa_s); +} + +int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->global->binder) + return 1; + + wpa_supplicant_binder::BinderManager *binder_manager = + wpa_supplicant_binder::BinderManager::getInstance(); + if (!binder_manager) + return 1; + + return binder_manager->unregisterInterface(wpa_s); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder.h b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder.h index 6d7abb1348944dcc54f649611da42564703676db..7203bd130e413b9a72082abb7e043fb78b702353 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder.h @@ -1,46 +1,46 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_SUPPLICANT_BINDER_BINDER_H -#define WPA_SUPPLICANT_BINDER_BINDER_H - -#ifdef _cplusplus -extern "C" { -#endif /* _cplusplus */ - -/** - * This is the binder RPC interface entry point to the wpa_supplicant core. - * This initializes the binder driver & BinderManager instance and then forwards - * all the notifications from the supplicant core to the BinderManager. - */ -struct wpas_binder_priv; -struct wpa_global; - -struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global); -void wpas_binder_deinit(struct wpas_binder_priv *priv); - -#ifdef CONFIG_CTRL_IFACE_BINDER -int wpas_binder_register_interface(struct wpa_supplicant *wpa_s); -int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s); -#else /* CONFIG_CTRL_IFACE_BINDER */ -static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s) -{ - return 0; -} -static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s) -{ - return 0; -} -#endif /* CONFIG_CTRL_IFACE_BINDER */ - -#ifdef _cplusplus -} -#endif /* _cplusplus */ - -#endif /* WPA_SUPPLICANT_BINDER_BINDER_H */ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_BINDER_H +#define WPA_SUPPLICANT_BINDER_BINDER_H + +#ifdef _cplusplus +extern "C" { +#endif /* _cplusplus */ + +/** + * This is the binder RPC interface entry point to the wpa_supplicant core. + * This initializes the binder driver & BinderManager instance and then forwards + * all the notifications from the supplicant core to the BinderManager. + */ +struct wpas_binder_priv; +struct wpa_global; + +struct wpas_binder_priv *wpas_binder_init(struct wpa_global *global); +void wpas_binder_deinit(struct wpas_binder_priv *priv); + +#ifdef CONFIG_CTRL_IFACE_BINDER +int wpas_binder_register_interface(struct wpa_supplicant *wpa_s); +int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s); +#else /* CONFIG_CTRL_IFACE_BINDER */ +static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s) +{ + return 0; +} +static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s) +{ + return 0; +} +#endif /* CONFIG_CTRL_IFACE_BINDER */ + +#ifdef _cplusplus +} +#endif /* _cplusplus */ + +#endif /* WPA_SUPPLICANT_BINDER_BINDER_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_constants.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_constants.cpp index 0d452b11baecbf82c62f2041086ab00e363dc8b4..e3abcf598c2116fa713765cce1ae59a660f59b55 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_constants.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_constants.cpp @@ -1,18 +1,18 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "binder_constants.h" - -namespace wpa_supplicant_binder { -namespace binder_constants { - -const char kServiceName[] = "wpa_supplicant"; - -} /* namespace binder_constants */ -} /* namespace wpa_supplicant_binder */ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "binder_constants.h" + +namespace wpa_supplicant_binder { +namespace binder_constants { + +const char kServiceName[] = "wpa_supplicant"; + +} /* namespace binder_constants */ +} /* namespace wpa_supplicant_binder */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_constants.h b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_constants.h index a4d9b558edc04fe0133e9afcd9c0b12da1e26276..803f19b76df789afdd90b346a79840831ac8949e 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_constants.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_constants.h @@ -1,21 +1,21 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H -#define WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H - -namespace wpa_supplicant_binder { -namespace binder_constants { - -extern const char kServiceName[]; - -} /* namespace binder_constants */ -} /* namespace wpa_supplicant_binder */ - -#endif /* WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H */ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H +#define WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H + +namespace wpa_supplicant_binder { +namespace binder_constants { + +extern const char kServiceName[]; + +} /* namespace binder_constants */ +} /* namespace wpa_supplicant_binder */ + +#endif /* WPA_SUPPLICANT_BINDER_BINDER_CONSTANTS_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_i.h b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_i.h index 5140d6d6c01d1e3e74db843a2e4558282877e7a2..3d91815988bc9deef7f4bf92277c73039f184206 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_i.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_i.h @@ -1,28 +1,28 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef BINDER_I_H -#define BINDER_I_H - -#ifdef _cplusplus -extern "C" { -#endif // _cplusplus - -struct wpas_binder_priv -{ - int binder_fd; - struct wpa_global *global; - void *binder_manager; -}; - -#ifdef _cplusplus -} -#endif /* _cplusplus */ - -#endif /* BINDER_I_H */ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef BINDER_I_H +#define BINDER_I_H + +#ifdef _cplusplus +extern "C" { +#endif // _cplusplus + +struct wpas_binder_priv +{ + int binder_fd; + struct wpa_global *global; + void *binder_manager; +}; + +#ifdef _cplusplus +} +#endif /* _cplusplus */ + +#endif /* BINDER_I_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_manager.cpp index 27e8dedca44a1e9d3cf91cffda02fcb4b4599e02..bc29ab9bb2cfd6a62928f2452baf1001c10145b7 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_manager.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_manager.cpp @@ -1,100 +1,100 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include - -#include "binder_constants.h" -#include "binder_manager.h" - -extern "C" { -#include "utils/common.h" -#include "utils/includes.h" -} - -namespace wpa_supplicant_binder { - -BinderManager *BinderManager::instance_ = NULL; - -BinderManager *BinderManager::getInstance() -{ - if (!instance_) - instance_ = new BinderManager(); - return instance_; -} - -void BinderManager::destroyInstance() -{ - if (instance_) - delete instance_; - instance_ = NULL; -} - -int BinderManager::registerBinderService(struct wpa_global *global) -{ - /* Create the main binder service object and register with - * system service manager. */ - supplicant_object_ = new Supplicant(global); - android::String16 service_name(binder_constants::kServiceName); - android::defaultServiceManager()->addService( - service_name, android::IInterface::asBinder(supplicant_object_)); - return 0; -} - -int BinderManager::registerInterface(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s) - return 1; - - /* Using the corresponding wpa_supplicant pointer as key to our - * object map. */ - const void *iface_key = wpa_s; - - /* Return failure if we already have an object for that iface_key. */ - if (iface_object_map_.find(iface_key) != iface_object_map_.end()) - return 1; - - iface_object_map_[iface_key] = new Iface(wpa_s); - if (!iface_object_map_[iface_key].get()) - return 1; - - wpa_s->binder_object_key = iface_key; - - return 0; -} - -int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s || !wpa_s->binder_object_key) - return 1; - - const void *iface_key = wpa_s; - if (iface_object_map_.find(iface_key) == iface_object_map_.end()) - return 1; - - /* Delete the corresponding iface object from our map. */ - iface_object_map_.erase(iface_key); - wpa_s->binder_object_key = NULL; - return 0; -} - -int BinderManager::getIfaceBinderObjectByKey( - const void *iface_object_key, - android::sp *iface_object) -{ - if (!iface_object_key || !iface_object) - return 1; - - if (iface_object_map_.find(iface_object_key) == iface_object_map_.end()) - return 1; - - *iface_object = iface_object_map_[iface_object_key]; - return 0; -} - -} /* namespace wpa_supplicant_binder */ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include + +#include "binder_constants.h" +#include "binder_manager.h" + +extern "C" { +#include "utils/common.h" +#include "utils/includes.h" +} + +namespace wpa_supplicant_binder { + +BinderManager *BinderManager::instance_ = NULL; + +BinderManager *BinderManager::getInstance() +{ + if (!instance_) + instance_ = new BinderManager(); + return instance_; +} + +void BinderManager::destroyInstance() +{ + if (instance_) + delete instance_; + instance_ = NULL; +} + +int BinderManager::registerBinderService(struct wpa_global *global) +{ + /* Create the main binder service object and register with + * system service manager. */ + supplicant_object_ = new Supplicant(global); + android::String16 service_name(binder_constants::kServiceName); + android::defaultServiceManager()->addService( + service_name, android::IInterface::asBinder(supplicant_object_)); + return 0; +} + +int BinderManager::registerInterface(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s) + return 1; + + /* Using the corresponding wpa_supplicant pointer as key to our + * object map. */ + const void *iface_key = wpa_s; + + /* Return failure if we already have an object for that iface_key. */ + if (iface_object_map_.find(iface_key) != iface_object_map_.end()) + return 1; + + iface_object_map_[iface_key] = new Iface(wpa_s); + if (!iface_object_map_[iface_key].get()) + return 1; + + wpa_s->binder_object_key = iface_key; + + return 0; +} + +int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s || !wpa_s->binder_object_key) + return 1; + + const void *iface_key = wpa_s; + if (iface_object_map_.find(iface_key) == iface_object_map_.end()) + return 1; + + /* Delete the corresponding iface object from our map. */ + iface_object_map_.erase(iface_key); + wpa_s->binder_object_key = NULL; + return 0; +} + +int BinderManager::getIfaceBinderObjectByKey( + const void *iface_object_key, + android::sp *iface_object) +{ + if (!iface_object_key || !iface_object) + return 1; + + if (iface_object_map_.find(iface_object_key) == iface_object_map_.end()) + return 1; + + *iface_object = iface_object_map_[iface_object_key]; + return 0; +} + +} /* namespace wpa_supplicant_binder */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_manager.h index d8b7dd0f87263a7572a122d557358527f6274886..b79edc83527e88c810781757abc5ed6bbfa7399e 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_manager.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/binder_manager.h @@ -1,58 +1,58 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H -#define WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H - -#include -#include - -#include "iface.h" -#include "supplicant.h" - -struct wpa_global; -struct wpa_supplicant; - -namespace wpa_supplicant_binder { - -/** - * BinderManager is responsible for managing the lifetime of all - * binder objects created by wpa_supplicant. This is a singleton - * class which is created by the supplicant core and can be used - * to get references to the binder objects. - */ -class BinderManager -{ -public: - static BinderManager *getInstance(); - static void destroyInstance(); - int registerBinderService(struct wpa_global *global); - int registerInterface(struct wpa_supplicant *wpa_s); - int unregisterInterface(struct wpa_supplicant *wpa_s); - int getIfaceBinderObjectByKey( - const void *iface_object_key, - android::sp *iface_object); - -private: - BinderManager() = default; - ~BinderManager() = default; - - /* Singleton instance of this class. */ - static BinderManager *instance_; - /* The main binder service object. */ - android::sp supplicant_object_; - /* Map of all the interface specific binder objects controlled by - * wpa_supplicant. This map is keyed in by the corresponding - * wpa_supplicant structure pointer. */ - std::map> iface_object_map_; -}; - -} /* namespace wpa_supplicant_binder */ - -#endif /* WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H */ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H +#define WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H + +#include +#include + +#include "iface.h" +#include "supplicant.h" + +struct wpa_global; +struct wpa_supplicant; + +namespace wpa_supplicant_binder { + +/** + * BinderManager is responsible for managing the lifetime of all + * binder objects created by wpa_supplicant. This is a singleton + * class which is created by the supplicant core and can be used + * to get references to the binder objects. + */ +class BinderManager +{ +public: + static BinderManager *getInstance(); + static void destroyInstance(); + int registerBinderService(struct wpa_global *global); + int registerInterface(struct wpa_supplicant *wpa_s); + int unregisterInterface(struct wpa_supplicant *wpa_s); + int getIfaceBinderObjectByKey( + const void *iface_object_key, + android::sp *iface_object); + +private: + BinderManager() = default; + ~BinderManager() = default; + + /* Singleton instance of this class. */ + static BinderManager *instance_; + /* The main binder service object. */ + android::sp supplicant_object_; + /* Map of all the interface specific binder objects controlled by + * wpa_supplicant. This map is keyed in by the corresponding + * wpa_supplicant structure pointer. */ + std::map> iface_object_map_; +}; + +} /* namespace wpa_supplicant_binder */ + +#endif /* WPA_SUPPLICANT_BINDER_BINDER_MANAGER_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl index ea11d426df1ffffbabdb36cc5e1b6afb471ffc4b..da567c3fd0757b57df9e2b5bb2018062d6fc59d8 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl @@ -1,16 +1,16 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -package fi.w1.wpa_supplicant; - -/** - * Interface exposed by wpa_supplicant for each network interface it controls. - */ -interface IIface { -} +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +package fi.w1.wpa_supplicant; + +/** + * Interface exposed by wpa_supplicant for each network interface it controls. + */ +interface IIface { +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl index 1cbee20a620f300ee8448bab862629ec87d3a764..e9b07f0b1931dcdbc38963bbdd4392268e8ebd61 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl @@ -1,59 +1,59 @@ -/* - * WPA Supplicant - binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -package fi.w1.wpa_supplicant; - -import android.os.PersistableBundle; -import fi.w1.wpa_supplicant.IIface; - -/** - * Interface exposed by the wpa_supplicant binder service registered - * with the service manager with name: fi.w1.wpa_supplicant. - */ -interface ISupplicant { - /* Error values returned by the service to RPC method calls. */ - const int ERROR_INVALID_ARGS = 1; - const int ERROR_UNKNOWN = 2; - const int ERROR_IFACE_EXISTS = 3; - const int ERROR_IFACE_UNKNOWN = 4; - - /** - * Registers a wireless interface in wpa_supplicant. - * - * @param args A dictionary with arguments used to add the interface to - * wpa_supplicant. - * The dictionary may contain the following entries: - * Ifname(String) Name of the network interface to control, e.g., - * wlan0. - * BridgeIfname(String) Name of the bridge interface to control, e.g., - * br0. - * Driver(String) Driver name which the interface uses, e.g., nl80211. - * ConfigFile(String) Configuration file path. - * - * @return Binder object representing the interface. - */ - IIface CreateInterface(in PersistableBundle args); - - /** - * Deregisters a wireless interface from wpa_supplicant. - * - * @param ifname Name of the network interface, e.g., wlan0 - */ - void RemoveInterface(in @utf8InCpp String ifname); - - /** - * Gets a binder object for the interface corresponding to ifname - * which wpa_supplicant already controls. - * - * @param ifname Name of the network interface, e.g., wlan0 - * - * @return Binder object representing the interface. - */ - IIface GetInterface(in @utf8InCpp String ifname); -} +/* + * WPA Supplicant - binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +package fi.w1.wpa_supplicant; + +import android.os.PersistableBundle; +import fi.w1.wpa_supplicant.IIface; + +/** + * Interface exposed by the wpa_supplicant binder service registered + * with the service manager with name: fi.w1.wpa_supplicant. + */ +interface ISupplicant { + /* Error values returned by the service to RPC method calls. */ + const int ERROR_INVALID_ARGS = 1; + const int ERROR_UNKNOWN = 2; + const int ERROR_IFACE_EXISTS = 3; + const int ERROR_IFACE_UNKNOWN = 4; + + /** + * Registers a wireless interface in wpa_supplicant. + * + * @param args A dictionary with arguments used to add the interface to + * wpa_supplicant. + * The dictionary may contain the following entries: + * Ifname(String) Name of the network interface to control, e.g., + * wlan0. + * BridgeIfname(String) Name of the bridge interface to control, e.g., + * br0. + * Driver(String) Driver name which the interface uses, e.g., nl80211. + * ConfigFile(String) Configuration file path. + * + * @return Binder object representing the interface. + */ + IIface CreateInterface(in PersistableBundle args); + + /** + * Deregisters a wireless interface from wpa_supplicant. + * + * @param ifname Name of the network interface, e.g., wlan0 + */ + void RemoveInterface(in @utf8InCpp String ifname); + + /** + * Gets a binder object for the interface corresponding to ifname + * which wpa_supplicant already controls. + * + * @param ifname Name of the network interface, e.g., wlan0 + * + * @return Binder object representing the interface. + */ + IIface GetInterface(in @utf8InCpp String ifname); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl index d624d913360391709f1084adf3356185c73f5581..52ed2f511f34f1d5bab5fe472429578cb1da0278 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl @@ -1,20 +1,20 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -package fi.w1.wpa_supplicant; - -import android.os.PersistableBundle; - -/** - * Callback Interface exposed by the wpa_supplicant service. Clients need - * to host an instance of this binder object and pass a reference of the object - * to wpa_supplicant via the registerCallbacksObject method. - */ -interface ISupplicantCallbacks { -} +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +package fi.w1.wpa_supplicant; + +import android.os.PersistableBundle; + +/** + * Callback Interface exposed by the wpa_supplicant service. Clients need + * to host an instance of this binder object and pass a reference of the object + * to wpa_supplicant via the registerCallbacksObject method. + */ +interface ISupplicantCallbacks { +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/iface.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/iface.cpp index c61b3b00642756aa8b756e5c191f2f89fa912a66..d1b6e0780739f143a2f934c7a7dd13e8ae595cf7 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/iface.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/iface.cpp @@ -1,16 +1,16 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "iface.h" - -namespace wpa_supplicant_binder { - -Iface::Iface(struct wpa_supplicant *wpa_s) : wpa_s_(wpa_s) {} - -} /* namespace wpa_supplicant_binder */ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "iface.h" + +namespace wpa_supplicant_binder { + +Iface::Iface(struct wpa_supplicant *wpa_s) : wpa_s_(wpa_s) {} + +} /* namespace wpa_supplicant_binder */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/iface.h b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/iface.h index c0ee12c65fa5da23b156f177111952facf32b685..f6ef73ea0dfa76a313d86fab05580b2c7a43cf75 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/iface.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/iface.h @@ -1,42 +1,42 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_SUPPLICANT_BINDER_IFACE_H -#define WPA_SUPPLICANT_BINDER_IFACE_H - -#include "fi/w1/wpa_supplicant/BnIface.h" - -extern "C" { -#include "utils/common.h" -#include "utils/includes.h" -#include "../wpa_supplicant_i.h" -} - -namespace wpa_supplicant_binder { - -/** - * Implementation of Iface binder object. Each unique binder - * object is used for control operations on a specific interface - * controlled by wpa_supplicant. - */ -class Iface : public fi::w1::wpa_supplicant::BnIface -{ -public: - Iface(struct wpa_supplicant *wpa_s); - virtual ~Iface() = default; - -private: - /* Raw pointer to the structure maintained by the core for this - * interface. */ - struct wpa_supplicant *wpa_s_; -}; - -} /* namespace wpa_supplicant_binder */ - -#endif /* WPA_SUPPLICANT_BINDER_IFACE_H */ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_IFACE_H +#define WPA_SUPPLICANT_BINDER_IFACE_H + +#include "fi/w1/wpa_supplicant/BnIface.h" + +extern "C" { +#include "utils/common.h" +#include "utils/includes.h" +#include "../wpa_supplicant_i.h" +} + +namespace wpa_supplicant_binder { + +/** + * Implementation of Iface binder object. Each unique binder + * object is used for control operations on a specific interface + * controlled by wpa_supplicant. + */ +class Iface : public fi::w1::wpa_supplicant::BnIface +{ +public: + Iface(struct wpa_supplicant *wpa_s); + virtual ~Iface() = default; + +private: + /* Raw pointer to the structure maintained by the core for this + * interface. */ + struct wpa_supplicant *wpa_s_; +}; + +} /* namespace wpa_supplicant_binder */ + +#endif /* WPA_SUPPLICANT_BINDER_IFACE_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/supplicant.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/supplicant.cpp index 76569b1471fbb27872c75ec5638de93580db7de1..77c6b6a662bbcc1a2821d329ac03859c58f14b1c 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/supplicant.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/supplicant.cpp @@ -1,127 +1,127 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "supplicant.h" -#include "binder_manager.h" - -namespace wpa_supplicant_binder { - -Supplicant::Supplicant(struct wpa_global *global) : wpa_global_(global) {} - -android::binder::Status Supplicant::CreateInterface( - const android::os::PersistableBundle ¶ms, - android::sp *aidl_return) -{ - android::String16 driver, ifname, confname, bridge_ifname; - - /* Check if required Ifname argument is missing */ - if (!params.getString(android::String16("Ifname"), &ifname)) - return android::binder::Status::fromServiceSpecificError( - ERROR_INVALID_ARGS, - android::String8("Ifname missing in params.")); - /* Retrieve the remaining params from the dictionary */ - params.getString(android::String16("Driver"), &driver); - params.getString(android::String16("ConfigFile"), &confname); - params.getString(android::String16("BridgeIfname"), &bridge_ifname); - - /* - * Try to get the wpa_supplicant record for this iface, return - * an error if we already control it. - */ - if (wpa_supplicant_get_iface( - wpa_global_, android::String8(ifname).string()) != NULL) - return android::binder::Status::fromServiceSpecificError( - ERROR_IFACE_EXISTS, - android::String8("wpa_supplicant already controls this " - "interface.")); - - android::binder::Status status; - struct wpa_supplicant *wpa_s = NULL; - struct wpa_interface iface; - - os_memset(&iface, 0, sizeof(iface)); - iface.driver = os_strdup(android::String8(driver).string()); - iface.ifname = os_strdup(android::String8(ifname).string()); - iface.confname = os_strdup(android::String8(confname).string()); - iface.bridge_ifname = - os_strdup(android::String8(bridge_ifname).string()); - /* Otherwise, have wpa_supplicant attach to it. */ - wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL); - /* The supplicant core creates a corresponding binder object via - * BinderManager when |wpa_supplicant_add_iface| is called. */ - if (!wpa_s || !wpa_s->binder_object_key) { - status = android::binder::Status::fromServiceSpecificError( - ERROR_UNKNOWN, - android::String8( - "wpa_supplicant couldn't grab this interface.")); - } else { - BinderManager *binder_manager = BinderManager::getInstance(); - - if (!binder_manager || - binder_manager->getIfaceBinderObjectByKey( - wpa_s->binder_object_key, aidl_return)) - status = - android::binder::Status::fromServiceSpecificError( - ERROR_UNKNOWN, - android::String8("wpa_supplicant encountered a " - "binder error.")); - else - status = android::binder::Status::ok(); - } - os_free((void *)iface.driver); - os_free((void *)iface.ifname); - os_free((void *)iface.confname); - os_free((void *)iface.bridge_ifname); - return status; -} - -android::binder::Status Supplicant::RemoveInterface(const std::string &ifname) -{ - struct wpa_supplicant *wpa_s; - - wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str()); - if (!wpa_s || !wpa_s->binder_object_key) - return android::binder::Status::fromServiceSpecificError( - ERROR_IFACE_UNKNOWN, - android::String8("wpa_supplicant does not control this " - "interface.")); - if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0)) - return android::binder::Status::fromServiceSpecificError( - ERROR_UNKNOWN, - android::String8( - "wpa_supplicant couldn't remove this interface.")); - return android::binder::Status::ok(); -} - -android::binder::Status Supplicant::GetInterface( - const std::string &ifname, - android::sp *aidl_return) -{ - struct wpa_supplicant *wpa_s; - - wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str()); - if (!wpa_s || !wpa_s->binder_object_key) - return android::binder::Status::fromServiceSpecificError( - ERROR_IFACE_UNKNOWN, - android::String8( - "wpa_supplicant does not control this interface.")); - - BinderManager *binder_manager = BinderManager::getInstance(); - if (!binder_manager || - binder_manager->getIfaceBinderObjectByKey( - wpa_s->binder_object_key, aidl_return)) - return android::binder::Status::fromServiceSpecificError( - ERROR_UNKNOWN, - android::String8( - "wpa_supplicant encountered a binder error.")); - - return android::binder::Status::ok(); -} - -} /* namespace wpa_supplicant_binder */ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "supplicant.h" +#include "binder_manager.h" + +namespace wpa_supplicant_binder { + +Supplicant::Supplicant(struct wpa_global *global) : wpa_global_(global) {} + +android::binder::Status Supplicant::CreateInterface( + const android::os::PersistableBundle ¶ms, + android::sp *aidl_return) +{ + android::String16 driver, ifname, confname, bridge_ifname; + + /* Check if required Ifname argument is missing */ + if (!params.getString(android::String16("Ifname"), &ifname)) + return android::binder::Status::fromServiceSpecificError( + ERROR_INVALID_ARGS, + android::String8("Ifname missing in params.")); + /* Retrieve the remaining params from the dictionary */ + params.getString(android::String16("Driver"), &driver); + params.getString(android::String16("ConfigFile"), &confname); + params.getString(android::String16("BridgeIfname"), &bridge_ifname); + + /* + * Try to get the wpa_supplicant record for this iface, return + * an error if we already control it. + */ + if (wpa_supplicant_get_iface( + wpa_global_, android::String8(ifname).string()) != NULL) + return android::binder::Status::fromServiceSpecificError( + ERROR_IFACE_EXISTS, + android::String8("wpa_supplicant already controls this " + "interface.")); + + android::binder::Status status; + struct wpa_supplicant *wpa_s = NULL; + struct wpa_interface iface; + + os_memset(&iface, 0, sizeof(iface)); + iface.driver = os_strdup(android::String8(driver).string()); + iface.ifname = os_strdup(android::String8(ifname).string()); + iface.confname = os_strdup(android::String8(confname).string()); + iface.bridge_ifname = + os_strdup(android::String8(bridge_ifname).string()); + /* Otherwise, have wpa_supplicant attach to it. */ + wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL); + /* The supplicant core creates a corresponding binder object via + * BinderManager when |wpa_supplicant_add_iface| is called. */ + if (!wpa_s || !wpa_s->binder_object_key) { + status = android::binder::Status::fromServiceSpecificError( + ERROR_UNKNOWN, + android::String8( + "wpa_supplicant couldn't grab this interface.")); + } else { + BinderManager *binder_manager = BinderManager::getInstance(); + + if (!binder_manager || + binder_manager->getIfaceBinderObjectByKey( + wpa_s->binder_object_key, aidl_return)) + status = + android::binder::Status::fromServiceSpecificError( + ERROR_UNKNOWN, + android::String8("wpa_supplicant encountered a " + "binder error.")); + else + status = android::binder::Status::ok(); + } + os_free((void *)iface.driver); + os_free((void *)iface.ifname); + os_free((void *)iface.confname); + os_free((void *)iface.bridge_ifname); + return status; +} + +android::binder::Status Supplicant::RemoveInterface(const std::string &ifname) +{ + struct wpa_supplicant *wpa_s; + + wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str()); + if (!wpa_s || !wpa_s->binder_object_key) + return android::binder::Status::fromServiceSpecificError( + ERROR_IFACE_UNKNOWN, + android::String8("wpa_supplicant does not control this " + "interface.")); + if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0)) + return android::binder::Status::fromServiceSpecificError( + ERROR_UNKNOWN, + android::String8( + "wpa_supplicant couldn't remove this interface.")); + return android::binder::Status::ok(); +} + +android::binder::Status Supplicant::GetInterface( + const std::string &ifname, + android::sp *aidl_return) +{ + struct wpa_supplicant *wpa_s; + + wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str()); + if (!wpa_s || !wpa_s->binder_object_key) + return android::binder::Status::fromServiceSpecificError( + ERROR_IFACE_UNKNOWN, + android::String8( + "wpa_supplicant does not control this interface.")); + + BinderManager *binder_manager = BinderManager::getInstance(); + if (!binder_manager || + binder_manager->getIfaceBinderObjectByKey( + wpa_s->binder_object_key, aidl_return)) + return android::binder::Status::fromServiceSpecificError( + ERROR_UNKNOWN, + android::String8( + "wpa_supplicant encountered a binder error.")); + + return android::binder::Status::ok(); +} + +} /* namespace wpa_supplicant_binder */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/supplicant.h b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/supplicant.h index 136b99b1432749d08edd4fbe22852da74e8a3109..b7dece6753fbe89f012963976facb891ae4ee011 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/binder/supplicant.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/binder/supplicant.h @@ -1,55 +1,55 @@ -/* - * binder interface for wpa_supplicant daemon - * Copyright (c) 2004-2016, Jouni Malinen - * Copyright (c) 2004-2016, Roshan Pius - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPA_SUPPLICANT_BINDER_SUPPLICANT_H -#define WPA_SUPPLICANT_BINDER_SUPPLICANT_H - -#include "fi/w1/wpa_supplicant/BnSupplicant.h" -#include "fi/w1/wpa_supplicant/IIface.h" -#include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h" - -extern "C" { -#include "utils/common.h" -#include "utils/includes.h" -#include "../wpa_supplicant_i.h" -} - -namespace wpa_supplicant_binder { - -/** - * Implementation of the supplicant binder object. This binder - * object is used core for global control operations on - * wpa_supplicant. - */ -class Supplicant : public fi::w1::wpa_supplicant::BnSupplicant -{ -public: - Supplicant(struct wpa_global *global); - virtual ~Supplicant() = default; - - android::binder::Status CreateInterface( - const android::os::PersistableBundle ¶ms, - android::sp *aidl_return) override; - android::binder::Status - RemoveInterface(const std::string &ifname) override; - android::binder::Status GetInterface( - const std::string &ifname, - android::sp *aidl_return) override; - -private: - /* Raw pointer to the global structure maintained by the core. */ - struct wpa_global *wpa_global_; - /* All the callback objects registered by the clients. */ - std::vector> - callbacks_; -}; - -} /* namespace wpa_supplicant_binder */ - -#endif /* WPA_SUPPLICANT_BINDER_SUPPLICANT_H */ +/* + * binder interface for wpa_supplicant daemon + * Copyright (c) 2004-2016, Jouni Malinen + * Copyright (c) 2004-2016, Roshan Pius + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPA_SUPPLICANT_BINDER_SUPPLICANT_H +#define WPA_SUPPLICANT_BINDER_SUPPLICANT_H + +#include "fi/w1/wpa_supplicant/BnSupplicant.h" +#include "fi/w1/wpa_supplicant/IIface.h" +#include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h" + +extern "C" { +#include "utils/common.h" +#include "utils/includes.h" +#include "../wpa_supplicant_i.h" +} + +namespace wpa_supplicant_binder { + +/** + * Implementation of the supplicant binder object. This binder + * object is used core for global control operations on + * wpa_supplicant. + */ +class Supplicant : public fi::w1::wpa_supplicant::BnSupplicant +{ +public: + Supplicant(struct wpa_global *global); + virtual ~Supplicant() = default; + + android::binder::Status CreateInterface( + const android::os::PersistableBundle ¶ms, + android::sp *aidl_return) override; + android::binder::Status + RemoveInterface(const std::string &ifname) override; + android::binder::Status GetInterface( + const std::string &ifname, + android::sp *aidl_return) override; + +private: + /* Raw pointer to the global structure maintained by the core. */ + struct wpa_global *wpa_global_; + /* All the callback objects registered by the clients. */ + std::vector> + callbacks_; +}; + +} /* namespace wpa_supplicant_binder */ + +#endif /* WPA_SUPPLICANT_BINDER_SUPPLICANT_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/bss.c b/wpa_supplicant-2.9_standard/wpa_supplicant/bss.c index 46d370cb1e5dd94b790dc0402043f896b116071d..b9a0587e29ce60992daf740fb99cd4e421eaa6e0 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/bss.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/bss.c @@ -13,10 +13,12 @@ #include "common/ieee802_11_defs.h" #include "drivers/driver.h" #include "eap_peer/eap.h" +#include "rsn_supp/wpa.h" #include "wpa_supplicant_i.h" #include "config.h" #include "notify.h" #include "scan.h" +#include "bssid_ignore.h" #include "bss.h" static void wpa_bss_set_hessid(struct wpa_bss *bss) @@ -183,9 +185,8 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) } -static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s, - struct wpa_bss *old_bss, - struct wpa_bss *new_bss) +static struct wpa_connect_work * +wpa_bss_check_pending_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { struct wpa_radio_work *work; struct wpa_connect_work *cwork; @@ -194,12 +195,19 @@ static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s, if (!work) work = radio_work_pending(wpa_s, "connect"); if (!work) - return; + return NULL; cwork = work->ctx; - if (cwork->bss != old_bss) - return; + if (cwork->bss != bss) + return NULL; + + return cwork; +} + +static void wpa_bss_update_pending_connect(struct wpa_connect_work *cwork, + struct wpa_bss *new_bss) +{ wpa_printf(MSG_DEBUG, "Update BSS pointer for the pending connect radio work"); cwork->bss = new_bss; @@ -211,6 +219,8 @@ static void wpa_bss_update_pending_connect(struct wpa_supplicant *wpa_s, void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const char *reason) { + struct wpa_connect_work *cwork; + if (wpa_s->last_scan_res) { unsigned int i; for (i = 0; i < wpa_s->last_scan_res_used; i++) { @@ -224,7 +234,9 @@ void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } } } - wpa_bss_update_pending_connect(wpa_s, bss, NULL); + cwork = wpa_bss_check_pending_connect(wpa_s, bss); + if (cwork) + wpa_bss_update_pending_connect(cwork, NULL); dl_list_del(&bss->list); dl_list_del(&bss->list_id); wpa_s->num_bss--; @@ -243,7 +255,7 @@ void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, /** * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID * @wpa_s: Pointer to wpa_supplicant data - * @bssid: BSSID + * @bssid: BSSID, or %NULL to match any BSSID * @ssid: SSID * @ssid_len: Length of @ssid * Returns: Pointer to the BSS entry or %NULL if not found @@ -252,10 +264,11 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *ssid, size_t ssid_len) { struct wpa_bss *bss; - if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) + + if (bssid && !wpa_supplicant_filter_bssid_match(wpa_s, bssid)) return NULL; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { - if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && + if ((!bssid || ether_addr_equal(bss->bssid, bssid)) && bss->ssid_len == ssid_len && os_memcmp(bss->ssid, ssid, ssid_len) == 0) return bss; @@ -288,12 +301,14 @@ static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src, dst->flags = src->flags; os_memcpy(dst->bssid, src->bssid, ETH_ALEN); dst->freq = src->freq; + dst->max_cw = src->max_cw; dst->beacon_int = src->beacon_int; dst->caps = src->caps; dst->qual = src->qual; dst->noise = src->noise; dst->level = src->level; dst->tsf = src->tsf; + dst->beacon_newer = src->beacon_newer; dst->est_throughput = src->est_throughput; dst->snr = src->snr; @@ -348,12 +363,11 @@ static bool is_p2p_pending_bss(struct wpa_supplicant *wpa_s, #ifdef CONFIG_P2P u8 addr[ETH_ALEN]; - if (os_memcmp(bss->bssid, wpa_s->pending_join_iface_addr, - ETH_ALEN) == 0) + if (ether_addr_equal(bss->bssid, wpa_s->pending_join_iface_addr)) 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) + ether_addr_equal(addr, wpa_s->pending_join_dev_addr)) return true; #endif /* CONFIG_P2P */ return false; @@ -381,29 +395,38 @@ static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { -#ifdef CONFIG_MLD_PATCH int i; -#endif + if (bss == wpa_s->current_bss) return 1; + if (bss == wpa_s->ml_connect_probe_bss) + return 1; + +#ifdef CONFIG_WNM + if (bss == wpa_s->wnm_target_bss) + return 1; +#endif /* CONFIG_WNM */ + if (wpa_s->current_bss && (bss->ssid_len != wpa_s->current_bss->ssid_len || os_memcmp(bss->ssid, wpa_s->current_bss->ssid, bss->ssid_len) != 0)) return 0; /* SSID has changed */ + if (!is_zero_ether_addr(bss->bssid) && - (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 || - os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0)) - return 1; -#ifdef CONFIG_MLD_PATCH + (ether_addr_equal(bss->bssid, wpa_s->bssid) || + ether_addr_equal(bss->bssid, wpa_s->pending_bssid))) + return 1; + if (!wpa_s->valid_links) return 0; + for_each_link(wpa_s->valid_links, i) { - if (os_memcmp(bss->bssid, wpa_s->links[i].bssid, ETH_ALEN) == 0) + if (ether_addr_equal(bss->bssid, wpa_s->links[i].bssid)) return 1; } -#endif + return 0; } @@ -455,14 +478,15 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, struct os_reltime *fetch_time) { struct wpa_bss *bss; - char extra[50]; + char extra[100]; #ifdef CONFIG_WAPI const u8 *wapi_ie; #endif -#ifdef CONFIG_MLD_PATCH const u8 *ml_ie; + char *pos, *end; + int ret = 0; const u8 *mld_addr; -#endif + bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len); if (bss == NULL) return NULL; @@ -490,16 +514,15 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, bss->beacon_ie_len = res->beacon_ie_len; os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len); wpa_bss_set_hessid(bss); -#ifdef CONFIG_MLD_PATCH + os_memset(bss->mld_addr, 0, ETH_ALEN); ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC); if (ml_ie) { mld_addr = get_basic_mle_mld_addr(&ml_ie[3], ml_ie[1] - 1); - if (mld_addr) { + if (mld_addr) os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN); - } } -#endif + if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count && wpa_bss_remove_oldest(wpa_s) != 0) { wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d " @@ -511,11 +534,21 @@ static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, dl_list_add_tail(&wpa_s->bss, &bss->list); dl_list_add_tail(&wpa_s->bss_id, &bss->list_id); wpa_s->num_bss++; + + extra[0] = '\0'; + pos = extra; + end = pos + sizeof(extra); if (!is_zero_ether_addr(bss->hessid)) - os_snprintf(extra, sizeof(extra), " HESSID " MACSTR, - MAC2STR(bss->hessid)); - else - extra[0] = '\0'; + ret = os_snprintf(pos, end - pos, " HESSID " MACSTR, + MAC2STR(bss->hessid)); + + if (!is_zero_ether_addr(bss->mld_addr) && + !os_snprintf_error(end - pos, ret)) { + pos += ret; + ret = os_snprintf(pos, end - pos, " MLD ADDR " MACSTR, + MAC2STR(bss->mld_addr)); + } + wpa_msg_only_for_cb(wpa_s, MSG_EXCESSIVE, "BSS: Add new id %u BSSID " MACSTR " SSID '%s' freq %d%s", bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len), @@ -732,7 +765,8 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, dl_list_del(&bss->list); #ifdef CONFIG_P2P if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) && - !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE)) { + !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE) && + !(changes & WPA_BSS_FREQ_CHANGED_FLAG)) { /* * This can happen when non-P2P station interface runs a scan * without P2P IE in the Probe Request frame. P2P GO would reply @@ -757,20 +791,34 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } else { struct wpa_bss *nbss; struct dl_list *prev = bss->list_id.prev; + struct wpa_connect_work *cwork; + unsigned int i; + bool update_current_bss = wpa_s->current_bss == bss; + bool update_ml_probe_bss = wpa_s->ml_connect_probe_bss == bss; + + cwork = wpa_bss_check_pending_connect(wpa_s, bss); + + for (i = 0; i < wpa_s->last_scan_res_used; i++) { + if (wpa_s->last_scan_res[i] == bss) + break; + } + dl_list_del(&bss->list_id); nbss = os_realloc(bss, sizeof(*bss) + res->ie_len + res->beacon_ie_len); if (nbss) { - unsigned int i; - for (i = 0; i < wpa_s->last_scan_res_used; i++) { - if (wpa_s->last_scan_res[i] == bss) { - wpa_s->last_scan_res[i] = nbss; - break; - } - } - if (wpa_s->current_bss == bss) + if (i != wpa_s->last_scan_res_used) + wpa_s->last_scan_res[i] = nbss; + + if (update_current_bss) wpa_s->current_bss = nbss; - wpa_bss_update_pending_connect(wpa_s, bss, nbss); + + if (update_ml_probe_bss) + wpa_s->ml_connect_probe_bss = nbss; + + if (cwork) + wpa_bss_update_pending_connect(cwork, nbss); + bss = nbss; os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len); @@ -780,17 +828,17 @@ wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, dl_list_add(prev, &bss->list_id); } if (changes & WPA_BSS_IES_CHANGED_FLAG) { - wpa_bss_set_hessid(bss); -#ifdef CONFIG_MLD_PATCH const u8 *ml_ie, *mld_addr; + + wpa_bss_set_hessid(bss); os_memset(bss->mld_addr, 0, ETH_ALEN); ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC); if (ml_ie) { - mld_addr = get_basic_mle_mld_addr(&ml_ie[3], ml_ie[1] - 1); + mld_addr = get_basic_mle_mld_addr(&ml_ie[3], + ml_ie[1] - 1); if (mld_addr) os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN); } -#endif } dl_list_add_tail(&wpa_s->bss, &bss->list); @@ -837,7 +885,6 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MAGICLINK_PC int legacyGO = 0; #endif /* CONFIG_MAGICLINK_PC */ - if (wpa_s->conf->ignore_old_scan_res) { struct os_reltime update; calculate_update_time(fetch_time, res->age, &update); @@ -860,7 +907,6 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, MACSTR, MAC2STR(res->bssid)); wpa_printf(MSG_DEBUG, "BSS: No SSID IE included for " MACSTR_SEC, MAC2STR_SEC(res->bssid)); - return; } if (ssid[1] > SSID_MAX_LEN) { @@ -890,7 +936,7 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, * If it's a P2P specific interface, then don't update * the scan result without a P2P IE. */ - wpa_printf(MSG_EXCESSIVE, "BSS: No P2P IE - skipping BSS " MACSTR_SEC + wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR_SEC " update for P2P interface", MAC2STR_SEC(res->bssid)); return; #ifdef CONFIG_MAGICLINK_PC @@ -1041,12 +1087,24 @@ void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age) return; os_get_reltime(&t); + + if (t.sec < age) + return; /* avoid underflow; there can be no older entries */ + t.sec -= age; dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; + if (wpa_s->reassoc_same_ess && + wpa_s->wpa_state != WPA_COMPLETED && + wpa_s->last_ssid && + bss->ssid_len == wpa_s->last_ssid->ssid_len && + os_memcmp(bss->ssid, wpa_s->last_ssid->ssid, + bss->ssid_len) == 0) + continue; + if (os_reltime_before(&bss->last_update, &t)) { wpa_bss_remove(wpa_s, bss, __func__); } else @@ -1115,7 +1173,7 @@ struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s, if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) return NULL; dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { - if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) + if (ether_addr_equal(bss->bssid, bssid)) return bss; } return NULL; @@ -1140,7 +1198,7 @@ struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s, if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) return NULL; dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { - if (os_memcmp(bss->bssid, bssid, ETH_ALEN) != 0) + if (!ether_addr_equal(bss->bssid, bssid)) continue; if (found == NULL || os_reltime_before(&found->last_update, &bss->last_update)) @@ -1169,7 +1227,7 @@ struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s, u8 addr[ETH_ALEN]; if (p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len, addr) != 0 || - os_memcmp(addr, dev_addr, ETH_ALEN) != 0) + !ether_addr_equal(addr, dev_addr)) continue; if (!found || os_reltime_before(&found->last_update, &bss->last_update)) @@ -1235,6 +1293,31 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie) } +/** + * wpa_bss_get_ie_beacon - Fetch a specified information element from a BSS entry + * @bss: BSS table entry + * @ie: Information element identitifier (WLAN_EID_*) + * 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. + * + * This function is like wpa_bss_get_ie(), but uses IE buffer only from Beacon + * frames instead of either Beacon or Probe Response frames. + */ +const u8 * wpa_bss_get_ie_beacon(const struct wpa_bss *bss, u8 ie) +{ + const u8 *ies; + + if (bss->beacon_ie_len == 0) + return NULL; + + ies = wpa_bss_ie_ptr(bss); + ies += bss->ie_len; + return get_ie(ies, bss->beacon_ie_len, ie); +} + + /** * wpa_bss_get_ie_ext - Fetch a specified extended IE from a BSS entry * @bss: BSS table entry @@ -1385,12 +1468,16 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss, end = pos + bss->beacon_ie_len; while (end - pos > 1) { - if (2 + pos[1] > end - pos) + u8 id, len; + + id = *pos++; + len = *pos++; + if (len > end - pos) 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]; + if (id == 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) { @@ -1498,14 +1585,361 @@ int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab) capab); } -#ifdef CONFIG_MLD_PATCH -struct wpabuf * wpa_bss_defrag_mle(const struct wpa_bss *bss, u8 type) + +static void +wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, u8 mbssid_idx, + const struct ieee80211_neighbor_ap_info *ap_info, + size_t len, u16 *seen, u16 *missing, + struct wpa_ssid *ssid) +{ + const u8 *pos, *end; + const u8 *mld_params; + u8 count, mld_params_offset; + u8 i, type, link_id; + + count = RNR_TBTT_INFO_COUNT_VAL(ap_info->tbtt_info_hdr) + 1; + type = ap_info->tbtt_info_hdr & RNR_TBTT_INFO_HDR_TYPE_MSK; + + /* MLD information is at offset 13 or at start */ + if (type == 0 && ap_info->tbtt_info_len >= RNR_TBTT_INFO_MLD_LEN) { + /* MLD info is appended */ + mld_params_offset = RNR_TBTT_INFO_LEN; + } else { + /* TODO: Support NSTR AP */ + return; + } + + pos = (const u8 *) ap_info; + end = pos + len; + pos += sizeof(*ap_info); + + for (i = 0; i < count; i++) { + u8 bss_params; + + if (end - pos < ap_info->tbtt_info_len) + break; + + bss_params = pos[1 + ETH_ALEN + 4]; + mld_params = pos + mld_params_offset; + + link_id = *(mld_params + 1) & EHT_ML_LINK_ID_MSK; + if (link_id >= MAX_NUM_MLD_LINKS) + return; + + if (*mld_params != mbssid_idx) { + wpa_printf(MSG_DEBUG, + "MLD: Reported link not part of MLD"); + } else if (!(BIT(link_id) & *seen)) { + struct wpa_bss *neigh_bss; + + if (ssid && ssid->ssid_len) + neigh_bss = wpa_bss_get(wpa_s, pos + 1, + ssid->ssid, + ssid->ssid_len); + else + neigh_bss = wpa_bss_get_bssid(wpa_s, pos + 1); + + *seen |= BIT(link_id); + wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u", + *mld_params, link_id); + + if (!neigh_bss) { + *missing |= BIT(link_id); + } else if ((!ssid || + (bss_params & (RNR_BSS_PARAM_SAME_SSID | + RNR_BSS_PARAM_CO_LOCATED)) || + wpa_scan_res_match(wpa_s, 0, neigh_bss, + ssid, 1, 0)) && + !wpa_bssid_ignore_is_listed( + wpa_s, neigh_bss->bssid)) { + struct mld_link_ *l; + + bss->valid_links |= BIT(link_id); + l = &bss->mld_links[link_id]; + os_memcpy(l->bssid, pos + 1, ETH_ALEN); + l->freq = neigh_bss->freq; + l->disabled = mld_params[2] & + RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED; + } + } + + pos += ap_info->tbtt_info_len; + } +} + + +/** + * wpa_bss_parse_basic_ml_element - Parse the Basic Multi-Link element + * @wpa_s: Pointer to wpa_supplicant data + * @bss: BSS table entry + * @mld_addr: AP MLD address (or %NULL) + * @link_info: Array to store link information (or %NULL), + * should be initialized and #MAX_NUM_MLD_LINKS elements long + * @missing_links: Result bitmask of links that were not discovered (or %NULL) + * @ssid: Target SSID (or %NULL) + * @ap_mld_id: On return would hold the corresponding AP MLD ID (or %NULL) + * Returns: 0 on success or -1 for non-MLD or parsing failures + * + * Parses the Basic Multi-Link element of the BSS into @link_info using the scan + * information stored in the wpa_supplicant data to fill in information for + * links where possible. The @missing_links out parameter will contain any links + * for which no corresponding BSS was found. + */ +int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, + u8 *ap_mld_addr, + u16 *missing_links, + struct wpa_ssid *ssid, + u8 *ap_mld_id) { struct ieee802_11_elems elems; + struct wpabuf *mlbuf; + const struct element *elem; + u8 mbssid_idx = 0; + size_t ml_ie_len; + const struct ieee80211_eht_ml *eht_ml; + const struct eht_ml_basic_common_info *ml_basic_common_info; + u8 i, link_id; + const u16 control_mask = + MULTI_LINK_CONTROL_TYPE_MASK | + BASIC_MULTI_LINK_CTRL_PRES_LINK_ID | + BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT | + BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA; + const u16 control = + MULTI_LINK_CONTROL_TYPE_BASIC | + BASIC_MULTI_LINK_CTRL_PRES_LINK_ID | + BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT | + BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA; + u16 missing = 0; + u16 seen; + const u8 *ies_pos = wpa_bss_ie_ptr(bss); + size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; + int ret = -1; + struct mld_link_ *l; + + if (ieee802_11_parse_elems(ies_pos, ies_len, &elems, 1) == + ParseFailed) { + wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Failed to parse elements"); + return ret; + } + + mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true); + if (!mlbuf) { + wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No Multi-Link element"); + return ret; + } + + ml_ie_len = wpabuf_len(mlbuf); + + if (ssid) { + struct wpa_ie_data ie; + + if (!elems.rsn_ie || + wpa_parse_wpa_ie(elems.rsn_ie - 2, 2 + elems.rsn_ie_len, + &ie)) { + wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RSN element"); + goto out; + } + + if (!(ie.capabilities & WPA_CAPABILITY_MFPC) || + wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) { + wpa_dbg(wpa_s, MSG_DEBUG, + "MLD: No management frame protection"); + goto out; + } + + ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256); + if (!(ie.key_mgmt & ssid->key_mgmt)) { + wpa_dbg(wpa_s, MSG_DEBUG, + "MLD: No valid key management"); + goto out; + } + } + + /* + * for ext ID + 2 control + common info len + MLD address + + * link info + */ + if (ml_ie_len < 2UL + 1UL + ETH_ALEN + 1UL) + goto out; + + eht_ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf); + if ((le_to_host16(eht_ml->ml_control) & control_mask) != control) { + wpa_printf(MSG_DEBUG, + "MLD: Unexpected Multi-Link element control=0x%x (mask 0x%x expected 0x%x)", + le_to_host16(eht_ml->ml_control), control_mask, + control); + goto out; + } + + ml_basic_common_info = + (const struct eht_ml_basic_common_info *) eht_ml->variable; + + /* Common info length should be valid */ + if (ml_basic_common_info->len < ETH_ALEN + 1UL) + goto out; + + /* Get the MLD address and MLD link ID */ + if (ap_mld_addr) + os_memcpy(ap_mld_addr, ml_basic_common_info->mld_addr, + ETH_ALEN); + + link_id = ml_basic_common_info->variable[0] & EHT_ML_LINK_ID_MSK; + + bss->mld_link_id = link_id; + seen = bss->valid_links = BIT(link_id); + + l = &bss->mld_links[link_id]; + os_memcpy(l->bssid, bss->bssid, ETH_ALEN); + l->freq = bss->freq; + + + /* + * The AP MLD ID in the RNR corresponds to the MBSSID index, see + * IEEE P802.11be/D4.0, 9.4.2.169.2 (Neighbor AP Information field). + * + * For the transmitting BSSID it is clear that both the MBSSID index + * and the AP MLD ID in the RNR are zero. + * + * For nontransmitted BSSIDs we will have a BSS generated from the + * MBSSID element(s) using inheritance rules. Included in the elements + * is the MBSSID Index Element. The RNR is copied from the Beacon/Probe + * Response frame that was send by the transmitting BSSID. As such, the + * reported AP MLD ID in the RNR will match the value in the MBSSID + * Index Element. + */ + elem = (const struct element *) + wpa_bss_get_ie(bss, WLAN_EID_MULTIPLE_BSSID_INDEX); + if (elem && elem->datalen >= 1) + mbssid_idx = elem->data[0]; + + for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT, + wpa_bss_ie_ptr(bss), + bss->ie_len ? bss->ie_len : bss->beacon_ie_len) { + const struct ieee80211_neighbor_ap_info *ap_info; + const u8 *pos = elem->data; + size_t len = elem->datalen; + + /* RNR IE may contain more than one Neighbor AP Info */ + while (sizeof(*ap_info) <= len) { + size_t ap_info_len = sizeof(*ap_info); + u8 count; + + ap_info = (const struct ieee80211_neighbor_ap_info *) + pos; + count = RNR_TBTT_INFO_COUNT_VAL(ap_info->tbtt_info_hdr) + 1; + ap_info_len += count * ap_info->tbtt_info_len; + + if (ap_info_len > len) + goto out; + + wpa_bss_parse_ml_rnr_ap_info(wpa_s, bss, mbssid_idx, + ap_info, len, &seen, + &missing, ssid); + + pos += ap_info_len; + len -= ap_info_len; + } + } + + wpa_printf(MSG_DEBUG, "MLD: valid_links=%04hx (unresolved: 0x%04hx)", + bss->valid_links, missing); + + for_each_link(bss->valid_links, i) { + wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR, + i, MAC2STR(bss->mld_links[i].bssid)); + } + + if (missing_links) + *missing_links = missing; + + if (ap_mld_id) + *ap_mld_id = mbssid_idx; + + ret = 0; +out: + wpabuf_free(mlbuf); + return ret; +} + + +/* + * wpa_bss_parse_reconf_ml_element - Parse the Reconfiguration ML element + * @wpa_s: Pointer to wpa_supplicant data + * @bss: BSS table entry + * Returns: The bitmap of links that are going to be removed + */ +u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) +{ + struct ieee802_11_elems elems; + struct wpabuf *mlbuf; const u8 *pos = wpa_bss_ie_ptr(bss); - size_t len = bss->ie_len; + size_t len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; + const struct ieee80211_eht_ml *ml; + u16 removed_links = 0; + u8 ml_common_len; + if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed) - return NULL; - return ieee802_11_defrag_mle(&elems, type); + return 0; + + if (!elems.reconf_mle || !elems.reconf_mle_len) + return 0; + + mlbuf = ieee802_11_defrag(elems.reconf_mle, elems.reconf_mle_len, true); + if (!mlbuf) + return 0; + + ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf); + len = wpabuf_len(mlbuf); + + if (len < sizeof(*ml)) + goto out; + + ml_common_len = 1; + if (ml->ml_control & RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR) + ml_common_len += ETH_ALEN; + + if (len < sizeof(*ml) + ml_common_len) { + wpa_printf(MSG_DEBUG, + "MLD: Unexpected Reconfiguration ML element length: (%zu < %zu)", + len, sizeof(*ml) + ml_common_len); + goto out; + } + + pos = ml->variable + ml_common_len; + len -= sizeof(*ml) + ml_common_len; + + while (len >= 2 + sizeof(struct ieee80211_eht_per_sta_profile)) { + size_t sub_elem_len = *(pos + 1); + + if (2 + sub_elem_len > len) { + wpa_printf(MSG_DEBUG, + "MLD: Invalid link info len: %zu %zu", + 2 + sub_elem_len, len); + goto out; + } + + if (*pos == EHT_ML_SUB_ELEM_PER_STA_PROFILE) { + const struct ieee80211_eht_per_sta_profile *sta_prof = + (const struct ieee80211_eht_per_sta_profile *) + (pos + 2); + u16 control = le_to_host16(sta_prof->sta_control); + u8 link_id; + + link_id = control & EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK; + removed_links |= BIT(link_id); + } + + pos += 2 + sub_elem_len; + len -= 2 + sub_elem_len; + } + + wpa_printf(MSG_DEBUG, "MLD: Reconfiguration: removed_links=0x%x", + removed_links); +out: + wpabuf_free(mlbuf); + return removed_links; } -#endif diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/bss.h b/wpa_supplicant-2.9_standard/wpa_supplicant/bss.h index e93d60e2fb0047fbd24aaf59141bde3279c8e295..479d01294326d10dfaea6777df09e55227f58c1c 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/bss.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/bss.h @@ -96,6 +96,8 @@ struct wpa_bss { size_t ssid_len; /** Frequency of the channel in MHz (e.g., 2412 = channel 1) */ int freq; + /** The max channel width supported by both the AP and the STA */ + enum chan_width max_cw; /** Beacon interval in TUs (host byte order) */ u16 beacon_int; /** Capability information field in host byte order */ @@ -115,6 +117,8 @@ struct wpa_bss { #ifdef CONFIG_MAGICLINK_PC int legacyGO; #endif + /** Whether the Beacon frame data is known to be newer */ + bool beacon_newer; /** Time of the last update (i.e., Beacon or Probe Response RX) */ struct os_reltime last_update; /** Estimated throughput in kbps */ @@ -130,10 +134,22 @@ struct wpa_bss { #ifdef CONFIG_WAPI size_t wapi_ie_len; #endif -#ifdef CONFIG_MLD_PATCH /** MLD address of the AP */ u8 mld_addr[ETH_ALEN]; -#endif + /** Link ID of this affiliated AP of the AP MLD */ + u8 mld_link_id; + + /** An array of MLD links */ + u16 valid_links; + // add underscore to the end of the structure name to distinguish from wpa_auth_i.h + struct mld_link_ { + u8 bssid[ETH_ALEN]; + int freq; + + /* Whether the link is valid but currently disabled */ + bool disabled; + } mld_links[MAX_NUM_MLD_LINKS]; + /* followed by ie_len octets of IEs */ /* followed by beacon_ie_len octets of IEs */ u8 ies[]; @@ -170,6 +186,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_beacon(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, @@ -183,14 +200,12 @@ 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(const struct wpa_bss *bss); - #ifdef CONFIG_MAGICLINK struct wpa_bss * hw_magiclink_bss_add(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len, struct wpa_scan_res *res, struct os_reltime *fetch_time); #endif /* CONFIG_MAGICLINK */ - int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab); static inline int bss_is_dmg(const struct wpa_bss *bss) @@ -218,12 +233,17 @@ static inline void wpa_bss_update_level(struct wpa_bss *bss, int new_level) void calculate_update_time(const struct os_reltime *fetch_time, unsigned int age_ms, struct os_reltime *update_time); - #ifdef CONFIG_VENDOR_EXT struct wpa_bss * wpa_vendor_ext_wpa_bss_add(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len, struct wpa_scan_res *res, struct os_reltime *fetch_time); #endif -#ifdef CONFIG_MLD_PATCH -struct wpabuf * wpa_bss_defrag_mle(const struct wpa_bss *bss, u8 type); -#endif +int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, + u8 *ap_mld_addr, + u16 *missing_links, + struct wpa_ssid *ssid, + u8 *ap_mld_id); +u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss); + #endif /* BSS_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/bssid_ignore.c b/wpa_supplicant-2.9_standard/wpa_supplicant/bssid_ignore.c index 3d649404be5a0db9f817fff3c14ef2466e7804bf..853b65d100ac06ce31b734893a0576a0f85a0576 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/bssid_ignore.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/bssid_ignore.c @@ -37,7 +37,7 @@ struct wpa_bssid_ignore * wpa_bssid_ignore_get(struct wpa_supplicant *wpa_s, e = wpa_s->bssid_ignore; while (e) { - if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) + if (ether_addr_equal(e->bssid, bssid)) return e; e = e->next; } @@ -85,9 +85,9 @@ int wpa_bssid_ignore_add(struct wpa_supplicant *wpa_s, const u8 *bssid) e->timeout_secs = 60; else e->timeout_secs = 10; - wpa_printf(MSG_INFO, "BSSID " MACSTR_SEC - " ignore list count incremented to %d, ignoring for %d seconds", - MAC2STR_SEC(bssid), e->count, e->timeout_secs); + wpa_msg(wpa_s, MSG_INFO, "BSSID " MACSTR_SEC + " ignore list count incremented to %d, ignoring for %d seconds", + MAC2STR_SEC(bssid), e->count, e->timeout_secs); return e->count; } @@ -100,9 +100,9 @@ int wpa_bssid_ignore_add(struct wpa_supplicant *wpa_s, const u8 *bssid) e->start = now; e->next = wpa_s->bssid_ignore; wpa_s->bssid_ignore = e; - wpa_printf(MSG_INFO, "Added BSSID " MACSTR_SEC - " into ignore list, ignoring for %d seconds", - MAC2STR_SEC(bssid), e->timeout_secs); + wpa_msg(wpa_s, MSG_INFO, "Added BSSID " MACSTR_SEC + " into ignore list, ignoring for %d seconds", + MAC2STR_SEC(bssid), e->timeout_secs); return e->count; } @@ -123,14 +123,14 @@ int wpa_bssid_ignore_del(struct wpa_supplicant *wpa_s, const u8 *bssid) e = wpa_s->bssid_ignore; while (e) { - if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) { + if (ether_addr_equal(e->bssid, bssid)) { if (prev == NULL) { wpa_s->bssid_ignore = e->next; } else { prev->next = e->next; } - wpa_printf(MSG_INFO, "Removed BSSID " MACSTR_SEC - " from ignore list", MAC2STR_SEC(bssid)); + wpa_msg(wpa_s, MSG_INFO, "Removed BSSID " MACSTR_SEC + " from ignore list", MAC2STR_SEC(bssid)); os_free(e); return 0; } @@ -175,8 +175,8 @@ void wpa_bssid_ignore_clear(struct wpa_supplicant *wpa_s) while (e) { prev = e; e = e->next; - wpa_printf(MSG_INFO, "Removed BSSID " MACSTR_SEC - " from ignore list (clear)", MAC2STR_SEC(prev->bssid)); + wpa_msg(wpa_s, MSG_INFO, "Removed BSSID " MACSTR_SEC + " from ignore list (clear)", MAC2STR_SEC(prev->bssid)); os_free(prev); } } @@ -209,9 +209,9 @@ void wpa_bssid_ignore_update(struct wpa_supplicant *wpa_s) wpa_s->bssid_ignore = e->next; e = wpa_s->bssid_ignore; } - wpa_printf(MSG_INFO, "Removed BSSID " MACSTR_SEC - " from ignore list (expired)", - MAC2STR_SEC(to_delete->bssid)); + wpa_msg(wpa_s, MSG_INFO, "Removed BSSID " MACSTR_SEC + " from ignore list (expired)", + MAC2STR_SEC(to_delete->bssid)); os_free(to_delete); } else { prev = e; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/config.c b/wpa_supplicant-2.9_standard/wpa_supplicant/config.c index 5a1ed887134033b00b7427a0a7c5910c250c5b77..bcf2915d0dfab94ce9a701bc81afb029ca27754e 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/config.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/config.c @@ -197,9 +197,10 @@ static char * wpa_config_write_str(const struct parse_data *data, #endif /* NO_CONFIG_WRITE */ -static int wpa_config_parse_int(const struct parse_data *data, - struct wpa_ssid *ssid, - int line, const char *value) +static int wpa_config_parse_int_impl(const struct parse_data *data, + struct wpa_ssid *ssid, + int line, const char *value, + bool check_range) { int val, *dst; char *end; @@ -212,31 +213,46 @@ static int wpa_config_parse_int(const struct parse_data *data, return -1; } - if (*dst == val) - return 1; - *dst = val; - wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst); - - if (data->param3 && *dst < (long) data->param3) { + if (check_range && val < (long) data->param3) { wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " - "min_value=%ld)", line, data->name, *dst, + "min_value=%ld)", line, data->name, val, (long) data->param3); - *dst = (long) data->param3; return -1; } - if (data->param4 && *dst > (long) data->param4) { + if (check_range && val > (long) data->param4) { wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " - "max_value=%ld)", line, data->name, *dst, + "max_value=%ld)", line, data->name, val, (long) data->param4); - *dst = (long) data->param4; return -1; } + if (*dst == val) + return 1; + + *dst = val; + wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst); + return 0; } +static int wpa_config_parse_int(const struct parse_data *data, + struct wpa_ssid *ssid, + int line, const char *value) +{ + return wpa_config_parse_int_impl(data, ssid, line, value, false); +} + + +static int wpa_config_parse_int_range(const struct parse_data *data, + struct wpa_ssid *ssid, + int line, const char *value) +{ + return wpa_config_parse_int_impl(data, ssid, line, value, true); +} + + #ifndef NO_CONFIG_WRITE static char * wpa_config_write_int(const struct parse_data *data, struct wpa_ssid *ssid) @@ -466,7 +482,6 @@ static int wpa_config_parse_bssid_blacklist(const struct parse_data *data, "bssid_ignore", 1, 1); } - #ifdef CONFIG_WAPI static int wpa_config_parse_wapi_psk(const struct parse_data *data, struct wpa_ssid *ssid, int line, @@ -794,7 +809,6 @@ static char * wpa_config_write_proto(const struct parse_data *data, pos += ret; } #endif - if (ssid->proto & WPA_PROTO_OSEN) { ret = os_snprintf(pos, end - pos, "%sOSEN", pos == buf ? "" : " "); @@ -861,6 +875,10 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384; #endif /* CONFIG_SHA384 */ #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_SHA384 + else if (os_strcmp(start, "WPA-EAP-SHA384") == 0) + val |= WPA_KEY_MGMT_IEEE8021X_SHA384; +#endif /* CONFIG_SHA384 */ else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) val |= WPA_KEY_MGMT_PSK_SHA256; else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) @@ -876,6 +894,8 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, val |= WPA_KEY_MGMT_SAE_EXT_KEY; else if (os_strcmp(start, "FT-SAE") == 0) val |= WPA_KEY_MGMT_FT_SAE; + else if (os_strcmp(start, "FT-SAE-EXT-KEY") == 0) + val |= WPA_KEY_MGMT_FT_SAE_EXT_KEY; #endif /* CONFIG_SAE */ #ifdef CONFIG_HS20 else if (os_strcmp(start, "OSEN") == 0) @@ -1004,7 +1024,6 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, } pos += ret; } - #ifdef CONFIG_WAPI if (ssid->key_mgmt & WPA_KEY_MGMT_WAPI_CERT) { ret = os_snprintf(pos, end - pos, "%sWAPI-CERT", @@ -1026,7 +1045,6 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, pos += ret; } #endif - #ifdef CONFIG_IEEE80211R if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) { ret = os_snprintf(pos, end - pos, "%sFT-PSK", @@ -1061,6 +1079,18 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, #endif /* CONFIG_SHA384 */ #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_SHA384 + if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) { + ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA384", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } +#endif /* CONFIG_SHA384 */ + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256", pos == buf ? "" : " "); @@ -1123,6 +1153,16 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, } pos += ret; } + + if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) { + ret = os_snprintf(pos, end - pos, "%sFT-SAE-EXT-KEY", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } #endif /* CONFIG_SAE */ #ifdef CONFIG_HS20 @@ -2439,6 +2479,50 @@ static char * wpa_config_write_peerkey(const struct parse_data *data, #endif /* NO_CONFIG_WRITE */ +static int wpa_config_parse_mac_value(const struct parse_data *data, + struct wpa_ssid *ssid, int line, + const char *value) +{ + u8 mac_value[ETH_ALEN]; + + if (hwaddr_aton(value, mac_value) == 0) { + if (ether_addr_equal(mac_value, ssid->mac_value)) + return 1; + os_memcpy(ssid->mac_value, mac_value, ETH_ALEN); + return 0; + } + + wpa_printf(MSG_ERROR, "Line %d: Invalid MAC address '%s'", + line, value); + return -1; +} + + +#ifndef NO_CONFIG_WRITE +static char * wpa_config_write_mac_value(const struct parse_data *data, + struct wpa_ssid *ssid) +{ + const size_t size = 3 * ETH_ALEN; + char *value; + int res; + + if (ssid->mac_addr != WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS) + return NULL; + + value = os_malloc(size); + if (!value) + return NULL; + res = os_snprintf(value, size, MACSTR, MAC2STR(ssid->mac_value)); + if (os_snprintf_error(size, res)) { + os_free(value); + return NULL; + } + value[size - 1] = '\0'; + return value; +} +#endif /* NO_CONFIG_WRITE */ + + /* Helper macros for network block parser */ #ifdef OFFSET @@ -2491,7 +2575,14 @@ static char * wpa_config_write_peerkey(const struct parse_data *data, #define INTe(f, m) _INTe(f, m), NULL, NULL, 0 /* INT_RANGE: Define an integer variable with allowed value range */ -#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0 +#ifdef NO_CONFIG_WRITE +#define INT_RANGE(f, min, max) #f, wpa_config_parse_int_range, OFFSET(f), \ + (void *) 0, (void *) (min), (void *) (max), 0 +#else /* NO_CONFIG_WRITE */ +#define INT_RANGE(f, min, max) #f, wpa_config_parse_int_range, \ + wpa_config_write_int, OFFSET(f), \ + (void *) 0, (void *) (min), (void *) (max), 0 +#endif /* NO_CONFIG_WRITE */ /* FUNC: Define a configuration variable that uses a custom function for * parsing and writing the value. */ @@ -2559,9 +2650,10 @@ static const struct parse_data ssid_fields[] = { #endif { INT_RANGE(ht, 0, 1) }, { INT_RANGE(vht, 0, 1) }, + { INT_RANGE(he, 0, 1) }, { INT_RANGE(ht40, -1, 1) }, - { INT_RANGE(max_oper_chwidth, CHANWIDTH_USE_HT, - CHANWIDTH_80P80MHZ) }, + { INT_RANGE(max_oper_chwidth, CONF_OPER_CHWIDTH_USE_HT, + CONF_OPER_CHWIDTH_80P80MHZ) }, { INT(vht_center_freq1) }, { INT(vht_center_freq2) }, #ifdef IEEE8021X_EAPOL @@ -2585,7 +2677,6 @@ static const struct parse_data ssid_fields[] = { { STRe(client_cert, cert.client_cert) }, { STRe(private_key, cert.private_key) }, { STR_KEYe(private_key_passwd, cert.private_key_passwd) }, - { STRe(dh_file, cert.dh_file) }, { STRe(subject_match, cert.subject_match) }, { STRe(check_cert_subject, cert.check_cert_subject) }, { STRe(altsubject_match, cert.altsubject_match) }, @@ -2596,7 +2687,6 @@ static const struct parse_data ssid_fields[] = { { STRe(client_cert2, phase2_cert.client_cert) }, { STRe(private_key2, phase2_cert.private_key) }, { STR_KEYe(private_key2_passwd, phase2_cert.private_key_passwd) }, - { STRe(dh_file2, phase2_cert.dh_file) }, { STRe(subject_match2, phase2_cert.subject_match) }, { STRe(check_cert_subject2, phase2_cert.check_cert_subject) }, { STRe(altsubject_match2, phase2_cert.altsubject_match) }, @@ -2624,7 +2714,6 @@ static const struct parse_data ssid_fields[] = { { STRe(machine_private_key, machine_cert.private_key) }, { STR_KEYe(machine_private_key_passwd, machine_cert.private_key_passwd) }, - { STRe(machine_dh_file, machine_cert.dh_file) }, { STRe(machine_subject_match, machine_cert.subject_match) }, { STRe(machine_check_cert_subject, machine_cert.check_cert_subject) }, { STRe(machine_altsubject_match, machine_cert.altsubject_match) }, @@ -2640,6 +2729,8 @@ static const struct parse_data ssid_fields[] = { { INTe(machine_ocsp, machine_cert.ocsp) }, { INT(eapol_flags) }, { INTe(sim_num, sim_num) }, + { STRe(imsi_privacy_cert, imsi_privacy_cert) }, + { STRe(imsi_privacy_attr, imsi_privacy_attr) }, { STRe(openssl_ciphers, openssl_ciphers) }, { INTe(erp, erp) }, #endif /* IEEE8021X_EAPOL */ @@ -2701,7 +2792,7 @@ static const struct parse_data ssid_fields[] = { #endif /* CONFIG_P2P */ #ifdef CONFIG_HT_OVERRIDES { INT_RANGE(disable_ht, 0, 1) }, - { INT_RANGE(disable_ht40, -1, 1) }, + { INT_RANGE(disable_ht40, 0, 1) }, { INT_RANGE(disable_sgi, 0, 1) }, { INT_RANGE(disable_ldpc, 0, 1) }, { INT_RANGE(ht40_intolerant, 0, 1) }, @@ -2744,8 +2835,10 @@ static const struct parse_data ssid_fields[] = { { INT_RANGE(macsec_integ_only, 0, 1) }, { INT_RANGE(macsec_replay_protect, 0, 1) }, { INT(macsec_replay_window) }, + { INT_RANGE(macsec_offload, 0, 2) }, { INT_RANGE(macsec_port, 1, 65534) }, { INT_RANGE(mka_priority, 0, 255) }, + { INT_RANGE(macsec_csindex, 0, 1) }, { FUNC_KEY(mka_cak) }, { FUNC_KEY(mka_ckn) }, #endif /* CONFIG_MACSEC */ @@ -2753,7 +2846,8 @@ static const struct parse_data ssid_fields[] = { { INT(update_identifier) }, { STR_RANGE(roaming_consortium_selection, 0, MAX_ROAMING_CONS_OI_LEN) }, #endif /* CONFIG_HS20 */ - { INT_RANGE(mac_addr, 0, 2) }, + { INT_RANGE(mac_addr, 0, 3) }, + { FUNC_KEY(mac_value) }, { INT_RANGE(pbss, 0, 2) }, { INT_RANGE(wps_disabled, 0, 1) }, { INT_RANGE(fils_dh_group, 0, 65535) }, @@ -2764,15 +2858,22 @@ static const struct parse_data ssid_fields[] = { { STR_LEN(dpp_csign) }, { STR_LEN(dpp_pp_key) }, { INT_RANGE(dpp_pfs, 0, 2) }, + { INT_RANGE(dpp_connector_privacy, 0, 1) }, #endif /* CONFIG_DPP */ { INT_RANGE(owe_group, 0, 65535) }, { INT_RANGE(owe_only, 0, 1) }, { INT_RANGE(owe_ptk_workaround, 0, 1) }, { INT_RANGE(multi_ap_backhaul_sta, 0, 1) }, { INT_RANGE(ft_eap_pmksa_caching, 0, 1) }, + { INT_RANGE(multi_ap_profile, MULTI_AP_PROFILE_1, + MULTI_AP_PROFILE_MAX) }, { INT_RANGE(beacon_prot, 0, 1) }, { INT_RANGE(transition_disable, 0, 255) }, { INT_RANGE(sae_pk, 0, 2) }, + { INT_RANGE(disable_eht, 0, 1)}, + { INT_RANGE(enable_4addr_mode, 0, 1)}, + { INT_RANGE(max_idle, 0, 65535)}, + { INT_RANGE(ssid_protection, 0, 1)}, }; #undef OFFSET @@ -2887,7 +2988,6 @@ static void eap_peer_config_free_cert(struct eap_peer_cert_config *cert) os_free(cert->client_cert); os_free(cert->private_key); str_clear_free(cert->private_key_passwd); - os_free(cert->dh_file); os_free(cert->subject_match); os_free(cert->check_cert_subject); os_free(cert->altsubject_match); @@ -2907,6 +3007,8 @@ static void eap_peer_config_free(struct eap_peer_config *eap) bin_clear_free(eap->identity, eap->identity_len); os_free(eap->anonymous_identity); os_free(eap->imsi_identity); + os_free(eap->imsi_privacy_cert); + os_free(eap->imsi_privacy_attr); os_free(eap->machine_identity); bin_clear_free(eap->password, eap->password_len); bin_clear_free(eap->machine_password, eap->machine_password_len); @@ -3015,6 +3117,8 @@ void wpa_config_free_cred(struct wpa_cred *cred) os_free(cred->req_conn_capab_port[i]); os_free(cred->req_conn_capab_port); os_free(cred->req_conn_capab_proto); + os_free(cred->imsi_privacy_cert); + os_free(cred->imsi_privacy_attr); os_free(cred); } @@ -3112,6 +3216,8 @@ void wpa_config_free(struct wpa_config *config) #endif /* CONFIG_MBO */ os_free(config->dpp_name); os_free(config->dpp_mud_url); + os_free(config->dpp_extra_conf_req_name); + os_free(config->dpp_extra_conf_req_value); os_free(config); } @@ -3300,10 +3406,30 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) #ifdef CONFIG_MACSEC ssid->mka_priority = DEFAULT_PRIO_NOT_KEY_SERVER; #endif /* CONFIG_MACSEC */ - ssid->mac_addr = -1; + ssid->mac_addr = WPAS_MAC_ADDR_STYLE_NOT_SET; ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH; } + +static const char *removed_fields[] = { + "dh_file", + "dh_file2", + "machine_dh_file", + NULL +}; + +static bool removed_field(const char *field) +{ + int i; + + for (i = 0; removed_fields[i]; i++) { + if (os_strcmp(field, removed_fields[i]) == 0) + return true; + } + + return false; +} + #ifdef CONFIG_EAP_AUTH static int wpa_config_eap_params(char *name) { @@ -3345,6 +3471,7 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, const struct parse_data *field = &ssid_fields[i]; if (os_strcmp(var, field->name) != 0) continue; + #ifdef CONFIG_EAP_AUTH if (wpa_config_eap_params(field->name)) { ret = 0; @@ -3354,7 +3481,6 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, #ifdef CONFIG_EAP_AUTH } #endif - if (ret < 0) { if (line) { wpa_printf(MSG_ERROR, "Line %d: failed to " @@ -3374,6 +3500,12 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, break; } if (i == NUM_SSID_FIELDS) { + if (removed_field(var)) { + wpa_printf(MSG_INFO, + "Line %d: Ignore removed configuration field '%s'", + line, var); + return ret; + } if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown network field " "'%s'.", line, var); @@ -3571,8 +3703,11 @@ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) void wpa_config_update_psk(struct wpa_ssid *ssid) { #ifndef CONFIG_NO_PBKDF2 - pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096, - ssid->psk, PMK_LEN); + if (pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096, + ssid->psk, PMK_LEN) != 0) { + wpa_printf(MSG_ERROR, "Error in pbkdf2_sha1()"); + return; + } wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", ssid->psk, PMK_LEN); ssid->psk_set = 1; @@ -3643,53 +3778,62 @@ static int wpa_config_set_cred_req_conn_capab(struct wpa_cred *cred, } -static int wpa_config_set_cred_roaming_consortiums(struct wpa_cred *cred, - const char *value) -{ - u8 roaming_consortiums[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; - size_t roaming_consortiums_len[MAX_ROAMING_CONS]; - unsigned int num_roaming_consortiums = 0; +static int +wpa_config_set_cred_ois(u8 cred_ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN], + size_t cred_ois_len[MAX_ROAMING_CONS], + unsigned int *cred_num_ois, + const char *value) +{ + u8 ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; + size_t ois_len[MAX_ROAMING_CONS]; + unsigned int num_ois = 0; const char *pos, *end; size_t len; - os_memset(roaming_consortiums, 0, sizeof(roaming_consortiums)); - os_memset(roaming_consortiums_len, 0, sizeof(roaming_consortiums_len)); + len = os_strlen(value); + if (len / 2 < 3) { + wpa_printf(MSG_ERROR, + "Invalid organisation identifier (OI) list: %s", + value); + return -1; + } + + os_memset(ois, 0, sizeof(ois)); + os_memset(ois_len, 0, sizeof(ois_len)); for (pos = value;;) { end = os_strchr(pos, ','); len = end ? (size_t) (end - pos) : os_strlen(pos); if (!end && len == 0) break; - if (len == 0 || (len & 1) != 0 || + if (len / 2 < 3 || (len & 1) != 0 || len / 2 > MAX_ROAMING_CONS_OI_LEN || hexstr2bin(pos, - roaming_consortiums[num_roaming_consortiums], + ois[num_ois], len / 2) < 0) { wpa_printf(MSG_INFO, - "Invalid roaming_consortiums entry: %s", + "Invalid organisation identifier (OI) entry: %s", pos); return -1; } - roaming_consortiums_len[num_roaming_consortiums] = len / 2; - num_roaming_consortiums++; + ois_len[num_ois] = len / 2; + num_ois++; if (!end) break; - if (num_roaming_consortiums >= MAX_ROAMING_CONS) { + if (num_ois >= MAX_ROAMING_CONS) { wpa_printf(MSG_INFO, - "Too many roaming_consortiums OIs"); + "Too many OIs"); return -1; } pos = end + 1; } - os_memcpy(cred->roaming_consortiums, roaming_consortiums, - sizeof(roaming_consortiums)); - os_memcpy(cred->roaming_consortiums_len, roaming_consortiums_len, - sizeof(roaming_consortiums_len)); - cred->num_roaming_consortiums = num_roaming_consortiums; + os_memcpy(cred_ois, ois, sizeof(ois)); + os_memcpy(cred_ois_len, ois_len, sizeof(ois_len)); + *cred_num_ois = num_ois; return 0; } @@ -3924,36 +4068,70 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, } if (os_strcmp(var, "roaming_consortium") == 0) { - if (len < 3 || len > sizeof(cred->roaming_consortium)) { + if (len < 3 || len > sizeof(cred->home_ois[0])) { wpa_printf(MSG_ERROR, "Line %d: invalid " "roaming_consortium length %d (3..15 " "expected)", line, (int) len); os_free(val); return -1; } - os_memcpy(cred->roaming_consortium, val, len); - cred->roaming_consortium_len = len; + wpa_printf(MSG_WARNING, + "Line %d: option roaming_consortium is deprecated and will be removed in the future", + line); + os_memcpy(cred->home_ois[0], val, len); + cred->home_ois_len[0] = len; + cred->num_home_ois = 1; os_free(val); return 0; } if (os_strcmp(var, "required_roaming_consortium") == 0) { - if (len < 3 || len > sizeof(cred->required_roaming_consortium)) - { + if (len < 3 || len > sizeof(cred->required_home_ois[0])) { wpa_printf(MSG_ERROR, "Line %d: invalid " "required_roaming_consortium length %d " "(3..15 expected)", line, (int) len); os_free(val); return -1; } - os_memcpy(cred->required_roaming_consortium, val, len); - cred->required_roaming_consortium_len = len; + wpa_printf(MSG_WARNING, + "Line %d: option required_roaming_consortium is deprecated and will be removed in the future", + line); + os_memcpy(cred->required_home_ois[0], val, len); + cred->required_home_ois_len[0] = len; + cred->num_required_home_ois = 1; os_free(val); return 0; } + if (os_strcmp(var, "home_ois") == 0) { + res = wpa_config_set_cred_ois(cred->home_ois, + cred->home_ois_len, + &cred->num_home_ois, + val); + if (res < 0) + wpa_printf(MSG_ERROR, "Line %d: invalid home_ois", + line); + os_free(val); + return res; + } + + if (os_strcmp(var, "required_home_ois") == 0) { + res = wpa_config_set_cred_ois(cred->required_home_ois, + cred->required_home_ois_len, + &cred->num_required_home_ois, + val); + if (res < 0) + wpa_printf(MSG_ERROR, + "Line %d: invalid required_home_ois", line); + os_free(val); + return res; + } + if (os_strcmp(var, "roaming_consortiums") == 0) { - res = wpa_config_set_cred_roaming_consortiums(cred, val); + res = wpa_config_set_cred_ois(cred->roaming_consortiums, + cred->roaming_consortiums_len, + &cred->num_roaming_consortiums, + val); if (res < 0) wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortiums", @@ -4053,6 +4231,18 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "imsi_privacy_cert") == 0) { + os_free(cred->imsi_privacy_cert); + cred->imsi_privacy_cert = val; + return 0; + } + + if (os_strcmp(var, "imsi_privacy_attr") == 0) { + os_free(cred->imsi_privacy_attr); + cred->imsi_privacy_attr = val; + return 0; + } + if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", line, var); @@ -4203,6 +4393,12 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) if (os_strcmp(var, "imsi") == 0) return alloc_strdup(cred->imsi); + if (os_strcmp(var, "imsi_privacy_cert") == 0) + return alloc_strdup(cred->imsi_privacy_cert); + + if (os_strcmp(var, "imsi_privacy_attr") == 0) + return alloc_strdup(cred->imsi_privacy_attr); + if (os_strcmp(var, "milenage") == 0) { if (!(cred->milenage)) return NULL; @@ -4247,14 +4443,14 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) size_t buflen; char *buf; - if (!cred->roaming_consortium_len) + if (!cred->num_home_ois || !cred->home_ois_len[0]) return NULL; - buflen = cred->roaming_consortium_len * 2 + 1; + buflen = cred->home_ois_len[0] * 2 + 1; buf = os_malloc(buflen); if (buf == NULL) return NULL; - wpa_snprintf_hex(buf, buflen, cred->roaming_consortium, - cred->roaming_consortium_len); + wpa_snprintf_hex(buf, buflen, cred->home_ois[0], + cred->home_ois_len[0]); return buf; } @@ -4262,14 +4458,64 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var) size_t buflen; char *buf; - if (!cred->required_roaming_consortium_len) + if (!cred->num_required_home_ois || + !cred->required_home_ois_len[0]) return NULL; - buflen = cred->required_roaming_consortium_len * 2 + 1; + buflen = cred->required_home_ois_len[0] * 2 + 1; buf = os_malloc(buflen); if (buf == NULL) return NULL; - wpa_snprintf_hex(buf, buflen, cred->required_roaming_consortium, - cred->required_roaming_consortium_len); + wpa_snprintf_hex(buf, buflen, cred->required_home_ois[0], + cred->required_home_ois_len[0]); + return buf; + } + + if (os_strcmp(var, "home_ois") == 0) { + size_t buflen; + char *buf, *pos; + size_t i; + + if (!cred->num_home_ois) + return NULL; + buflen = cred->num_home_ois * MAX_ROAMING_CONS_OI_LEN * 2 + 1; + buf = os_malloc(buflen); + if (!buf) + return NULL; + pos = buf; + for (i = 0; i < cred->num_home_ois; i++) { + if (i > 0) + *pos++ = ','; + pos += wpa_snprintf_hex( + pos, buf + buflen - pos, + cred->home_ois[i], + cred->home_ois_len[i]); + } + *pos = '\0'; + return buf; + } + + if (os_strcmp(var, "required_home_ois") == 0) { + size_t buflen; + char *buf, *pos; + size_t i; + + if (!cred->num_required_home_ois) + return NULL; + buflen = cred->num_required_home_ois * + MAX_ROAMING_CONS_OI_LEN * 2 + 1; + buf = os_malloc(buflen); + if (!buf) + return NULL; + pos = buf; + for (i = 0; i < cred->num_required_home_ois; i++) { + if (i > 0) + *pos++ = ','; + pos += wpa_snprintf_hex( + pos, buf + buflen - pos, + cred->required_home_ois[i], + cred->required_home_ois_len[i]); + } + *pos = '\0'; return buf; } @@ -4601,6 +4847,10 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->driver_param = os_strdup(driver_param); config->gas_rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME; +#ifdef CONFIG_TESTING_OPTIONS + config->mld_connect_band_pref = DEFAULT_MLD_CONNECT_BAND_PREF; +#endif /* CONFIG_TESTING_OPTIONS */ + return config; } @@ -4659,9 +4909,10 @@ struct global_parse_data { }; -static int wpa_global_config_parse_int(const struct global_parse_data *data, - struct wpa_config *config, int line, - const char *pos) +static int +wpa_global_config_parse_int_impl(const struct global_parse_data *data, + struct wpa_config *config, int line, + const char *pos, bool check_range) { int val, *dst; char *end; @@ -4674,31 +4925,47 @@ 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); - - if (data->param2 && *dst < (long) data->param2) { + if (check_range && val < (long) data->param2) { wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " - "min_value=%ld)", line, data->name, *dst, + "min_value=%ld)", line, data->name, val, (long) data->param2); - *dst = (long) data->param2; return -1; } - if (data->param3 && *dst > (long) data->param3) { + if (check_range && val > (long) data->param3) { wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " - "max_value=%ld)", line, data->name, *dst, + "max_value=%ld)", line, data->name, val, (long) data->param3); - *dst = (long) data->param3; return -1; } + same = *dst == val; + *dst = val; + + wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst); + return same; } +static int wpa_global_config_parse_int(const struct global_parse_data *data, + struct wpa_config *config, int line, + const char *pos) +{ + return wpa_global_config_parse_int_impl(data, config, line, pos, false); +} + + +static int +wpa_global_config_parse_int_range(const struct global_parse_data *data, + struct wpa_config *config, int line, + const char *pos) +{ + return wpa_global_config_parse_int_impl(data, config, line, pos, true); +} + + static int wpa_global_config_parse_str(const struct global_parse_data *data, struct wpa_config *config, int line, const char *pos) @@ -5235,6 +5502,23 @@ static int wpa_config_get_ipv4(const char *name, struct wpa_config *config, #endif /* CONFIG_P2P */ +#ifdef CONFIG_TESTING_OPTIONS +static int wpa_config_process_mld_connect_bssid_pref( + const struct global_parse_data *data, + struct wpa_config *config, int line, const char *pos) +{ + if (hwaddr_aton2(pos, config->mld_connect_bssid_pref) < 0) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid mld_connect_bssid_pref '%s'", + line, pos); + return -1; + } + + return 0; +} +#endif /* CONFIG_TESTING_OPTIONS */ + + #ifdef OFFSET #undef OFFSET #endif /* OFFSET */ @@ -5245,7 +5529,8 @@ static int wpa_config_get_ipv4(const char *name, struct wpa_config *config, #define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL, NULL #define _INT(f) #f, wpa_global_config_parse_int, wpa_config_get_int, OFFSET(f) #define INT(f) _INT(f), NULL, NULL -#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max +#define INT_RANGE(f, min, max) #f, wpa_global_config_parse_int_range, \ + wpa_config_get_int, OFFSET(f), (void *) min, (void *) max #define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f) #define STR(f) _STR(f), NULL, NULL #define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max @@ -5382,6 +5667,7 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(auto_interworking, 0, 1), 0 }, { INT(okc), 0 }, { INT(pmf), 0 }, + { INT_RANGE(sae_check_mfp, 0, 1), 0 }, { FUNC(sae_groups), 0 }, { INT_RANGE(sae_pwe, 0, 3), 0 }, { INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 }, @@ -5400,9 +5686,9 @@ static const struct global_parse_data global_fields[] = { { STR(osu_dir), 0 }, { STR(wowlan_triggers), CFG_CHANGED_WOWLAN_TRIGGERS }, { INT(p2p_search_delay), 0}, - { INT(mac_addr), 0 }, + { INT_RANGE(mac_addr, 0, 2), 0 }, { INT(rand_addr_lifetime), 0 }, - { INT(preassoc_mac_addr), 0 }, + { INT_RANGE(preassoc_mac_addr, 0, 2), 0 }, { INT(key_mgmt_offload), 0}, { INT(passive_scan), 0 }, { INT(reassoc_same_bss_optim), 0 }, @@ -5431,6 +5717,9 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(dpp_config_processing, 0, 2), 0 }, { STR(dpp_name), 0 }, { STR(dpp_mud_url), 0 }, + { STR(dpp_extra_conf_req_name), 0 }, + { STR(dpp_extra_conf_req_value), 0 }, + { INT_RANGE(dpp_connector_privacy_default, 0, 1), 0 }, #endif /* CONFIG_DPP */ { INT_RANGE(coloc_intf_reporting, 0, 1), 0 }, #ifdef CONFIG_WNM @@ -5444,6 +5733,15 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(pasn_corrupt_mic, 0, 1), 0 }, #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_PASN */ +#ifdef CONFIG_TESTING_OPTIONS + { INT_RANGE(mld_force_single_link, 0, 1), 0 }, + { INT_RANGE(mld_connect_band_pref, 0, MLD_CONNECT_BAND_PREF_MAX), 0 }, + { FUNC(mld_connect_bssid_pref), 0 }, +#endif /* CONFIG_TESTING_OPTIONS */ + { INT_RANGE(ft_prepend_pmkid, 0, 1), CFG_CHANGED_FT_PREPEND_PMKID }, + /* NOTE: When adding new parameters here, add_interface() in + * wpa_supplicant/dbus_new_introspect.c may need to be modified to + * increase the size of the iface->xml buffer. */ }; #undef FUNC @@ -5577,6 +5875,7 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line) line); return -1; } + return ret; } if (os_strncmp(pos, "wmm_ac_", 7) == 0) { diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/config.h b/wpa_supplicant-2.9_standard/wpa_supplicant/config.h index 291213b9723f07f543a75412b51aa58d824df77e..8981305c2a7ae884473d7ea6985bd6e0762d7f12 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/config.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/config.h @@ -47,6 +47,7 @@ #define DEFAULT_OCE_SUPPORT OCE_STA #define DEFAULT_EXTENDED_KEY_ID 0 #define DEFAULT_SCAN_RES_VALID_FOR_CONNECT 5 +#define DEFAULT_MLD_CONNECT_BAND_PREF MLD_CONNECT_BAND_PREF_AUTO #include "config_ssid.h" #include "wps/wps.h" @@ -180,6 +181,26 @@ struct wpa_cred { */ char *milenage; + /** + * imsi_privacy_cert - IMSI privacy certificate + * + * This field is used with EAP-SIM/AKA/AKA' to encrypt the permanent + * identity (IMSI) to improve privacy. The referenced PEM-encoded + * X.509v3 certificate needs to include a 2048-bit RSA public key and + * this is from the operator who authenticates the SIM/USIM. + */ + char *imsi_privacy_cert; + + /** + * imsi_privacy_attr - IMSI privacy attribute + * + * This field is used to help the EAP-SIM/AKA/AKA' server to identify + * the used certificate (and as such, the matching private key). This + * is set to an attribute in name=value format if the operator needs + * this information. + */ + char *imsi_privacy_attr; + /** * engine - Use an engine for private key operations */ @@ -239,36 +260,50 @@ struct wpa_cred { size_t num_domain; /** - * roaming_consortium - Roaming Consortium OI + * home_ois - Home OIs * - * If roaming_consortium_len is non-zero, this field contains the - * Roaming Consortium OI that can be used to determine which access - * points support authentication with this credential. This is an - * alternative to the use of the realm parameter. When using Roaming - * Consortium to match the network, the EAP parameters need to be - * pre-configured with the credential since the NAI Realm information - * may not be available or fetched. + * If num_home_ois is non-zero, this field contains the set of Home OIs + * that can be use to determine which access points support + * authentication with this credential. These are an alternative to the + * use of the realm parameter. When using Home OIs to match the network, + * the EAP parameters need to be pre-configured with the credentials + * since the NAI Realm information may not be available or fetched. + * A successful authentication with the access point is possible as soon + * as at least one Home OI from the list matches an OI in the Roaming + * Consortium list advertised by the access point. + * (Hotspot 2.0 PerProviderSubscription//HomeSP/HomeOIList//HomeOI) */ - u8 roaming_consortium[15]; + u8 home_ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; /** - * roaming_consortium_len - Length of roaming_consortium + * home_ois_len - Length of home_ois[i] */ - size_t roaming_consortium_len; + size_t home_ois_len[MAX_ROAMING_CONS]; /** - * required_roaming_consortium - Required Roaming Consortium OI + * num_home_ois - Number of entries in home_ois + */ + unsigned int num_home_ois; + + /** + * required_home_ois - Required Home OI(s) * - * If required_roaming_consortium_len is non-zero, this field contains - * the Roaming Consortium OI that is required to be advertised by the AP - * for the credential to be considered matching. + * If required_home_ois_len is non-zero, this field contains the set of + * Home OI(s) that are required to be advertised by the AP for the + * credential to be considered matching. + * (Hotspot 2.0 PerProviderSubscription//HomeSP/HomeOIList//HomeOIRequired) */ - u8 required_roaming_consortium[15]; + u8 required_home_ois[MAX_ROAMING_CONS][MAX_ROAMING_CONS_OI_LEN]; /** - * required_roaming_consortium_len - Length of required_roaming_consortium + * required_home_ois_len - Length of required_home_ois */ - size_t required_roaming_consortium_len; + size_t required_home_ois_len[MAX_ROAMING_CONS]; + + /** + * num_required_home_ois - Number of entries in required_home_ois + */ + unsigned int num_required_home_ois; /** * roaming_consortiums - Roaming Consortium OI(s) memberships @@ -404,6 +439,7 @@ struct wpa_cred { #define CFG_CHANGED_WOWLAN_TRIGGERS BIT(18) #define CFG_CHANGED_DISABLE_BTM BIT(19) #define CFG_CHANGED_BGSCAN BIT(20) +#define CFG_CHANGED_FT_PREPEND_PMKID BIT(21) /** * struct wpa_config - wpa_supplicant configuration data @@ -677,6 +713,14 @@ struct wpa_config { */ unsigned int dot11RSNAConfigSATimeout; + /** + * ft_prepend_pmkid - Whether to prepend PMKR1Name with PMKIDs + * + * This control whether PMKR1Name is prepended to the PMKID list + * insread of replacing the full list when constructing RSNE for + * EAPOL-Key msg 2/4 for FT cases. */ + bool ft_prepend_pmkid; + /** * update_config - Is wpa_supplicant allowed to update configuration * @@ -1224,6 +1268,25 @@ struct wpa_config { */ enum mfp_options pmf; + /** + * sae_check_mfp - Whether to limit SAE based on PMF capabilities + * + * With this check SAE key_mgmt will not be selected if PMF is + * not enabled. + * Scenarios where enabling this check will limit SAE: + * 1) ieee8011w=0 is set for the network. + * 2) The AP does not have PMF enabled. + * 3) ieee8011w for the network is the default(3), pmf=1 is enabled + * globally and the device does not support the BIP cipher. + * + * Useful to allow the BIP cipher check that occurs for ieee80211w=3 + * and pmf=1 to also avoid using SAE key_mgmt. + * Useful when hardware does not support BIP to still to allow + * connecting to sae_require_mfp=1 WPA2+WPA3-Personal transition mode + *access points by automatically selecting PSK instead of SAE. + */ + int sae_check_mfp; + /** * sae_groups - Preference list of enabled groups for SAE * @@ -1240,7 +1303,7 @@ struct wpa_config { * 1 = hash-to-element only * 2 = both hunting-and-pecking loop and hash-to-element enabled */ - int sae_pwe; + enum sae_pwe sae_pwe; /** * sae_pmkid_in_assoc - Whether to include PMKID in SAE Assoc Req @@ -1360,7 +1423,7 @@ struct wpa_config { * the per-network mac_addr parameter. Global mac_addr=1 can be used to * change this default behavior. */ - int mac_addr; + enum wpas_mac_addr_style mac_addr; /** * rand_addr_lifetime - Lifetime of random MAC address in seconds @@ -1374,7 +1437,7 @@ struct wpa_config { * 1 = use random MAC address * 2 = like 1, but maintain OUI (with local admin bit set) */ - int preassoc_mac_addr; + enum wpas_mac_addr_style preassoc_mac_addr; /** * key_mgmt_offload - Use key management offload @@ -1576,7 +1639,7 @@ struct wpa_config { * 1 = use random MAC address * 2 = like 1, but maintain OUI (with local admin bit set) */ - int gas_rand_mac_addr; + enum wpas_mac_addr_style gas_rand_mac_addr; /** * dpp_config_processing - How to process DPP configuration @@ -1603,6 +1666,25 @@ struct wpa_config { */ char *dpp_mud_url; + /** + * dpp_extra_conf_req_name - JSON node name of additional data for + * Enrollee's DPP Configuration Request + */ + char *dpp_extra_conf_req_name; + + /** + * dpp_extra_conf_req_value - JSON node data of additional data for + * Enrollee's DPP Configuration Request + */ + char *dpp_extra_conf_req_value; + + /* dpp_connector_privacy_default - Default valur for Connector privacy + * + * This value is used as the default for the dpp_connector_privacy + * network parameter for all new networks provisioned using DPP. + */ + int dpp_connector_privacy_default; + /** * coloc_intf_reporting - Colocated interference reporting * @@ -1705,6 +1787,20 @@ struct wpa_config { #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_PASN*/ + +#ifdef CONFIG_TESTING_OPTIONS + enum { + MLD_CONNECT_BAND_PREF_AUTO = 0, + MLD_CONNECT_BAND_PREF_2GHZ = 1, + MLD_CONNECT_BAND_PREF_5GHZ = 2, + MLD_CONNECT_BAND_PREF_6GHZ = 3, + MLD_CONNECT_BAND_PREF_MAX = 4, + } mld_connect_band_pref; + + u8 mld_connect_bssid_pref[ETH_ALEN]; + + int mld_force_single_link; +#endif /* CONFIG_TESTING_OPTIONS */ }; @@ -1774,6 +1870,7 @@ const char * wpa_config_get_global_field_name(unsigned int i, int *no_var); * @name: Name of the configuration (e.g., path and file name for the * configuration file) * @cfgp: Pointer to previously allocated configuration data or %NULL if none + * @ro: Whether to mark networks from this configuration as read-only * Returns: Pointer to allocated configuration data or %NULL on failure * * This function reads configuration data, parses its contents, and allocates @@ -1782,7 +1879,8 @@ const char * wpa_config_get_global_field_name(unsigned int i, int *no_var); * * Each configuration backend needs to implement this function. */ -struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp); +struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, + bool ro); /** * wpa_config_write - Write or update configuration data diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/config_file.c b/wpa_supplicant-2.9_standard/wpa_supplicant/config_file.c index 0855bf78c25ecdec461b897a5537ab5dc8cc1bd9..d462e4645a8aa66f84d94b2a60e08454f6942476 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/config_file.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/config_file.c @@ -29,7 +29,6 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line) { int errors = 0; - #ifdef CONFIG_WAPI if ((ssid->wapi != WAPI_TYPE_NONE) && (ssid->key_mgmt != WPA_KEY_MGMT_WAPI_PSK) && (ssid->key_mgmt != WPA_KEY_MGMT_WAPI_CERT)) { @@ -65,7 +64,6 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line) } } else { #endif - if (ssid->passphrase) { if (ssid->psk_set) { wpa_printf(MSG_ERROR, "Line %d: both PSK and " @@ -91,6 +89,13 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line) #ifdef CONFIG_WAPI } #endif + if (is_6ghz_freq(ssid->frequency) && ssid->mode == WPAS_MODE_MESH && + ssid->key_mgmt == WPA_KEY_MGMT_NONE) { + wpa_printf(MSG_ERROR, + "Line %d: key_mgmt for mesh network in 6 GHz should be SAE", + line); + errors++; + } if (ssid->mode == WPAS_MODE_MESH && (ssid->key_mgmt != WPA_KEY_MGMT_NONE && ssid->key_mgmt != WPA_KEY_MGMT_SAE)) { @@ -327,7 +332,8 @@ static int wpa_config_process_blob(struct wpa_config *config, FILE *f, #endif /* CONFIG_NO_CONFIG_BLOBS */ -struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) +struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, + bool ro) { FILE *f; char buf[512], *pos; @@ -335,8 +341,8 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) struct wpa_ssid *ssid, *tail, *head; struct wpa_cred *cred, *cred_tail, *cred_head; struct wpa_config *config; - int id = 0; - int cred_id = 0; + static int id = 0; + static int cred_id = 0; if (name == NULL) return NULL; @@ -375,6 +381,7 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) errors++; continue; } + ssid->ro = ro; if (head == NULL) { head = tail = ssid; } else { @@ -434,7 +441,6 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) head = NULL; } #endif /* WPA_IGNORE_CONFIG_ERRORS */ - wpa_printf(MSG_INFO, "Read configuration file finished."); return config; } @@ -750,7 +756,6 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(client_cert); STR(private_key); STR(private_key_passwd); - STR(dh_file); STR(subject_match); STR(check_cert_subject); STR(altsubject_match); @@ -761,7 +766,6 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(client_cert2); STR(private_key2); STR(private_key2_passwd); - STR(dh_file2); STR(subject_match2); STR(check_cert_subject2); STR(altsubject_match2); @@ -772,7 +776,6 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(machine_client_cert); STR(machine_private_key); STR(machine_private_key_passwd); - STR(machine_dh_file); STR(machine_subject_match); STR(machine_check_cert_subject); STR(machine_altsubject_match); @@ -859,8 +862,10 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT(macsec_integ_only); INT(macsec_replay_protect); INT(macsec_replay_window); + INT(macsec_offload); INT(macsec_port); INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER); + INT(macsec_csindex); #endif /* CONFIG_MACSEC */ #ifdef CONFIG_HS20 INT(update_identifier); @@ -886,12 +891,14 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(dpp_csign); STR(dpp_pp_key); INT(dpp_pfs); + INT(dpp_connector_privacy); #endif /* CONFIG_DPP */ INT(owe_group); INT(owe_only); INT(owe_ptk_workaround); INT(multi_ap_backhaul_sta); INT(ft_eap_pmksa_caching); + INT(multi_ap_profile); INT(beacon_prot); INT(transition_disable); INT(sae_pk); @@ -932,6 +939,10 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) #ifdef CONFIG_HE_OVERRIDES INT(disable_he); #endif /* CONFIG_HE_OVERRIDES */ + INT(disable_eht); + INT(enable_4addr_mode); + INT(max_idle); + INT(ssid_protection); #undef STR #undef INT @@ -973,12 +984,6 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) if (cred->domain_suffix_match) fprintf(f, "\tdomain_suffix_match=\"%s\"\n", cred->domain_suffix_match); - if (cred->roaming_consortium_len) { - fprintf(f, "\troaming_consortium="); - for (i = 0; i < cred->roaming_consortium_len; i++) - fprintf(f, "%02x", cred->roaming_consortium[i]); - fprintf(f, "\n"); - } if (cred->eap_method) { const char *name; name = eap_get_name(cred->eap_method[0].vendor, @@ -1054,12 +1059,32 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) } } - if (cred->required_roaming_consortium_len) { - fprintf(f, "\trequired_roaming_consortium="); - for (i = 0; i < cred->required_roaming_consortium_len; i++) - fprintf(f, "%02x", - cred->required_roaming_consortium[i]); - fprintf(f, "\n"); + if (cred->num_home_ois) { + size_t j; + + fprintf(f, "\thome_ois=\""); + for (i = 0; i < cred->num_home_ois; i++) { + if (i > 0) + fprintf(f, ","); + for (j = 0; j < cred->home_ois_len[i]; j++) + fprintf(f, "%02x", + cred->home_ois[i][j]); + } + fprintf(f, "\"\n"); + } + + if (cred->num_required_home_ois) { + size_t j; + + fprintf(f, "\trequired_home_ois=\""); + for (i = 0; i < cred->num_required_home_ois; i++) { + if (i > 0) + fprintf(f, ","); + for (j = 0; j < cred->required_home_ois_len[i]; j++) + fprintf(f, "%02x", + cred->required_home_ois[i][j]); + } + fprintf(f, "\"\n"); } if (cred->num_roaming_consortiums) { @@ -1089,6 +1114,13 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) fprintf(f, "\tcert_id=\"%s\"\n", cred->cert_id); if (cred->ca_cert_id) fprintf(f, "\tca_cert_id=\"%s\"\n", cred->ca_cert_id); + + if (cred->imsi_privacy_cert) + fprintf(f, "\timsi_privacy_cert=\"%s\"\n", + cred->imsi_privacy_cert); + if (cred->imsi_privacy_attr) + fprintf(f, "\timsi_privacy_attr=\"%s\"\n", + cred->imsi_privacy_attr); } @@ -1406,6 +1438,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->beacon_int) fprintf(f, "beacon_int=%d\n", config->beacon_int); + if (config->sae_check_mfp) + fprintf(f, "sae_check_mfp=%d\n", config->sae_check_mfp); + if (config->sae_groups) { int i; fprintf(f, "sae_groups="); @@ -1595,6 +1630,19 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->dpp_config_processing) fprintf(f, "dpp_config_processing=%d\n", config->dpp_config_processing); + if (config->dpp_name) + fprintf(f, "dpp_name=%s\n", config->dpp_name); + if (config->dpp_mud_url) + fprintf(f, "dpp_mud_url=%s\n", config->dpp_mud_url); + if (config->dpp_extra_conf_req_name) + fprintf(f, "dpp_extra_conf_req_name=%s\n", + config->dpp_extra_conf_req_name); + if (config->dpp_extra_conf_req_value) + fprintf(f, "dpp_extra_conf_req_value=%s\n", + config->dpp_extra_conf_req_value); + if (config->dpp_connector_privacy_default) + fprintf(f, "dpp_connector_privacy_default=%d\n", + config->dpp_connector_privacy_default); if (config->coloc_intf_reporting) fprintf(f, "coloc_intf_reporting=%d\n", config->coloc_intf_reporting); @@ -1615,6 +1663,18 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->wowlan_disconnect_on_deinit) fprintf(f, "wowlan_disconnect_on_deinit=%d\n", config->wowlan_disconnect_on_deinit); +#ifdef CONFIG_TESTING_OPTIONS + if (config->mld_force_single_link) + fprintf(f, "mld_force_single_link=1\n"); + if (config->mld_connect_band_pref != MLD_CONNECT_BAND_PREF_AUTO) + fprintf(f, "mld_connect_band_pref=%d\n", + config->mld_connect_band_pref); + if (!is_zero_ether_addr(config->mld_connect_bssid_pref)) + fprintf(f, "mld_connect_bssid_pref=" MACSTR "\n", + MAC2STR(config->mld_connect_bssid_pref)); +#endif /* CONFIG_TESTING_OPTIONS */ + if (config->ft_prepend_pmkid) + fprintf(f, "ft_prepend_pmkid=%d", config->ft_prepend_pmkid); } #endif /* CONFIG_NO_CONFIG_WRITE */ @@ -1646,7 +1706,7 @@ int wpa_config_write(const char *name, struct wpa_config *config) name = tmp_name; } - wpa_printf(MSG_EXCESSIVE, "Writing configuration file '%s'", name); + wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name); f = fopen(name, "w"); if (f == NULL) { @@ -1666,7 +1726,8 @@ int wpa_config_write(const char *name, struct wpa_config *config) } for (ssid = config->ssid; ssid; ssid = ssid->next) { - if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary) + if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary || + ssid->ro) continue; /* do not save temporary networks */ if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt) && !ssid->psk_set && !ssid->passphrase) @@ -1704,7 +1765,7 @@ int wpa_config_write(const char *name, struct wpa_config *config) os_free(tmp_name); } - wpa_printf(MSG_EXCESSIVE, "Configuration file '%s' written %ssuccessfully", + wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully", orig_name, ret ? "un" : ""); return ret; #else /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/config_none.c b/wpa_supplicant-2.9_standard/wpa_supplicant/config_none.c index 0bc977e3961b037c7906893977fa2f8bad1e667f..01e7aad44bd9c5687d993d5b506cb58b2d8571a2 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/config_none.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/config_none.c @@ -17,7 +17,8 @@ #include "base64.h" -struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) +struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, + bool ro) { struct wpa_config *config; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/config_ssid.h b/wpa_supplicant-2.9_standard/wpa_supplicant/config_ssid.h index a9f4421dd3c6cb1588b01cd17883eae46da7a7ab..5d87baf280c712588003873bdeba88cddadd84e1 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/config_ssid.h @@ -62,7 +62,7 @@ enum WAPI_TYPE { #define DEFAULT_MAX_OPER_CHWIDTH -1 /* Consider global sae_pwe for SAE mechanism for PWE derivation */ -#define DEFAULT_SAE_PWE 4 +#define DEFAULT_SAE_PWE SAE_PWE_NOT_SET struct psk_list_entry { struct dl_list list; @@ -86,6 +86,14 @@ enum sae_pk_mode { SAE_PK_MODE_DISABLED = 2, }; +enum wpas_mac_addr_style { + WPAS_MAC_ADDR_STYLE_NOT_SET = -1, + WPAS_MAC_ADDR_STYLE_PERMANENT = 0, + WPAS_MAC_ADDR_STYLE_RANDOM = 1, + WPAS_MAC_ADDR_STYLE_RANDOM_SAME_OUI = 2, + WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS = 3, +}; + /** * struct wpa_ssid - Network configuration data * @@ -122,6 +130,21 @@ struct wpa_ssid { */ int id; + /** + * ro - Whether a network is declared as read-only + * + * Every network which is defined in a config file that is passed to + * wpa_supplicant using the -I option will be marked as read-only + * using this flag. It has the effect that it won't be written to + * /etc/wpa_supplicant.conf (from -c argument) if, e.g., wpa_gui tells + * the daemon to save all changed configs. + * + * This is necessary because networks from /etc/wpa_supplicant.conf + * have a higher priority and changes from an alternative file would be + * silently overwritten without this. + */ + bool ro; + /** * priority - Priority group * @@ -585,7 +608,9 @@ struct wpa_ssid { int he; - int max_oper_chwidth; + int eht; + + enum oper_chan_width max_oper_chwidth; unsigned int vht_center_freq1; unsigned int vht_center_freq2; @@ -861,6 +886,14 @@ struct wpa_ssid { */ struct os_reltime disabled_until; + /** + * disabled_due_to - BSSID of the disabling failure + * + * This identifies the BSS that failed the connection attempt that + * resulted in the network being temporarily disabled. + */ + u8 disabled_due_to[ETH_ALEN]; + /** * parent_cred - Pointer to parent wpa_cred entry * @@ -919,6 +952,18 @@ struct wpa_ssid { */ u32 macsec_replay_window; + /** + * macsec_offload - Enable MACsec hardware offload + * + * This setting applies only when MACsec is in use, i.e., + * - the key server has decided to enable MACsec + * + * 0 = MACSEC_OFFLOAD_OFF (default) + * 1 = MACSEC_OFFLOAD_PHY + * 2 = MACSEC_OFFLOAD_MAC + */ + int macsec_offload; + /** * macsec_port - MACsec port (in SCI) * @@ -935,6 +980,13 @@ struct wpa_ssid { */ int mka_priority; + /** + * macsec_csindex - Cipher suite index for MACsec + * + * Range: 0-1 (default: 0) + */ + int macsec_csindex; + /** * mka_ckn - MKA pre-shared CKN */ @@ -983,12 +1035,21 @@ struct wpa_ssid { * 0 = use permanent MAC address * 1 = use random MAC address for each ESS connection * 2 = like 1, but maintain OUI (with local admin bit set) + * 3 = use dedicated/pregenerated MAC address (see mac_value) * * Internally, special value -1 is used to indicate that the parameter * was not specified in the configuration (i.e., default behavior is * followed). */ - int mac_addr; + enum wpas_mac_addr_style mac_addr; + + /** + * mac_value - Specific MAC address to be used + * + * When mac_addr policy is equal to 3 this is the value of the MAC + * address that should be used. + */ + u8 mac_value[ETH_ALEN]; /** * no_auto_peer - Do not automatically peer with compatible mesh peers @@ -1081,6 +1142,14 @@ struct wpa_ssid { */ int dpp_pfs_fallback; + /** + * dpp_connector_privacy - Network introduction type + * 0: unprotected variant from DPP R1 + * 1: privacy protecting (station Connector encrypted) variant from + * DPP R3 + */ + int dpp_connector_privacy; + /** * owe_group - OWE DH Group * @@ -1142,6 +1211,11 @@ struct wpa_ssid { */ int ft_eap_pmksa_caching; + /** + * multi_ap_profile - Supported Multi-AP profile + */ + int multi_ap_profile; + /** * beacon_prot - Whether Beacon protection is enabled * @@ -1200,7 +1274,39 @@ struct wpa_ssid { * 1 = hash-to-element only * 2 = both hunting-and-pecking loop and hash-to-element enabled */ - int sae_pwe; + enum sae_pwe sae_pwe; + + /** + * disable_eht - Disable EHT (IEEE 802.11be) for this network + * + * By default, use it if it is available, but this can be configured + * to 1 to have it disabled. + */ + int disable_eht; + + /** + * enable_4addr_mode - Set 4addr mode after association + * 0 = Do not attempt to set 4addr mode + * 1 = Try to set 4addr mode after association + * + * Linux requires that an interface is set to 4addr mode before it can + * be added to a bridge. Set this to 1 for networks where you intent + * to use the interface in a bridge. + */ + int enable_4addr_mode; + + /** + * max_idle - BSS max idle period to request + * + * If nonzero, request the specified number of 1000 TU (i.e., 1.024 s) + * as the maximum idle period for the STA during association. + */ + int max_idle; + + /** + * ssid_protection - Whether to use SSID protection in 4-way handshake + */ + bool ssid_protection; }; #endif /* CONFIG_SSID_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/config_winreg.c b/wpa_supplicant-2.9_standard/wpa_supplicant/config_winreg.c index 1b7f96ed2fb12d8980d2820e4b33069c688e53b4..05e6e37944bba36739b6d9393e74ed768efcc0c6 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/config_winreg.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/config_winreg.c @@ -446,7 +446,8 @@ static int wpa_config_read_networks(struct wpa_config *config, HKEY hk) } -struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp) +struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp, + bool ro) { TCHAR buf[256]; int errors = 0; @@ -905,7 +906,6 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) STR(client_cert); STR(private_key); STR(private_key_passwd); - STR(dh_file); STR(subject_match); STR(check_cert_subject); STR(altsubject_match); @@ -914,7 +914,6 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) STR(client_cert2); STR(private_key2); STR(private_key2_passwd); - STR(dh_file2); STR(subject_match2); STR(check_cert_subject2); STR(altsubject_match2); diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.c b/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.c index 776c3d4fd1df890820540da2e3d02a6978ced9c4..334aac1148761f81e9abc8e2f3728d71b64e67e7 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Control interface (shared code for all backends) - * Copyright (c) 2004-2020, Jouni Malinen + * Copyright (c) 2004-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -22,6 +22,7 @@ #ifdef CONFIG_DPP #include "common/dpp.h" #endif /* CONFIG_DPP */ +#include "common/nan_de.h" #include "common/ptksa_cache.h" #include "crypto/tls.h" #include "ap/hostapd.h" @@ -58,6 +59,7 @@ #include "mesh.h" #include "dpp_supplicant.h" #include "sme.h" +#include "nan_usd.h" #ifdef CONFIG_MAGICLINK #include "wpa_magiclink.h" #endif @@ -320,7 +322,6 @@ static int wpas_ctrl_pno(struct wpa_supplicant *wpa_s, char *cmd) char *pos; int *freqs = NULL; int ret; - wpa_printf(MSG_INFO, "%s: %s", __func__, cmd); if (atoi(cmd)) { params = os_strchr(cmd, ' '); @@ -485,7 +486,7 @@ static int wpas_ctrl_iface_set_dso(struct wpa_supplicant *wpa_s, dl_list_for_each(tmp, &wpa_s->drv_signal_override, struct driver_signal_override, list) { - if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) { + if (ether_addr_equal(bssid, tmp->bssid)) { dso = tmp; break; } @@ -713,6 +714,9 @@ int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) { os_free(wpa_s->dpp_configurator_params); wpa_s->dpp_configurator_params = os_strdup(value); +#ifdef CONFIG_DPP2 + dpp_controller_set_params(wpa_s->dpp, value); +#endif /* CONFIG_DPP2 */ } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) { wpa_s->dpp_init_max_tries = atoi(value); } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) { @@ -775,6 +779,12 @@ int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wpa_s->ext_eapol_frame_io; } #endif /* CONFIG_AP */ + } else if (os_strcasecmp(cmd, "encrypt_eapol_m2") == 0) { + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_ENCRYPT_EAPOL_M2, + !!atoi(value)); + } else if (os_strcasecmp(cmd, "encrypt_eapol_m4") == 0) { + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_ENCRYPT_EAPOL_M4, + !!atoi(value)); } else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) { wpa_s->extra_roc_dur = atoi(value); } else if (os_strcasecmp(cmd, "test_failure") == 0) { @@ -869,10 +879,19 @@ 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); +#ifndef CONFIG_NO_ROBUST_AV } else if (os_strcasecmp(cmd, "disable_scs_support") == 0) { wpa_s->disable_scs_support = !!atoi(value); } else if (os_strcasecmp(cmd, "disable_mscs_support") == 0) { wpa_s->disable_mscs_support = !!atoi(value); +#endif /* CONFIG_NO_ROBUST_AV */ + } else if (os_strcasecmp(cmd, "disable_eapol_g2_tx") == 0) { + wpa_s->disable_eapol_g2_tx = !!atoi(value); + /* Populate value to wpa_sm if already associated. */ + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX, + wpa_s->disable_eapol_g2_tx); + } else if (os_strcasecmp(cmd, "test_assoc_comeback_type") == 0) { + wpa_s->test_assoc_comeback_type = atoi(value); #ifdef CONFIG_DPP } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) { os_free(wpa_s->dpp_config_obj_override); @@ -895,6 +914,8 @@ int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, } else if (os_strcasecmp(cmd, "dpp_ignore_netaccesskey_mismatch") == 0) { wpa_s->dpp_ignore_netaccesskey_mismatch = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_discard_public_action") == 0) { + wpa_s->dpp_discard_public_action = atoi(value); } else if (os_strcasecmp(cmd, "dpp_test") == 0) { dpp_test = atoi(value); #endif /* CONFIG_DPP */ @@ -919,9 +940,20 @@ int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wpa_config_process_global(wpa_s->conf, cmd, -1); } } else if (os_strcasecmp(cmd, "mbo_cell_capa") == 0) { - wpas_mbo_update_cell_capa(wpa_s, atoi(value)); + int val = atoi(value); + + if (val < MBO_CELL_CAPA_AVAILABLE || + val > MBO_CELL_CAPA_NOT_SUPPORTED) + return -1; + + wpas_mbo_update_cell_capa(wpa_s, val); } else if (os_strcasecmp(cmd, "oce") == 0) { - wpa_s->conf->oce = atoi(value); + int val = atoi(value); + + if (val < 0 || val > 3) + return -1; + + wpa_s->conf->oce = val; if (wpa_s->conf->oce) { if ((wpa_s->conf->oce & OCE_STA) && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA)) @@ -961,8 +993,10 @@ int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, return -1; wnm_set_coloc_intf_elems(wpa_s, elems); #endif /* CONFIG_WNM */ +#ifndef CONFIG_NO_ROBUST_AV } else if (os_strcasecmp(cmd, "enable_dscp_policy_capa") == 0) { wpa_s->enable_dscp_policy_capa = !!atoi(value); +#endif /* CONFIG_NO_ROBUST_AV */ } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); @@ -1289,6 +1323,8 @@ static int wpa_supplicant_ctrl_iface_tdls_link_status( #endif /* CONFIG_TDLS */ +#ifndef CONFIG_NO_WMM_AC + static int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd) { char *token, *context = NULL; @@ -1338,6 +1374,8 @@ static int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd) return wpas_wmm_ac_delts(wpa_s, tsid); } +#endif /* CONFIG_NO_WMM_AC */ + #ifdef CONFIG_IEEE80211R static int wpa_supplicant_ctrl_iface_ft_ds( @@ -1346,6 +1384,7 @@ static int wpa_supplicant_ctrl_iface_ft_ds( u8 target_ap[ETH_ALEN]; struct wpa_bss *bss; const u8 *mdie; + bool force = os_strstr(addr, " force") != NULL; if (hwaddr_aton(addr, target_ap)) { wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid " @@ -1361,7 +1400,7 @@ static int wpa_supplicant_ctrl_iface_ft_ds( else mdie = NULL; - return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie); + return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie, force); } #endif /* CONFIG_IEEE80211R */ @@ -2398,11 +2437,12 @@ int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, if (wpa_s->connection_set && (wpa_s->connection_ht || wpa_s->connection_vht || - wpa_s->connection_he)) { + wpa_s->connection_he || wpa_s->connection_eht)) { ret = os_snprintf(pos, end - pos, "wifi_generation=%u\n", - wpa_s->connection_he ? 6 : - (wpa_s->connection_vht ? 5 : 4)); + wpa_s->connection_eht ? 7 : + (wpa_s->connection_he ? 6 : + (wpa_s->connection_vht ? 5 : 4))); if (os_snprintf_error(end - pos, ret)) return pos - buf; pos += ret; @@ -2474,6 +2514,14 @@ int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, return pos - buf; pos += ret; + if (wpa_s->valid_links) { + ret = os_snprintf(pos, end - pos, "ap_mld_addr=" MACSTR "\n", + MAC2STR(wpa_s->ap_mld_addr)); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + #ifdef CONFIG_HS20 if (wpa_s->current_bss && (hs20 = wpa_bss_get_vendor_ie(wpa_s->current_bss, @@ -2611,6 +2659,30 @@ int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, pos += ret; } +#ifdef CONFIG_SME + if (wpa_s->sme.bss_max_idle_period) { + ret = os_snprintf(pos, end - pos, "bss_max_idle_period=%d\n", + wpa_s->sme.bss_max_idle_period); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_SME */ + + if (wpa_s->ssid_verified) { + ret = os_snprintf(pos, end - pos, "ssid_verified=1\n"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + + if (wpa_s->bigtk_set) { + ret = os_snprintf(pos, end - pos, "bigtk_set=1\n"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + #ifdef ANDROID /* * Allow using the STATUS command with default behavior, say for debug, @@ -2619,21 +2691,30 @@ int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, */ if (os_strcmp(params, "-NO_EVENTS")) { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE - "id=%d state=%d BSSID=" MACSTR " SSID=%s", - wpa_s->current_ssid ? wpa_s->current_ssid->id : -1, - wpa_s->wpa_state, - MAC2STR(wpa_s->bssid), - wpa_s->current_ssid && wpa_s->current_ssid->ssid ? - wpa_ssid_txt(wpa_s->current_ssid->ssid, - wpa_s->current_ssid->ssid_len) : ""); + "id=%d state=%d BSSID=" MACSTR " SSID=%s", + wpa_s->current_ssid ? wpa_s->current_ssid->id : -1, + wpa_s->wpa_state, + MAC2STR(wpa_s->bssid), + wpa_s->current_ssid && wpa_s->current_ssid->ssid ? + wpa_ssid_txt(wpa_s->current_ssid->ssid, + wpa_s->current_ssid->ssid_len) : ""); if (wpa_s->wpa_state == WPA_COMPLETED) { struct wpa_ssid *ssid = wpa_s->current_ssid; + char mld_addr[50]; + + mld_addr[0] = '\0'; + if (wpa_s->valid_links) + os_snprintf(mld_addr, sizeof(mld_addr), + " ap_mld_addr=" MACSTR, + MAC2STR(wpa_s->ap_mld_addr)); + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED - "- connection to " MACSTR - " completed %s [id=%d id_str=%s]", - MAC2STR(wpa_s->bssid), "(auth)", - ssid ? ssid->id : -1, - ssid && ssid->id_str ? ssid->id_str : ""); + "- connection to " MACSTR + " completed %s [id=%d id_str=%s]%s", + MAC2STR(wpa_s->bssid), "(auth)", + ssid ? ssid->id : -1, + ssid && ssid->id_str ? ssid->id_str : "", + mld_addr); } } #endif /* ANDROID */ @@ -2641,7 +2722,6 @@ int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s, return pos - buf; } - static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s, char *cmd) { @@ -2857,7 +2937,6 @@ static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher) return pos; } - #ifdef CONFIG_WAPI #define WAPIIE_ELEMENT_ID_LEN 1 #define WAPIIE_LENGTH_LEN 1 @@ -2999,6 +3078,13 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, return pos; pos += ret; } + if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) { + ret = os_snprintf(pos, end - pos, "%sFT/SAE-EXT-KEY", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } #endif /* CONFIG_IEEE80211R */ if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) { ret = os_snprintf(pos, end - pos, "%sEAP-SHA256", @@ -3096,6 +3182,16 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, pos += ret; } +#ifdef CONFIG_SHA384 + if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) { + ret = os_snprintf(pos, end - pos, "%sEAP-SHA384", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } +#endif /* CONFIG_SHA384 */ + pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher); if (data.capabilities & WPA_CAPABILITY_PREAUTH) { @@ -3172,6 +3268,7 @@ static int wpa_supplicant_ctrl_iface_scan_result( #endif wpa_printf(MSG_INFO, "enter wpa_supplicant_ctrl_iface_scan_result"); + mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID); p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE); if (!p2p) @@ -3331,7 +3428,6 @@ static int wpa_supplicant_ctrl_iface_scan_result( return -1; pos += ret; } - #ifdef CONFIG_OPEN_HARMONY_PATCH ret = os_snprintf(pos, end - pos, "\t%s\t", wpa_ssid_txt(bss->ssid, bss->ssid_len)); @@ -3339,10 +3435,10 @@ static int wpa_supplicant_ctrl_iface_scan_result( ret = os_snprintf(pos, end - pos, "\t%s", wpa_ssid_txt(bss->ssid, bss->ssid_len)); #endif + if (os_snprintf_error(end - pos, ret)) return -1; pos += ret; - #ifdef CONFIG_OPEN_HARMONY_PATCH for (int j = 0; j < WLAN_EID_EXTENSION; j++) { if ((j != WLAN_EID_VHT_OPERATION) && (j != WLAN_EID_HT_OPERATION) && @@ -3390,7 +3486,6 @@ static int wpa_supplicant_ctrl_iface_scan_result( } } #endif - ret = os_snprintf(pos, end - pos, "\n"); if (os_snprintf_error(end - pos, ret)) return -1; @@ -3818,7 +3913,8 @@ static int wpa_supplicant_ctrl_iface_update_network( #endif /* CONFIG_BGSCAN */ if (os_strcmp(name, "bssid") != 0 && - os_strcmp(name, "bssid_hint") != 0 && + os_strncmp(name, "bssid_", 6) != 0 && + os_strcmp(name, "scan_freq") != 0 && os_strcmp(name, "priority") != 0) { wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); @@ -3899,7 +3995,6 @@ int wpa_supplicant_ctrl_iface_set_network( wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK %s", os_strstr(cmd, "bssid") ? get_anonymized_result_setnetwork_for_bssid(cmd) : get_anonymized_result_setnetwork(cmd)); } - /* cmd: " " */ name = os_strchr(cmd, ' '); if (name == NULL) @@ -3961,7 +4056,7 @@ int wpa_supplicant_ctrl_iface_set_network( #endif /* CONFIG_DRIVER_NL80211_HISI */ if (ret == 0 && (ssid->bssid_set != prev_bssid_set || - os_memcmp(ssid->bssid, prev_bssid, ETH_ALEN) != 0)) + !ether_addr_equal(ssid->bssid, prev_bssid))) wpas_notify_network_bssid_set_changed(wpa_s, ssid); if (prev_disabled != ssid->disabled && @@ -4640,6 +4735,12 @@ static int ctrl_iface_get_capability_key_mgmt(int res, bool strict, return pos - buf; pos += ret; } + if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE_EXT_KEY) { + ret = os_snprintf(pos, end - pos, " FT-SAE-EXT-KEY"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } #endif /* CONFIG_SAE */ #ifdef CONFIG_SHA384 if (key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384) { @@ -5131,6 +5232,15 @@ static int wpa_supplicant_ctrl_iface_get_capability( } #endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + if (os_strcmp(field, "nan") == 0) { + res = os_snprintf(buf, buflen, "USD"); + if (os_snprintf_error(buflen, res)) + return -1; + return res; + } +#endif /* CONFIG_NAN_USD */ + #ifdef CONFIG_SAE if (os_strcmp(field, "sae") == 0 && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) { @@ -5226,7 +5336,7 @@ static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end) ie_end = ie + 2 + ie[1]; ie += 2; if (ie_end - ie < 2) - return -1; + return 0; info = WPA_GET_LE16(ie); ie += 2; @@ -5238,7 +5348,7 @@ static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end) if (info & BIT(7)) { /* Cache Identifier Included */ if (ie_end - ie < 2) - return -1; + return 0; ret = os_snprintf(pos, end - pos, "fils_cache_id=%02x%02x\n", ie[0], ie[1]); if (os_snprintf_error(end - pos, ret)) @@ -5250,7 +5360,7 @@ static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end) if (info & BIT(8)) { /* HESSID Included */ if (ie_end - ie < ETH_ALEN) - return -1; + return 0; ret = os_snprintf(pos, end - pos, "fils_hessid=" MACSTR "\n", MAC2STR(ie)); if (os_snprintf_error(end - pos, ret)) @@ -5262,7 +5372,7 @@ static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end) realms = (info & (BIT(3) | BIT(4) | BIT(5))) >> 3; if (realms) { if (ie_end - ie < realms * 2) - return -1; + return 0; ret = os_snprintf(pos, end - pos, "fils_realms="); if (os_snprintf_error(end - pos, ret)) return 0; @@ -5284,6 +5394,255 @@ static int print_fils_indication(struct wpa_bss *bss, char *pos, char *end) #endif /* CONFIG_FILS */ +static int print_rnr(struct wpa_bss *bss, char *pos, char *end) +{ + char *start = pos; + const u8 *ie, *ie_end; + unsigned int n = 0; + int ret; + + ie = wpa_bss_get_ie(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT); + if (!ie) + return 0; + + ie_end = ie + 2 + ie[1]; + ie += 2; + + while (ie < ie_end) { + const struct ieee80211_neighbor_ap_info *info = + (const struct ieee80211_neighbor_ap_info *) ie; + const u8 *tbtt_start; + size_t left = ie_end - ie; + + if (left < sizeof(struct ieee80211_neighbor_ap_info)) + return 0; + + left -= sizeof(struct ieee80211_neighbor_ap_info); + if (left < info->tbtt_info_len) + return 0; + + ret = os_snprintf(pos, end - pos, + "ap_info[%u]: tbtt_info: hdr=0x%x, len=%u, op_c=%u, channel=%u, ", + n, *ie, info->tbtt_info_len, + info->op_class, info->channel); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + ie += sizeof(struct ieee80211_neighbor_ap_info); + tbtt_start = ie; + if (info->tbtt_info_len >= 1) { + ret = os_snprintf(pos, end - pos, + "tbtt_offset=%u, ", *ie); + if (os_snprintf_error(end - pos, ret)) + return 0; + + ie++; + pos += ret; + } + + if (info->tbtt_info_len >= 7) { + ret = os_snprintf(pos, end - pos, + "bssid=" MACSTR ", ", + MAC2STR(ie)); + if (os_snprintf_error(end - pos, ret)) + return 0; + + ie += ETH_ALEN; + pos += ret; + } + + if (info->tbtt_info_len >= 11) { + ret = os_snprintf(pos, end - pos, + "short SSID=0x%x, ", + WPA_GET_LE32(ie)); + if (os_snprintf_error(end - pos, ret)) + return 0; + + ie += 4; + pos += ret; + } + + if (info->tbtt_info_len >= 12) { + ret = os_snprintf(pos, end - pos, + "bss_params=0x%x, ", *ie); + if (os_snprintf_error(end - pos, ret)) + return 0; + + ie++; + pos += ret; + } + + if (info->tbtt_info_len >= 13) { + ret = os_snprintf(pos, end - pos, + "PSD=0x%x, ", *ie); + if (os_snprintf_error(end - pos, ret)) + return 0; + + ie++; + pos += ret; + } + + if (info->tbtt_info_len >= 16) { + ret = os_snprintf(pos, end - pos, + "mld ID=%u, link ID=%u", + *ie, *(ie + 1) & 0xF); + if (os_snprintf_error(end - pos, ret)) + return 0; + + ie += 3; + pos += ret; + } + + ie = tbtt_start + info->tbtt_info_len; + + ret = os_snprintf(pos, end - pos, "\n"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + n++; + } + + return pos - start; +} + + +static int print_ml(struct wpa_bss *bss, char *pos, char *end) +{ + const struct ieee80211_eht_ml *ml; + char *start = pos; + const u8 *ie, *ie_end; + u16 ml_control; + u8 common_info_length; + int ret; + + ie = get_ml_ie(wpa_bss_ie_ptr(bss), bss->ie_len, + MULTI_LINK_CONTROL_TYPE_BASIC); + if (!ie) + return 0; + + ie_end = ie + 2 + ie[1]; + ie += 3; + ml = (const struct ieee80211_eht_ml *) ie; + + /* control + common info length + MLD MAC Address */ + if (ie_end - ie < 2 + 1 + ETH_ALEN) + return 0; + + ml_control = le_to_host16(ml->ml_control); + + common_info_length = *(ie + 2); + ret = os_snprintf(pos, end - pos, + "multi-link: control=0x%x, common info len=%u", + ml_control, common_info_length); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + ie += 2; + if (ie_end - ie < common_info_length) + return 0; + + ie++; + common_info_length--; + + if (common_info_length < ETH_ALEN) + return 0; + + ret = os_snprintf(pos, end - pos, ", MLD addr=" MACSTR, MAC2STR(ie)); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + ie += ETH_ALEN; + common_info_length -= ETH_ALEN; + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID) { + if (common_info_length < 1) + return 0; + + ret = os_snprintf(pos, end - pos, ", link ID=%u", *ie & 0x0f); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + ie++; + common_info_length--; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT) { + if (common_info_length < 1) + return 0; + + ret = os_snprintf(pos, end - pos, + ", BSS change parameters=0x%x", *ie); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + ie++; + common_info_length--; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MSD_INFO) { + if (common_info_length < 2) + return 0; + + ret = os_snprintf(pos, end - pos, ", MSD Info=0x%x", + WPA_GET_LE16(ie)); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + ie += 2; + common_info_length -= 2; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA) { + if (common_info_length < 2) + return 0; + + ret = os_snprintf(pos, end - pos, ", EML capabilities=0x%x", + WPA_GET_LE16(ie)); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + ie += 2; + common_info_length -= 2; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA) { + if (common_info_length < 2) + return 0; + + ret = os_snprintf(pos, end - pos, ", MLD capabilities=0x%x", + WPA_GET_LE16(ie)); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + ie += 2; + common_info_length -= 2; + } + + if (ml_control & BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID) { + if (common_info_length < 1) + return 0; + + ret = os_snprintf(pos, end - pos, ", MLD ID=0x%x", *ie); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + ie += 1; + common_info_length--; + } + + ret = os_snprintf(pos, end - pos, "\n"); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + + return pos - start; +} + + static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, unsigned long mask, char *buf, size_t buflen) { @@ -5364,7 +5723,6 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, return 0; pos += ret; } - #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(CONFIG_HILINK_OKC_STA) if (mask & WPA_BSS_MASK_HILINK) { ret = snprintf_s(pos, end - pos, (end - pos - 1), "hilink=%d\n", bss->hilink); @@ -5427,13 +5785,13 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, if (ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SAE_H2E)) { ret = os_snprintf(pos, end - pos, "[SAE-H2E]"); if (os_snprintf_error(end - pos, ret)) - return -1; + return 0; pos += ret; } if (ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SAE_PK)) { ret = os_snprintf(pos, end - pos, "[SAE-PK]"); if (os_snprintf_error(end - pos, ret)) - return -1; + return 0; pos += ret; } osen_ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE); @@ -5749,12 +6107,26 @@ static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, #ifdef CONFIG_FILS if (mask & WPA_BSS_MASK_FILS_INDICATION) { ret = print_fils_indication(bss, pos, end); - if (ret < 0) - return 0; pos += ret; } #endif /* CONFIG_FILS */ + if (!is_zero_ether_addr(bss->mld_addr) && + (mask & WPA_BSS_MASK_AP_MLD_ADDR)) { + ret = os_snprintf(pos, end - pos, + "ap_mld_addr=" MACSTR "\n", + MAC2STR(bss->mld_addr)); + if (os_snprintf_error(end - pos, ret)) + return 0; + pos += ret; + } + + if (mask & WPA_BSS_MASK_RNR) + pos += print_rnr(bss, pos, end); + + if (mask & WPA_BSS_MASK_ML) + pos += print_ml(bss, pos, end); + if (mask & WPA_BSS_MASK_DELIM) { ret = os_snprintf(pos, end - pos, "====\n"); if (os_snprintf_error(end - pos, ret)) @@ -5960,7 +6332,6 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s) { wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication"); /* MLME-DELETEKEYS.request */ -#ifdef CONFIG_MLD_PATCH wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0, KEY_FLAG_GROUP); wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, @@ -5978,27 +6349,7 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s) NULL, 0, KEY_FLAG_PAIRWISE); if (wpa_sm_ext_key_id(wpa_s->wpa)) wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, wpa_s->bssid, 1, 0, - NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE); -#else - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, - 0, KEY_FLAG_GROUP); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, - 0, KEY_FLAG_GROUP); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, - 0, KEY_FLAG_GROUP); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, - 0, KEY_FLAG_GROUP); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, - 0, KEY_FLAG_GROUP); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, - 0, KEY_FLAG_GROUP); - - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL, - 0, KEY_FLAG_PAIRWISE); - if (wpa_sm_ext_key_id(wpa_s->wpa)) - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 1, 0, - NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE); -#endif + NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE); /* MLME-SETPROTECTION.request(None) */ wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid, MLME_SETPROTECTION_PROTECT_TYPE_NONE, @@ -6414,30 +6765,6 @@ static int p2p_ctrl_deliver_data(struct wpa_supplicant *wpa_s, char *cmd) return 0; } -static int parse_freq(int chwidth, int freq2) -{ - if (freq2 < 0) - return -1; - if (freq2) - return CHANWIDTH_80P80MHZ; - - switch (chwidth) { - case 0: - case 20: - case 40: - return CHANWIDTH_USE_HT; - case 80: - return CHANWIDTH_80MHZ; - case 160: - return CHANWIDTH_160MHZ; - default: - wpa_printf(MSG_DEBUG, "Unknown max oper bandwidth: %d", - chwidth); - return -1; - } -} - - int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -6516,7 +6843,6 @@ int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, if (go_intent < 0 || go_intent > 15) return -1; } - #ifdef CONFIG_OPEN_HARMONY_PATCH #ifdef OPEN_HARMONY_MIRACAST_SINK_OPT go_intent = hm_wpas_go_neg_vendor_intent_opt(wpa_s, go_intent, addr); @@ -6527,7 +6853,6 @@ int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, #endif #endif #endif - pos2 = os_strstr(pos, " freq="); if (pos2) { pos2 += 6; @@ -6544,12 +6869,12 @@ int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd, if (pos2) chwidth = atoi(pos2 + 18); - max_oper_chwidth = parse_freq(chwidth, freq2); + max_oper_chwidth = chwidth_freq2_to_ch_width(chwidth, freq2); if (max_oper_chwidth < 0) return -1; if (allow_6ghz && chwidth == 40) - max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ; + max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ; pos2 = os_strstr(pos, " ssid="); if (pos2) { @@ -6837,6 +7162,7 @@ static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s, char *pos; size_t len; struct wpabuf *query, *resp; + int ret; pos = os_strchr(cmd, ' '); if (pos == NULL) @@ -6850,34 +7176,28 @@ static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s, query = wpabuf_alloc(len); if (query == NULL) return -1; - if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) { - wpabuf_free(query); - return -1; - } - + ret = hexstr2bin(cmd, wpabuf_put(query, len), len); + if (ret < 0) + goto err_query; + ret = -1; len = os_strlen(pos); - if (len & 1) { - wpabuf_free(query); - return -1; - } + if (len & 1) + goto err_query; len /= 2; resp = wpabuf_alloc(len); - if (resp == NULL) { - wpabuf_free(query); - return -1; - } - if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) { - wpabuf_free(query); - wpabuf_free(resp); - return -1; - } + if (!resp) + goto err_query; + ret = hexstr2bin(pos, wpabuf_put(resp, len), len); + if (ret < 0) + goto err_resp; - if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) { - wpabuf_free(query); - wpabuf_free(resp); - return -1; - } - return 0; + ret = wpas_p2p_service_add_bonjour(wpa_s, query, resp); + +err_resp: + wpabuf_free(resp); +err_query: + wpabuf_free(query); + return ret; } @@ -7198,14 +7518,14 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd) if (pos) chwidth = atoi(pos + 18); - max_oper_chwidth = parse_freq(chwidth, freq2); + max_oper_chwidth = chwidth_freq2_to_ch_width(chwidth, freq2); if (max_oper_chwidth < 0) return -1; allow_6ghz = os_strstr(cmd, " allow_6ghz") != NULL; if (allow_6ghz && chwidth == 40) - max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ; + max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ; return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht, max_oper_chwidth, pref_freq, he, edmg, @@ -7261,7 +7581,8 @@ int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd) static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, int id, int freq, int vht_center_freq2, int ht40, int vht, int vht_chwidth, - int he, int edmg, bool allow_6ghz) + int he, int edmg, bool allow_6ghz, + const u8 *go_bssid) { struct wpa_ssid *ssid; @@ -7273,10 +7594,11 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, return -1; } - return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, - vht_center_freq2, 0, ht40, vht, + return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, + vht_center_freq2, ht40, vht, vht_chwidth, he, edmg, - NULL, 0, 0, allow_6ghz); + NULL, 0, 0, allow_6ghz, 0, + go_bssid); } @@ -7290,6 +7612,7 @@ int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) int edmg = wpa_s->conf->p2p_go_edmg; int max_oper_chwidth, chwidth = 0, freq2 = 0; char *token, *context = NULL; + u8 go_bssid_buf[ETH_ALEN], *go_bssid = NULL; #ifdef CONFIG_ACS int acs = 0; #endif /* CONFIG_ACS */ @@ -7318,6 +7641,10 @@ int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) persistent = 1; } else if (os_strcmp(token, "allow_6ghz") == 0) { allow_6ghz = true; + } else if (os_strncmp(token, "go_bssid=", 9) == 0) { + if (hwaddr_aton(token + 9, go_bssid_buf)) + return -1; + go_bssid = go_bssid_buf; #ifdef CONFIG_VENDOR_EXT } else if (os_strstr(token, "{") != NULL) { p2p_cmd_parse_add_group(wpa_s, token); @@ -7363,7 +7690,6 @@ int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) wpa_s->p2p_go_do_acs = 0; } #endif /* CONFIG_ACS */ - #ifdef CONFIG_OPEN_HARMONY_PATCH #ifdef CONFIG_P2P_160M if (freq & P2P_160M_MASK) { @@ -7374,14 +7700,14 @@ int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) } #endif #endif - max_oper_chwidth = parse_freq(chwidth, freq2); - wpa_printf(MSG_DEBUG, "wpa_supplicant::p2p_ctrl_group_add freq = %d, max_oper_chwidth = %d, group_id = %d", + max_oper_chwidth = chwidth_freq2_to_ch_width(chwidth, freq2); + wpa_printf(MSG_DEBUG, "wpa_supplicant::p2p_ctrl_group_add freq = %d, max_oper_chwidth = %d, group_id = %d", freq, max_oper_chwidth, group_id); if (max_oper_chwidth < 0) return -1; if (allow_6ghz && chwidth == 40) - max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ; + max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ; /* Allow DFS to be used for Autonomous GO */ wpa_s->p2p_go_allow_dfs = !!(wpa_s->drv_flags & @@ -7391,7 +7717,8 @@ int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd) return p2p_ctrl_group_add_persistent(wpa_s, group_id, freq, freq2, ht40, vht, max_oper_chwidth, he, - edmg, allow_6ghz); + edmg, allow_6ghz, + go_bssid); return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht, max_oper_chwidth, he, edmg, allow_6ghz); @@ -7811,6 +8138,7 @@ int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) return 0; } #endif + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", cmd); @@ -8009,7 +8337,7 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst, dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) { - if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && + if (ether_addr_equal(bss->bssid, bssid) && bss->ssid_len > 0) { found = 1; break; @@ -8176,11 +8504,11 @@ static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf, dialog_token = atoi(pos); if (wpa_s->last_gas_resp && - os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) == 0 && + ether_addr_equal(addr, wpa_s->last_gas_addr) && dialog_token == wpa_s->last_gas_dialog_token) resp = wpa_s->last_gas_resp; else if (wpa_s->prev_gas_resp && - os_memcmp(addr, wpa_s->prev_gas_addr, ETH_ALEN) == 0 && + ether_addr_equal(addr, wpa_s->prev_gas_addr) && dialog_token == wpa_s->prev_gas_dialog_token) resp = wpa_s->prev_gas_resp; else @@ -8543,9 +8871,9 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf, pos = buf; end = buf + buflen; - ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%d\n" + ret = os_snprintf(pos, end - pos, "RSSI=%d\nLINKSPEED=%lu\n" "NOISE=%d\nFREQUENCY=%u\n", - si.current_signal, si.current_txrate / 1000, + si.data.signal, si.data.current_tx_rate / 1000, si.current_noise, si.frequency); if (os_snprintf_error(end - pos, ret)) return -1; @@ -8575,17 +8903,18 @@ static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf, pos += ret; } - if (si.avg_signal) { + if (si.data.avg_signal) { ret = os_snprintf(pos, end - pos, - "AVG_RSSI=%d\n", si.avg_signal); + "AVG_RSSI=%d\n", si.data.avg_signal); if (os_snprintf_error(end - pos, ret)) return -1; pos += ret; } - if (si.avg_beacon_signal) { + if (si.data.avg_beacon_signal) { ret = os_snprintf(pos, end - pos, - "AVG_BEACON_RSSI=%d\n", si.avg_beacon_signal); + "AVG_BEACON_RSSI=%d\n", + si.data.avg_beacon_signal); if (os_snprintf_error(end - pos, ret)) return -1; pos += ret; @@ -8621,7 +8950,7 @@ static int wpas_ctrl_iface_signal_monitor(struct wpa_supplicant *wpa_s, int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, enum wpa_driver_if_type if_type, unsigned int *num, - unsigned int *freq_list) + struct weighted_pcl *freq_list) { char *pos = wpa_s->get_pref_freq_list_override; char *end; @@ -8645,7 +8974,8 @@ int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, pos++; end = os_strchr(pos, ' '); while (pos && (!end || pos < end) && count < *num) { - freq_list[count++] = atoi(pos); + freq_list[count].freq = atoi(pos); + freq_list[count++].flag = WEIGHTED_PCL_GO | WEIGHTED_PCL_CLI; pos = os_strchr(pos, ','); if (pos) pos++; @@ -8660,10 +8990,11 @@ int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, static int wpas_ctrl_iface_get_pref_freq_list( struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { - unsigned int freq_list[100], num = 100, i; + unsigned int num = 100, i; int ret; enum wpa_driver_if_type iface_type; char *pos, *end; + struct weighted_pcl freq_list[100]; pos = buf; end = buf + buflen; @@ -8694,7 +9025,7 @@ static int wpas_ctrl_iface_get_pref_freq_list( for (i = 0; i < num; i++) { ret = os_snprintf(pos, end - pos, "%s%u", - i > 0 ? "," : "", freq_list[i]); + i > 0 ? "," : "", freq_list[i].freq); if (os_snprintf_error(end - pos, ret)) return -1; pos += ret; @@ -8717,11 +9048,9 @@ static int wpas_ctrl_iface_driver_flags(struct wpa_supplicant *wpa_s, pos = buf + ret; end = buf + buflen; - if (strcmp(wpa_s->ifname, "p2p0") == 0) { wpa_s->drv_flags |= WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE; } - for (i = 0; i < 64; i++) { if (wpa_s->drv_flags & (1LLU << i)) { ret = os_snprintf(pos, end - pos, "%s\n", @@ -8781,8 +9110,6 @@ static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf, return ret; } - - int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -8817,6 +9144,7 @@ int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd, #endif /* ANDROID || CONFIG_DRIVER_NL80211_HISI */ } + static int wpa_supplicant_vendor_cmd(struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen) { @@ -8947,6 +9275,19 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpas_dpp_chirp_stop(wpa_s); wpa_s->dpp_pfs_fallback = 0; #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + { + int i; + + for (i = 0; i < DPP_PB_INFO_COUNT; i++) { + struct dpp_pb_info *info; + + info = &wpa_s->dpp_pb[i]; + info->rx_time.sec = 0; + info->rx_time.usec = 0; + } + } +#endif /* CONFIG_DPP3 */ #ifdef CONFIG_TESTING_OPTIONS os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN); os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN); @@ -9014,6 +9355,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->next_ssid = NULL; + wnm_btm_reset(wpa_s); + #ifdef CONFIG_INTERWORKING #ifdef CONFIG_HS20 hs20_cancel_fetch_osu(wpa_s); @@ -9035,6 +9378,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->ft_rsnxe_used = 0; wpa_s->reject_btm_req_reason = 0; wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL); + wpa_sm_set_test_eapol_m2_elems(wpa_s->wpa, NULL); + wpa_sm_set_test_eapol_m4_elems(wpa_s->wpa, NULL); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_ENCRYPT_EAPOL_M2, 0); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_ENCRYPT_EAPOL_M4, 0); os_free(wpa_s->get_pref_freq_list_override); wpa_s->get_pref_freq_list_override = NULL; wpabuf_free(wpa_s->sae_commit_override); @@ -9048,9 +9395,11 @@ 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); +#ifndef CONFIG_NO_ROBUST_AV wpa_s->disable_scs_support = 0; wpa_s->disable_mscs_support = 0; wpa_s->enable_dscp_policy_capa = 0; +#endif /* CONFIG_NO_ROBUST_AV */ wpa_s->oci_freq_override_eapol = 0; wpa_s->oci_freq_override_saquery_req = 0; wpa_s->oci_freq_override_saquery_resp = 0; @@ -9058,6 +9407,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->oci_freq_override_ft_assoc = 0; wpa_s->oci_freq_override_fils_assoc = 0; wpa_s->oci_freq_override_wnm_sleep = 0; + wpa_s->disable_eapol_g2_tx = 0; + wpa_s->test_assoc_comeback_type = -1; #ifdef CONFIG_DPP os_free(wpa_s->dpp_config_obj_override); wpa_s->dpp_config_obj_override = NULL; @@ -9065,6 +9416,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->dpp_discovery_override = NULL; os_free(wpa_s->dpp_groups_override); wpa_s->dpp_groups_override = NULL; + wpa_s->dpp_ignore_netaccesskey_mismatch = 0; + wpa_s->dpp_discard_public_action = 0; dpp_test = DPP_TEST_DISABLED; #endif /* CONFIG_DPP */ #endif /* CONFIG_TESTING_OPTIONS */ @@ -9076,7 +9429,9 @@ 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; +#ifndef CONFIG_NO_ROBUST_AV os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data)); +#endif /* CONFIG_NO_ROBUST_AV */ wpa_bss_flush(wpa_s); if (!dl_list_empty(&wpa_s->bss)) { @@ -9103,7 +9458,9 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) free_bss_tmp_disallowed(wpa_s); +#ifndef CONFIG_NO_ROBUST_AV os_memset(&wpa_s->robust_av, 0, sizeof(struct robust_av_data)); +#endif /* CONFIG_NO_ROBUST_AV */ #ifdef CONFIG_PASN wpas_pasn_auth_stop(wpa_s); @@ -9111,6 +9468,12 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) if (wpa_s->mac_addr_changed && wpa_s->conf->mac_addr == 0) wpas_restore_permanent_mac_addr(wpa_s); + + wpa_s->conf->ignore_old_scan_res = 0; + +#ifdef CONFIG_NAN_USD + wpas_nan_usd_flush(wpa_s); +#endif /* CONFIG_NAN_USD */ } @@ -9348,13 +9711,13 @@ void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, unsigned int manual_scan_only_new = 0; unsigned int scan_only = 0; unsigned int scan_id_count = 0; + unsigned int manual_non_coloc_6ghz = 0; int scan_id[MAX_SCAN_ID]; void (*scan_res_handler)(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); int *manual_scan_freqs = NULL; struct wpa_ssid_value *ssid = NULL, *ns; unsigned int ssid_count = 0; - wpa_printf(MSG_DEBUG, "enter wpas_ctrl_scan"); if (wpa_s != NULL) { @@ -9362,7 +9725,6 @@ void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, } else { wpa_printf(MSG_DEBUG, "wpa_s = NULL"); } - if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { *reply_len = -1; return; @@ -9433,6 +9795,10 @@ void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, os_strstr(params, "wildcard_ssid=1") != NULL; } + pos = os_strstr(params, "non_coloc_6ghz="); + if (pos) + manual_non_coloc_6ghz = !!atoi(pos + 15); + pos = params; while (pos && *pos != '\0') { if (os_strncmp(pos, "ssid ", 5) == 0) { @@ -9502,6 +9868,7 @@ void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, wpa_s->manual_scan_use_id = manual_scan_use_id; wpa_s->manual_scan_only_new = manual_scan_only_new; wpa_s->scan_id_count = scan_id_count; + wpa_s->manual_non_coloc_6ghz = manual_non_coloc_6ghz; os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int)); wpa_s->scan_res_handler = scan_res_handler; os_free(wpa_s->manual_scan_freqs); @@ -9525,6 +9892,7 @@ void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, wpa_s->manual_scan_use_id = manual_scan_use_id; wpa_s->manual_scan_only_new = manual_scan_only_new; wpa_s->scan_id_count = scan_id_count; + wpa_s->manual_non_coloc_6ghz = manual_non_coloc_6ghz; os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int)); wpa_s->scan_res_handler = scan_res_handler; os_free(wpa_s->manual_scan_freqs); @@ -10045,7 +10413,7 @@ static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd) return -1; } - wpa_supplicant_rx_eapol(wpa_s, src, buf, len); + wpa_supplicant_rx_eapol(wpa_s, src, buf, len, FRAME_ENCRYPTION_UNKNOWN); os_free(buf); return 0; @@ -10309,72 +10677,6 @@ done: } -static int wpas_ctrl_test_alloc_fail(struct wpa_supplicant *wpa_s, char *cmd) -{ -#ifdef WPA_TRACE_BFD - char *pos; - - wpa_trace_fail_after = atoi(cmd); - pos = os_strchr(cmd, ':'); - if (pos) { - pos++; - os_strlcpy(wpa_trace_fail_func, pos, - sizeof(wpa_trace_fail_func)); - } else { - wpa_trace_fail_after = 0; - } - return 0; -#else /* WPA_TRACE_BFD */ - return -1; -#endif /* WPA_TRACE_BFD */ -} - - -static int wpas_ctrl_get_alloc_fail(struct wpa_supplicant *wpa_s, - char *buf, size_t buflen) -{ -#ifdef WPA_TRACE_BFD - return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after, - wpa_trace_fail_func); -#else /* WPA_TRACE_BFD */ - return -1; -#endif /* WPA_TRACE_BFD */ -} - - -static int wpas_ctrl_test_fail(struct wpa_supplicant *wpa_s, char *cmd) -{ -#ifdef WPA_TRACE_BFD - char *pos; - - wpa_trace_test_fail_after = atoi(cmd); - pos = os_strchr(cmd, ':'); - if (pos) { - pos++; - os_strlcpy(wpa_trace_test_fail_func, pos, - sizeof(wpa_trace_test_fail_func)); - } else { - wpa_trace_test_fail_after = 0; - } - return 0; -#else /* WPA_TRACE_BFD */ - return -1; -#endif /* WPA_TRACE_BFD */ -} - - -static int wpas_ctrl_get_fail(struct wpa_supplicant *wpa_s, - char *buf, size_t buflen) -{ -#ifdef WPA_TRACE_BFD - return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after, - wpa_trace_test_fail_func); -#else /* WPA_TRACE_BFD */ - return -1; -#endif /* WPA_TRACE_BFD */ -} - - static void wpas_ctrl_event_test_cb(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; @@ -10402,13 +10704,12 @@ static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd) } -static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, - const char *cmd) +static int wpas_get_hex_buf(const char *val, struct wpabuf **ret) { struct wpabuf *buf; size_t len; - len = os_strlen(cmd); + len = os_strlen(val); if (len & 1) return -1; len /= 2; @@ -10417,20 +10718,56 @@ static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, buf = NULL; } else { buf = wpabuf_alloc(len); - if (buf == NULL) + if (!buf) return -1; - if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) { + if (hexstr2bin(val, wpabuf_put(buf, len), len) < 0) { wpabuf_free(buf); return -1; } } + *ret = buf; + return 0; +} + + +static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct wpabuf *buf; + + if (wpas_get_hex_buf(cmd, &buf) < 0) + return -1; wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf); return 0; } +static int wpas_ctrl_test_eapol_m2_elems(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct wpabuf *buf; + + if (wpas_get_hex_buf(cmd, &buf) < 0) + return -1; + wpa_sm_set_test_eapol_m2_elems(wpa_s->wpa, buf); + return 0; +} + + +static int wpas_ctrl_test_eapol_m4_elems(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + struct wpabuf *buf; + + if (wpas_get_hex_buf(cmd, &buf) < 0) + return -1; + wpa_sm_set_test_eapol_m4_elems(wpa_s->wpa, buf); + return 0; +} + + static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s) { u8 zero[WPA_TK_MAX_LEN]; @@ -10443,22 +10780,15 @@ static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s) /* First, use a zero key to avoid any possible duplicate key avoidance * in the driver. */ -#ifdef CONFIG_MLD_PATCH if (wpa_drv_set_key(wpa_s, -1, wpa_s->last_tk_alg, wpa_s->last_tk_addr, -#else - if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr, -#endif wpa_s->last_tk_key_idx, 1, zero, 6, zero, wpa_s->last_tk_len, KEY_FLAG_PAIRWISE_RX_TX) < 0) return -1; /* Set the previously configured key to reset its TSC/RSC */ -#ifdef CONFIG_MLD_PATCH - return wpa_drv_set_key(wpa_s, -1, wpa_s->last_tk_alg, wpa_s->last_tk_addr, -#else - return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr, -#endif + return wpa_drv_set_key(wpa_s, -1, wpa_s->last_tk_alg, + wpa_s->last_tk_addr, wpa_s->last_tk_key_idx, 1, zero, 6, wpa_s->last_tk, wpa_s->last_tk_len, KEY_FLAG_PAIRWISE_RX_TX); @@ -10530,8 +10860,9 @@ static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s, int flow_id = 0; bool protection = false; u8 twt_channel = 0; - u8 control = BIT(4); /* Control field (IEEE P802.11ax/D8.0 Figure - * 9-687): B4 = TWT Information Frame Disabled */ + u8 control = BIT(4); /* Control field (IEEE Std 802.11ax-2021, + * Figure 9-687 - Control field format): + * B4 = TWT Information Frame Disabled */ const char *tok_s; tok_s = os_strstr(cmd, " dialog="); @@ -10555,8 +10886,9 @@ static int wpas_ctrl_iface_send_twt_setup(struct wpa_supplicant *wpa_s, setup_cmd = atoi(tok_s + os_strlen(" setup_cmd=")); tok_s = os_strstr(cmd, " twt="); - if (tok_s) - sscanf(tok_s + os_strlen(" twt="), "%llu", &twt); + if (tok_s && + sscanf(tok_s + os_strlen(" twt="), "%llu", &twt) != 1) + return -1; tok_s = os_strstr(cmd, " requestor="); if (tok_s) @@ -10751,6 +11083,8 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) } +#ifndef CONFIG_NO_RRM + static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep) { struct wpa_supplicant *wpa_s = ctx; @@ -10895,6 +11229,8 @@ static int wpas_ctrl_iface_send_neighbor_rep(struct wpa_supplicant *wpa_s, return ret; } +#endif /* CONFIG_NO_RRM */ + static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s) { @@ -11152,6 +11488,7 @@ static int wpas_ctrl_iface_pmksa_add(struct wpa_supplicant *wpa_s, entry->reauth_time = now.sec + reauth_time; entry->network_ctx = ssid; + os_memcpy(entry->spa, wpa_s->own_addr, ETH_ALEN); entry->external = true; @@ -11234,7 +11571,7 @@ fail: #endif /* CONFIG_FILS */ -static int wpas_ctrl_cmd_debug_level(const char *cmd) +int wpas_ctrl_cmd_debug_level(const char *cmd) { if (os_strcmp(cmd, "PING") == 0 || os_strncmp(cmd, "BSS ", 4) == 0 || @@ -11247,6 +11584,7 @@ static int wpas_ctrl_cmd_debug_level(const char *cmd) } +#ifndef CONFIG_NO_ROBUST_AV static int wpas_ctrl_iface_configure_mscs(struct wpa_supplicant *wpa_s, const char *cmd) { @@ -11315,6 +11653,7 @@ static int wpas_ctrl_iface_configure_mscs(struct wpa_supplicant *wpa_s, return wpas_send_mscs_req(wpa_s); } +#endif /* CONFIG_NO_ROBUST_AV */ #ifdef CONFIG_PASN @@ -11350,6 +11689,8 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd) #ifdef CONFIG_SAE } else if (os_strcmp(token, "akmp=SAE") == 0) { akmp = WPA_KEY_MGMT_SAE; + } else if (os_strcmp(token, "akmp=SAE-EXT-KEY") == 0) { + akmp = WPA_KEY_MGMT_SAE_EXT_KEY; #endif /* CONFIG_SAE */ #ifdef CONFIG_FILS } else if (os_strcmp(token, "akmp=FILS-SHA256") == 0) { @@ -11392,8 +11733,8 @@ static int wpas_ctrl_iface_pasn_start(struct wpa_supplicant *wpa_s, char *cmd) goto out; } - ret = wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, id, - comeback, comeback_len); + ret = wpas_pasn_auth_start(wpa_s, wpa_s->own_addr, bssid, akmp, cipher, + group, id, comeback, comeback_len); out: os_free(comeback); return ret; @@ -11411,126 +11752,56 @@ static int wpas_ctrl_iface_pasn_deauthenticate(struct wpa_supplicant *wpa_s, return -1; } - return wpas_pasn_deauthenticate(wpa_s, bssid); + return wpas_pasn_deauthenticate(wpa_s, wpa_s->own_addr, bssid); } -#endif /* CONFIG_PASN */ -#ifdef CONFIG_MLD_PATCH_EXT -static int wpas_ctrl_iface_mlo_signal_poll(struct wpa_supplicant *wpa_s, - char *buf, size_t buflen) +#ifdef CONFIG_TESTING_OPTIONS +static int wpas_ctrl_iface_pasn_driver(struct wpa_supplicant *wpa_s, + const char *cmd) { - int ret, i; - char *pos, *end; - struct wpa_mlo_signal_info mlo_si; + union wpa_event_data event; + const char *pos = cmd; + u8 addr[ETH_ALEN]; - if (!wpa_s->valid_links) - return -1; + os_memset(&event, 0, sizeof(event)); - ret = wpa_drv_mlo_signal_poll(wpa_s, &mlo_si); - if (ret) + if (os_strncmp(pos, "auth ", 5) == 0) + event.pasn_auth.action = PASN_ACTION_AUTH; + else if (os_strncmp(pos, "del ", 4) == 0) + event.pasn_auth.action = + PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT; + else return -1; - pos = buf; - end = buf + buflen; - - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(mlo_si.valid_links & BIT(i))) - continue; + pos = os_strchr(pos, ' '); + if (!pos) + return -1; + pos++; + while (hwaddr_aton(pos, addr) == 0) { + struct pasn_peer *peer; - ret = os_snprintf(pos, end - pos, - "LINK_ID=%d\nRSSI=%d\nLINKSPEED=%d\n" - "NOISE=%d\nFREQUENCY=%u\n", - i, mlo_si.links[i].current_signal, - mlo_si.links[i].current_txrate / 1000, - mlo_si.links[i].current_noise, - mlo_si.links[i].frequency); - if (os_snprintf_error(end - pos, ret)) + if (event.pasn_auth.num_peers == WPAS_MAX_PASN_PEERS) return -1; - pos += ret; - - if (mlo_si.links[i].chanwidth != CHAN_WIDTH_UNKNOWN) { - ret = os_snprintf(pos, end - pos, "WIDTH=%s\n", - channel_width_to_string( - mlo_si.links[i].chanwidth)); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } - - if (mlo_si.links[i].center_frq1 > 0) { - ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\n", - mlo_si.links[i].center_frq1); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } - - if (mlo_si.links[i].center_frq2 > 0) { - ret = os_snprintf(pos, end - pos, "CENTER_FRQ2=%d\n", - mlo_si.links[i].center_frq2); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } - - if (mlo_si.links[i].avg_signal) { - ret = os_snprintf(pos, end - pos, - "AVG_RSSI=%d\n", - mlo_si.links[i].avg_signal); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } + peer = &event.pasn_auth.peer[event.pasn_auth.num_peers]; + os_memcpy(peer->own_addr, wpa_s->own_addr, ETH_ALEN); + os_memcpy(peer->peer_addr, addr, ETH_ALEN); + event.pasn_auth.num_peers++; - if (mlo_si.links[i].avg_beacon_signal) { - ret = os_snprintf( - pos, end - pos, "AVG_BEACON_RSSI=%d\n", - mlo_si.links[i].avg_beacon_signal); - if (os_snprintf_error(end - pos, ret)) - return -1; - pos += ret; - } + pos = os_strchr(pos, ' '); + if (!pos) + break; + pos++; } - return pos - buf; + wpa_supplicant_event(wpa_s, EVENT_PASN_AUTH, &event); + return 0; } -#endif -#ifdef CONFIG_MLD_PATCH -static int wpas_ctrl_iface_mlo_status(struct wpa_supplicant *wpa_s, - char *buf, size_t buflen) -{ - int ret, i; - char *pos, *end; +#endif /* CONFIG_TESTING_OPTIONS */ - if (!wpa_s->valid_links) - return -1; +#endif /* CONFIG_PASN */ - pos = buf; - end = buf + buflen; - if (!is_zero_ether_addr(wpa_s->ap_mld_addr)) { - ret = os_snprintf(pos, end - pos, "ap_mld_addr=" MACSTR "\n", - MAC2STR(wpa_s->ap_mld_addr)); - if (os_snprintf_error(end - pos, ret)) - return pos - buf; - pos += ret; - } - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(wpa_s->valid_links & BIT(i))) - continue; - ret = os_snprintf(pos, end - pos, "link_id=%d\nfreq=%u\n" - "ap_link_addr=" MACSTR - "\nsta_link_addr=" MACSTR "\n", - i, wpa_s->links[i].freq, - MAC2STR(wpa_s->links[i].bssid), - MAC2STR(wpa_s->links[i].addr)); - if (os_snprintf_error(end - pos, ret)) - return pos - buf; - pos += ret; - } - return pos - buf; -} -#endif +#ifndef CONFIG_NO_ROBUST_AV static int set_type4_frame_classifier(const char *cmd, struct type4_params *param) @@ -11833,7 +12104,16 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s, * [scs_id=] [scs_up=<0-7>] * [classifier_type=<4|10>] * [classifier params based on classifier type] - * [tclas_processing=<0|1>] [scs_id=] ... + * [tclas_processing=<0|1>] + * [qos_characteristics] [min_si=] + * [max_si=] [min_data_rate=] + * [delay_bound=] [max_msdu=] + * [service_start_time=] + * [service_start_time_link_id=] + * [mean_data_rate=] [burst_size=] + * [msdu_lifetime=] + * [msdu_delivery_info=] [medium_time=] + * [scs_id=] ... */ pos1 = os_strstr(cmd, "scs_id="); if (!pos1) { @@ -11846,9 +12126,10 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s, while (pos1) { struct scs_desc_elem *n1; struct active_scs_elem *active_scs_desc; - char *next_scs_desc; + char *next_scs_desc, *pos2; unsigned int num_tclas_elem = 0; - bool scsid_active = false; + bool scsid_active = false, tclas_present = false; + struct qos_characteristics *qos_elem = &desc_elem.qos_char_elem; desc_elem.scs_id = atoi(pos1 + 7); pos1 += 7; @@ -11924,8 +12205,9 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s, pos = os_strstr(pos1, "classifier_type="); if (!pos) { wpa_printf(MSG_ERROR, "classifier type empty"); - goto free_scs_desc; + goto qos_characteristics; } + tclas_present = true; while (pos) { struct tclas_element elem = { 0 }, *n; @@ -11989,22 +12271,133 @@ static int wpas_ctrl_iface_configure_scs(struct wpa_supplicant *wpa_s, desc_elem.tclas_processing = val; } -scs_desc_end: - n1 = os_realloc(scs_data->scs_desc_elems, (num_scs_desc + 1) * - sizeof(struct scs_desc_elem)); - if (!n1) + qos_characteristics: + pos1 = os_strstr(pos1, "qos_characteristics"); + if (!pos1 && !tclas_present) goto free_scs_desc; + if (!pos1) + goto scs_desc_end; - scs_data->scs_desc_elems = n1; - os_memcpy((u8 *) scs_data->scs_desc_elems + num_scs_desc * - sizeof(desc_elem), &desc_elem, sizeof(desc_elem)); - num_scs_desc++; - scs_data->num_scs_desc = num_scs_desc; - pos1 = next_scs_desc; - os_memset(&desc_elem, 0, sizeof(desc_elem)); - } - - return wpas_send_scs_req(wpa_s); + qos_elem->available = true; + if (os_strstr(pos1, "up ")) { + qos_elem->direction = SCS_DIRECTION_UP; + if (tclas_present) { + wpa_printf(MSG_ERROR, + "TCLAS with direction:UP not allowed"); + goto free_scs_desc; + } + } else if (os_strstr(pos1, "down ")) { + qos_elem->direction = SCS_DIRECTION_DOWN; + } else if (os_strstr(pos1, "direct ")) { + qos_elem->direction = SCS_DIRECTION_DIRECT; + } + + pos1 = os_strstr(pos1, "min_si="); + if (!pos1) { + wpa_printf(MSG_ERROR, "Min SI is required"); + goto free_scs_desc; + } + qos_elem->min_si = atoi(pos1 + 7); + + pos1 = os_strstr(pos1, "max_si="); + if (!pos1) { + wpa_printf(MSG_ERROR, "Max SI is required"); + goto free_scs_desc; + } + qos_elem->max_si = atoi(pos1 + 7); + + if (qos_elem->min_si && qos_elem->max_si && + qos_elem->max_si < qos_elem->min_si) { + wpa_printf(MSG_ERROR, "Invalid Max SI"); + goto free_scs_desc; + } + + pos1 = os_strstr(pos1, "min_data_rate="); + if (!pos1) { + wpa_printf(MSG_ERROR, "Min data rate is required"); + goto free_scs_desc; + } + qos_elem->min_data_rate = atoi(pos1 + 14); + + pos1 = os_strstr(pos1, "delay_bound="); + if (!pos1) { + wpa_printf(MSG_ERROR, "Delay Bound is required"); + goto free_scs_desc; + } + qos_elem->delay_bound = atoi(pos1 + 12); + + if (qos_elem->min_data_rate >= BIT(24) || + qos_elem->delay_bound >= BIT(24)) { + wpa_printf(MSG_ERROR, + "Invalid min_data_rate or delay_bound"); + goto free_scs_desc; + } + + pos2 = os_strstr(pos1, "max_msdu="); + if (pos2) { + qos_elem->max_msdu_size = atoi(pos2 + 9); + qos_elem->mask |= SCS_QOS_BIT_MAX_MSDU_SIZE; + } + + pos2 = os_strstr(pos1, "service_start_time="); + if (pos2) { + qos_elem->service_start_time = atoi(pos2 + 19); + qos_elem->mask |= SCS_QOS_BIT_SERVICE_START_TIME; + } + + pos2 = os_strstr(pos1, "service_start_time_link_id="); + if (pos2) { + qos_elem->service_start_time_link_id = atoi(pos2 + 27); + qos_elem->mask |= SCS_QOS_BIT_SERVICE_START_TIME_LINKID; + } + + pos2 = os_strstr(pos1, "mean_data_rate="); + if (pos2) { + qos_elem->mean_data_rate = atoi(pos2 + 15); + qos_elem->mask |= SCS_QOS_BIT_MEAN_DATA_RATE; + } + + pos2 = os_strstr(pos1, "burst_size="); + if (pos2) { + qos_elem->burst_size = atoi(pos2 + 11); + qos_elem->mask |= + SCS_QOS_BIT_DELAYED_BOUNDED_BURST_SIZE; + } + + pos2 = os_strstr(pos1, "msdu_lifetime="); + if (pos2) { + qos_elem->msdu_lifetime = atoi(pos2 + 14); + qos_elem->mask |= SCS_QOS_BIT_MSDU_LIFETIME; + } + + pos2 = os_strstr(pos1, "msdu_delivery_info="); + if (pos2) { + qos_elem->msdu_delivery_info = atoi(pos2 + 19); + qos_elem->mask |= SCS_QOS_BIT_MSDU_DELIVERY_INFO; + } + + pos2 = os_strstr(pos1, "medium_time="); + if (pos2) { + qos_elem->medium_time = atoi(pos2 + 12); + qos_elem->mask |= SCS_QOS_BIT_MEDIUM_TIME; + } + +scs_desc_end: + n1 = os_realloc(scs_data->scs_desc_elems, (num_scs_desc + 1) * + sizeof(struct scs_desc_elem)); + if (!n1) + goto free_scs_desc; + + scs_data->scs_desc_elems = n1; + os_memcpy((u8 *) scs_data->scs_desc_elems + num_scs_desc * + sizeof(desc_elem), &desc_elem, sizeof(desc_elem)); + num_scs_desc++; + scs_data->num_scs_desc = num_scs_desc; + pos1 = next_scs_desc; + os_memset(&desc_elem, 0, sizeof(desc_elem)); + } + + return wpas_send_scs_req(wpa_s); free_scs_desc: free_up_tclas_elem(&desc_elem); @@ -12106,6 +12499,7 @@ static int wpas_ctrl_iface_send_dscp_query(struct wpa_supplicant *wpa_s, return wpas_send_dscp_query(wpa_s, pos + 12, os_strlen(pos + 12)); } +#endif /* CONFIG_NO_ROBUST_AV */ enum { UNKNOWN = 0, LEGACY = 1, @@ -12292,6 +12686,506 @@ static int wpa_supplicant_sta_shell_cmd(struct wpa_supplicant *wpa_s, char *para } } +static int wpas_ctrl_iface_mlo_signal_poll(struct wpa_supplicant *wpa_s, + char *buf, size_t buflen) +{ + int ret, i; + char *pos, *end; + struct wpa_mlo_signal_info mlo_si; + + if (!wpa_s->valid_links) + return -1; + + ret = wpa_drv_mlo_signal_poll(wpa_s, &mlo_si); + if (ret) + return -1; + + pos = buf; + end = buf + buflen; + + for_each_link(mlo_si.valid_links, i) { + ret = os_snprintf(pos, end - pos, + "LINK_ID=%d\nRSSI=%d\nLINKSPEED=%lu\n" + "NOISE=%d\nFREQUENCY=%u\n", + i, mlo_si.links[i].data.signal, + mlo_si.links[i].data.current_tx_rate / 1000, + mlo_si.links[i].current_noise, + mlo_si.links[i].frequency); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + + if (mlo_si.links[i].chanwidth != CHAN_WIDTH_UNKNOWN) { + ret = os_snprintf(pos, end - pos, "WIDTH=%s\n", + channel_width_to_string( + mlo_si.links[i].chanwidth)); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + + if (mlo_si.links[i].center_frq1 > 0) { + ret = os_snprintf(pos, end - pos, "CENTER_FRQ1=%d\n", + mlo_si.links[i].center_frq1); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + + if (mlo_si.links[i].center_frq2 > 0) { + ret = os_snprintf(pos, end - pos, "CENTER_FRQ2=%d\n", + mlo_si.links[i].center_frq2); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + + if (mlo_si.links[i].data.avg_signal) { + ret = os_snprintf(pos, end - pos, + "AVG_RSSI=%d\n", + mlo_si.links[i].data.avg_signal); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + + if (mlo_si.links[i].data.avg_beacon_signal) { + ret = os_snprintf( + pos, end - pos, "AVG_BEACON_RSSI=%d\n", + mlo_si.links[i].data.avg_beacon_signal); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + } + + return pos - buf; +} + + +static int wpas_ctrl_iface_mlo_status(struct wpa_supplicant *wpa_s, + char *buf, size_t buflen) +{ + int ret, i; + char *pos, *end; + + if (!wpa_s->valid_links) + return -1; + + pos = buf; + end = buf + buflen; + + for_each_link(wpa_s->valid_links, i) { + ret = os_snprintf(pos, end - pos, "link_id=%d\nfreq=%u\n" + "ap_link_addr=" MACSTR + "\nsta_link_addr=" MACSTR "\n", + i, wpa_s->links[i].freq, + MAC2STR(wpa_s->links[i].bssid), + MAC2STR(wpa_s->links[i].addr)); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + + return pos - buf; +} + + +#ifdef CONFIG_TESTING_OPTIONS +static int wpas_ctrl_ml_probe(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *token, *context = NULL; + u8 bssid[ETH_ALEN]; + int mld_id = -1, link_id = -1; + struct wpa_bss *bss; + int *freqs; + + os_memset(bssid, 0, sizeof(bssid)); + + while ((token = str_token(cmd, " ", &context))) { + if (os_strncmp(token, "bssid=", 6) == 0) { + if (hwaddr_aton(token + 6, bssid)) + return -1; + } else if (os_strncmp(token, "mld_id=", 7) == 0) { + mld_id = atoi(token + 7); + } else if (os_strncmp(token, "link_id=", 8) == 0) { + link_id = atoi(token + 8); + } + } + + if (is_zero_ether_addr(bssid)) { + wpa_printf(MSG_DEBUG, + "MLD: Failed parsing ML probe request arguments"); + return -1; + } + + bss = wpa_bss_get_bssid(wpa_s, bssid); + if (!bss) { + wpa_printf(MSG_DEBUG, + "MLD: Unknown BSS for " MACSTR, MAC2STR(bssid)); + return -1; + } + + if (wpa_s->sched_scanning || wpa_s->scanning || + (wpa_s->wpa_state > WPA_SCANNING && + wpa_s->wpa_state != WPA_COMPLETED)) { + wpa_printf(MSG_DEBUG, + "MLO: Ongoing scan: Reject ML probe request"); + return -1; + } + + freqs = os_malloc(sizeof(int) * 2); + if (!freqs) + return -1; + + freqs[0] = bss->freq; + freqs[1] = 0; + + wpa_s->manual_scan_passive = 0; + wpa_s->manual_scan_use_id = 0; + wpa_s->manual_scan_only_new = 0; + wpa_s->scan_id_count = 0; + wpa_s->scan_res_handler = scan_only_handler; + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = freqs; + + os_memcpy(wpa_s->ml_probe_bssid, bssid, ETH_ALEN); + wpa_s->ml_probe_mld_id = mld_id; + if (link_id >= 0) + wpa_s->ml_probe_links = BIT(link_id); + + wpa_s->normal_scans = 0; + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_s->after_wps = 0; + wpa_s->known_wps_freq = 0; + wpa_supplicant_req_scan(wpa_s, 0, 0); + + return 0; +} +#endif /* CONFIG_TESTING_OPTIONS */ + + +#ifdef CONFIG_NAN_USD + +static int wpas_ctrl_nan_publish(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + char *token, *context = NULL; + int publish_id; + struct nan_publish_params params; + const char *service_name = NULL; + struct wpabuf *ssi = NULL; + int ret = -1; + enum nan_service_protocol_type srv_proto_type = 0; + int *freq_list = NULL; + + os_memset(¶ms, 0, sizeof(params)); + /* USD shall use both solicited and unsolicited transmissions */ + params.unsolicited = true; + params.solicited = true; + /* USD shall require FSD without GAS */ + params.fsd = true; + params.freq = NAN_USD_DEFAULT_FREQ; + + while ((token = str_token(cmd, " ", &context))) { + if (os_strncmp(token, "service_name=", 13) == 0) { + service_name = token + 13; + continue; + } + + if (os_strncmp(token, "ttl=", 4) == 0) { + params.ttl = atoi(token + 4); + continue; + } + + if (os_strncmp(token, "freq=", 5) == 0) { + params.freq = atoi(token + 5); + continue; + } + + if (os_strncmp(token, "freq_list=", 10) == 0) { + char *pos = token + 10; + + if (os_strcmp(pos, "all") == 0) { + os_free(freq_list); + freq_list = wpas_nan_usd_all_freqs(wpa_s); + params.freq_list = freq_list; + continue; + } + + while (pos && pos[0]) { + int_array_add_unique(&freq_list, atoi(pos)); + pos = os_strchr(pos, ','); + if (pos) + pos++; + } + + params.freq_list = freq_list; + continue; + } + + if (os_strncmp(token, "srv_proto_type=", 15) == 0) { + srv_proto_type = atoi(token + 15); + continue; + } + + if (os_strncmp(token, "ssi=", 4) == 0) { + if (ssi) + goto fail; + ssi = wpabuf_parse_bin(token + 4); + if (!ssi) + goto fail; + continue; + } + + if (os_strcmp(token, "solicited=0") == 0) { + params.solicited = false; + continue; + } + + if (os_strcmp(token, "unsolicited=0") == 0) { + params.unsolicited = false; + continue; + } + + if (os_strcmp(token, "fsd=0") == 0) { + params.fsd = false; + continue; + } + + wpa_printf(MSG_INFO, "CTRL: Invalid NAN_PUBLISH parameter: %s", + token); + goto fail; + } + + publish_id = wpas_nan_usd_publish(wpa_s, service_name, srv_proto_type, + ssi, ¶ms); + if (publish_id > 0) + ret = os_snprintf(buf, buflen, "%d", publish_id); +fail: + wpabuf_free(ssi); + os_free(freq_list); + return ret; +} + + +static int wpas_ctrl_nan_cancel_publish(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *token, *context = NULL; + int publish_id = 0; + + while ((token = str_token(cmd, " ", &context))) { + if (sscanf(token, "publish_id=%i", &publish_id) == 1) + continue; + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_CANCEL_PUBLISH parameter: %s", + token); + return -1; + } + + if (publish_id <= 0) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_CANCEL_PUBLISH publish_id"); + return -1; + } + + wpas_nan_usd_cancel_publish(wpa_s, publish_id); + return 0; +} + + +static int wpas_ctrl_nan_update_publish(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *token, *context = NULL; + int publish_id = 0; + struct wpabuf *ssi = NULL; + int ret = -1; + + while ((token = str_token(cmd, " ", &context))) { + if (sscanf(token, "publish_id=%i", &publish_id) == 1) + continue; + if (os_strncmp(token, "ssi=", 4) == 0) { + if (ssi) + goto fail; + ssi = wpabuf_parse_bin(token + 4); + if (!ssi) + goto fail; + continue; + } + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_UPDATE_PUBLISH parameter: %s", + token); + goto fail; + } + + if (publish_id <= 0) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_UPDATE_PUBLISH publish_id"); + goto fail; + } + + ret = wpas_nan_usd_update_publish(wpa_s, publish_id, ssi); +fail: + wpabuf_free(ssi); + return ret; +} + + +static int wpas_ctrl_nan_subscribe(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + char *token, *context = NULL; + int subscribe_id; + struct nan_subscribe_params params; + const char *service_name = NULL; + struct wpabuf *ssi = NULL; + int ret = -1; + enum nan_service_protocol_type srv_proto_type = 0; + + os_memset(¶ms, 0, sizeof(params)); + params.freq = NAN_USD_DEFAULT_FREQ; + + while ((token = str_token(cmd, " ", &context))) { + if (os_strncmp(token, "service_name=", 13) == 0) { + service_name = token + 13; + continue; + } + + if (os_strcmp(token, "active=1") == 0) { + params.active = true; + continue; + } + + if (os_strncmp(token, "ttl=", 4) == 0) { + params.ttl = atoi(token + 4); + continue; + } + + if (os_strncmp(token, "freq=", 5) == 0) { + params.freq = atoi(token + 5); + continue; + } + + if (os_strncmp(token, "srv_proto_type=", 15) == 0) { + srv_proto_type = atoi(token + 15); + continue; + } + + if (os_strncmp(token, "ssi=", 4) == 0) { + if (ssi) + goto fail; + ssi = wpabuf_parse_bin(token + 4); + if (!ssi) + goto fail; + continue; + } + + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_SUBSCRIBE parameter: %s", + token); + goto fail; + } + + subscribe_id = wpas_nan_usd_subscribe(wpa_s, service_name, + srv_proto_type, ssi, + ¶ms); + if (subscribe_id > 0) + ret = os_snprintf(buf, buflen, "%d", subscribe_id); +fail: + wpabuf_free(ssi); + return ret; +} + + +static int wpas_ctrl_nan_cancel_subscribe(struct wpa_supplicant *wpa_s, + char *cmd) +{ + char *token, *context = NULL; + int subscribe_id = 0; + + while ((token = str_token(cmd, " ", &context))) { + if (sscanf(token, "subscribe_id=%i", &subscribe_id) == 1) + continue; + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_CANCEL_SUBSCRIBE parameter: %s", + token); + return -1; + } + + if (subscribe_id <= 0) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_CANCEL_SUBSCRIBE subscribe_id"); + return -1; + } + + wpas_nan_usd_cancel_subscribe(wpa_s, subscribe_id); + return 0; +} + + +static int wpas_ctrl_nan_transmit(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *token, *context = NULL; + int handle = 0; + int req_instance_id = 0; + struct wpabuf *ssi = NULL; + u8 peer_addr[ETH_ALEN]; + int ret = -1; + + os_memset(peer_addr, 0, ETH_ALEN); + + while ((token = str_token(cmd, " ", &context))) { + if (sscanf(token, "handle=%i", &handle) == 1) + continue; + + if (sscanf(token, "req_instance_id=%i", &req_instance_id) == 1) + continue; + + if (os_strncmp(token, "address=", 8) == 0) { + if (hwaddr_aton(token + 8, peer_addr) < 0) + return -1; + continue; + } + + if (os_strncmp(token, "ssi=", 4) == 0) { + if (ssi) + goto fail; + ssi = wpabuf_parse_bin(token + 4); + if (!ssi) + goto fail; + continue; + } + + wpa_printf(MSG_INFO, + "CTRL: Invalid NAN_TRANSMIT parameter: %s", + token); + goto fail; + } + + if (handle <= 0) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_TRANSMIT handle"); + goto fail; + } + + if (is_zero_ether_addr(peer_addr)) { + wpa_printf(MSG_INFO, + "CTRL: Invalid or missing NAN_TRANSMIT address"); + goto fail; + } + + ret = wpas_nan_usd_transmit(wpa_s, handle, ssi, NULL, peer_addr, + req_instance_id); +fail: + wpabuf_free(ssi); + return ret; +} + +#endif /* CONFIG_NAN_USD */ + + char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { @@ -12916,6 +13810,58 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) { if (wpas_ap_update_beacon(wpa_s)) reply_len = -1; + } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) { + if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) { + if (ap_ctrl_iface_acl_add_mac(wpa_s, + DENY_UNLESS_ACCEPTED, + buf + 19) || + ap_ctrl_iface_set_acl(wpa_s)) + reply_len = -1; + } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) { + if (ap_ctrl_iface_acl_del_mac(wpa_s, + DENY_UNLESS_ACCEPTED, + buf + 19) || + ap_ctrl_iface_set_acl(wpa_s) || + ap_ctrl_iface_disassoc_accept_mac(wpa_s)) + reply_len = -1; + } else if (os_strcmp(buf + 11, "SHOW") == 0) { + reply_len = ap_ctrl_iface_acl_show_mac( + wpa_s, DENY_UNLESS_ACCEPTED, + reply, reply_size); + } else if (os_strcmp(buf + 11, "CLEAR") == 0) { + ap_ctrl_iface_acl_clear_list(wpa_s, + DENY_UNLESS_ACCEPTED); + if (ap_ctrl_iface_set_acl(wpa_s) || + ap_ctrl_iface_disassoc_accept_mac(wpa_s)) + reply_len = -1; + } else { + reply_len = -1; + } + } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) { + if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) { + if (ap_ctrl_iface_acl_add_mac(wpa_s, + ACCEPT_UNLESS_DENIED, + buf + 17) || + ap_ctrl_iface_set_acl(wpa_s) || + ap_ctrl_iface_disassoc_deny_mac(wpa_s)) + reply_len = -1; + } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) { + if (ap_ctrl_iface_acl_del_mac(wpa_s, + ACCEPT_UNLESS_DENIED, + buf + 17) || + ap_ctrl_iface_set_acl(wpa_s)) + reply_len = -1; + } else if (os_strcmp(buf + 9, "SHOW") == 0) { + reply_len = ap_ctrl_iface_acl_show_mac( + wpa_s, ACCEPT_UNLESS_DENIED, reply, reply_size); + } else if (os_strcmp(buf + 9, "CLEAR") == 0) { + ap_ctrl_iface_acl_clear_list(wpa_s, + ACCEPT_UNLESS_DENIED); + if (ap_ctrl_iface_set_acl(wpa_s)) + reply_len = -1; + } else { + reply_len = -1; + } #endif /* CONFIG_AP */ } else if (os_strcmp(buf, "SUSPEND") == 0) { wpas_notify_suspend(wpa_s->global); @@ -12961,6 +13907,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = wpa_supplicant_ctrl_iface_tdls_link_status( wpa_s, buf + 17, reply, reply_size); #endif /* CONFIG_TDLS */ +#ifndef CONFIG_NO_WMM_AC } else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) { reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size); } else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) { @@ -12969,6 +13916,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) { if (wmm_ac_ctrl_delts(wpa_s, buf + 13)) reply_len = -1; +#endif /* CONFIG_NO_WMM_AC */ } else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) { reply_len = wpa_supplicant_signal_poll(wpa_s, reply, reply_size); @@ -12993,7 +13941,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "DRIVER ", 7) == 0) { reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply, reply_size); -#endif /* ANDROID || CONFIG_DRIVER_NL80211_HISI */ +#endif /* ANDROID */ } else if (os_strncmp(buf, "VENDOR ", 7) == 0) { reply_len = wpa_supplicant_vendor_cmd(wpa_s, buf + 7, reply, reply_size); @@ -13011,6 +13959,17 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18)) reply_len = -1; #endif /* CONFIG_WNM */ +#ifdef CONFIG_WNM_AP + } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) { + if (ap_ctrl_iface_disassoc_imminent(wpa_s, buf + 18)) + reply_len = -1; + } else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) { + if (ap_ctrl_iface_ess_disassoc(wpa_s, buf + 13)) + reply_len = -1; + } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) { + if (ap_ctrl_iface_bss_tm_req(wpa_s, buf + 11)) + reply_len = -1; +#endif /* CONFIG_WNM_AP */ } else if (os_strcmp(buf, "FLUSH") == 0) { wpa_supplicant_ctrl_iface_flush(wpa_s); } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) { @@ -13044,21 +14003,27 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0) reply_len = -1; } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) { - if (wpas_ctrl_test_alloc_fail(wpa_s, buf + 16) < 0) + if (testing_set_fail_pattern(true, buf + 16) < 0) reply_len = -1; } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) { - reply_len = wpas_ctrl_get_alloc_fail(wpa_s, reply, reply_size); + reply_len = testing_get_fail_pattern(true, reply, reply_size); } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) { - if (wpas_ctrl_test_fail(wpa_s, buf + 10) < 0) + if (testing_set_fail_pattern(false, buf + 10) < 0) reply_len = -1; } else if (os_strcmp(buf, "GET_FAIL") == 0) { - reply_len = wpas_ctrl_get_fail(wpa_s, reply, reply_size); + reply_len = testing_get_fail_pattern(false, reply, reply_size); } else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) { if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0) reply_len = -1; } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) { if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0) reply_len = -1; + } else if (os_strncmp(buf, "TEST_EAPOL_M2_ELEMS ", 20) == 0) { + if (wpas_ctrl_test_eapol_m2_elems(wpa_s, buf + 20) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "TEST_EAPOL_M4_ELEMS ", 20) == 0) { + if (wpas_ctrl_test_eapol_m4_elems(wpa_s, buf + 20) < 0) + reply_len = -1; } else if (os_strcmp(buf, "RESET_PN") == 0) { if (wpas_ctrl_reset_pn(wpa_s) < 0) reply_len = -1; @@ -13084,6 +14049,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strcmp(buf, "TWT_TEARDOWN") == 0) { if (wpas_ctrl_iface_send_twt_teardown(wpa_s, "")) reply_len = -1; + } else if (os_strncmp(buf, "ML_PROBE_REQ ", 13) == 0) { + if (wpas_ctrl_ml_probe(wpa_s, buf + 13)) + reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) { if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0) @@ -13094,9 +14062,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) { if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0) reply_len = -1; +#ifndef CONFIG_NO_RRM } else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) { if (wpas_ctrl_iface_send_neighbor_rep(wpa_s, buf + 20)) reply_len = -1; +#endif /* CONFIG_NO_RRM */ } else if (os_strcmp(buf, "ERP_FLUSH") == 0) { wpas_ctrl_iface_erp_flush(wpa_s); } else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) { @@ -13209,6 +14179,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (os_snprintf_error(reply_size, reply_len)) reply_len = -1; } + } else if (os_strncmp(buf, "DPP_CONFIGURATOR_SET ", 21) == 0) { + if (dpp_configurator_set(wpa_s->dpp, buf + 20) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DPP_CONFIGURATOR_REMOVE ", 24) == 0) { if (dpp_configurator_remove(wpa_s->dpp, buf + 24) < 0) reply_len = -1; @@ -13233,6 +14206,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) { if (wpas_dpp_pkex_remove(wpa_s, buf + 16) < 0) reply_len = -1; + } else if (os_strncmp(buf, "DPP_CONF_SET ", 13) == 0) { + if (wpas_dpp_conf_set(wpa_s, buf + 12) < 0) + reply_len = -1; #ifdef CONFIG_DPP2 } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) { if (wpas_dpp_controller_start(wpa_s, buf + 20) < 0) @@ -13254,10 +14230,35 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpas_dpp_ca_set(wpa_s, buf + 10) < 0) reply_len = -1; #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + } else if (os_strcmp(buf, "DPP_PUSH_BUTTON") == 0) { + if (wpas_dpp_push_button(wpa_s, NULL) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "DPP_PUSH_BUTTON ", 16) == 0) { + if (wpas_dpp_push_button(wpa_s, buf + 15) < 0) + reply_len = -1; +#endif /* CONFIG_DPP3 */ #endif /* CONFIG_DPP */ - } else if (os_strncmp(buf, "MSCS ", 5) == 0) { - if (wpas_ctrl_iface_configure_mscs(wpa_s, buf + 5)) +#ifdef CONFIG_NAN_USD + } else if (os_strncmp(buf, "NAN_PUBLISH ", 12) == 0) { + reply_len = wpas_ctrl_nan_publish(wpa_s, buf + 12, reply, + reply_size); + } else if (os_strncmp(buf, "NAN_CANCEL_PUBLISH ", 19) == 0) { + if (wpas_ctrl_nan_cancel_publish(wpa_s, buf + 19) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "NAN_UPDATE_PUBLISH ", 19) == 0) { + if (wpas_ctrl_nan_update_publish(wpa_s, buf + 19) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "NAN_SUBSCRIBE ", 14) == 0) { + reply_len = wpas_ctrl_nan_subscribe(wpa_s, buf + 14, reply, + reply_size); + } else if (os_strncmp(buf, "NAN_CANCEL_SUBSCRIBE ", 21) == 0) { + if (wpas_ctrl_nan_cancel_subscribe(wpa_s, buf + 21) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "NAN_TRANSMIT ", 13) == 0) { + if (wpas_ctrl_nan_transmit(wpa_s, buf + 13) < 0) reply_len = -1; +#endif /* CONFIG_NAN_USD */ #ifdef CONFIG_PASN } else if (os_strncmp(buf, "PASN_START ", 11) == 0) { if (wpas_ctrl_iface_pasn_start(wpa_s, buf + 11) < 0) @@ -13269,7 +14270,16 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "PASN_DEAUTH ", 12) == 0) { if (wpas_ctrl_iface_pasn_deauthenticate(wpa_s, buf + 12) < 0) reply_len = -1; +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strncmp(buf, "PASN_DRIVER ", 12) == 0) { + if (wpas_ctrl_iface_pasn_driver(wpa_s, buf + 12) < 0) + reply_len = -1; +#endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_PASN */ +#ifndef CONFIG_NO_ROBUST_AV + } else if (os_strncmp(buf, "MSCS ", 5) == 0) { + if (wpas_ctrl_iface_configure_mscs(wpa_s, buf + 5)) + reply_len = -1; } else if (os_strncmp(buf, "SCS ", 4) == 0) { if (wpas_ctrl_iface_configure_scs(wpa_s, buf + 4)) reply_len = -1; @@ -13279,16 +14289,13 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "DSCP_QUERY ", 11) == 0) { if (wpas_ctrl_iface_send_dscp_query(wpa_s, buf + 11)) reply_len = -1; -#ifdef CONFIG_MLD_PATCH +#endif /* CONFIG_NO_ROBUST_AV */ } else if (os_strcmp(buf, "MLO_STATUS") == 0) { reply_len = wpas_ctrl_iface_mlo_status(wpa_s, reply, reply_size); -#endif -#ifdef CONFIG_MLD_PATCH_EXT } else if (os_strcmp(buf, "MLO_SIGNAL_POLL") == 0) { reply_len = wpas_ctrl_iface_mlo_signal_poll(wpa_s, reply, reply_size); -#endif } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; @@ -13431,15 +14438,18 @@ int wpa_supplicant_global_iface_add(struct wpa_global *global, if (!wpa_s) goto fail; wpa_s->added_vif = create_iface; - return 0; fail: - if (create_iface) + if (create_iface) { + /* wpa_supplicant does not create multi-BSS AP, so collapse to + * WPA_IF_STATION to avoid unwanted clean up in the driver. */ wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, iface.ifname); + } return -1; } + int wpa_supplicant_global_iface_remove(struct wpa_global *global, char *cmd) { @@ -13457,6 +14467,8 @@ int wpa_supplicant_global_iface_remove(struct wpa_global *global, if (!ret && delete_iface) { wpa_printf(MSG_INFO, "CTRL_IFACE deleting the interface '%s'", cmd); + /* wpa_supplicant does not create multi-BSS AP, so collapse to + * WPA_IF_STATION to avoid unwanted clean up in the driver. */ ret = wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, cmd); } return ret; @@ -13576,12 +14588,7 @@ static char * wpas_global_ctrl_iface_ifname(struct wpa_global *global, *resp_len = 1; return resp; } -#ifdef CONFIG_OPEN_HARMONY_PATCH - if (disable_anonymized_print()) { - wpa_printf(MSG_DEBUG, - "wpa global ctrl iface ifname cmd=%s", cmd); - } -#endif + return wpa_supplicant_ctrl_iface_process(wpa_s, cmd, resp_len); } @@ -13919,12 +14926,6 @@ char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global, int reply_len; int level = MSG_EXCESSIVE; -#ifdef CONFIG_OPEN_HARMONY_PATCH - if (disable_anonymized_print()) { - wpa_printf(MSG_DEBUG, - "wpa global ctrl iface process buf=%s", buf); - } -#endif if (os_strncmp(buf, "IFNAME=", 7) == 0) { char *pos = os_strchr(buf + 7, ' '); if (pos) { @@ -14049,5 +15050,4 @@ int p2p_wifi_display_subelem_set(struct wpa_global *global, char *cmd) #else return 0; #endif -} - +} \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.h b/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.h index 41c08060cde0c32621fd3215d989dea2509d5ab6..0c2805b09bad1209b59c46c793cd00acf14e5cce 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.h @@ -121,6 +121,8 @@ void wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s); +int wpas_ctrl_cmd_debug_level(const char *cmd); + int wpa_supplicant_ctrl_iface_add_network(struct wpa_supplicant *wpa_s, char *buf, size_t buflen); int wpa_supplicant_ctrl_iface_remove_network(struct wpa_supplicant *wpa_s, char *cmd); @@ -182,7 +184,6 @@ int hw_magiclink_ctrl_iface_update_network( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, char *name, char *value); #endif /* CONFIG_MAGICLINK */ - #else /* CONFIG_CTRL_IFACE */ static inline struct ctrl_iface_priv * @@ -224,11 +225,9 @@ static inline void wpas_ctrl_radio_work_flush(struct wpa_supplicant *wpa_s) } #endif /* CONFIG_CTRL_IFACE */ - #ifdef CONFIG_HUAWEI_WIFI_RPT #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) int channel_to_frequency(int chan, int band); #endif #endif - #endif /* CTRL_IFACE_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface_named_pipe.c b/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface_named_pipe.c index bddc0414245ef7e7cb95ef44ea058fbcc5e10aa9..2b4e3812ab22b09db9fb1641ee8455f6f0e90e26 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface_named_pipe.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface_named_pipe.c @@ -197,7 +197,7 @@ static int ctrl_open_pipe(struct ctrl_iface_priv *priv) "connected"); if (SetEvent(dst->overlap.hEvent)) break; - /* fall through */ + __attribute__((fallthrough)); default: wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", (int) err); @@ -631,7 +631,7 @@ static int global_open_pipe(struct ctrl_iface_global_priv *priv) "connected"); if (SetEvent(dst->overlap.hEvent)) break; - /* fall through */ + __attribute__((fallthrough)); default: wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d", (int) err); diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface_unix.c index 916ffebd48d885e3c29ea7b317d61befba8df7e9..91480e4eb7d414fbcb695a98803693ff1fcae2f3 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface_unix.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface_unix.c @@ -178,6 +178,9 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, else reply_len = 2; } else { + sockaddr_print(wpas_ctrl_cmd_debug_level(buf), + "Control interface recv command from:", + &from, fromlen); reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf, &reply_len); reply = reply_buf; @@ -687,6 +690,7 @@ havesock: wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); #endif + os_free(buf); return 0; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_dict_helpers.c index e4e9b8da96b7f21cba9b59b5c48828f2651241e2..27003eb44e59da780ac2eec01365e4cef503fb02 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_dict_helpers.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_dict_helpers.c @@ -298,6 +298,25 @@ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, } +/** + * Add a 64-bit unsigned integer entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The 64-bit unsigned integer value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint64_t value) +{ + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64, + &value); +} + + /** * Add a DBus object path entry to the dict. * @@ -342,6 +361,27 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, } +/** + * Add a double entry to the dict. + * + * @param iter_dict A valid DBusMessageIter returned from + * wpa_dbus_dict_open_write() + * @param key The key of the dict item + * @param value The double value + * @return TRUE on success, FALSE on failure + * + */ +dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, + const char *key, + const double value) +{ + if (!key) + return FALSE; + return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE, + &value); +} + + /** * Begin an array entry in the dict * @@ -666,6 +706,59 @@ done: } +#define UINT16_ARRAY_CHUNK_SIZE 18 +#define UINT16_ARRAY_ITEM_SIZE (sizeof(dbus_uint16_t)) + +static dbus_bool_t _wpa_dbus_dict_entry_get_uint16_array( + DBusMessageIter *iter, struct wpa_dbus_dict_entry *entry) +{ + dbus_uint32_t count = 0; + dbus_uint16_t *buffer, *nbuffer; + + entry->uint16array_value = NULL; + entry->array_type = DBUS_TYPE_UINT16; + + buffer = os_calloc(UINT16_ARRAY_CHUNK_SIZE, UINT16_ARRAY_ITEM_SIZE); + if (!buffer) + return FALSE; + + entry->array_len = 0; + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_UINT16) { + dbus_uint16_t value; + + if ((count % UINT16_ARRAY_CHUNK_SIZE) == 0 && count != 0) { + nbuffer = os_realloc_array( + buffer, count + UINT16_ARRAY_CHUNK_SIZE, + UINT16_ARRAY_ITEM_SIZE); + if (!nbuffer) { + os_free(buffer); + wpa_printf(MSG_ERROR, + "dbus: %s out of memory trying to retrieve the uint16 array", + __func__); + return FALSE; + } + buffer = nbuffer; + } + + dbus_message_iter_get_basic(iter, &value); + buffer[count] = value; + entry->array_len = ++count; + dbus_message_iter_next(iter); + } + entry->uint16array_value = buffer; + wpa_hexdump_key(MSG_MSGDUMP, "dbus: uint16 array contents", + entry->bytearray_value, entry->array_len); + + /* Zero-length arrays are valid. */ + if (entry->array_len == 0) { + os_free(entry->uint16array_value); + entry->uint16array_value = NULL; + } + + return TRUE; +} + + #define STR_ARRAY_CHUNK_SIZE 8 #define STR_ARRAY_ITEM_SIZE (sizeof(char *)) @@ -833,6 +926,10 @@ static dbus_bool_t _wpa_dbus_dict_entry_get_array( success = _wpa_dbus_dict_entry_get_byte_array(&iter_array, entry); break; + case DBUS_TYPE_UINT16: + success = _wpa_dbus_dict_entry_get_uint16_array(&iter_array, + entry); + break; case DBUS_TYPE_STRING: success = _wpa_dbus_dict_entry_get_string_array(&iter_array, array_type, @@ -1041,6 +1138,9 @@ void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry) case DBUS_TYPE_BYTE: os_free(entry->bytearray_value); break; + case DBUS_TYPE_UINT16: + os_free(entry->uint16array_value); + break; case DBUS_TYPE_STRING: if (!entry->strarray_value) break; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_dict_helpers.h index 94a0efdbeb1fde6b092325426f53deff2540c2e8..1d33689a8e4412ac3227e5c550ee694663702451 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_dict_helpers.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_dict_helpers.h @@ -46,6 +46,10 @@ dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict, const char *key, const dbus_uint32_t value); +dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict, + const char *key, + const dbus_uint64_t value); + dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict, const char *key, const char *value); @@ -55,6 +59,10 @@ dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict, const char *value, const dbus_uint32_t value_len); +dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict, + const char *key, + const double value); + /* Manual construction and addition of array elements */ dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict, const char *key, const char *type, @@ -131,6 +139,7 @@ struct wpa_dbus_dict_entry { dbus_uint64_t uint64_value; double double_value; char *bytearray_value; + dbus_uint16_t *uint16array_value; char **strarray_value; struct wpabuf **binarray_value; }; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new.c index 150be4594578b6b00a58f091d89b7fb9001ab403..28c05f06876b997881d33c3c6b2df402767f35e3 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new.c @@ -1023,6 +1023,40 @@ void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s) dbus_message_unref(msg); } + +void wpas_dbus_signal_anqp_query_done(struct wpa_supplicant *wpa_s, + const u8 *dst, const char *result) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + DBusMessageIter iter; + char addr[WPAS_DBUS_OBJECT_PATH_MAX], *bssid; + + os_snprintf(addr, WPAS_DBUS_OBJECT_PATH_MAX, MACSTR, MAC2STR(dst)); + bssid = addr; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "ANQPQueryDone"); + if (!msg) + return; + + dbus_message_iter_init_append(msg, &iter); + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bssid) || + !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &result)) + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + else + dbus_connection_send(iface->con, msg, NULL); + dbus_message_unref(msg); +} + #endif /* CONFIG_INTERWORKING */ @@ -1108,6 +1142,29 @@ void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, } +void wpas_dbus_signal_psk_mismatch(struct wpa_supplicant *wpa_s) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "PskMismatch"); + if (!msg) + return; + + dbus_connection_send(iface->con, msg, NULL); + + dbus_message_unref(msg); +} + + /** * wpas_dbus_signal_sta - Send a station related event signal * @wpa_s: %wpa_supplicant network interface data @@ -1612,7 +1669,8 @@ void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s, wpa_s->dbus_new_path) || !wpa_dbus_dict_append_string(&dict_iter, "role", client ? "client" : "GO") || - !wpa_dbus_dict_append_bool(&dict_iter, "persistent", persistent) || + !wpa_dbus_dict_append_bool(&dict_iter, "persistent", + !!persistent) || !wpa_dbus_dict_append_object_path(&dict_iter, "group_object", wpa_s->dbus_groupobj_path) || (ip && @@ -2350,6 +2408,12 @@ void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s, case WPAS_DBUS_PROP_BSS_TM_STATUS: prop = "BSSTMStatus"; break; + case WPAS_DBUS_PROP_MAC_ADDRESS: + prop = "MACAddress"; + break; + case WPAS_DBUS_PROP_SIGNAL_CHANGE: + prop = "SignalChange"; + break; default: wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d", __func__, property); @@ -2416,6 +2480,9 @@ void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s, case WPAS_DBUS_BSS_PROP_AGE: prop = "Age"; break; + case WPAS_DBUS_BSS_PROP_ANQP: + prop = "ANQP"; + break; default: wpa_printf(MSG_ERROR, "dbus: %s: Unknown Property value %d", __func__, property); @@ -2954,6 +3021,11 @@ static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = { NULL, NULL }, + {"ANQP", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}", + wpas_dbus_getter_bss_anqp, + NULL, + NULL, + }, { NULL, NULL, NULL, NULL, NULL, NULL } }; @@ -3693,6 +3765,13 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = { END_ARGS } }, + {"ANQPGet", WPAS_DBUS_NEW_IFACE_INTERFACE, + (WPADBusMethodHandler) wpas_dbus_handler_anqp_get, + { + { "args", "a{sv}", ARG_IN }, + END_ARGS + }, + }, #endif /* CONFIG_INTERWORKING */ { NULL, NULL, NULL, { END_ARGS } } }; @@ -3945,6 +4024,16 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = { wpas_dbus_setter_mac_address_randomization_mask, NULL }, + { "MACAddress", WPAS_DBUS_NEW_IFACE_INTERFACE, "ay", + wpas_dbus_getter_mac_address, + NULL, + NULL, + }, + { "SignalChange", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}", + wpas_dbus_getter_signal_change, + NULL, + NULL + }, { NULL, NULL, NULL, NULL, NULL, NULL } }; @@ -4275,7 +4364,22 @@ static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = { END_ARGS } }, + {"ANQPQueryDone", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "addr", "s", ARG_OUT }, + { "result", "s", ARG_OUT }, + END_ARGS + } + }, #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_HS20 + { "HS20TermsAndConditions", WPAS_DBUS_NEW_IFACE_INTERFACE, + { + { "url", "s", ARG_OUT }, + END_ARGS + } + }, +#endif /* CONFIG_HS20 */ { NULL, NULL, { END_ARGS } } }; @@ -5109,3 +5213,39 @@ int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_P2P */ + + +#ifdef CONFIG_HS20 +/** + * wpas_dbus_signal_hs20_t_c_acceptance - Signals a terms and conditions was + * received. + * + * @wpa_s: %wpa_supplicant network interface data + * @url: URL of the terms and conditions acceptance page. + */ +void wpas_dbus_signal_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s, + const char *url) +{ + struct wpas_dbus_priv *iface; + DBusMessage *msg; + + iface = wpa_s->global->dbus; + + /* Do nothing if the control interface is not turned on */ + if (!iface || !wpa_s->dbus_new_path) + return; + + msg = dbus_message_new_signal(wpa_s->dbus_new_path, + WPAS_DBUS_NEW_IFACE_INTERFACE, + "HS20TermsAndConditions"); + if (!msg) + return; + + if (dbus_message_append_args(msg, DBUS_TYPE_STRING, &url, + DBUS_TYPE_INVALID)) + dbus_connection_send(iface->con, msg, NULL); + else + wpa_printf(MSG_ERROR, "dbus: Failed to construct signal"); + dbus_message_unref(msg); +} +#endif /* CONFIG_HS20 */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new.h index 26bdcb548de85c888eac9fd3fe376cb137eab9fe..952bb422a6d618eadc1d5ac3673672e6cd12afc2 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new.h @@ -38,6 +38,8 @@ enum wpas_dbus_prop { WPAS_DBUS_PROP_ROAM_COMPLETE, WPAS_DBUS_PROP_SESSION_LENGTH, WPAS_DBUS_PROP_BSS_TM_STATUS, + WPAS_DBUS_PROP_MAC_ADDRESS, + WPAS_DBUS_PROP_SIGNAL_CHANGE, }; enum wpas_dbus_bss_prop { @@ -51,6 +53,7 @@ enum wpas_dbus_bss_prop { WPAS_DBUS_BSS_PROP_WPS, WPAS_DBUS_BSS_PROP_IES, WPAS_DBUS_BSS_PROP_AGE, + WPAS_DBUS_BSS_PROP_ANQP, }; enum wpas_dbus_sta_prop { @@ -252,6 +255,7 @@ void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s, const u8 *ie, size_t ie_len, u32 ssi_signal); void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter); +void wpas_dbus_signal_psk_mismatch(struct wpa_supplicant *wpa_s); void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *sta); void wpas_dbus_signal_sta_deauthorized(struct wpa_supplicant *wpa_s, @@ -276,6 +280,10 @@ void wpas_dbus_signal_interworking_ap_added(struct wpa_supplicant *wpa_s, int bh, int bss_load, int conn_capab); void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s); +void wpas_dbus_signal_anqp_query_done(struct wpa_supplicant *wpa_s, + const u8 *dst, const char *result); +void wpas_dbus_signal_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s, + const char *url); #else /* CONFIG_CTRL_IFACE_DBUS_NEW */ @@ -583,6 +591,10 @@ static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s, { } +static inline void wpas_dbus_signal_psk_mismatch(struct wpa_supplicant *wpa_s) +{ +} + static inline void wpas_dbus_signal_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *sta) @@ -643,6 +655,18 @@ void wpas_dbus_signal_interworking_select_done(struct wpa_supplicant *wpa_s) { } +static inline +void wpas_dbus_signal_anqp_query_done(struct wpa_supplicant *wpa_s, + const u8 *dst, const char *result) +{ +} + +static inline +void wpas_dbus_signal_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s, + const char *url) +{ +} + #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ #endif /* CTRL_IFACE_DBUS_H_NEW */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers.c index 0f1863c53569164bd6f80cd046ea229462a11e03..43d5d0cc2245b9a2e6300467c46f24068373a33c 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers.c @@ -152,7 +152,7 @@ static const char * const dont_quote[] = { #ifdef CONFIG_INTERWORKING "roaming_consortium", "required_roaming_consortium", #endif /* CONFIG_INTERWORKING */ - NULL + "mac_value", NULL }; static dbus_bool_t should_quote_opt(const char *key) @@ -206,6 +206,8 @@ dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s, struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; DBusMessageIter iter_dict; char *value = NULL; + bool mac_addr3_set = false; + bool mac_value_set = false; if (!wpa_dbus_dict_open_read(iter, &iter_dict, error)) return FALSE; @@ -315,12 +317,30 @@ 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); + /* + * MAC address policy "3" needs to come with mac_value in + * the message so make sure that it is present (checked after + * the loop - here we just note what has been supplied). + */ + if (os_strcmp(entry.key, "mac_addr") == 0 && + atoi(value) == 3) + mac_addr3_set = true; + if (os_strcmp(entry.key, "mac_value") == 0) + mac_value_set = true; + skip_update: os_free(value); value = NULL; wpa_dbus_dict_entry_clear(&entry); } + if (mac_addr3_set && !mac_value_set) { + wpa_printf(MSG_INFO, "dbus: Invalid mac_addr policy config"); + dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, + "Invalid mac_addr policy config"); + return FALSE; + } + return TRUE; error: @@ -332,6 +352,118 @@ error: } +static int set_cred_property(struct wpa_cred *cred, + struct wpa_dbus_dict_entry *entry) +{ + size_t size; + int ret; + char *value; + + if (entry->type == DBUS_TYPE_ARRAY && + entry->array_type == DBUS_TYPE_STRING) { + dbus_uint32_t i; + + if (entry->array_len <= 0) + return -1; + + for (i = 0; i < entry->array_len; i++) { + if (should_quote_opt(entry->key)) { + size = os_strlen(entry->strarray_value[i]); + + size += 3; + value = os_zalloc(size); + if (!value) + return -1; + + ret = os_snprintf(value, size, "\"%s\"", + entry->strarray_value[i]); + if (os_snprintf_error(size, ret)) { + os_free(value); + return -1; + } + } else { + value = os_strdup(entry->strarray_value[i]); + if (!value) + return -1; + } + + ret = wpa_config_set_cred(cred, entry->key, value, 0); + os_free(value); + if (ret < 0) + return -1; + } + return 0; + } + + if (entry->type == DBUS_TYPE_ARRAY && + entry->array_type == DBUS_TYPE_BYTE) { + if (entry->array_len <= 0) + return -1; + + size = entry->array_len * 2 + 1; + value = os_zalloc(size); + if (!value) + return -1; + + ret = wpa_snprintf_hex(value, size, + (u8 *) entry->bytearray_value, + entry->array_len); + if (ret <= 0) { + os_free(value); + return -1; + } + } else if (entry->type == DBUS_TYPE_STRING) { + if (should_quote_opt(entry->key)) { + size = os_strlen(entry->str_value); + + size += 3; + value = os_zalloc(size); + if (!value) + return -1; + + ret = os_snprintf(value, size, "\"%s\"", + entry->str_value); + if (os_snprintf_error(size, ret)) { + os_free(value); + return -1; + } + } else { + value = os_strdup(entry->str_value); + if (!value) + return -1; + } + } else if (entry->type == DBUS_TYPE_UINT32) { + size = 50; + value = os_zalloc(size); + if (!value) + return -1; + + ret = os_snprintf(value, size, "%u", entry->uint32_value); + if (os_snprintf_error(size, ret)) { + os_free(value); + return -1; + } + } else if (entry->type == DBUS_TYPE_INT32) { + size = 50; + value = os_zalloc(size); + if (!value) + return -1; + + ret = os_snprintf(value, size, "%d", entry->int32_value); + if (os_snprintf_error(size, ret)) { + os_free(value); + return -1; + } + } else { + return -1; + } + + ret = wpa_config_set_cred(cred, entry->key, value, 0); + os_free(value); + return ret; +} + + /** * set_cred_properties - Set the properties of a configured credential * @wpa_s: wpa_supplicant structure for a network interface @@ -348,91 +480,28 @@ static dbus_bool_t set_cred_properties(struct wpa_supplicant *wpa_s, { struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; DBusMessageIter iter_dict; - char *value = NULL; if (!wpa_dbus_dict_open_read(iter, &iter_dict, error)) return FALSE; while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { - size_t size = 50; - int ret; - - if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) - goto error; - - value = NULL; - if (entry.type == DBUS_TYPE_ARRAY && - entry.array_type == DBUS_TYPE_BYTE) { - if (entry.array_len <= 0) - goto error; + int res; - size = entry.array_len * 2 + 1; - value = os_zalloc(size); - if (!value) - goto error; - - ret = wpa_snprintf_hex(value, size, - (u8 *) entry.bytearray_value, - entry.array_len); - if (ret <= 0) - goto error; - } else if (entry.type == DBUS_TYPE_STRING) { - if (should_quote_opt(entry.key)) { - size = os_strlen(entry.str_value); - - size += 3; - value = os_zalloc(size); - if (!value) - goto error; - - ret = os_snprintf(value, size, "\"%s\"", - entry.str_value); - if (os_snprintf_error(size, ret)) - goto error; - } else { - value = os_strdup(entry.str_value); - if (!value) - goto error; - } - } else if (entry.type == DBUS_TYPE_UINT32) { - value = os_zalloc(size); - if (!value) - goto error; - - ret = os_snprintf(value, size, "%u", - entry.uint32_value); - if (os_snprintf_error(size, ret)) - goto error; - } else if (entry.type == DBUS_TYPE_INT32) { - value = os_zalloc(size); - if (!value) - goto error; - - ret = os_snprintf(value, size, "%d", - entry.int32_value); - if (os_snprintf_error(size, ret)) - goto error; + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { + res = -1; } else { - goto error; + res = set_cred_property(cred, &entry); + wpa_dbus_dict_entry_clear(&entry); } - ret = wpa_config_set_cred(cred, entry.key, value, 0); - if (ret < 0) - goto error; - - os_free(value); - value = NULL; - wpa_dbus_dict_entry_clear(&entry); + if (res < 0) { + dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, + "invalid message format"); + return FALSE; + } } return TRUE; - -error: - os_free(value); - wpa_dbus_dict_entry_clear(&entry); - dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, - "invalid message format"); - return FALSE; } @@ -704,6 +773,9 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, char *ifname = NULL; char *confname = NULL; char *bridge_ifname = NULL; + bool create_iface = false; + u8 *if_addr = NULL; + enum wpa_driver_if_type if_type = WPA_IF_STATION; dbus_message_iter_init(message, &iter); @@ -740,6 +812,33 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, wpa_dbus_dict_entry_clear(&entry); if (bridge_ifname == NULL) goto oom; + } else if (os_strcmp(entry.key, "Create") == 0 && + entry.type == DBUS_TYPE_BOOLEAN) { + create_iface = entry.bool_value; + wpa_dbus_dict_entry_clear(&entry); + } else if (os_strcmp(entry.key, "Type") == 0 && + entry.type == DBUS_TYPE_STRING) { + if (os_strcmp(entry.str_value, "sta") == 0) { + if_type = WPA_IF_STATION; + } else if (os_strcmp(entry.str_value, "ap") == 0) { + if_type = WPA_IF_AP_BSS; + } else { + wpa_dbus_dict_entry_clear(&entry); + goto error; + } + wpa_dbus_dict_entry_clear(&entry); + } else if (os_strcmp(entry.key, "Address") == 0 && + entry.type == DBUS_TYPE_STRING) { + if_addr = os_malloc(ETH_ALEN); + if (if_addr == NULL) { + wpa_dbus_dict_entry_clear(&entry); + goto oom; + } + if (hwaddr_aton(entry.str_value, if_addr)) { + wpa_dbus_dict_entry_clear(&entry); + goto error; + } + wpa_dbus_dict_entry_clear(&entry); } else { wpa_dbus_dict_entry_clear(&entry); goto error; @@ -761,6 +860,23 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, struct wpa_supplicant *wpa_s; struct wpa_interface iface; + if (create_iface) { + u8 mac_addr[ETH_ALEN]; + + wpa_printf(MSG_DEBUG, + "%s[dbus]: creating an interface '%s'", + __func__, ifname); + if (!global->ifaces || + wpa_drv_if_add(global->ifaces, if_type, ifname, + if_addr, NULL, NULL, mac_addr, + NULL) < 0) { + reply = wpas_dbus_error_unknown_error( + message, + "interface creation failed."); + goto out; + } + } + os_memset(&iface, 0, sizeof(iface)); iface.driver = driver; iface.ifname = ifname; @@ -771,6 +887,7 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, if (wpa_s && wpa_s->dbus_new_path) { const char *path = wpa_s->dbus_new_path; + wpa_s->added_vif = create_iface; reply = dbus_message_new_method_return(message); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); @@ -778,6 +895,13 @@ DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message, reply = wpas_dbus_error_unknown_error( message, "wpa_supplicant couldn't grab this interface."); + if (create_iface) { + /* wpa_supplicant does not create multi-BSS AP, + * so collapse to WPA_IF_STATION to avoid + * unwanted clean up in the driver. */ + wpa_drv_if_remove(global->ifaces, + WPA_IF_STATION, ifname); + } } } @@ -786,6 +910,7 @@ out: os_free(ifname); os_free(confname); os_free(bridge_ifname); + os_free(if_addr); return reply; error: @@ -814,19 +939,38 @@ DBusMessage * wpas_dbus_handler_remove_interface(DBusMessage *message, struct wpa_supplicant *wpa_s; char *path; DBusMessage *reply = NULL; + bool delete_iface; dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); wpa_s = get_iface_by_dbus_path(global, path); - if (wpa_s == NULL) + if (!wpa_s) { reply = wpas_dbus_error_iface_unknown(message); - else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) { + goto out; + } + delete_iface = wpa_s->added_vif; + if (wpa_supplicant_remove_iface(global, wpa_s, 0)) { reply = wpas_dbus_error_unknown_error( message, "wpa_supplicant couldn't remove this interface."); + goto out; + } + + if (delete_iface) { + wpa_printf(MSG_DEBUG, "%s[dbus]: deleting the interface '%s'", + __func__, wpa_s->ifname); + /* wpa_supplicant does not create multi-BSS AP, so collapse to + * WPA_IF_STATION to avoid unwanted clean up in the driver. */ + if (wpa_drv_if_remove(global->ifaces, WPA_IF_STATION, + wpa_s->ifname)) { + reply = wpas_dbus_error_unknown_error( + message, + "wpa_supplicant couldn't delete this interface."); + } } +out: return reply; } @@ -908,8 +1052,10 @@ dbus_bool_t wpas_dbus_getter_debug_timestamp( const struct wpa_dbus_property_desc *property_desc, DBusMessageIter *iter, DBusError *error, void *user_data) { + dbus_bool_t b = wpa_debug_timestamp ? TRUE : FALSE; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, - &wpa_debug_timestamp, error); + &b, error); } @@ -927,8 +1073,10 @@ dbus_bool_t wpas_dbus_getter_debug_show_keys( const struct wpa_dbus_property_desc *property_desc, DBusMessageIter *iter, DBusError *error, void *user_data) { + dbus_bool_t b = wpa_debug_show_keys ? TRUE : FALSE; + return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN, - &wpa_debug_show_keys, error); + &b, error); } @@ -1121,7 +1269,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[13]; + const char *capabilities[14]; size_t num_items = 0; struct wpa_global *global = user_data; struct wpa_supplicant *wpa_s; @@ -1177,6 +1325,9 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( #endif /* CONFIG_SUITEB192 */ if (ext_key_id_supported) capabilities[num_items++] = "extended_key_id"; +#ifndef CONFIG_WEP + capabilities[num_items++] = "wep_disabled"; +#endif /* !CONFIG_WEP */ return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_STRING, @@ -1443,10 +1594,10 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, } -static int wpas_dbus_get_scan_allow_roam(DBusMessage *message, - DBusMessageIter *var, - dbus_bool_t *allow, - DBusMessage **reply) +static int wpas_dbus_get_scan_boolean(DBusMessage *message, + DBusMessageIter *var, + dbus_bool_t *allow, + DBusMessage **reply) { if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) { wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean", @@ -1478,7 +1629,10 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, char *key = NULL, *type = NULL; struct wpa_driver_scan_params params; size_t i; - dbus_bool_t allow_roam = 1; + dbus_bool_t allow_roam = TRUE; + dbus_bool_t non_coloc_6ghz = FALSE; + dbus_bool_t scan_6ghz_only = FALSE; + bool custom_ies = false; os_memset(¶ms, 0, sizeof(params)); @@ -1505,15 +1659,28 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, if (wpas_dbus_get_scan_ies(message, &variant_iter, ¶ms, &reply) < 0) goto out; + custom_ies = true; } else if (os_strcmp(key, "Channels") == 0) { if (wpas_dbus_get_scan_channels(message, &variant_iter, ¶ms, &reply) < 0) goto out; } else if (os_strcmp(key, "AllowRoam") == 0) { - if (wpas_dbus_get_scan_allow_roam(message, - &variant_iter, - &allow_roam, - &reply) < 0) + if (wpas_dbus_get_scan_boolean(message, + &variant_iter, + &allow_roam, + &reply) < 0) + goto out; + } else if (os_strcmp(key, "NonColoc6GHz") == 0) { + if (wpas_dbus_get_scan_boolean(message, + &variant_iter, + &non_coloc_6ghz, + &reply) < 0) + goto out; + } else if (os_strcmp(key, "6GHzOnly") == 0) { + if (wpas_dbus_get_scan_boolean(message, + &variant_iter, + &scan_6ghz_only, + &reply) < 0) goto out; } else { wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s", @@ -1532,6 +1699,13 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, goto out; } + if (non_coloc_6ghz) + params.non_coloc_6ghz = 1; + + if (scan_6ghz_only && !params.freqs) + wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, ¶ms, + true, false, false); + if (os_strcmp(type, "passive") == 0) { if (params.num_ssids || params.extra_ies_len) { wpa_printf(MSG_DEBUG, @@ -1552,10 +1726,12 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, if (params.freqs && params.freqs[0]) { wpa_s->last_scan_req = MANUAL_SCAN_REQ; if (wpa_supplicant_trigger_scan(wpa_s, - ¶ms)) { + ¶ms, + false, false)) { reply = wpas_dbus_error_scan_error( message, "Scan request rejected"); + goto out; } } else { wpa_s->scan_req = MANUAL_SCAN_REQ; @@ -1578,9 +1754,11 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message, } wpa_s->last_scan_req = MANUAL_SCAN_REQ; - if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) { + if (wpa_supplicant_trigger_scan(wpa_s, ¶ms, !custom_ies, + false)) { reply = wpas_dbus_error_scan_error( message, "Scan request rejected"); + goto out; } } else { wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s", @@ -1781,6 +1959,7 @@ DBusMessage * wpas_dbus_handler_remove_all_creds(DBusMessage *message, #ifdef CONFIG_INTERWORKING + DBusMessage * wpas_dbus_handler_interworking_select(DBusMessage *message, struct wpa_supplicant *wpa_s) @@ -1801,6 +1980,111 @@ wpas_dbus_handler_interworking_select(DBusMessage *message, return reply; } + + +DBusMessage * +wpas_dbus_handler_anqp_get(DBusMessage *message, struct wpa_supplicant *wpa_s) +{ + DBusMessageIter iter, iter_dict; + struct wpa_dbus_dict_entry entry; + int ret; + u8 dst_addr[ETH_ALEN]; + bool is_addr_present = false; + unsigned int freq = 0; +#define MAX_ANQP_INFO_ID 100 /* Max info ID count from CLI implementation */ + u16 id[MAX_ANQP_INFO_ID]; + size_t num_id = 0; + u32 subtypes = 0; + u32 mbo_subtypes = 0; + size_t i; + + dbus_message_iter_init(message, &iter); + + if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) + return wpas_dbus_error_invalid_args(message, NULL); + + while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { + if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) + return wpas_dbus_error_invalid_args(message, NULL); + + if (os_strcmp(entry.key, "addr") == 0 && + entry.type == DBUS_TYPE_STRING) { + if (hwaddr_aton(entry.str_value, dst_addr)) { + wpa_printf(MSG_DEBUG, + "%s[dbus]: Invalid address '%s'", + __func__, entry.str_value); + wpa_dbus_dict_entry_clear(&entry); + return wpas_dbus_error_invalid_args( + message, "invalid address"); + } + + is_addr_present = true; + } else if (os_strcmp(entry.key, "freq") == 0 && + entry.type == DBUS_TYPE_UINT32) { + freq = entry.uint32_value; + } else if (os_strcmp(entry.key, "ids") == 0 && + entry.type == DBUS_TYPE_ARRAY && + entry.array_type == DBUS_TYPE_UINT16) { + for (i = 0; i < entry.array_len && + num_id < MAX_ANQP_INFO_ID; i++) { + id[num_id] = entry.uint16array_value[i]; + num_id++; + } + } else if (os_strcmp(entry.key, "hs20_ids") == 0 && + entry.type == DBUS_TYPE_ARRAY && + entry.array_type == DBUS_TYPE_BYTE) { + for (i = 0; i < entry.array_len; i++) { + int num = entry.bytearray_value[i]; + + if (num <= 0 || num > 31) { + wpa_dbus_dict_entry_clear(&entry); + return wpas_dbus_error_invalid_args( + message, + "invalid HS20 ANQP id"); + } + subtypes |= BIT(num); + } + } else if (os_strcmp(entry.key, "mbo_ids") == 0 && + entry.type == DBUS_TYPE_ARRAY && + entry.array_type == DBUS_TYPE_BYTE) { + for (i = 0; i < entry.array_len; i++) { + int num = entry.bytearray_value[i]; + + if (num <= 0 || num > MAX_MBO_ANQP_SUBTYPE) { + wpa_dbus_dict_entry_clear(&entry); + return wpas_dbus_error_invalid_args( + message, "invalid MBO ANQP id"); + } + mbo_subtypes |= BIT(num); + } + } else { + wpa_dbus_dict_entry_clear(&entry); + return wpas_dbus_error_invalid_args( + message, "unsupported parameter"); + } + + wpa_dbus_dict_entry_clear(&entry); + } + + if (!is_addr_present) { + wpa_printf(MSG_DEBUG, + "%s[dbus]: address not provided", __func__); + return wpas_dbus_error_invalid_args(message, + "address not provided"); + } + + ret = anqp_send_req(wpa_s, dst_addr, freq, id, num_id, subtypes, + mbo_subtypes); + if (ret < 0) { + wpa_printf(MSG_ERROR, "%s[dbus]: failed to send ANQP request", + __func__); + return wpas_dbus_error_unknown_error( + message, "error sending ANQP request"); + } + + return NULL; +} + #endif /* CONFIG_INTERWORKING */ @@ -1819,7 +2103,7 @@ DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message, { struct wpa_signal_info si; DBusMessage *reply = NULL; - DBusMessageIter iter, iter_dict, variant_iter; + DBusMessageIter iter; int ret; ret = wpa_drv_signal_poll(wpa_s, &si); @@ -1834,31 +2118,7 @@ DBusMessage * wpas_dbus_handler_signal_poll(DBusMessage *message, dbus_message_iter_init_append(reply, &iter); - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, - "a{sv}", &variant_iter) || - !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) || - !wpa_dbus_dict_append_int32(&iter_dict, "rssi", - si.current_signal) || - !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed", - si.current_txrate / 1000) || - !wpa_dbus_dict_append_int32(&iter_dict, "noise", - si.current_noise) || - !wpa_dbus_dict_append_uint32(&iter_dict, "frequency", - si.frequency) || - (si.chanwidth != CHAN_WIDTH_UNKNOWN && - !wpa_dbus_dict_append_string( - &iter_dict, "width", - channel_width_to_string(si.chanwidth))) || - (si.center_frq1 > 0 && si.center_frq2 > 0 && - (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1", - si.center_frq1) || - !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2", - si.center_frq2))) || - (si.avg_signal && - !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi", - si.avg_signal)) || - !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || - !dbus_message_iter_close_container(&iter, &variant_iter)) + if (wpas_dbus_new_from_signal_information(&iter, &si) != 0) goto nomem; return reply; @@ -3128,11 +3388,15 @@ dbus_bool_t wpas_dbus_getter_capabilities( if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) { if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "wpa-eap") || - ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) && + &iter_array, "wpa-eap")) + goto nomem; + +#ifdef CONFIG_IEEE80211R + if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) && !wpa_dbus_dict_string_array_add_element( - &iter_array, "wpa-ft-eap"))) + &iter_array, "wpa-ft-eap")) goto nomem; +#endif /* CONFIG_IEEE80211R */ /* TODO: Ensure that driver actually supports sha256 encryption. */ if (!wpa_dbus_dict_string_array_add_element( @@ -3143,12 +3407,16 @@ dbus_bool_t wpas_dbus_getter_capabilities( if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { if (!wpa_dbus_dict_string_array_add_element( - &iter_array, "wpa-psk") || - ((capa.key_mgmt & + &iter_array, "wpa-psk")) + goto nomem; + +#ifdef CONFIG_IEEE80211R + if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) && !wpa_dbus_dict_string_array_add_element( - &iter_array, "wpa-ft-psk"))) + &iter_array, "wpa-ft-psk")) goto nomem; +#endif /* CONFIG_IEEE80211R */ /* TODO: Ensure that driver actually supports sha256 encryption. */ if (!wpa_dbus_dict_string_array_add_element( @@ -3951,7 +4219,7 @@ dbus_bool_t wpas_dbus_getter_current_auth_mode( const char *auth_mode; char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX]; - if (wpa_s->wpa_state != WPA_COMPLETED) { + if (wpa_s->wpa_state <= WPA_SCANNING) { auth_mode = "INACTIVE"; } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { @@ -4183,6 +4451,7 @@ dbus_bool_t wpas_dbus_getter_pkcs11_engine_path( const struct wpa_dbus_property_desc *property_desc, DBusMessageIter *iter, DBusError *error, void *user_data) { + #ifndef CONFIG_PKCS11_ENGINE_PATH struct wpa_supplicant *wpa_s = user_data; @@ -4321,6 +4590,7 @@ dbus_bool_t wpas_dbus_setter_iface_global( const char *new_value = NULL; char buf[250]; size_t combined_len; + int wpa_sm_param; int ret; if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING, @@ -4339,6 +4609,35 @@ dbus_bool_t wpas_dbus_setter_iface_global( if (!new_value[0]) new_value = "NULL"; + wpa_sm_param = -1; + if (os_strcmp(property_desc->data, "dot11RSNAConfigPMKLifetime") == 0) + wpa_sm_param = RSNA_PMK_LIFETIME; + else if (os_strcmp(property_desc->data, + "dot11RSNAConfigPMKReauthThreshold") == 0) + wpa_sm_param = RSNA_PMK_REAUTH_THRESHOLD; + else if (os_strcmp(property_desc->data, "dot11RSNAConfigSATimeout") == 0) + wpa_sm_param = RSNA_SA_TIMEOUT; + + if (wpa_sm_param != -1) { + char *end; + int val; + + val = strtol(new_value, &end, 0); + if (*end) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "Invalid value for property %s", + property_desc->dbus_property); + return FALSE; + } + + if (wpa_sm_set_param(wpa_s->wpa, wpa_sm_param, val)) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "Failed to apply interface property %s", + property_desc->dbus_property); + return FALSE; + } + } + ret = os_snprintf(buf, combined_len, "%s=%s", property_desc->data, new_value); if (os_snprintf_error(combined_len, ret)) { @@ -4596,6 +4895,27 @@ dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask( } +/** + * wpas_dbus_getter_mac_address - Get MAC address of an interface + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: a list of stations + * + * Getter for "MACAddress" property. + */ +dbus_bool_t wpas_dbus_getter_mac_address( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + + return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, + wpa_s->own_addr, ETH_ALEN, + error); +} + + /** * wpas_dbus_getter_sta_address - Return the address of a connected station * @iter: Pointer to incoming dbus message iter @@ -5104,7 +5424,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop( DBusMessageIter iter_dict, variant_iter; const char *group; const char *pairwise[5]; /* max 5 pairwise ciphers is supported */ - const char *key_mgmt[18]; /* max 18 key managements may be supported */ + const char *key_mgmt[19]; /* max 19 key managements may be supported */ int n; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, @@ -5158,6 +5478,8 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop( key_mgmt[n++] = "sae-ext-key"; if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE) key_mgmt[n++] = "ft-sae"; + if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) + key_mgmt[n++] = "ft-sae-ext-key"; #endif /* CONFIG_SAE */ #ifdef CONFIG_OWE if (ie_data->key_mgmt & WPA_KEY_MGMT_OWE) @@ -5165,6 +5487,10 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop( #endif /* CONFIG_OWE */ if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE) key_mgmt[n++] = "wpa-none"; +#ifdef CONFIG_SHA384 + if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) + key_mgmt[n++] = "wpa-eap-sha384"; +#endif /* CONFIG_SHA384 */ if (!wpa_dbus_dict_append_string_array(&iter_dict, "KeyMgmt", key_mgmt, n)) @@ -5433,6 +5759,177 @@ dbus_bool_t wpas_dbus_getter_bss_age( } +/** + * wpas_dbus_getter_bss_anqp - Return all the ANQP fields of a BSS + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "ANQP" property. + */ +dbus_bool_t wpas_dbus_getter_bss_anqp( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + DBusMessageIter iter_dict, variant_iter; + struct bss_handler_args *args = user_data; + struct wpa_bss *bss; + struct wpa_bss_anqp *anqp; + struct wpa_bss_anqp_elem *elem; + + bss = get_bss_helper(args, error, __func__); + if (!bss) + return FALSE; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter) || + !wpa_dbus_dict_open_write(&variant_iter, &iter_dict)) + goto nomem; + + anqp = bss->anqp; + if (anqp) { +#ifdef CONFIG_INTERWORKING + if (anqp->capability_list && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "CapabilityList", + wpabuf_head(anqp->capability_list), + wpabuf_len(anqp->capability_list))) + goto nomem; + if (anqp->venue_name && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "VenueName", + wpabuf_head(anqp->venue_name), + wpabuf_len(anqp->venue_name))) + goto nomem; + if (anqp->network_auth_type && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "NetworkAuthType", + wpabuf_head(anqp->network_auth_type), + wpabuf_len(anqp->network_auth_type))) + goto nomem; + if (anqp->roaming_consortium && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "RoamingConsortium", + wpabuf_head(anqp->roaming_consortium), + wpabuf_len(anqp->roaming_consortium))) + goto nomem; + if (anqp->ip_addr_type_availability && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "IPAddrTypeAvailability", + wpabuf_head(anqp->ip_addr_type_availability), + wpabuf_len(anqp->ip_addr_type_availability))) + goto nomem; + if (anqp->nai_realm && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "NAIRealm", + wpabuf_head(anqp->nai_realm), + wpabuf_len(anqp->nai_realm))) + goto nomem; + if (anqp->anqp_3gpp && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "3GPP", + wpabuf_head(anqp->anqp_3gpp), + wpabuf_len(anqp->anqp_3gpp))) + goto nomem; + if (anqp->domain_name && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "DomainName", + wpabuf_head(anqp->domain_name), + wpabuf_len(anqp->domain_name))) + goto nomem; + if (anqp->fils_realm_info && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "FilsRealmInfo", + wpabuf_head(anqp->fils_realm_info), + wpabuf_len(anqp->fils_realm_info))) + goto nomem; + +#ifdef CONFIG_HS20 + if (anqp->hs20_capability_list && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "HS20CapabilityList", + wpabuf_head(anqp->hs20_capability_list), + wpabuf_len(anqp->hs20_capability_list))) + goto nomem; + if (anqp->hs20_operator_friendly_name && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "HS20OperatorFriendlyName", + wpabuf_head(anqp->hs20_operator_friendly_name), + wpabuf_len(anqp->hs20_operator_friendly_name))) + goto nomem; + if (anqp->hs20_wan_metrics && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "HS20WanMetrics", + wpabuf_head(anqp->hs20_wan_metrics), + wpabuf_len(anqp->hs20_wan_metrics))) + goto nomem; + if (anqp->hs20_connection_capability && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "HS20ConnectionCapability", + wpabuf_head(anqp->hs20_connection_capability), + wpabuf_len(anqp->hs20_connection_capability))) + goto nomem; + if (anqp->hs20_operating_class && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "HS20OperatingClass", + wpabuf_head(anqp->hs20_operating_class), + wpabuf_len(anqp->hs20_operating_class))) + goto nomem; + if (anqp->hs20_osu_providers_list && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "HS20OSUProvidersList", + wpabuf_head(anqp->hs20_osu_providers_list), + wpabuf_len(anqp->hs20_osu_providers_list))) + goto nomem; + if (anqp->hs20_operator_icon_metadata && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "HS20OperatorIconMetadata", + wpabuf_head(anqp->hs20_operator_icon_metadata), + wpabuf_len(anqp->hs20_operator_icon_metadata))) + goto nomem; + if (anqp->hs20_osu_providers_nai_list && + !wpa_dbus_dict_append_byte_array( + &iter_dict, "HS20OSUProvidersNAIList", + wpabuf_head(anqp->hs20_osu_providers_nai_list), + wpabuf_len(anqp->hs20_osu_providers_nai_list))) + goto nomem; +#endif /* CONFIG_HS20 */ + + dl_list_for_each(elem, &anqp->anqp_elems, + struct wpa_bss_anqp_elem, list) { + char title[32]; + + os_snprintf(title, sizeof(title), "anqp[%u]", + elem->infoid); + if (!wpa_dbus_dict_append_byte_array( + &iter_dict, title, + wpabuf_head(elem->payload), + wpabuf_len(elem->payload))) + goto nomem; + + os_snprintf(title, sizeof(title), + "protected-anqp-info[%u]", elem->infoid); + if (!wpa_dbus_dict_append_bool( + &iter_dict, title, + elem->protected_response)) + goto nomem; + } +#endif /* CONFIG_INTERWORKING */ + } + + if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || + !dbus_message_iter_close_container(iter, &variant_iter)) + goto nomem; + + return TRUE; + +nomem: + dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory"); + return FALSE; +} + + /** * wpas_dbus_getter_enabled - Check whether network is enabled or disabled * @iter: Pointer to incoming dbus message iter @@ -5940,3 +6437,28 @@ dbus_bool_t wpas_dbus_getter_mesh_group( } #endif /* CONFIG_MESH */ + + +/** + * wpas_dbus_getter_signal_change - Get signal change + * @iter: Pointer to incoming dbus message iter + * @error: Location to store error on failure + * @user_data: Function specific data + * Returns: TRUE on success, FALSE on failure + * + * Getter for "SignalChange" property. + */ +dbus_bool_t wpas_dbus_getter_signal_change( + const struct wpa_dbus_property_desc *property_desc, + DBusMessageIter *iter, DBusError *error, void *user_data) +{ + struct wpa_supplicant *wpa_s = user_data; + struct wpa_signal_info si = wpa_s->last_signal_info; + + if (wpas_dbus_new_from_signal_information(iter, &si) != 0) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "%s: error constructing reply", __func__); + return FALSE; + } + return TRUE; +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers.h index a421083f7fe2334f95c169914a0eb74c7ad99762..acd6af7ffa38b65b01d475d80f393d17510ac62c 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers.h @@ -157,6 +157,9 @@ DBusMessage * wpas_dbus_handler_interworking_select(DBusMessage *message, struct wpa_supplicant *wpa_s); +DBusMessage * +wpas_dbus_handler_anqp_get(DBusMessage *message, struct wpa_supplicant *wpa_s); + DECLARE_ACCESSOR(wpas_dbus_getter_capabilities); DECLARE_ACCESSOR(wpas_dbus_getter_state); DECLARE_ACCESSOR(wpas_dbus_getter_scanning); @@ -196,6 +199,7 @@ DECLARE_ACCESSOR(wpas_dbus_getter_blobs); DECLARE_ACCESSOR(wpas_dbus_getter_stas); DECLARE_ACCESSOR(wpas_dbus_getter_mac_address_randomization_mask); DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask); +DECLARE_ACCESSOR(wpas_dbus_getter_mac_address); DECLARE_ACCESSOR(wpas_dbus_getter_sta_address); DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid); DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps); @@ -215,6 +219,7 @@ DECLARE_ACCESSOR(wpas_dbus_getter_bss_rsn); DECLARE_ACCESSOR(wpas_dbus_getter_bss_wps); DECLARE_ACCESSOR(wpas_dbus_getter_bss_ies); DECLARE_ACCESSOR(wpas_dbus_getter_bss_age); +DECLARE_ACCESSOR(wpas_dbus_getter_bss_anqp); DECLARE_ACCESSOR(wpas_dbus_getter_enabled); DECLARE_ACCESSOR(wpas_dbus_setter_enabled); DECLARE_ACCESSOR(wpas_dbus_getter_network_properties); @@ -246,6 +251,8 @@ DECLARE_ACCESSOR(wpas_dbus_setter_wps_device_device_type); DECLARE_ACCESSOR(wpas_dbus_getter_mesh_peers); DECLARE_ACCESSOR(wpas_dbus_getter_mesh_group); +DECLARE_ACCESSOR(wpas_dbus_getter_signal_change); + DBusMessage * wpas_dbus_handler_tdls_discover(DBusMessage *message, struct wpa_supplicant *wpa_s); DBusMessage * wpas_dbus_handler_tdls_setup(DBusMessage *message, diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index de79178f465533c6d28479d97548b5d90ceffc5f..418a8fd4292e3ef8916d7c5b26dc3da4a13cdcce 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -14,6 +14,7 @@ #include "../wpa_supplicant_i.h" #include "../wps_supplicant.h" #include "../notify.h" +#include "../bss.h" #include "dbus_new_helpers.h" #include "dbus_new.h" #include "dbus_new_handlers.h" @@ -355,9 +356,17 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, char *pg_object_path = NULL; int persistent_group = 0; int freq = 0; + int retry_limit = 0; char *iface = NULL; unsigned int group_id = 0; struct wpa_ssid *ssid; + u8 go_bssid_buf[ETH_ALEN], *go_bssid = NULL; + bool allow_6ghz = false; + int vht = wpa_s->conf->p2p_go_vht; + int ht40 = wpa_s->conf->p2p_go_ht40 || vht; + int he = wpa_s->conf->p2p_go_he; + int edmg = wpa_s->conf->p2p_go_edmg; + int max_oper_chwidth, chwidth = 0, freq2 = 0; dbus_message_iter_init(message, &iter); @@ -376,16 +385,56 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, freq = entry.int32_value; if (freq <= 0) goto inv_args_clear; + } else if (os_strcmp(entry.key, "retry_limit") == 0 && + entry.type == DBUS_TYPE_INT32) { + retry_limit = entry.int32_value; + if (retry_limit <= 0) + goto inv_args_clear; } else if (os_strcmp(entry.key, "persistent_group_object") == 0 && - entry.type == DBUS_TYPE_OBJECT_PATH) + entry.type == DBUS_TYPE_OBJECT_PATH) { pg_object_path = os_strdup(entry.str_value); - else + } else if (os_strcmp(entry.key, "go_bssid") == 0 && + entry.type == DBUS_TYPE_STRING) { + if (hwaddr_aton(entry.str_value, go_bssid_buf)) + goto inv_args_clear; + go_bssid = go_bssid_buf; + } else if (os_strcmp(entry.key, "ht40") == 0 && + entry.type == DBUS_TYPE_BOOLEAN) { + ht40 = entry.bool_value; + } else if (os_strcmp(entry.key, "vht") == 0 && + entry.type == DBUS_TYPE_BOOLEAN) { + vht = entry.bool_value; + ht40 |= vht; + } else if (os_strcmp(entry.key, "he") == 0 && + entry.type == DBUS_TYPE_BOOLEAN) { + he = entry.bool_value; + } else if (os_strcmp(entry.key, "edmg") == 0 && + entry.type == DBUS_TYPE_BOOLEAN) { + edmg = entry.bool_value; + } else if (os_strcmp(entry.key, "allow_6ghz") == 0 && + entry.type == DBUS_TYPE_BOOLEAN) { + allow_6ghz = entry.bool_value; + } else if (os_strcmp(entry.key, "freq2") == 0 && + entry.type == DBUS_TYPE_INT32) { + freq2 = entry.int32_value; + } else if (os_strcmp(entry.key, "max_oper_chwidth") == 0 && + entry.type == DBUS_TYPE_INT32) { + chwidth = entry.int32_value; + } else { goto inv_args_clear; + } wpa_dbus_dict_entry_clear(&entry); } + max_oper_chwidth = chwidth_freq2_to_ch_width(chwidth, freq2); + if (max_oper_chwidth < 0) + goto inv_args; + + if (allow_6ghz && chwidth == 40) + max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ; + wpa_s = wpa_s->global->p2p_init_wpa_s; if (!wpa_s) { reply = wpas_dbus_error_no_p2p_mgmt_iface(message); @@ -424,16 +473,19 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, if (ssid == NULL || ssid->disabled != 2) goto inv_args; - if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0, - 0, 0, 0, 0, NULL, 0, 0, - false)) { + if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, + freq2, ht40, vht, + max_oper_chwidth, he, edmg, + NULL, 0, 0, allow_6ghz, + retry_limit, go_bssid)) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); goto out; } - } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0, 0, - 0, 0, 0, false)) + } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, freq2, + ht40, vht, max_oper_chwidth, he, edmg, + allow_6ghz)) goto inv_args; out: @@ -2413,9 +2465,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_bssid( u8 *p_bssid; if (role == WPAS_P2P_ROLE_CLIENT) { - if (wpa_s->current_ssid == NULL) + if (!wpa_s->current_bss) return FALSE; - p_bssid = wpa_s->current_ssid->bssid; + p_bssid = wpa_s->current_bss->bssid; } else { if (wpa_s->ap_iface == NULL) return FALSE; @@ -2437,9 +2489,9 @@ dbus_bool_t wpas_dbus_getter_p2p_group_frequency( u8 role = wpas_get_p2p_role(wpa_s); if (role == WPAS_P2P_ROLE_CLIENT) { - if (wpa_s->go_params == NULL) + if (!wpa_s->current_bss) return FALSE; - op_freq = wpa_s->go_params->freq; + op_freq = wpa_s->current_bss->freq; } else { if (wpa_s->ap_iface == NULL) return FALSE; @@ -2726,20 +2778,20 @@ DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message, if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) goto error; - query = NULL; - resp = NULL; } else goto error; +out: os_free(service); + wpabuf_free(query); + wpabuf_free(resp); + return reply; error_clear: wpa_dbus_dict_entry_clear(&entry); error: - os_free(service); - wpabuf_free(query); - wpabuf_free(resp); - return wpas_dbus_error_invalid_args(message, NULL); + reply = wpas_dbus_error_invalid_args(message, NULL); + goto out; } @@ -2873,6 +2925,7 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_req( if (entry.type != DBUS_TYPE_ARRAY || entry.array_type != DBUS_TYPE_BYTE) goto error_clear; + wpabuf_free(tlv); tlv = wpabuf_alloc_copy(entry.bytearray_value, entry.array_len); } else @@ -2900,7 +2953,6 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_req( if (tlv == NULL) goto error; ref = wpas_p2p_sd_request(wpa_s, addr, tlv); - wpabuf_free(tlv); } if (ref != 0) { @@ -2912,14 +2964,13 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_req( message, "Unable to send SD request"); } out: + wpabuf_free(tlv); os_free(service); os_free(peer_object_path); return reply; error_clear: wpa_dbus_dict_entry_clear(&entry); error: - if (tlv) - wpabuf_free(tlv); reply = wpas_dbus_error_invalid_args(message, NULL); goto out; } @@ -2961,6 +3012,7 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_res( if (entry.type != DBUS_TYPE_ARRAY || entry.array_type != DBUS_TYPE_BYTE) goto error_clear; + wpabuf_free(tlv); tlv = wpabuf_alloc_copy(entry.bytearray_value, entry.array_len); } else @@ -2974,8 +3026,8 @@ DBusMessage * wpas_dbus_handler_p2p_service_sd_res( goto error; wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv); - wpabuf_free(tlv); out: + wpabuf_free(tlv); os_free(peer_object_path); return reply; error_clear: diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_helpers.c index d9009ba85e9cb83690f19d3fe615f6b4ae0013f7..28f1aa45d3f5f85d310afa541b3ce8e142ed1322 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_helpers.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_helpers.c @@ -11,6 +11,7 @@ #include "utils/common.h" #include "utils/eloop.h" +#include "drivers/driver.h" #include "dbus_common.h" #include "dbus_common_i.h" #include "dbus_new.h" @@ -670,20 +671,27 @@ static void do_send_prop_changed_signal( &interface) || /* Changed properties dict */ !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, - "{sv}", &dict_iter) || - !put_changed_properties(obj_dsc, interface, &dict_iter, 0) || - !dbus_message_iter_close_container(&signal_iter, &dict_iter) || + "{sv}", &dict_iter)) + goto fail; + if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0)) { + dbus_message_iter_close_container(&signal_iter, &dict_iter); + goto fail; + } + if (!dbus_message_iter_close_container(&signal_iter, &dict_iter) || /* Invalidated properties array (empty) */ !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, "s", &dict_iter) || - !dbus_message_iter_close_container(&signal_iter, &dict_iter)) { - wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", - __func__); - } else { - dbus_connection_send(con, msg, NULL); - } + !dbus_message_iter_close_container(&signal_iter, &dict_iter)) + goto fail; + dbus_connection_send(con, msg, NULL); + +out: dbus_message_unref(msg); + return; +fail: + wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", __func__); + goto out; } @@ -701,16 +709,23 @@ static void do_send_deprecated_prop_changed_signal( dbus_message_iter_init_append(msg, &signal_iter); if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, - "{sv}", &dict_iter) || - !put_changed_properties(obj_dsc, interface, &dict_iter, 1) || - !dbus_message_iter_close_container(&signal_iter, &dict_iter)) { - wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", - __func__); - } else { - dbus_connection_send(con, msg, NULL); + "{sv}", &dict_iter)) + goto fail; + if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1)) { + dbus_message_iter_close_container(&signal_iter, &dict_iter); + goto fail; } + if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) + goto fail; + + dbus_connection_send(con, msg, NULL); +out: dbus_message_unref(msg); + return; +fail: + wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", __func__); + goto out; } @@ -1023,3 +1038,165 @@ DBusMessage * wpas_dbus_reply_new_from_error(DBusMessage *message, } return NULL; } + + +static double guard_interval_to_double(enum guard_interval value) +{ + switch (value) { + case GUARD_INTERVAL_0_4: + return 0.4; + case GUARD_INTERVAL_0_8: + return 0.8; + case GUARD_INTERVAL_1_6: + return 1.6; + case GUARD_INTERVAL_3_2: + return 3.2; + default: + return 0; + } +} + + +/** + * wpas_dbus_new_from_signal_information - Adds a wpa_signal_info + * to a DBusMessage. + * @msg: Pointer to message to append fields to + * @si: Pointer to wpa_signal_info to add to the message + * Returns: 0 on success, otherwise, an errorcode + * + * Adds all the pertinent fields from a wpa_signal_info to a DBusMessage. + * The same logic is useful in both responding to signal_poll calls, and + * sending signal_change signals. + */ +int wpas_dbus_new_from_signal_information(DBusMessageIter *iter, + struct wpa_signal_info *si) +{ + DBusMessageIter iter_dict, variant_iter; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + "a{sv}", &variant_iter) || + !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) || + !wpa_dbus_dict_append_int32(&iter_dict, "rssi", + si->data.signal) || + !wpa_dbus_dict_append_uint32(&iter_dict, "linkspeed", + si->data.current_tx_rate / 1000) || + !wpa_dbus_dict_append_int32(&iter_dict, "noise", + si->current_noise) || + !wpa_dbus_dict_append_uint32(&iter_dict, "frequency", + si->frequency) || + (si->chanwidth != CHAN_WIDTH_UNKNOWN && + !wpa_dbus_dict_append_string( + &iter_dict, "width", + channel_width_to_string(si->chanwidth))) || + (si->center_frq1 > 0 && si->center_frq2 > 0 && + (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1", + si->center_frq1) || + !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2", + si->center_frq2))) || + (si->data.avg_signal && + !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi", + si->data.avg_signal)) || + (si->data.rx_bytes && + !wpa_dbus_dict_append_uint64(&iter_dict, "rx-bytes", + si->data.rx_bytes)) || + (si->data.tx_bytes && + !wpa_dbus_dict_append_uint64(&iter_dict, "tx-bytes", + si->data.tx_bytes)) || + (si->data.rx_packets && + !wpa_dbus_dict_append_uint32(&iter_dict, "rx-packets", + si->data.rx_packets)) || + (si->data.tx_packets && + !wpa_dbus_dict_append_uint32(&iter_dict, "tx-packets", + si->data.tx_packets)) || + (si->data.beacons_count && + !wpa_dbus_dict_append_uint64(&iter_dict, "beacons", + si->data.beacons_count)) || + (si->data.current_rx_rate && + !wpa_dbus_dict_append_uint32(&iter_dict, "linkrxspeed", + si->data.current_rx_rate)) || + (si->data.current_rx_rate && + !wpa_dbus_dict_append_uint32(&iter_dict, "linktxspeed", + si->data.current_tx_rate)) || + (si->data.inactive_msec && + !wpa_dbus_dict_append_uint32(&iter_dict, "inactive-time", + si->data.inactive_msec)) || + (si->data.tx_retry_failed && + !wpa_dbus_dict_append_uint32(&iter_dict, "retries-failed", + si->data.tx_retry_failed)) || + (si->data.tx_retry_count && + !wpa_dbus_dict_append_uint32(&iter_dict, "retries", + si->data.tx_retry_count)) || + (si->data.last_ack_rssi && + !wpa_dbus_dict_append_int32(&iter_dict, "last-ack-rssi", + si->data.last_ack_rssi)) || + (si->data.fcs_error_count && + !wpa_dbus_dict_append_uint32(&iter_dict, "fcs-errors", + si->data.fcs_error_count)) || + (si->data.beacon_loss_count && + !wpa_dbus_dict_append_uint32(&iter_dict, "beacon-losses", + si->data.beacon_loss_count)) || + (si->data.expected_throughput && + !wpa_dbus_dict_append_uint32(&iter_dict, "expected-throughput", + si->data.expected_throughput)) || + (si->data.rx_drop_misc && + !wpa_dbus_dict_append_uint32(&iter_dict, "rx-drop-misc", + si->data.rx_drop_misc)) || + (si->data.rx_mpdus && + !wpa_dbus_dict_append_uint32(&iter_dict, "rx-mpdus", + si->data.rx_mpdus)) || + (si->data.rx_hemcs && + !wpa_dbus_dict_append_uint32(&iter_dict, "rx-he-mcs", + si->data.rx_hemcs)) || + (si->data.tx_hemcs && + !wpa_dbus_dict_append_uint32(&iter_dict, "tx-he-mcs", + si->data.tx_hemcs)) || + (si->data.rx_vhtmcs && + !wpa_dbus_dict_append_uint32(&iter_dict, "rx-vht-mcs", + si->data.rx_vhtmcs)) || + (si->data.tx_vhtmcs && + !wpa_dbus_dict_append_uint32(&iter_dict, "tx-vht-mcs", + si->data.tx_vhtmcs)) || + (si->data.rx_mcs && + !wpa_dbus_dict_append_uint32(&iter_dict, "rx-mcs", + si->data.rx_mcs)) || + (si->data.tx_mcs && + !wpa_dbus_dict_append_uint32(&iter_dict, "tx-mcs", + si->data.tx_mcs)) || + (si->data.rx_he_nss && + !wpa_dbus_dict_append_uint32(&iter_dict, "rx-he-nss", + si->data.rx_he_nss)) || + (si->data.tx_he_nss && + !wpa_dbus_dict_append_uint32(&iter_dict, "tx-he-nss", + si->data.tx_he_nss)) || + (si->data.rx_vht_nss && + !wpa_dbus_dict_append_uint32(&iter_dict, "rx-vht-nss", + si->data.rx_vht_nss)) || + (si->data.tx_vht_nss && + !wpa_dbus_dict_append_uint32(&iter_dict, "tx-vht-nss", + si->data.tx_vht_nss)) || + (si->data.avg_beacon_signal && + !wpa_dbus_dict_append_int32(&iter_dict, "avg-beacon-rssi", + si->data.avg_beacon_signal)) || + (si->data.avg_ack_signal && + !wpa_dbus_dict_append_int32(&iter_dict, "avg-ack-rssi", + si->data.avg_ack_signal)) || + (si->data.rx_guard_interval && + !wpa_dbus_dict_append_double( + &iter_dict, "rx-guard-interval", + guard_interval_to_double(si->data.rx_guard_interval))) || + (si->data.tx_guard_interval && + !wpa_dbus_dict_append_double( + &iter_dict, "tx-guard-interval", + guard_interval_to_double(si->data.tx_guard_interval))) || + ((si->data.flags & STA_DRV_DATA_RX_HE_DCM) && + !wpa_dbus_dict_append_bool(&iter_dict, "rx-dcm", + si->data.rx_dcm)) || + ((si->data.flags & STA_DRV_DATA_TX_HE_DCM) && + !wpa_dbus_dict_append_bool(&iter_dict, "tx-dcm", + si->data.tx_dcm)) || + !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) || + !dbus_message_iter_close_container(iter, &variant_iter)) + return -ENOMEM; + + return 0; +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_helpers.h index 7b63b28d7707db4e416b8b697c82936658eaf929..c8d44a00bee8ee39b5883db7d819ab996a2beb01 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_helpers.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_helpers.h @@ -12,6 +12,8 @@ #include +struct wpa_signal_info; + typedef DBusMessage * (*WPADBusMethodHandler)(DBusMessage *message, void *user_data); typedef void (*WPADBusArgumentFreeFunction)(void *handler_arg); @@ -151,4 +153,7 @@ DBusMessage *wpas_dbus_reply_new_from_error(DBusMessage *message, const char *fallback_name, const char *fallback_string); +int wpas_dbus_new_from_signal_information(DBusMessageIter *iter, + struct wpa_signal_info *si); + #endif /* WPA_DBUS_CTRL_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_introspect.c index 6c721bf556db26c28de29aa4c17549834c04d60b..a8c0d28398d4624c01a60878b4de5722745d2129 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_introspect.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dbus/dbus_new_introspect.c @@ -38,7 +38,7 @@ static struct interfaces * add_interface(struct dl_list *list, if (!iface) return NULL; iface->dbus_interface = os_strdup(dbus_interface); - iface->xml = wpabuf_alloc(15000); + iface->xml = wpabuf_alloc(16000); if (iface->dbus_interface == NULL || iface->xml == NULL) { os_free(iface->dbus_interface); wpabuf_free(iface->xml); diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/defconfig b/wpa_supplicant-2.9_standard/wpa_supplicant/defconfig index 22ddcc21e40df51d3b777007e90856a0e934efce..52befd8f15fc1e01f2a9a3e90ede99b79b9677dd 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/defconfig +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/defconfig @@ -101,6 +101,9 @@ CONFIG_EAP_MSCHAPV2=y # EAP-TLS CONFIG_EAP_TLS=y +# Enable EAP-TLSv1.3 support by default (currently disabled unless explicitly +# enabled in network configuration) +#CONFIG_EAP_TLSV1_3=y # EAL-PEAP CONFIG_EAP_PEAP=y @@ -203,9 +206,15 @@ CONFIG_SMARTCARD=y # Support VHT overrides (disable VHT, mask MCS rates, etc.) #CONFIG_VHT_OVERRIDES=y +# Support HE overrides +#CONFIG_HE_OVERRIDES=y + # Development testing #CONFIG_EAPOL_TEST=y +# Support IPv6 +CONFIG_IPV6=y + # Select control interface backend for external programs, e.g, wpa_cli: # unix = UNIX domain sockets (default for Linux/*BSD) # udp = UDP sockets using localhost (127.0.0.1) @@ -248,6 +257,9 @@ CONFIG_CTRL_IFACE=y # Simultaneous Authentication of Equals (SAE), WPA3-Personal CONFIG_SAE=y +# SAE Public Key, WPA3-Personal +#CONFIG_SAE_PK=y + # Disable scan result processing (ap_scan=1) to save code size by about 1 kB. # This can be used if ap_scan=1 mode is never enabled. #CONFIG_NO_SCAN_PROCESSING=y @@ -490,6 +502,16 @@ CONFIG_DEBUG_SYSLOG=y # IEEE 802.11ac (Very High Throughput) support (mainly for AP mode) CONFIG_IEEE80211AC=y +# IEEE 802.11ax HE support (mainly for AP mode) +CONFIG_IEEE80211AX=y + +# IEEE 802.11be EHT support (mainly for AP mode) +# CONFIG_IEEE80211AX is mandatory for setting CONFIG_IEEE80211BE. +# Note: This is experimental and work in progress. The definitions are still +# subject to change and this should not be expected to interoperate with the +# final IEEE 802.11be version. +#CONFIG_IEEE80211BE=y + # Wireless Network Management (IEEE Std 802.11v-2011) # Note: This is experimental and not complete implementation. #CONFIG_WNM=y @@ -649,3 +671,18 @@ CONFIG_DPP2=y # design is still subject to change. As such, this should not yet be enabled in # production use. #CONFIG_PASN=y + +# Disable support for Radio Measurement (IEEE 802.11k) and supported operating +# class indication. Removing these is not recommended since they can help the +# AP manage the network and STA steering. +#CONFIG_NO_RRM=y + +# Disable support for Robust AV streaming for consumer and enterprise Wi-Fi +# applications; IEEE Std 802.11-2020, 4.3.24; SCS, MSCS, QoS Management +#CONFIG_NO_ROBUST_AV=y + +# Disable support for WMM admission control +#CONFIG_NO_WMM_AC=y + +# Wi-Fi Aware unsynchronized service discovery (NAN USD) +#CONFIG_NAN_USD=y diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant-2.9_standard/wpa_supplicant/doc/docbook/wpa_supplicant.sgml index 02012d1b08dec526fc0a3cf508087a41128845ee..df538e3327bbb1495c1704fe50a47e44bc105bc5 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/doc/docbook/wpa_supplicant.sgml +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/doc/docbook/wpa_supplicant.sgml @@ -2,7 +2,7 @@ - 07 August 2019 + 1 February 2023 @@ -22,6 +22,7 @@ -Ddriver -PPID_file -foutput file + -Iadditional config file @@ -29,7 +30,7 @@ Wireless networks do not require physical access to the network equipment - in the same way as wired networks. This makes it easier for unauthorized + in the same way that wired networks do. This makes it easier for unauthorized users to passively monitor a network and capture all transmitted frames. In addition, unauthorized use of the network is much easier. In many cases, this can happen even without user's explicit knowledge since the wireless @@ -41,14 +42,14 @@ Link-layer encryption can be used to provide a layer of security for wireless networks. The original wireless LAN standard, IEEE 802.11, included a simple encryption mechanism, WEP. However, that proved to - be flawed in many areas and network protected with WEP cannot be consider + be flawed in many areas and networks protected with WEP cannot be considered secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys can be used to improve the network security, but even that has inherited security issues due to the use of WEP for encryption. Wi-Fi Protected - Access and IEEE 802.11i amendment to the wireless LAN standard introduce + Access and the IEEE 802.11i amendment to the wireless LAN standard introduce a much improved mechanism for securing wireless networks. IEEE 802.11i - enabled networks that are using CCMP (encryption mechanism based on strong - cryptographic algorithm AES) can finally be called secure used for + enabled networks that are using CCMP (an encryption mechanism based on the strong + cryptographic algorithm AES) can finally be called secure and used for applications which require efficient protection against unauthorized access. @@ -69,13 +70,13 @@ wpa_supplicant. Before wpa_supplicant can do its work, the network interface - must be available. That means that the physical device must be + must be available. That means that the physical device must be present and enabled, and the driver for the device must be loaded. The daemon will exit immediately if the device is not already available. After wpa_supplicant has configured the - network device, higher level configuration such as DHCP may + network device, higher level configuration of the device, such as DHCP, may proceed. There are a variety of ways to integrate wpa_supplicant into a machine's networking scripts, a few of which are described in sections below. @@ -86,7 +87,7 @@ wpa_supplicant requests the kernel - driver to scan neighboring BSSes + driver to scan neighboring BSSes (Basic Service Set) @@ -272,6 +273,13 @@ + + macsec_linux + + MACsec Ethernet driver for Linux + + + roboswitch @@ -279,6 +287,13 @@ + + none + + no driver (RADIUS server/WPS ER only) + + + bsd @@ -340,6 +355,13 @@ + + -I filename + + Path to additional configuration file. + + + -d @@ -512,10 +534,10 @@ wpa_supplicant -B -c/etc/wpa_supplicant.conf -iwlan0 - This makes the process fork into background. + This makes the process fork into the background. - The easiest way to debug problems, and to get debug log for - bug reports, is to start wpa_supplicant on + The easiest way to debug problems, and to get a debug log for + bug reports, is to start wpa_supplicant in the foreground with debugging enabled:
@@ -699,7 +721,7 @@ wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B Interface to pcmcia-cs/cardmrg - For example, following small changes to pcmcia-cs scripts + For example, the following small changes to pcmcia-cs scripts can be used to enable WPA support: Add MODE="Managed" and WPA="y" to the network scheme in diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant-2.9_standard/wpa_supplicant/dpp_supplicant.c index 4ec5691859a60b16e6681b49224fee4e66db8f23..121bd63d6f60cd9837dc581606fcf73c9ae48c12 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dpp_supplicant.c @@ -2,6 +2,7 @@ * wpa_supplicant - DPP * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -16,6 +17,7 @@ #include "common/dpp.h" #include "common/gas.h" #include "common/gas_server.h" +#include "crypto/random.h" #include "rsn_supp/wpa.h" #include "rsn_supp/pmksa_cache.h" #include "wpa_supplicant_i.h" @@ -47,12 +49,14 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *bssid, const u8 *data, size_t data_len, enum offchannel_send_action_result result); +static void wpas_dpp_gas_client_timeout(void *eloop_ctx, void *timeout_ctx); #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); +static bool wpas_dpp_tcp_msg_sent(void *ctx, struct dpp_authentication *auth); #endif /* CONFIG_DPP2 */ static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -233,6 +237,12 @@ static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s) wait_time = wpa_s->dpp_resp_retry_time; else wait_time = 1000; + if (wpa_s->dpp_tx_chan_change) { + wpa_s->dpp_tx_chan_change = false; + if (wait_time > 100) + wait_time = 100; + } + wpa_printf(MSG_DEBUG, "DPP: Schedule retransmission of Authentication Response frame in %u ms", wait_time); @@ -295,7 +305,8 @@ static void wpas_dpp_conn_status_result_timeout(void *eloop_ctx, struct dpp_authentication *auth = wpa_s->dpp_auth; enum dpp_status_error result; - if (!auth || !auth->conn_status_requested) + if ((!auth || !auth->conn_status_requested) && + !dpp_tcp_conn_status_requested(wpa_s->dpp)) return; wpa_printf(MSG_DEBUG, @@ -371,9 +382,10 @@ void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s, eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL); - if (!auth || !auth->conn_status_requested) + if ((!auth || !auth->conn_status_requested) && + !dpp_tcp_conn_status_requested(wpa_s->dpp)) return; - auth->conn_status_requested = 0; + wpa_printf(MSG_DEBUG, "DPP: Report connection status result %d", result); @@ -382,6 +394,19 @@ void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s, channel_list = channel_list_buf; } + if (!auth || !auth->conn_status_requested) { + dpp_tcp_send_conn_status(wpa_s->dpp, result, + ssid ? ssid->ssid : + wpa_s->dpp_last_ssid, + ssid ? ssid->ssid_len : + wpa_s->dpp_last_ssid_len, + channel_list); + os_free(channel_list_buf); + return; + } + + auth->conn_status_requested = 0; + msg = dpp_build_conn_status_result(auth, result, ssid ? ssid->ssid : wpa_s->dpp_last_ssid, @@ -412,17 +437,67 @@ void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s, } -void wpas_dpp_connected(struct wpa_supplicant *wpa_s) +static void wpas_dpp_connected_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->conn_status_requested) + if ((auth && auth->conn_status_requested) || + dpp_tcp_conn_status_requested(wpa_s->dpp)) wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_OK); } + +void wpas_dpp_connected(struct wpa_supplicant *wpa_s) +{ + struct dpp_authentication *auth = wpa_s->dpp_auth; + + if ((auth && auth->conn_status_requested) || + dpp_tcp_conn_status_requested(wpa_s->dpp)) { + /* Report connection result from an eloop timeout to avoid delay + * to completing all connection completion steps since this + * function is called in a middle of the post 4-way handshake + * processing. */ + eloop_register_timeout(0, 0, wpas_dpp_connected_timeout, + wpa_s, NULL); + } +} + #endif /* CONFIG_DPP2 */ +static void wpas_dpp_drv_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_resp) { + wpa_printf(MSG_DEBUG, + "DPP: Call wpas_dpp_auth_init_next() from %s", + __func__); + wpas_dpp_auth_init_next(wpa_s); + } else { + wpa_printf(MSG_DEBUG, "DPP: %s, but no waiting_auth_resp", + __func__); + } +} + + +static void wpas_dpp_neg_freq_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_authentication *auth = wpa_s->dpp_auth; + + if (!wpa_s->dpp_listen_on_tx_expire || !auth || !auth->neg_freq) + return; + + wpa_printf(MSG_DEBUG, + "DPP: Start listen on neg_freq %u MHz based on timeout for TX wait expiration", + auth->neg_freq); + wpas_dpp_listen_start(wpa_s, auth->neg_freq); +} + + static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, @@ -499,7 +574,12 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, /* In case of DPP Authentication Request frame, move to * the next channel immediately. */ offchannel_send_action_done(wpa_s); - wpas_dpp_auth_init_next(wpa_s); + /* Call wpas_dpp_auth_init_next(wpa_s) from driver event + * notifying frame wait was completed or from eloop + * timeout. */ + eloop_register_timeout(0, 10000, + wpas_dpp_drv_wait_timeout, + wpa_s, NULL); return; } if (auth->waiting_auth_conf) { @@ -533,7 +613,9 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, wpa_s->dpp_auth->curr_freq, wpa_s->dpp_auth->neg_freq); offchannel_send_action_done(wpa_s); - wpas_dpp_listen_start(wpa_s, wpa_s->dpp_auth->neg_freq); + wpa_s->dpp_listen_on_tx_expire = true; + eloop_register_timeout(0, 100000, wpas_dpp_neg_freq_timeout, + wpa_s, NULL); } if (wpa_s->dpp_auth_ok_on_ack) @@ -661,6 +743,8 @@ static int wpas_dpp_auth_init_next(struct wpa_supplicant *wpa_s) unsigned int wait_time, max_wait_time, freq, max_tries, used; struct os_reltime now, diff; + eloop_cancel_timeout(wpas_dpp_drv_wait_timeout, wpa_s, NULL); + wpa_s->dpp_in_response_listen = 0; if (!auth) return -1; @@ -759,6 +843,7 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) #endif /* CONFIG_DPP2 */ wpa_s->dpp_gas_client = 0; + wpa_s->dpp_gas_server = 0; pos = os_strstr(cmd, " peer="); if (!pos) @@ -779,7 +864,17 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) } addr = get_param(cmd, " tcp_addr="); - if (addr) { + if (addr && os_strcmp(addr, "from-uri") == 0) { + os_free(addr); + if (!peer_bi->host) { + wpa_printf(MSG_INFO, + "DPP: TCP address not available in peer URI"); + return -1; + } + tcp = 1; + os_memcpy(&ipaddr, peer_bi->host, sizeof(ipaddr)); + tcp_port = peer_bi->port; + } else if (addr) { int res; res = hostapd_parse_ip_addr(addr, &ipaddr); @@ -874,7 +969,11 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) if (tcp) 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); + wpa_s->conf->dpp_mud_url, + wpa_s->conf->dpp_extra_conf_req_name, + wpa_s->conf->dpp_extra_conf_req_value, + wpa_s, wpa_s, wpas_dpp_process_conf_obj, + wpas_dpp_tcp_msg_sent); #endif /* CONFIG_DPP2 */ wpa_s->dpp_auth = auth; @@ -944,6 +1043,8 @@ static void dpp_start_listen_cb(struct wpa_radio_work *work, int deinit) wpa_s->off_channel_freq = 0; wpa_s->roc_waiting_drv_freq = lwork->freq; wpa_drv_dpp_listen(wpa_s, true); + wpa_s->dpp_tx_auth_resp_on_roc_stop = false; + wpa_s->dpp_tx_chan_change = false; } @@ -1043,11 +1144,58 @@ void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s, } +static void wpas_dpp_tx_auth_resp(struct wpa_supplicant *wpa_s) +{ + struct dpp_authentication *auth = wpa_s->dpp_auth; + + if (!auth) + return; + + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(auth->peer_mac_addr), auth->curr_freq, + DPP_PA_AUTHENTICATION_RESP); + offchannel_send_action(wpa_s, auth->curr_freq, + auth->peer_mac_addr, wpa_s->own_addr, broadcast, + wpabuf_head(auth->resp_msg), + wpabuf_len(auth->resp_msg), + 500, wpas_dpp_tx_status, 0); +} + + +static void wpas_dpp_tx_auth_resp_roc_timeout(void *eloop_ctx, + void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_authentication *auth = wpa_s->dpp_auth; + + if (!auth || !wpa_s->dpp_tx_auth_resp_on_roc_stop) + return; + + wpa_s->dpp_tx_auth_resp_on_roc_stop = false; + wpa_s->dpp_tx_chan_change = true; + wpa_printf(MSG_DEBUG, + "DPP: Send postponed Authentication Response on remain-on-channel termination timeout"); + wpas_dpp_tx_auth_resp(wpa_s); +} + + void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq) { + wpa_printf(MSG_DEBUG, "DPP: Remain on channel cancel for %u MHz", freq); wpas_dpp_listen_work_done(wpa_s); + if (wpa_s->dpp_auth && wpa_s->dpp_tx_auth_resp_on_roc_stop) { + eloop_cancel_timeout(wpas_dpp_tx_auth_resp_roc_timeout, + wpa_s, NULL); + wpa_s->dpp_tx_auth_resp_on_roc_stop = false; + wpa_s->dpp_tx_chan_change = true; + wpa_printf(MSG_DEBUG, + "DPP: Send postponed Authentication Response on remain-on-channel termination"); + wpas_dpp_tx_auth_resp(wpa_s); + return; + } + if (wpa_s->dpp_auth && wpa_s->dpp_in_response_listen) { unsigned int new_freq; @@ -1118,13 +1266,30 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src, return; } + if (own_bi->type == DPP_BOOTSTRAP_PKEX) { + if (!peer_bi || peer_bi->type != DPP_BOOTSTRAP_PKEX) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL + "No matching peer bootstrapping key found for PKEX - ignore message"); + return; + } + + if (os_memcmp(peer_bi->pubkey_hash, own_bi->peer_pubkey_hash, + SHA256_MAC_LEN) != 0) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL + "Mismatching peer PKEX bootstrapping key - ignore message"); + return; + } + } + if (wpa_s->dpp_auth) { wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL "Already in DPP authentication exchange - ignore new one"); return; } + wpa_s->dpp_pkex_wait_auth_req = false; wpa_s->dpp_gas_client = 0; + wpa_s->dpp_gas_server = 0; wpa_s->dpp_auth_ok_on_ack = 0; wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s->dpp, wpa_s, wpa_s->dpp_allowed_roles, @@ -1148,23 +1313,67 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src, wpa_printf(MSG_DEBUG, "DPP: Stop listen on %u MHz to allow response on the request %u MHz", wpa_s->dpp_listen_freq, wpa_s->dpp_auth->curr_freq); + wpa_s->dpp_tx_auth_resp_on_roc_stop = true; + eloop_register_timeout(0, 100000, + wpas_dpp_tx_auth_resp_roc_timeout, + wpa_s, NULL); wpas_dpp_listen_stop(wpa_s); + return; } + wpa_s->dpp_tx_auth_resp_on_roc_stop = false; + wpa_s->dpp_tx_chan_change = false; - wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", - MAC2STR(src), wpa_s->dpp_auth->curr_freq, - DPP_PA_AUTHENTICATION_RESP); - offchannel_send_action(wpa_s, wpa_s->dpp_auth->curr_freq, - src, wpa_s->own_addr, broadcast, - wpabuf_head(wpa_s->dpp_auth->resp_msg), - wpabuf_len(wpa_s->dpp_auth->resp_msg), - 500, wpas_dpp_tx_status, 0); + wpas_dpp_tx_auth_resp(wpa_s); +} + + +void wpas_dpp_tx_wait_expire(struct wpa_supplicant *wpa_s) +{ + struct dpp_authentication *auth = wpa_s->dpp_auth; + int freq; + + if (wpa_s->dpp_listen_on_tx_expire && auth && auth->neg_freq) { + wpa_printf(MSG_DEBUG, + "DPP: Start listen on neg_freq %u MHz based on TX wait expiration on the previous channel", + auth->neg_freq); + eloop_cancel_timeout(wpas_dpp_neg_freq_timeout, wpa_s, NULL); + wpas_dpp_listen_start(wpa_s, auth->neg_freq); + return; + } + + if (!wpa_s->dpp_gas_server || !auth) { + if (auth && auth->waiting_auth_resp && + eloop_is_timeout_registered(wpas_dpp_drv_wait_timeout, + wpa_s, NULL)) { + eloop_cancel_timeout(wpas_dpp_drv_wait_timeout, + wpa_s, NULL); + wpa_printf(MSG_DEBUG, + "DPP: Call wpas_dpp_auth_init_next() from %s", + __func__); + wpas_dpp_auth_init_next(wpa_s); + } + return; + } + + freq = auth->neg_freq > 0 ? auth->neg_freq : auth->curr_freq; + if (wpa_s->dpp_listen_work || (int) wpa_s->dpp_listen_freq == freq) + return; /* listen state is already in progress */ + + wpa_printf(MSG_DEBUG, "DPP: Start listen on %u MHz for GAS", freq); + wpa_s->dpp_in_response_listen = 1; + wpas_dpp_listen_start(wpa_s, freq); } static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s) { - /* TODO: stop wait and start ROC */ + struct dpp_authentication *auth = wpa_s->dpp_auth; + + wpa_printf(MSG_DEBUG, + "DPP: Starting GAS server (curr_freq=%d neg_freq=%d dpp_listen_freq=%d dpp_listen_work=%d)", + auth->curr_freq, auth->neg_freq, wpa_s->dpp_listen_freq, + !!wpa_s->dpp_listen_work); + wpa_s->dpp_gas_server = 1; } @@ -1217,6 +1426,9 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s, ssid->dpp_connector = os_strdup(conf->connector); if (!ssid->dpp_connector) goto fail; + + ssid->dpp_connector_privacy = + wpa_s->conf->dpp_connector_privacy_default; } if (conf->c_sign_key) { @@ -1259,7 +1471,10 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s, if (dpp_akm_sae(conf->akm)) ssid->key_mgmt |= WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE; - ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL; + if (dpp_akm_psk(conf->akm)) + ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL; + else + ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; if (conf->passphrase[0]) { if (wpa_config_set_quoted(ssid, "psk", conf->passphrase) < 0) @@ -1280,7 +1495,7 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s, ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_IEEE8021X_SHA256 | - WPA_KEY_MGMT_IEEE8021X_SHA256; + WPA_KEY_MGMT_IEEE8021X_SHA384; ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL; if (conf->cacert) { @@ -1556,6 +1771,14 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s, conf->server_name); #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + if (!wpa_s->dpp_pb_result_indicated) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "success"); + wpa_s->dpp_pb_result_indicated = true; + } + +#endif /* CONFIG_DPP3 */ + return wpas_dpp_process_config(wpa_s, auth, conf); } @@ -1612,6 +1835,21 @@ static void wpas_dpp_build_csr(void *eloop_ctx, void *timeout_ctx) #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 +static void wpas_dpp_build_new_key(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_new_key) + return; + + wpa_printf(MSG_DEBUG, "DPP: Build config request with a new key"); + wpas_dpp_start_gas_client(wpa_s); +} +#endif /* CONFIG_DPP3 */ + + 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, @@ -1624,10 +1862,11 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED; unsigned int i; + eloop_cancel_timeout(wpas_dpp_gas_client_timeout, wpa_s, NULL); wpa_s->dpp_gas_dialog_token = -1; if (!auth || (!auth->auth_success && !auth->reconfig_success) || - os_memcmp(addr, auth->peer_mac_addr, ETH_ALEN) != 0) { + !ether_addr_equal(addr, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); return; } @@ -1664,6 +1903,14 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, return; } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + if (res == -3) { + wpa_printf(MSG_DEBUG, "DPP: New protocol key needed"); + eloop_register_timeout(0, 0, wpas_dpp_build_new_key, wpa_s, + NULL); + return; + } +#endif /* CONFIG_DPP3 */ if (res < 0) { wpa_printf(MSG_DEBUG, "DPP: Configuration attempt failed"); goto fail; @@ -1725,6 +1972,22 @@ fail2: } +static void wpas_dpp_gas_client_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_authentication *auth = wpa_s->dpp_auth; + + if (!wpa_s->dpp_gas_client || !auth || + (!auth->auth_success && !auth->reconfig_success)) + return; + + wpa_printf(MSG_DEBUG, "DPP: Timeout while waiting for Config Response"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; +} + + static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s) { struct dpp_authentication *auth = wpa_s->dpp_auth; @@ -1736,11 +1999,17 @@ static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s) offchannel_send_action_done(wpa_s); wpas_dpp_listen_stop(wpa_s); +#ifdef CONFIG_NO_RRM + supp_op_classes = NULL; +#else /* CONFIG_NO_RRM */ supp_op_classes = wpas_supp_op_classes(wpa_s); +#endif /* CONFIG_NO_RRM */ buf = dpp_build_conf_req_helper(auth, wpa_s->conf->dpp_name, wpa_s->dpp_netrole, wpa_s->conf->dpp_mud_url, - supp_op_classes); + supp_op_classes, + wpa_s->conf->dpp_extra_conf_req_name, + wpa_s->conf->dpp_extra_conf_req_value); os_free(supp_op_classes); if (!buf) { wpa_printf(MSG_DEBUG, @@ -1751,6 +2020,16 @@ static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "DPP: GAS request to " MACSTR_SEC " (freq %u MHz)", MAC2STR_SEC(auth->peer_mac_addr), auth->curr_freq); + /* Use a 120 second timeout since the gas_query_req() operation could + * remain waiting indefinitely for the response if the Configurator + * keeps sending out comeback responses with additional delay. The + * DPP technical specification expects the Enrollee to continue sending + * out new Config Requests for 60 seconds, so this gives an extra 60 + * second time after the last expected new Config Request for the + * Configurator to determine what kind of configuration to provide. */ + eloop_register_timeout(120, 0, wpas_dpp_gas_client_timeout, + wpa_s, NULL); + res = gas_query_req(wpa_s->gas, auth->peer_mac_addr, auth->curr_freq, 1, 1, buf, wpas_dpp_gas_resp_cb, wpa_s); if (res < 0) { @@ -1767,7 +2046,7 @@ static void wpas_dpp_start_gas_client(struct wpa_supplicant *wpa_s) static void wpas_dpp_auth_success(struct wpa_supplicant *wpa_s, int initiator) { wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded"); - wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", initiator); + dpp_notify_auth_success(wpa_s->dpp_auth, initiator); #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) { wpa_printf(MSG_INFO, @@ -1804,7 +2083,7 @@ static void wpas_dpp_rx_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src, } if (!is_zero_ether_addr(auth->peer_mac_addr) && - os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + !ether_addr_equal(src, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " MACSTR_SEC ") - drop", MAC2STR_SEC(auth->peer_mac_addr)); return; @@ -1858,7 +2137,7 @@ static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src, return; } - if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(src, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " MACSTR_SEC ") - drop", MAC2STR_SEC(auth->peer_mac_addr)); return; @@ -1912,6 +2191,42 @@ static void wpas_dpp_conn_status_result_wait_timeout(void *eloop_ctx, } +#ifdef CONFIG_DPP3 + +static bool wpas_dpp_pb_active(struct wpa_supplicant *wpa_s) +{ + return (wpa_s->dpp_pb_time.sec || wpa_s->dpp_pb_time.usec) && + wpa_s->dpp_pb_configurator; +} + + +static void wpas_dpp_remove_pb_hash(struct wpa_supplicant *wpa_s) +{ + int i; + + if (!wpa_s->dpp_pb_bi) + return; + for (i = 0; i < DPP_PB_INFO_COUNT; i++) { + struct dpp_pb_info *info = &wpa_s->dpp_pb[i]; + + if (info->rx_time.sec == 0 && info->rx_time.usec == 0) + continue; + if (os_memcmp(info->hash, wpa_s->dpp_pb_resp_hash, + SHA256_MAC_LEN) == 0) { + /* Allow a new push button session to be established + * immediately without the successfully completed + * session triggering session overlap. */ + info->rx_time.sec = 0; + info->rx_time.usec = 0; + wpa_printf(MSG_DEBUG, + "DPP: Removed PB hash from session overlap detection due to successfully completed provisioning"); + } + } +} + +#endif /* CONFIG_DPP3 */ + + static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *hdr, const u8 *buf, size_t len) { @@ -1923,7 +2238,7 @@ static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src, if (!auth || !auth->waiting_conf_result) { if (auth && - os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) == 0 && + ether_addr_equal(src, auth->peer_mac_addr) && gas_server_response_sent(wpa_s->gas_server, auth->gas_server_ctx)) { /* This could happen if the TX status event gets delayed @@ -1940,7 +2255,7 @@ static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src, } } - if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(src, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " MACSTR_SEC ") - drop", MAC2STR_SEC(auth->peer_mac_addr)); return; @@ -1949,8 +2264,11 @@ static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src, status = dpp_conf_result_rx(auth, hdr, buf, len); if (status == DPP_STATUS_OK && auth->send_conn_status) { + int freq; + wpa_msg(wpa_s, MSG_INFO, - DPP_EVENT_CONF_SENT "wait_conn_status=1"); + DPP_EVENT_CONF_SENT "wait_conn_status=1 conf_status=%d", + auth->conf_resp_status); wpa_printf(MSG_DEBUG, "DPP: Wait for Connection Status Result"); eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); @@ -1961,19 +2279,36 @@ static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src, wpas_dpp_conn_status_result_wait_timeout, wpa_s, NULL); offchannel_send_action_done(wpa_s); - wpas_dpp_listen_start(wpa_s, auth->neg_freq ? auth->neg_freq : - auth->curr_freq); + freq = auth->neg_freq ? auth->neg_freq : auth->curr_freq; + if (!wpa_s->dpp_in_response_listen || + (int) wpa_s->dpp_listen_freq != freq) + wpas_dpp_listen_start(wpa_s, freq); return; } offchannel_send_action_done(wpa_s); wpas_dpp_listen_stop(wpa_s); if (status == DPP_STATUS_OK) - wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT "conf_status=%d", + auth->conf_resp_status); else wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); dpp_auth_deinit(auth); wpa_s->dpp_auth = NULL; eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); +#ifdef CONFIG_DPP3 + if (!wpa_s->dpp_pb_result_indicated && wpas_dpp_pb_active(wpa_s)) { + if (status == DPP_STATUS_OK) + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT + "success"); + else + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT + "no-configuration-available"); + wpa_s->dpp_pb_result_indicated = true; + if (status == DPP_STATUS_OK) + wpas_dpp_remove_pb_hash(wpa_s); + wpas_dpp_push_button_stop(wpa_s); + } +#endif /* CONFIG_DPP3 */ } @@ -2035,6 +2370,34 @@ static int wpas_dpp_process_conf_obj(void *ctx, } +static bool wpas_dpp_tcp_msg_sent(void *ctx, struct dpp_authentication *auth) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpa_printf(MSG_DEBUG, "DPP: TCP message sent callback"); + + if (auth->connect_on_tx_status) { + auth->connect_on_tx_status = 0; + wpa_printf(MSG_DEBUG, + "DPP: Try to connect after completed configuration result"); + wpas_dpp_try_to_connect(wpa_s); + if (auth->conn_status_requested) { + wpa_printf(MSG_DEBUG, + "DPP: Start 15 second timeout for reporting connection status result"); + eloop_cancel_timeout( + wpas_dpp_conn_status_result_timeout, + wpa_s, NULL); + eloop_register_timeout( + 15, 0, wpas_dpp_conn_status_result_timeout, + wpa_s, NULL); + return true; + } + } + + return false; +} + + static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi) { struct wpa_supplicant *wpa_s = ctx; @@ -2053,6 +2416,7 @@ wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src, u16 r_bootstrap_len; struct dpp_bootstrap_info *peer_bi; struct dpp_authentication *auth; + unsigned int wait_time, max_wait_time; if (!wpa_s->dpp) return; @@ -2084,6 +2448,9 @@ wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src, return; } + wpa_printf(MSG_DEBUG, "DPP: Start Authentication exchange with " MACSTR + " based on the received Presence Announcement", + MAC2STR(src)); auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, NULL, DPP_CAPAB_CONFIGURATOR, freq, NULL, 0); if (!auth) @@ -2100,6 +2467,13 @@ wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src, * MAC address information from the bootstrapping information. */ os_memcpy(auth->peer_mac_addr, src, ETH_ALEN); + wait_time = wpa_s->max_remain_on_chan; + max_wait_time = wpa_s->dpp_resp_wait_time ? + wpa_s->dpp_resp_wait_time : 2000; + if (wait_time > max_wait_time) + wait_time = max_wait_time; + wpas_dpp_stop_listen_for_tx(wpa_s, freq, wait_time); + wpa_s->dpp_auth = auth; if (wpas_dpp_auth_init_next(wpa_s) < 0) { dpp_auth_deinit(wpa_s->dpp_auth); @@ -2294,7 +2668,7 @@ wpas_dpp_rx_reconfig_auth_resp(struct wpa_supplicant *wpa_s, const u8 *src, return; } - if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(src, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " MACSTR_SEC ") - drop", MAC2STR_SEC(auth->peer_mac_addr)); return; @@ -2338,7 +2712,7 @@ wpas_dpp_rx_reconfig_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src, return; } - if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(src, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected " MACSTR_SEC ") - drop", MAC2STR_SEC(auth->peer_mac_addr)); return; @@ -2376,7 +2750,7 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR_SEC, MAC2STR_SEC(src)); if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) || - os_memcmp(src, wpa_s->dpp_intro_bssid, ETH_ALEN) != 0) { + !ether_addr_equal(src, wpa_s->dpp_intro_bssid)) { wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from " MACSTR_SEC " - drop", MAC2STR_SEC(src)); return; @@ -2394,6 +2768,8 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, return; } + os_memset(&intro, 0, sizeof(intro)); + trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID, &trans_id_len); if (!trans_id || trans_id_len != 1) { @@ -2445,7 +2821,7 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, ssid->dpp_netaccesskey_len, ssid->dpp_csign, ssid->dpp_csign_len, - connector, connector_len, &expiry); + connector, connector_len, &expiry, NULL); if (res != DPP_STATUS_OK) { wpa_printf(MSG_INFO, "DPP: Network Introduction protocol resulted in failure"); @@ -2461,6 +2837,7 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, if (!entry) goto fail; os_memcpy(entry->aa, src, ETH_ALEN); + os_memcpy(entry->spa, wpa_s->own_addr, ETH_ALEN); os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN); os_memcpy(entry->pmk, intro.pmk, intro.pmk_len); entry->pmk_len = intro.pmk_len; @@ -2504,7 +2881,7 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, wpa_supplicant_req_scan(wpa_s, 0, 0); } fail: - os_memset(&intro, 0, sizeof(intro)); + dpp_peer_intro_deinit(&intro); } @@ -2564,41 +2941,193 @@ static int wpas_dpp_pkex_next_channel(struct wpa_supplicant *wpa_s, } -static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx) +static void wpas_dpp_pkex_clear_code(struct wpa_supplicant *wpa_s) { - struct wpa_supplicant *wpa_s = eloop_ctx; - struct dpp_pkex *pkex = wpa_s->dpp_pkex; - - if (!pkex || !pkex->exchange_req) + if (!wpa_s->dpp_pkex_code && !wpa_s->dpp_pkex_identifier) return; - if (pkex->exch_req_tries >= 5) { - if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) { - wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL - "No response from PKEX peer"); - dpp_pkex_free(pkex); - wpa_s->dpp_pkex = NULL; - return; - } - pkex->exch_req_tries = 0; - } - pkex->exch_req_tries++; - wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)", - pkex->exch_req_tries); - wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", - MAC2STR(broadcast), pkex->freq, - pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ : - DPP_PA_PKEX_V1_EXCHANGE_REQ); - offchannel_send_action(wpa_s, pkex->freq, broadcast, - wpa_s->own_addr, broadcast, - wpabuf_head(pkex->exchange_req), - wpabuf_len(pkex->exchange_req), - pkex->exch_req_wait_time, - wpas_dpp_tx_pkex_status, 0); + /* Delete PKEX code and identifier on successful completion of + * PKEX. We are not supposed to reuse these without being + * explicitly requested to perform PKEX again. */ + wpa_printf(MSG_DEBUG, "DPP: Delete PKEX code/identifier"); + os_free(wpa_s->dpp_pkex_code); + wpa_s->dpp_pkex_code = NULL; + os_free(wpa_s->dpp_pkex_identifier); + wpa_s->dpp_pkex_identifier = NULL; + } -static void +#ifdef CONFIG_DPP2 +static int wpas_dpp_pkex_done(void *ctx, void *conn, + struct dpp_bootstrap_info *peer_bi) +{ + struct wpa_supplicant *wpa_s = ctx; + char cmd[500]; + const char *pos; + u8 allowed_roles = DPP_CAPAB_CONFIGURATOR; + struct dpp_bootstrap_info *own_bi = NULL; + struct dpp_authentication *auth; + + wpas_dpp_pkex_clear_code(wpa_s); + + os_snprintf(cmd, sizeof(cmd), " peer=%u %s", peer_bi->id, + wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : ""); + wpa_printf(MSG_DEBUG, "DPP: Start authentication after PKEX (cmd: %s)", + cmd); + + pos = os_strstr(cmd, " own="); + if (pos) { + pos += 5; + own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); + if (!own_bi) { + wpa_printf(MSG_INFO, + "DPP: Could not find bootstrapping info for the identified local entry"); + return -1; + } + + if (peer_bi->curve != own_bi->curve) { + wpa_printf(MSG_INFO, + "DPP: Mismatching curves in bootstrapping info (peer=%s own=%s)", + peer_bi->curve->name, own_bi->curve->name); + return -1; + } + } + + pos = os_strstr(cmd, " role="); + if (pos) { + pos += 6; + if (os_strncmp(pos, "configurator", 12) == 0) + allowed_roles = DPP_CAPAB_CONFIGURATOR; + else if (os_strncmp(pos, "enrollee", 8) == 0) + allowed_roles = DPP_CAPAB_ENROLLEE; + else if (os_strncmp(pos, "either", 6) == 0) + allowed_roles = DPP_CAPAB_CONFIGURATOR | + DPP_CAPAB_ENROLLEE; + else + return -1; + } + + auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles, + 0, wpa_s->hw.modes, wpa_s->hw.num_modes); + if (!auth) + return -1; + + wpas_dpp_set_testing_options(wpa_s, auth); + if (dpp_set_configurator(auth, cmd) < 0) { + dpp_auth_deinit(auth); + return -1; + } + + return dpp_tcp_auth(wpa_s->dpp, conn, auth, wpa_s->conf->dpp_name, + DPP_NETROLE_STA, + wpa_s->conf->dpp_mud_url, + wpa_s->conf->dpp_extra_conf_req_name, + wpa_s->conf->dpp_extra_conf_req_value, + wpas_dpp_process_conf_obj, + wpas_dpp_tcp_msg_sent); +} +#endif /* CONFIG_DPP2 */ + + +static int wpas_dpp_pkex_init(struct wpa_supplicant *wpa_s, + enum dpp_pkex_ver ver, + const struct hostapd_ip_addr *ipaddr, + int tcp_port) +{ + struct dpp_pkex *pkex; + struct wpabuf *msg; + unsigned int wait_time; + bool v2 = ver != PKEX_VER_ONLY_1; + + wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1); + dpp_pkex_free(wpa_s->dpp_pkex); + wpa_s->dpp_pkex = NULL; + pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi, wpa_s->own_addr, + wpa_s->dpp_pkex_identifier, + wpa_s->dpp_pkex_code, wpa_s->dpp_pkex_code_len, + v2); + if (!pkex) + return -1; + pkex->forced_ver = ver != PKEX_VER_AUTO; + + if (ipaddr) { +#ifdef CONFIG_DPP2 + return dpp_tcp_pkex_init(wpa_s->dpp, pkex, ipaddr, tcp_port, + wpa_s, wpa_s, wpas_dpp_pkex_done); +#else /* CONFIG_DPP2 */ + return -1; +#endif /* CONFIG_DPP2 */ + } + + wpa_s->dpp_pkex = pkex; + msg = pkex->exchange_req; + wait_time = wpa_s->max_remain_on_chan; + if (wait_time > 2000) + wait_time = 2000; + pkex->freq = 2437; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", + MAC2STR(broadcast), pkex->freq, + v2 ? DPP_PA_PKEX_EXCHANGE_REQ : + DPP_PA_PKEX_V1_EXCHANGE_REQ); + offchannel_send_action(wpa_s, pkex->freq, broadcast, + wpa_s->own_addr, broadcast, + wpabuf_head(msg), wpabuf_len(msg), + wait_time, wpas_dpp_tx_pkex_status, 0); + if (wait_time == 0) + wait_time = 2000; + pkex->exch_req_wait_time = wait_time; + pkex->exch_req_tries = 1; + + return 0; +} + + +static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct dpp_pkex *pkex = wpa_s->dpp_pkex; + + if (!pkex || !pkex->exchange_req) + return; + if (pkex->exch_req_tries >= 5) { + if (wpas_dpp_pkex_next_channel(wpa_s, pkex) < 0) { +#ifdef CONFIG_DPP3 + if (pkex->v2 && !pkex->forced_ver) { + wpa_printf(MSG_DEBUG, + "DPP: Fall back to PKEXv1"); + wpas_dpp_pkex_init(wpa_s, PKEX_VER_ONLY_1, + NULL, 0); + return; + } +#endif /* CONFIG_DPP3 */ + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL + "No response from PKEX peer"); + dpp_pkex_free(pkex); + wpa_s->dpp_pkex = NULL; + return; + } + pkex->exch_req_tries = 0; + } + + pkex->exch_req_tries++; + wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)", + pkex->exch_req_tries); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(broadcast), pkex->freq, + pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ : + DPP_PA_PKEX_V1_EXCHANGE_REQ); + offchannel_send_action(wpa_s, pkex->freq, broadcast, + wpa_s->own_addr, broadcast, + wpabuf_head(pkex->exchange_req), + wpabuf_len(pkex->exchange_req), + pkex->exch_req_wait_time, + wpas_dpp_tx_pkex_status, 0); +} + + +static void wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *dst, const u8 *src, const u8 *bssid, @@ -2656,6 +3185,17 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src, wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request from " MACSTR_SEC, MAC2STR_SEC(src)); + if (wpa_s->dpp_pkex_ver == PKEX_VER_ONLY_1 && v2) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore PKEXv2 Exchange Request when configured to be PKEX v1 only"); + return; + } + if (wpa_s->dpp_pkex_ver == PKEX_VER_ONLY_2 && !v2) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore PKEXv1 Exchange Request when configured to be PKEX v2 only"); + return; + } + /* TODO: Support multiple PKEX codes by iterating over all the enabled * values here */ @@ -2665,6 +3205,14 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src, return; } +#ifdef CONFIG_DPP2 + if (dpp_controller_is_own_pkex_req(wpa_s->dpp, buf, len)) { + wpa_printf(MSG_DEBUG, + "DPP: PKEX Exchange Request is from local Controller - ignore request"); + return; + } +#endif /* CONFIG_DPP2 */ + if (wpa_s->dpp_pkex) { /* TODO: Support parallel operations */ wpa_printf(MSG_DEBUG, @@ -2676,6 +3224,7 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src, wpa_s->own_addr, src, wpa_s->dpp_pkex_identifier, wpa_s->dpp_pkex_code, + wpa_s->dpp_pkex_code_len, buf, len, v2); if (!wpa_s->dpp_pkex) { wpa_printf(MSG_DEBUG, @@ -2683,6 +3232,15 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src, return; } +#ifdef CONFIG_DPP3 + if (wpa_s->dpp_pb_bi && wpa_s->dpp_pb_announcement) { + wpa_printf(MSG_DEBUG, + "DPP: Started PB PKEX (no more PB announcements)"); + wpabuf_free(wpa_s->dpp_pb_announcement); + wpa_s->dpp_pb_announcement = NULL; + } +#endif /* CONFIG_DPP3 */ + wpa_s->dpp_pkex_wait_auth_req = false; msg = wpa_s->dpp_pkex->exchange_resp; wait_time = wpa_s->max_remain_on_chan; if (wait_time > 2000) @@ -2746,10 +3304,35 @@ wpas_dpp_pkex_finish(struct wpa_supplicant *wpa_s, const u8 *peer, { struct dpp_bootstrap_info *bi; + wpas_dpp_pkex_clear_code(wpa_s); bi = dpp_pkex_finish(wpa_s->dpp, wpa_s->dpp_pkex, peer, freq); if (!bi) return NULL; + wpa_s->dpp_pkex = NULL; + +#ifdef CONFIG_DPP3 + if (wpa_s->dpp_pb_bi && !wpa_s->dpp_pb_configurator && + os_memcmp(bi->pubkey_hash_chirp, wpa_s->dpp_pb_init_hash, + SHA256_MAC_LEN) != 0) { + char id[20]; + + wpa_printf(MSG_INFO, + "DPP: Peer bootstrap key from PKEX does not match PB announcement response hash"); + wpa_hexdump(MSG_DEBUG, + "DPP: Peer provided bootstrap key hash(chirp) from PB PKEX", + bi->pubkey_hash_chirp, SHA256_MAC_LEN); + wpa_hexdump(MSG_DEBUG, + "DPP: Peer provided bootstrap key hash(chirp) from PB announcement response", + wpa_s->dpp_pb_init_hash, SHA256_MAC_LEN); + + os_snprintf(id, sizeof(id), "%u", bi->id); + dpp_bootstrap_remove(wpa_s->dpp, id); + wpas_dpp_push_button_stop(wpa_s); + return NULL; + } +#endif /* CONFIG_DPP3 */ + return bi; } @@ -2799,6 +3382,7 @@ wpas_dpp_rx_pkex_commit_reveal_req(struct wpa_supplicant *wpa_s, const u8 *src, wpabuf_free(msg); wpas_dpp_pkex_finish(wpa_s, src, freq); + wpa_s->dpp_pkex_wait_auth_req = true; } @@ -2820,30 +3404,635 @@ wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src, return; } - res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len); - if (res < 0) { - wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); - return; + res = dpp_pkex_rx_commit_reveal_resp(pkex, hdr, buf, len); + if (res < 0) { + wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); + return; + } + + bi = wpas_dpp_pkex_finish(wpa_s, src, freq); + if (!bi) + return; + +#ifdef CONFIG_DPP3 + if (wpa_s->dpp_pb_bi && wpa_s->dpp_pb_configurator && + os_memcmp(bi->pubkey_hash_chirp, wpa_s->dpp_pb_resp_hash, + SHA256_MAC_LEN) != 0) { + char id[20]; + + wpa_printf(MSG_INFO, + "DPP: Peer bootstrap key from PKEX does not match PB announcement hash"); + wpa_hexdump(MSG_DEBUG, + "DPP: Peer provided bootstrap key hash(chirp) from PB PKEX", + bi->pubkey_hash_chirp, SHA256_MAC_LEN); + wpa_hexdump(MSG_DEBUG, + "DPP: Peer provided bootstrap key hash(chirp) from PB announcement", + wpa_s->dpp_pb_resp_hash, SHA256_MAC_LEN); + + os_snprintf(id, sizeof(id), "%u", bi->id); + dpp_bootstrap_remove(wpa_s->dpp, id); + wpas_dpp_push_button_stop(wpa_s); + return; + } +#endif /* CONFIG_DPP3 */ + + os_snprintf(cmd, sizeof(cmd), " peer=%u %s", + bi->id, + wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : ""); + wpa_printf(MSG_DEBUG, + "DPP: Start authentication after PKEX with parameters: %s", + cmd); + if (wpas_dpp_auth_init(wpa_s, cmd) < 0) { + wpa_printf(MSG_DEBUG, + "DPP: Authentication initialization failed"); + offchannel_send_action_done(wpa_s); + return; + } +} + + +#ifdef CONFIG_DPP3 + +static void wpas_dpp_pb_pkex_init(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *src, + const u8 *r_hash) +{ + struct dpp_pkex *pkex; + struct wpabuf *msg; + unsigned int wait_time; + size_t len; + + if (wpa_s->dpp_pkex) { + wpa_printf(MSG_DEBUG, + "DPP: Sending previously generated PKEX Exchange Request to " + MACSTR, MAC2STR(src)); + msg = wpa_s->dpp_pkex->exchange_req; + wait_time = wpa_s->max_remain_on_chan; + if (wait_time > 2000) + wait_time = 2000; + offchannel_send_action(wpa_s, freq, src, + wpa_s->own_addr, broadcast, + wpabuf_head(msg), wpabuf_len(msg), + wait_time, wpas_dpp_tx_pkex_status, 0); + return; + } + + wpa_printf(MSG_DEBUG, "DPP: Initiate PKEX for push button with " + MACSTR, MAC2STR(src)); + + if (!wpa_s->dpp_pb_cmd) { + wpa_printf(MSG_INFO, + "DPP: No configuration to provision as push button Configurator"); + wpas_dpp_push_button_stop(wpa_s); + return; + } + + wpa_s->dpp_pkex_bi = wpa_s->dpp_pb_bi; + os_memcpy(wpa_s->dpp_pb_resp_hash, r_hash, SHA256_MAC_LEN); + + pkex = dpp_pkex_init(wpa_s, wpa_s->dpp_pkex_bi, wpa_s->own_addr, + "PBPKEX", (const char *) wpa_s->dpp_pb_c_nonce, + wpa_s->dpp_pb_bi->curve->nonce_len, + true); + if (!pkex) { + wpas_dpp_push_button_stop(wpa_s); + return; + } + pkex->freq = freq; + + wpa_s->dpp_pkex = pkex; + msg = wpa_s->dpp_pkex->exchange_req; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", MAC2STR(src), freq, + DPP_PA_PKEX_EXCHANGE_REQ); + wait_time = wpa_s->max_remain_on_chan; + if (wait_time > 2000) + wait_time = 2000; + offchannel_send_action(wpa_s, pkex->freq, src, + wpa_s->own_addr, broadcast, + wpabuf_head(msg), wpabuf_len(msg), + wait_time, wpas_dpp_tx_pkex_status, 0); + pkex->exch_req_wait_time = 2000; + pkex->exch_req_tries = 1; + + /* Use the externally provided configuration */ + os_free(wpa_s->dpp_pkex_auth_cmd); + len = 30 + os_strlen(wpa_s->dpp_pb_cmd); + wpa_s->dpp_pkex_auth_cmd = os_malloc(len); + if (wpa_s->dpp_pkex_auth_cmd) + os_snprintf(wpa_s->dpp_pkex_auth_cmd, len, " own=%d %s", + wpa_s->dpp_pkex_bi->id, wpa_s->dpp_pb_cmd); + else + wpas_dpp_push_button_stop(wpa_s); +} + + +static void +wpas_dpp_rx_pb_presence_announcement(struct wpa_supplicant *wpa_s, + const u8 *src, const u8 *hdr, + const u8 *buf, size_t len, + unsigned int freq) +{ + const u8 *r_hash; + u16 r_hash_len; + unsigned int i; + bool found = false; + struct dpp_pb_info *info, *tmp; + struct os_reltime now, age; + struct wpabuf *msg; + + os_get_reltime(&now); + wpa_printf(MSG_DEBUG, "DPP: Push Button Presence Announcement from " + MACSTR, MAC2STR(src)); + + r_hash = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, + &r_hash_len); + if (!r_hash || r_hash_len != SHA256_MAC_LEN) { + wpa_printf(MSG_DEBUG, + "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute"); + return; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", + r_hash, r_hash_len); + + for (i = 0; i < DPP_PB_INFO_COUNT; i++) { + info = &wpa_s->dpp_pb[i]; + if ((info->rx_time.sec == 0 && info->rx_time.usec == 0) || + os_memcmp(r_hash, info->hash, SHA256_MAC_LEN) != 0) + continue; + wpa_printf(MSG_DEBUG, + "DPP: Active push button Enrollee already known"); + found = true; + info->rx_time = now; + } + + if (!found) { + for (i = 0; i < DPP_PB_INFO_COUNT; i++) { + tmp = &wpa_s->dpp_pb[i]; + if (tmp->rx_time.sec == 0 && tmp->rx_time.usec == 0) + continue; + + if (os_reltime_expired(&now, &tmp->rx_time, 120)) { + wpa_hexdump(MSG_DEBUG, + "DPP: Push button Enrollee hash expired", + tmp->hash, SHA256_MAC_LEN); + tmp->rx_time.sec = 0; + tmp->rx_time.usec = 0; + continue; + } + + wpa_hexdump(MSG_DEBUG, + "DPP: Push button session overlap with hash", + tmp->hash, SHA256_MAC_LEN); + if (!wpa_s->dpp_pb_result_indicated && + wpas_dpp_pb_active(wpa_s)) { + wpa_msg(wpa_s, MSG_INFO, + DPP_EVENT_PB_RESULT "session-overlap"); + wpa_s->dpp_pb_result_indicated = true; + } + wpas_dpp_push_button_stop(wpa_s); + return; + } + + /* Replace the oldest entry */ + info = &wpa_s->dpp_pb[0]; + for (i = 1; i < DPP_PB_INFO_COUNT; i++) { + tmp = &wpa_s->dpp_pb[i]; + if (os_reltime_before(&tmp->rx_time, &info->rx_time)) + info = tmp; + } + wpa_printf(MSG_DEBUG, "DPP: New active push button Enrollee"); + os_memcpy(info->hash, r_hash, SHA256_MAC_LEN); + info->rx_time = now; + } + + if (!wpas_dpp_pb_active(wpa_s)) { + wpa_printf(MSG_DEBUG, + "DPP: Discard message since own push button has not been pressed"); + return; + } + + if (wpa_s->dpp_pb_announce_time.sec == 0 && + wpa_s->dpp_pb_announce_time.usec == 0) { + /* Start a wait before allowing PKEX to be initiated */ + wpa_s->dpp_pb_announce_time = now; + } + + if (!wpa_s->dpp_pb_bi) { + int res; + + res = dpp_bootstrap_gen(wpa_s->dpp, "type=pkex"); + if (res < 0) + return; + wpa_s->dpp_pb_bi = dpp_bootstrap_get_id(wpa_s->dpp, res); + if (!wpa_s->dpp_pb_bi) + return; + + if (random_get_bytes(wpa_s->dpp_pb_c_nonce, + wpa_s->dpp_pb_bi->curve->nonce_len)) { + wpa_printf(MSG_ERROR, + "DPP: Failed to generate C-nonce"); + wpas_dpp_push_button_stop(wpa_s); + return; + } + } + + /* Skip the response if one was sent within last 50 ms since the + * Enrollee is going to send out at least three announcement messages. + */ + os_reltime_sub(&now, &wpa_s->dpp_pb_last_resp, &age); + if (age.sec == 0 && age.usec < 50000) { + wpa_printf(MSG_DEBUG, + "DPP: Skip Push Button Presence Announcement Response frame immediately after having sent one"); + return; + } + + msg = dpp_build_pb_announcement_resp( + wpa_s->dpp_pb_bi, r_hash, wpa_s->dpp_pb_c_nonce, + wpa_s->dpp_pb_bi->curve->nonce_len); + if (!msg) { + wpas_dpp_push_button_stop(wpa_s); + return; + } + + wpa_printf(MSG_DEBUG, + "DPP: Send Push Button Presence Announcement Response to " + MACSTR, MAC2STR(src)); + wpa_s->dpp_pb_last_resp = now; + + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(src), freq, DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP); + offchannel_send_action(wpa_s, freq, src, wpa_s->own_addr, broadcast, + wpabuf_head(msg), wpabuf_len(msg), + 0, NULL, 0); + wpabuf_free(msg); + + if (os_reltime_expired(&now, &wpa_s->dpp_pb_announce_time, 15)) + wpas_dpp_pb_pkex_init(wpa_s, freq, src, r_hash); +} + + +static void +wpas_dpp_rx_pb_presence_announcement_resp(struct wpa_supplicant *wpa_s, + const u8 *src, const u8 *hdr, + const u8 *buf, size_t len, + unsigned int freq) +{ + const u8 *i_hash, *r_hash, *c_nonce; + u16 i_hash_len, r_hash_len, c_nonce_len; + bool overlap = false; + + if (!wpa_s->dpp_pb_announcement || !wpa_s->dpp_pb_bi || + wpa_s->dpp_pb_configurator) { + wpa_printf(MSG_INFO, + "DPP: Not in active push button Enrollee mode - discard Push Button Presence Announcement Response from " + MACSTR, MAC2STR(src)); + return; + } + + wpa_printf(MSG_DEBUG, + "DPP: Push Button Presence Announcement Response from " + MACSTR, MAC2STR(src)); + + i_hash = dpp_get_attr(buf, len, DPP_ATTR_I_BOOTSTRAP_KEY_HASH, + &i_hash_len); + r_hash = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, + &r_hash_len); + c_nonce = dpp_get_attr(buf, len, DPP_ATTR_CONFIGURATOR_NONCE, + &c_nonce_len); + if (!i_hash || i_hash_len != SHA256_MAC_LEN || + !r_hash || r_hash_len != SHA256_MAC_LEN || + !c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) { + wpa_printf(MSG_DEBUG, + "DPP: Missing or invalid required attribute"); + return; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Bootstrapping Key Hash", + i_hash, i_hash_len); + wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", + r_hash, r_hash_len); + wpa_hexdump(MSG_MSGDUMP, "DPP: Configurator Nonce", + c_nonce, c_nonce_len); + +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_PB_REQ && + os_memcmp(r_hash, wpa_s->dpp_pb_bi->pubkey_hash_chirp, + SHA256_MAC_LEN - 1) == 0) + goto skip_hash_check; +#endif /* CONFIG_TESTING_OPTIONS */ + if (os_memcmp(r_hash, wpa_s->dpp_pb_bi->pubkey_hash_chirp, + SHA256_MAC_LEN) != 0) { + wpa_printf(MSG_INFO, + "DPP: Unexpected push button Responder hash - abort"); + overlap = true; + } +#ifdef CONFIG_TESTING_OPTIONS +skip_hash_check: +#endif /* CONFIG_TESTING_OPTIONS */ + + if (wpa_s->dpp_pb_resp_freq && + os_memcmp(i_hash, wpa_s->dpp_pb_init_hash, SHA256_MAC_LEN) != 0) { + wpa_printf(MSG_INFO, + "DPP: Push button session overlap detected - abort"); + overlap = true; + } + + if (overlap) { + if (!wpa_s->dpp_pb_result_indicated) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT + "session-overlap"); + wpa_s->dpp_pb_result_indicated = true; + } + wpas_dpp_push_button_stop(wpa_s); + return; + } + + if (!wpa_s->dpp_pb_resp_freq) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS + "discovered push button AP/Configurator " MACSTR, + MAC2STR(src)); + wpa_s->dpp_pb_resp_freq = freq; + os_memcpy(wpa_s->dpp_pb_init_hash, i_hash, SHA256_MAC_LEN); + os_memcpy(wpa_s->dpp_pb_c_nonce, c_nonce, c_nonce_len); + wpa_s->dpp_pb_c_nonce_len = c_nonce_len; + /* Stop announcement iterations after at least one more full + * round and one extra round for postponed session overlap + * detection. */ + wpa_s->dpp_pb_stop_iter = 3; + } +} + + +static void +wpas_dpp_tx_priv_intro_status(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, + const u8 *data, size_t data_len, + enum offchannel_send_action_result result) +{ + const char *res_txt; + + res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" : + (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" : + "FAILED"); + wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR + " result=%s (DPP Private Peer Introduction Update)", + freq, MAC2STR(dst), res_txt); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR + " freq=%u result=%s", MAC2STR(dst), freq, res_txt); + + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR " version=%u", + MAC2STR(src), wpa_s->dpp_intro_peer_version); + + wpa_printf(MSG_DEBUG, + "DPP: Try connection again after successful network introduction"); + if (wpa_supplicant_fast_associate(wpa_s) != 1) { + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_supplicant_req_scan(wpa_s, 0, 0); + } +} + + +static int +wpas_dpp_send_private_peer_intro_update(struct wpa_supplicant *wpa_s, + struct dpp_introduction *intro, + struct wpa_ssid *ssid, + const u8 *dst, unsigned int freq) +{ + struct wpabuf *pt, *msg, *enc_ct; + size_t len; + u8 ver = DPP_VERSION; + int conn_ver; + const u8 *aad; + size_t aad_len; + unsigned int wait_time; + + wpa_printf(MSG_DEBUG, "HPKE(kem_id=%u kdf_id=%u aead_id=%u)", + intro->kem_id, intro->kdf_id, intro->aead_id); + + /* Plaintext for HPKE */ + len = 5 + 4 + os_strlen(ssid->dpp_connector); + pt = wpabuf_alloc(len); + if (!pt) + return -1; + + /* Protocol Version */ + conn_ver = dpp_get_connector_version(ssid->dpp_connector); + if (conn_ver > 0 && ver != conn_ver) { + wpa_printf(MSG_DEBUG, + "DPP: Use Connector version %d instead of current protocol version %d", + conn_ver, ver); + ver = conn_ver; + } + wpabuf_put_le16(pt, DPP_ATTR_PROTOCOL_VERSION); + wpabuf_put_le16(pt, 1); + wpabuf_put_u8(pt, ver); + + /* Connector */ + wpabuf_put_le16(pt, DPP_ATTR_CONNECTOR); + wpabuf_put_le16(pt, os_strlen(ssid->dpp_connector)); + wpabuf_put_str(pt, ssid->dpp_connector); + wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Plaintext for HPKE", pt); + + /* HPKE(pt) using AP's public key (from its Connector) */ + msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_UPDATE, 0); + if (!msg) { + wpabuf_free(pt); + return -1; + } + aad = wpabuf_head_u8(msg) + 2; /* from the OUI field (inclusive) */ + aad_len = DPP_HDR_LEN; /* to the DPP Frame Type field (inclusive) */ + wpa_hexdump(MSG_MSGDUMP, "DPP: AAD for HPKE", aad, aad_len); + + enc_ct = hpke_base_seal(intro->kem_id, intro->kdf_id, intro->aead_id, + intro->peer_key, NULL, 0, aad, aad_len, + wpabuf_head(pt), wpabuf_len(pt)); + wpabuf_free(pt); + wpabuf_free(msg); + if (!enc_ct) { + wpa_printf(MSG_INFO, "DPP: HPKE Seal(Connector) failed"); + return -1; + } + wpa_hexdump_buf(MSG_MSGDUMP, "DPP: HPKE enc|ct", enc_ct); + + /* HPKE(pt) to generate payload for Wrapped Data */ + len = 5 + 4 + wpabuf_len(enc_ct); + msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_UPDATE, len); + if (!msg) { + wpabuf_free(enc_ct); + return -1; + } + + /* Transaction ID */ + wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, TRANSACTION_ID); + + /* Wrapped Data */ + wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); + wpabuf_put_le16(msg, wpabuf_len(enc_ct)); + wpabuf_put_buf(msg, enc_ct); + wpabuf_free(enc_ct); + + wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Private Peer Intro Update", msg); + + /* TODO: Timeout on AP response */ + wait_time = wpa_s->max_remain_on_chan; + if (wait_time > 2000) + wait_time = 2000; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(dst), freq, DPP_PA_PRIV_PEER_INTRO_QUERY); + offchannel_send_action(wpa_s, freq, dst, wpa_s->own_addr, broadcast, + wpabuf_head(msg), wpabuf_len(msg), + wait_time, wpas_dpp_tx_priv_intro_status, 0); + wpabuf_free(msg); + + return 0; +} + + +static void +wpas_dpp_rx_priv_peer_intro_notify(struct wpa_supplicant *wpa_s, + const u8 *src, const u8 *hdr, + const u8 *buf, size_t len, + unsigned int freq) +{ + struct wpa_ssid *ssid; + const u8 *connector, *trans_id, *version; + u16 connector_len, trans_id_len, version_len; + u8 peer_version = 1; + struct dpp_introduction intro; + struct rsn_pmksa_cache_entry *entry; + struct os_time now; + struct os_reltime rnow; + os_time_t expiry; + unsigned int seconds; + enum dpp_status_error res; + + os_memset(&intro, 0, sizeof(intro)); + + wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction Notify from " + MACSTR, MAC2STR(src)); + if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) || + !ether_addr_equal(src, wpa_s->dpp_intro_bssid)) { + wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from " + MACSTR " - drop", MAC2STR(src)); + return; + } + offchannel_send_action_done(wpa_s); + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (ssid == wpa_s->dpp_intro_network) + break; + } + if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey || + !ssid->dpp_csign) { + wpa_printf(MSG_DEBUG, + "DPP: Profile not found for network introduction"); + return; + } + + trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID, + &trans_id_len); + if (!trans_id || trans_id_len != 1) { + wpa_printf(MSG_DEBUG, + "DPP: Peer did not include Transaction ID"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=missing_transaction_id", MAC2STR(src)); + goto fail; + } + if (trans_id[0] != TRANSACTION_ID) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore frame with unexpected Transaction ID %u", + trans_id[0]); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=transaction_id_mismatch", MAC2STR(src)); + goto fail; + } + + connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len); + if (!connector) { + wpa_printf(MSG_DEBUG, + "DPP: Peer did not include its Connector"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=missing_connector", MAC2STR(src)); + goto fail; + } + + version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION, + &version_len); + if (!version || version_len < 1) { + wpa_printf(MSG_DEBUG, + "DPP: Peer did not include valid Version"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=missing_version", MAC2STR(src)); + goto fail; + } + + res = dpp_peer_intro(&intro, ssid->dpp_connector, + ssid->dpp_netaccesskey, + ssid->dpp_netaccesskey_len, + ssid->dpp_csign, + ssid->dpp_csign_len, + connector, connector_len, &expiry, NULL); + if (res != DPP_STATUS_OK) { + wpa_printf(MSG_INFO, + "DPP: Network Introduction protocol resulted in failure"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=peer_connector_validation_failed", MAC2STR(src)); + wpas_dpp_send_conn_status_result(wpa_s, res); + goto fail; + } + + peer_version = version[0]; + if (intro.peer_version && intro.peer_version >= 2 && + peer_version != intro.peer_version) { + wpa_printf(MSG_INFO, + "DPP: Protocol version mismatch (Connector: %d Attribute: %d", + intro.peer_version, peer_version); + wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_NO_MATCH); + goto fail; } + wpa_s->dpp_intro_peer_version = peer_version; - bi = wpas_dpp_pkex_finish(wpa_s, src, freq); - if (!bi) - return; + entry = os_zalloc(sizeof(*entry)); + if (!entry) + goto fail; + entry->dpp_pfs = peer_version >= 2; + os_memcpy(entry->aa, src, ETH_ALEN); + os_memcpy(entry->spa, wpa_s->own_addr, ETH_ALEN); + os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN); + os_memcpy(entry->pmk, intro.pmk, intro.pmk_len); + entry->pmk_len = intro.pmk_len; + entry->akmp = WPA_KEY_MGMT_DPP; + if (expiry) { + os_get_time(&now); + seconds = expiry - now.sec; + } else { + seconds = 86400 * 7; + } - os_snprintf(cmd, sizeof(cmd), " peer=%u %s", - bi->id, - wpa_s->dpp_pkex_auth_cmd ? wpa_s->dpp_pkex_auth_cmd : ""); - wpa_printf(MSG_DEBUG, - "DPP: Start authentication after PKEX with parameters: %s", - cmd); - if (wpas_dpp_auth_init(wpa_s, cmd) < 0) { - wpa_printf(MSG_DEBUG, - "DPP: Authentication initialization failed"); - offchannel_send_action_done(wpa_s); - return; + if (wpas_dpp_send_private_peer_intro_update(wpa_s, &intro, ssid, src, + freq) < 0) { + os_free(entry); + goto fail; } + + os_get_reltime(&rnow); + entry->expiration = rnow.sec + seconds; + entry->reauth_time = rnow.sec + seconds; + entry->network_ctx = ssid; + wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry); + + /* Association will be initiated from TX status handler for the Private + * Peer Intro Update: wpas_dpp_tx_priv_intro_status() */ + +fail: + dpp_peer_intro_deinit(&intro); } +#endif /* CONFIG_DPP3 */ + void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *buf, size_t len, unsigned int freq) @@ -2868,6 +4057,15 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, "DPP: Received DPP Public Action frame crypto suite %u type %d from " MACSTR_SEC " freq=%u", crypto_suite, type, MAC2STR_SEC(src), freq); +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->dpp_discard_public_action && + type != DPP_PA_PEER_DISCOVERY_RESP && + type != DPP_PA_PRIV_PEER_INTRO_NOTIFY) { + wpa_printf(MSG_DEBUG, + "TESTING: Discard received DPP Public Action frame"); + return; + } +#endif /* CONFIG_TESTING_OPTIONS */ if (crypto_suite != 1) { wpa_printf(MSG_DEBUG, "DPP: Unsupported crypto suite %u", crypto_suite); @@ -2947,6 +4145,20 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, wpas_dpp_rx_reconfig_auth_conf(wpa_s, src, hdr, buf, len, freq); break; #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + case DPP_PA_PB_PRESENCE_ANNOUNCEMENT: + wpas_dpp_rx_pb_presence_announcement(wpa_s, src, hdr, + buf, len, freq); + break; + case DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP: + wpas_dpp_rx_pb_presence_announcement_resp(wpa_s, src, hdr, + buf, len, freq); + break; + case DPP_PA_PRIV_PEER_INTRO_NOTIFY: + wpas_dpp_rx_priv_peer_intro_notify(wpa_s, src, hdr, + buf, len, freq); + break; +#endif /* CONFIG_DPP3 */ default: wpa_printf(MSG_DEBUG, "DPP: Ignored unsupported frame subtype %d", type); @@ -2966,9 +4178,25 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, } +static void wpas_dpp_gas_initial_resp_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_config || !auth->config_resp_ctx) + return; + + wpa_printf(MSG_DEBUG, + "DPP: No configuration available from upper layers - send initial response with comeback delay"); + gas_server_set_comeback_delay(wpa_s->gas_server, auth->config_resp_ctx, + 500); +} + + static struct wpabuf * wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa, - const u8 *query, size_t query_len, u16 *comeback_delay) + const u8 *query, size_t query_len, int *comeback_delay) { struct wpa_supplicant *wpa_s = ctx; struct dpp_authentication *auth = wpa_s->dpp_auth; @@ -2977,7 +4205,7 @@ wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa, wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR_SEC, MAC2STR_SEC(sa)); if (!auth || (!auth->auth_success && !auth->reconfig_success) || - os_memcmp(sa, auth->peer_mac_addr, ETH_ALEN) != 0) { + !ether_addr_equal(sa, auth->peer_mac_addr)) { wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); return NULL; } @@ -2989,8 +4217,15 @@ wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa, * TX status handler, but since there was no such handler call * yet, simply send out the event message and proceed with * exchange. */ - wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=1"); + dpp_notify_auth_success(auth, 1); wpa_s->dpp_auth_ok_on_ack = 0; +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_STOP_AT_AUTH_CONF) { + wpa_printf(MSG_INFO, + "DPP: TESTING - stop at Authentication Confirm"); + return NULL; + } +#endif /* CONFIG_TESTING_OPTIONS */ } wpa_hexdump(MSG_DEBUG, @@ -3000,19 +4235,76 @@ wpas_dpp_gas_req_handler(void *ctx, void *resp_ctx, const u8 *sa, MAC2STR(sa)); resp = dpp_conf_req_rx(auth, query, query_len); + auth->gas_server_ctx = resp_ctx; + #ifdef CONFIG_DPP2 if (!resp && auth->waiting_cert) { wpa_printf(MSG_DEBUG, "DPP: Certificate not yet ready"); - auth->cert_resp_ctx = resp_ctx; + auth->config_resp_ctx = resp_ctx; *comeback_delay = 500; return NULL; } #endif /* CONFIG_DPP2 */ - if (!resp) - wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); + if (!resp && auth->waiting_config && + (auth->peer_bi || auth->tmp_peer_bi)) { + char *buf = NULL, *name = ""; + char band[200], *pos, *end; + int i, res, *opclass = auth->e_band_support; + char *mud_url = "N/A"; + + wpa_printf(MSG_DEBUG, "DPP: Configuration not yet ready"); + auth->config_resp_ctx = resp_ctx; + *comeback_delay = -1; + if (auth->e_name) { + size_t len = os_strlen(auth->e_name); + + buf = os_malloc(len * 4 + 1); + if (buf) { + printf_encode(buf, len * 4 + 1, + (const u8 *) auth->e_name, len); + name = buf; + } + } + band[0] = '\0'; + pos = band; + end = band + sizeof(band); + for (i = 0; opclass && opclass[i]; i++) { + res = os_snprintf(pos, end - pos, "%s%d", + pos == band ? "" : ",", opclass[i]); + if (os_snprintf_error(end - pos, res)) { + *pos = '\0'; + break; + } + pos += res; + } + if (auth->e_mud_url) { + size_t len = os_strlen(auth->e_mud_url); + + if (!has_ctrl_char((const u8 *) auth->e_mud_url, len)) + mud_url = auth->e_mud_url; + } + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_NEEDED "peer=%d src=" + MACSTR " net_role=%s name=\"%s\" opclass=%s mud_url=%s", + auth->peer_bi ? auth->peer_bi->id : + auth->tmp_peer_bi->id, MAC2STR(sa), + dpp_netrole_str(auth->e_netrole), name, band, mud_url); + os_free(buf); + + eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, + NULL); + eloop_register_timeout(0, 50000, + wpas_dpp_gas_initial_resp_timeout, wpa_s, + NULL); + return NULL; + } + auth->conf_resp = resp; - auth->gas_server_ctx = resp_ctx; + if (!resp) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + } return resp; } @@ -3043,6 +4335,14 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok) } #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + if (auth->waiting_new_key && ok) { + wpa_printf(MSG_DEBUG, "DPP: Waiting for a new key"); + wpabuf_free(resp); + return; + } +#endif /* CONFIG_DPP3 */ + wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)", ok); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); @@ -3067,12 +4367,27 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok) offchannel_send_action_done(wpa_s); wpas_dpp_listen_stop(wpa_s); if (ok) - wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT "conf_status=%d", + auth->conf_resp_status); else wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); dpp_auth_deinit(wpa_s->dpp_auth); wpa_s->dpp_auth = NULL; wpabuf_free(resp); +#ifdef CONFIG_DPP3 + if (!wpa_s->dpp_pb_result_indicated && wpas_dpp_pb_active(wpa_s)) { + if (ok) + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT + "success"); + else + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT + "could-not-connect"); + wpa_s->dpp_pb_result_indicated = true; + if (ok) + wpas_dpp_remove_pb_hash(wpa_s); + wpas_dpp_push_button_stop(wpa_s); + } +#endif /* CONFIG_DPP3 */ } @@ -3123,6 +4438,63 @@ wpas_dpp_tx_introduction_status(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_DPP3 +static int wpas_dpp_start_private_peer_intro(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + struct wpa_bss *bss) +{ + struct wpabuf *msg; + unsigned int wait_time; + size_t len; + u8 ver = DPP_VERSION; + int conn_ver; + + len = 5 + 5; + msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_QUERY, len); + if (!msg) + return -1; + + /* Transaction ID */ + wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, TRANSACTION_ID); + + conn_ver = dpp_get_connector_version(ssid->dpp_connector); + if (conn_ver > 0 && ver != conn_ver) { + wpa_printf(MSG_DEBUG, + "DPP: Use Connector version %d instead of current protocol version %d", + conn_ver, ver); + ver = conn_ver; + } + + /* Protocol Version */ + wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, ver); + + wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Private Peer Intro Query", msg); + + /* TODO: Timeout on AP response */ + wait_time = wpa_s->max_remain_on_chan; + if (wait_time > 2000) + wait_time = 2000; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(bss->bssid), bss->freq, DPP_PA_PRIV_PEER_INTRO_QUERY); + offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr, + broadcast, + wpabuf_head(msg), wpabuf_len(msg), + wait_time, wpas_dpp_tx_introduction_status, 0); + wpabuf_free(msg); + + /* Request this connection attempt to terminate - new one will be + * started when network introduction protocol completes */ + os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN); + wpa_s->dpp_intro_network = ssid; + return 1; +} +#endif /* CONFIG_DPP3 */ + + int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_bss *bss) { @@ -3139,7 +4511,7 @@ int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 && !(ied.key_mgmt & WPA_KEY_MGMT_DPP)) return 0; /* AP does not support DPP AKM - continue */ - if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid)) + if (wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, wpa_s->own_addr, ssid)) return 0; /* PMKSA exists for DPP AKM - continue */ if (!ssid->dpp_connector || !ssid->dpp_netaccesskey || @@ -3162,8 +4534,17 @@ int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, } wpa_printf(MSG_DEBUG, - "DPP: Starting network introduction protocol to derive PMKSA for " - MACSTR_SEC, MAC2STR_SEC(bss->bssid)); + "DPP: Starting %snetwork introduction protocol to derive PMKSA for " + MACSTR_SEC, + ssid->dpp_connector_privacy ? "private " : "", + MAC2STR_SEC(bss->bssid)); + if (wpa_s->wpa_state == WPA_SCANNING) + wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state); + +#ifdef CONFIG_DPP3 + if (ssid->dpp_connector_privacy) + return wpas_dpp_start_private_peer_intro(wpa_s, ssid, bss); +#endif /* CONFIG_DPP3 */ len = 5 + 4 + os_strlen(ssid->dpp_connector); #ifdef CONFIG_DPP2 @@ -3243,6 +4624,13 @@ skip_connector: } #endif /* CONFIG_DPP3 */ +#ifdef CONFIG_TESTING_OPTIONS + if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_PEER_DISC_REQ) { + wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version"); + ver = 1; + } +#endif /* CONFIG_TESTING_OPTIONS */ + /* Protocol Version */ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); wpabuf_put_le16(msg, 1); @@ -3278,7 +4666,34 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) { struct dpp_bootstrap_info *own_bi; const char *pos, *end; - unsigned int wait_time; +#ifdef CONFIG_DPP3 + enum dpp_pkex_ver ver = PKEX_VER_AUTO; +#else /* CONFIG_DPP3 */ + enum dpp_pkex_ver ver = PKEX_VER_ONLY_1; +#endif /* CONFIG_DPP3 */ + int tcp_port = DPP_TCP_PORT; + struct hostapd_ip_addr *ipaddr = NULL; +#ifdef CONFIG_DPP2 + struct hostapd_ip_addr ipaddr_buf; + char *addr; + + 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_buf); + os_free(addr); + if (res) + return -1; + ipaddr = &ipaddr_buf; + } +#endif /* CONFIG_DPP2 */ pos = os_strstr(cmd, " own="); if (!pos) @@ -3320,39 +4735,32 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd) wpa_s->dpp_pkex_code = os_strdup(pos + 6); if (!wpa_s->dpp_pkex_code) return -1; + wpa_s->dpp_pkex_code_len = os_strlen(wpa_s->dpp_pkex_code); - if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) { - struct dpp_pkex *pkex; - struct wpabuf *msg; - bool v2 = os_strstr(cmd, " init=2") != NULL; - - wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX"); - dpp_pkex_free(wpa_s->dpp_pkex); - wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr, - wpa_s->dpp_pkex_identifier, - wpa_s->dpp_pkex_code, v2); - pkex = wpa_s->dpp_pkex; - if (!pkex) + pos = os_strstr(cmd, " ver="); + if (pos) { + int v; + + pos += 5; + v = atoi(pos); + if (v == 1) + ver = PKEX_VER_ONLY_1; + else if (v == 2) + ver = PKEX_VER_ONLY_2; + else return -1; + } + wpa_s->dpp_pkex_ver = ver; - msg = pkex->exchange_req; - wait_time = wpa_s->max_remain_on_chan; - if (wait_time > 2000) - wait_time = 2000; - pkex->freq = 2437; - wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR - " freq=%u type=%d", - MAC2STR(broadcast), pkex->freq, - v2 ? DPP_PA_PKEX_EXCHANGE_REQ : - DPP_PA_PKEX_V1_EXCHANGE_REQ); - offchannel_send_action(wpa_s, pkex->freq, broadcast, - wpa_s->own_addr, broadcast, - wpabuf_head(msg), wpabuf_len(msg), - wait_time, wpas_dpp_tx_pkex_status, 0); - if (wait_time == 0) - wait_time = 2000; - pkex->exch_req_wait_time = wait_time; - pkex->exch_req_tries = 1; + if (os_strstr(cmd, " init=1")) { + if (wpas_dpp_pkex_init(wpa_s, ver, ipaddr, tcp_port) < 0) + return -1; + } else { +#ifdef CONFIG_DPP2 + dpp_controller_pkex_add(wpa_s->dpp, own_bi, + wpa_s->dpp_pkex_code, + wpa_s->dpp_pkex_identifier); +#endif /* CONFIG_DPP2 */ } /* TODO: Support multiple PKEX info entries */ @@ -3376,7 +4784,7 @@ int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id) return -1; } - if ((id_val != 0 && id_val != 1) || !wpa_s->dpp_pkex_code) + if ((id_val != 0 && id_val != 1)) return -1; /* TODO: Support multiple PKEX entries */ @@ -3396,14 +4804,18 @@ int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id) void wpas_dpp_stop(struct wpa_supplicant *wpa_s) { - if (wpa_s->dpp_auth || wpa_s->dpp_pkex) + if (wpa_s->dpp_auth || wpa_s->dpp_pkex || wpa_s->dpp_pkex_wait_auth_req) offchannel_send_action_done(wpa_s); dpp_auth_deinit(wpa_s->dpp_auth); wpa_s->dpp_auth = NULL; dpp_pkex_free(wpa_s->dpp_pkex); wpa_s->dpp_pkex = NULL; + wpa_s->dpp_pkex_wait_auth_req = false; if (wpa_s->dpp_gas_client && wpa_s->dpp_gas_dialog_token >= 0) gas_query_stop(wpa_s->gas, wpa_s->dpp_gas_dialog_token); +#ifdef CONFIG_DPP3 + wpas_dpp_push_button_stop(wpa_s); +#endif /* CONFIG_DPP3 */ } @@ -3451,28 +4863,118 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) 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); + eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_gas_client_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_drv_wait_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_tx_auth_resp_roc_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_neg_freq_timeout, wpa_s, NULL); +#ifdef CONFIG_DPP2 + eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout, + wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_reconfig_reply_wait_timeout, + wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_build_csr, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_connected_timeout, 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 */ +#ifdef CONFIG_DPP3 + eloop_cancel_timeout(wpas_dpp_build_new_key, wpa_s, NULL); +#endif /* CONFIG_DPP3 */ + offchannel_send_action_done(wpa_s); + wpas_dpp_listen_stop(wpa_s); + wpas_dpp_stop(wpa_s); + wpas_dpp_pkex_remove(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); +} + + +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; + } + + eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, NULL); + if (gas_server_set_resp(wpa_s->gas_server, auth->config_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_conf_set(struct wpa_supplicant *wpa_s, const char *cmd) +{ + int peer; + const char *pos; + struct dpp_authentication *auth = wpa_s->dpp_auth; + bool tcp = false; + + pos = os_strstr(cmd, " peer="); + if (!pos) + return -1; + peer = atoi(pos + 6); #ifdef CONFIG_DPP2 - eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL); - eloop_cancel_timeout(wpas_dpp_conn_status_result_wait_timeout, - wpa_s, NULL); - eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL); - 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; + if (!auth || !auth->waiting_config || + (auth->peer_bi && + (unsigned int) peer != auth->peer_bi->id)) { + auth = dpp_controller_get_auth(wpa_s->dpp, peer); + tcp = true; + } #endif /* CONFIG_DPP2 */ - offchannel_send_action_done(wpa_s); - wpas_dpp_listen_stop(wpa_s); - wpas_dpp_stop(wpa_s); - wpas_dpp_pkex_remove(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); + + if (!auth || !auth->waiting_config) { + wpa_printf(MSG_DEBUG, + "DPP: No authentication exchange waiting for configuration information"); + return -1; + } + + if ((!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, " comeback="); + if (pos) { + eloop_cancel_timeout(wpas_dpp_gas_initial_resp_timeout, wpa_s, + NULL); + gas_server_set_comeback_delay(wpa_s->gas_server, + auth->config_resp_ctx, + atoi(pos + 10)); + return 0; + } + + if (dpp_set_configurator(auth, cmd) < 0) + return -1; + + auth->use_config_query = false; + auth->waiting_config = false; + return wpas_dpp_build_conf_resp(wpa_s, auth, tcp); } @@ -3489,6 +4991,7 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd) config.msg_ctx = wpa_s; config.cb_ctx = wpa_s; config.process_conf_obj = wpas_dpp_process_conf_obj; + config.tcp_msg_sent = wpas_dpp_tcp_msg_sent; if (cmd) { pos = os_strstr(cmd, " tcp_port="); if (pos) { @@ -3591,29 +5094,20 @@ static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s) } -static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *scan_res) +static int * wpas_dpp_presence_ann_channels(struct wpa_supplicant *wpa_s, + struct dpp_bootstrap_info *bi) { - struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi; unsigned int i; struct hostapd_hw_modes *mode; int c; struct wpa_bss *bss; bool chan6 = wpa_s->hw.modes == NULL; - - if (!bi && !wpa_s->dpp_reconfig_ssid) - return; - - wpa_s->dpp_chirp_scan_done = 1; - - os_free(wpa_s->dpp_chirp_freqs); - wpa_s->dpp_chirp_freqs = NULL; + int *freqs = NULL; /* Channels from own bootstrapping info */ if (bi) { for (i = 0; i < bi->num_freq; i++) - int_array_add_unique(&wpa_s->dpp_chirp_freqs, - bi->freq[i]); + int_array_add_unique(&freqs, bi->freq[i]); } /* Preferred chirping channels */ @@ -3631,7 +5125,7 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s, } } if (chan6) - int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437); + int_array_add_unique(&freqs, 2437); mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, HOSTAPD_MODE_IEEE80211A, false); @@ -3650,9 +5144,9 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s, chan149 = 1; } if (chan149) - int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5745); + int_array_add_unique(&freqs, 5745); else if (chan44) - int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5220); + int_array_add_unique(&freqs, 5220); } mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, @@ -3665,7 +5159,7 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s, HOSTAPD_CHAN_RADAR)) || chan->freq != 60480) continue; - int_array_add_unique(&wpa_s->dpp_chirp_freqs, 60480); + int_array_add_unique(&freqs, 60480); break; } } @@ -3674,10 +5168,26 @@ static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s, * Connectivity element */ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE)) - int_array_add_unique(&wpa_s->dpp_chirp_freqs, - bss->freq); + int_array_add_unique(&freqs, bss->freq); } + return freqs; +} + + +static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res) +{ + struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi; + + if (!bi && !wpa_s->dpp_reconfig_ssid) + return; + + wpa_s->dpp_chirp_scan_done = 1; + + os_free(wpa_s->dpp_chirp_freqs); + wpa_s->dpp_chirp_freqs = wpas_dpp_presence_ann_channels(wpa_s, bi); + if (!wpa_s->dpp_chirp_freqs || eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0) wpas_dpp_chirp_stop(wpa_s); @@ -3797,6 +5307,7 @@ int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd) wpas_dpp_chirp_stop(wpa_s); wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; + wpa_s->dpp_netrole = DPP_NETROLE_STA; wpa_s->dpp_qr_mutual = 0; wpa_s->dpp_chirp_bi = bi; wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi); @@ -3881,6 +5392,7 @@ int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd) } wpas_dpp_chirp_stop(wpa_s); wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; + wpa_s->dpp_netrole = DPP_NETROLE_STA; wpa_s->dpp_qr_mutual = 0; wpa_s->dpp_reconfig_ssid = ssid; wpa_s->dpp_reconfig_ssid_id = ssid->id; @@ -3893,33 +5405,6 @@ int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd) } -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; @@ -4000,3 +5485,318 @@ int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd) } #endif /* CONFIG_DPP2 */ + + +#ifdef CONFIG_DPP3 + +#define DPP_PB_ANNOUNCE_PER_CHAN 3 + +static int wpas_dpp_pb_announce(struct wpa_supplicant *wpa_s, int freq); +static void wpas_dpp_pb_next(void *eloop_ctx, void *timeout_ctx); + + +static void wpas_dpp_pb_tx_status(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, + const u8 *data, size_t data_len, + enum offchannel_send_action_result result) +{ + if (result == OFFCHANNEL_SEND_ACTION_FAILED) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to send push button announcement on %d MHz", + freq); + if (eloop_register_timeout(0, 0, wpas_dpp_pb_next, + wpa_s, NULL) < 0) + wpas_dpp_push_button_stop(wpa_s); + return; + } + + wpa_printf(MSG_DEBUG, "DPP: Push button announcement on %d MHz sent", + freq); + if (wpa_s->dpp_pb_discovery_done) { + wpa_s->dpp_pb_announce_count = 0; + wpa_printf(MSG_DEBUG, + "DPP: Wait for push button announcement response and PKEX on %d MHz", + freq); + if (eloop_register_timeout(0, 500000, wpas_dpp_pb_next, + wpa_s, NULL) < 0) + wpas_dpp_push_button_stop(wpa_s); + return; + } else if (wpa_s->dpp_pb_announce_count >= DPP_PB_ANNOUNCE_PER_CHAN) { + wpa_printf(MSG_DEBUG, + "DPP: Wait for push button announcement response on %d MHz", + freq); + if (eloop_register_timeout(0, 50000, wpas_dpp_pb_next, + wpa_s, NULL) < 0) + wpas_dpp_push_button_stop(wpa_s); + return; + } + + if (wpas_dpp_pb_announce(wpa_s, freq) < 0) + wpas_dpp_push_button_stop(wpa_s); +} + + +static int wpas_dpp_pb_announce(struct wpa_supplicant *wpa_s, int freq) +{ + struct wpabuf *msg; + int type; + + msg = wpa_s->dpp_pb_announcement; + if (!msg) + return -1; + + wpa_s->dpp_pb_announce_count++; + wpa_printf(MSG_DEBUG, + "DPP: Send push button announcement %d/%d (%d MHz)", + wpa_s->dpp_pb_announce_count, DPP_PB_ANNOUNCE_PER_CHAN, + freq); + + type = DPP_PA_PB_PRESENCE_ANNOUNCEMENT; + if (wpa_s->dpp_pb_announce_count == 1) + wpa_msg(wpa_s, MSG_INFO, + DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(broadcast), freq, type); + if (offchannel_send_action( + wpa_s, freq, broadcast, wpa_s->own_addr, broadcast, + wpabuf_head(msg), wpabuf_len(msg), + 1000, wpas_dpp_pb_tx_status, 0) < 0) + return -1; + + return 0; +} + + +static void wpas_dpp_pb_next(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct os_reltime now; + int freq; + + if (!wpa_s->dpp_pb_freqs) + return; + + os_get_reltime(&now); + offchannel_send_action_done(wpa_s); + + if (os_reltime_expired(&now, &wpa_s->dpp_pb_time, 100)) { + wpa_printf(MSG_DEBUG, "DPP: Push button wait time expired"); + wpas_dpp_push_button_stop(wpa_s); + return; + } + + if (wpa_s->dpp_pb_freq_idx >= int_array_len(wpa_s->dpp_pb_freqs)) { + wpa_printf(MSG_DEBUG, + "DPP: Completed push button announcement round"); + wpa_s->dpp_pb_freq_idx = 0; + if (wpa_s->dpp_pb_stop_iter > 0) { + wpa_s->dpp_pb_stop_iter--; + + if (wpa_s->dpp_pb_stop_iter == 1) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS + "wait for AP/Configurator to allow PKEX to be initiated"); + if (eloop_register_timeout(10, 0, + wpas_dpp_pb_next, + wpa_s, NULL) < 0) { + wpas_dpp_push_button_stop(wpa_s); + return; + } + return; + } + + if (wpa_s->dpp_pb_stop_iter == 0) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS + "start push button PKEX responder on the discovered channel (%d MHz)", + wpa_s->dpp_pb_resp_freq); + wpa_s->dpp_pb_discovery_done = true; + + wpa_s->dpp_pkex_bi = wpa_s->dpp_pb_bi; + + os_free(wpa_s->dpp_pkex_code); + wpa_s->dpp_pkex_code = os_memdup( + wpa_s->dpp_pb_c_nonce, + wpa_s->dpp_pb_c_nonce_len); + wpa_s->dpp_pkex_code_len = + wpa_s->dpp_pb_c_nonce_len; + + os_free(wpa_s->dpp_pkex_identifier); + wpa_s->dpp_pkex_identifier = + os_strdup("PBPKEX"); + + if (!wpa_s->dpp_pkex_code || + !wpa_s->dpp_pkex_identifier) { + wpas_dpp_push_button_stop(wpa_s); + return; + } + + wpa_s->dpp_pkex_ver = PKEX_VER_ONLY_2; + + os_free(wpa_s->dpp_pkex_auth_cmd); + wpa_s->dpp_pkex_auth_cmd = NULL; + } + } + } + + if (wpa_s->dpp_pb_discovery_done) + freq = wpa_s->dpp_pb_resp_freq; + else + freq = wpa_s->dpp_pb_freqs[wpa_s->dpp_pb_freq_idx++]; + wpa_s->dpp_pb_announce_count = 0; + if (!wpa_s->dpp_pb_announcement) { + wpa_printf(MSG_DEBUG, "DPP: Push button announcements stopped"); + return; + } + if (wpas_dpp_pb_announce(wpa_s, freq) < 0) { + wpas_dpp_push_button_stop(wpa_s); + return; + } +} + + +static void wpas_dpp_push_button_expire(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + wpa_printf(MSG_DEBUG, + "DPP: Active push button Configurator mode expired"); + wpas_dpp_push_button_stop(wpa_s); +} + + +static int wpas_dpp_push_button_configurator(struct wpa_supplicant *wpa_s, + const char *cmd) +{ + wpa_s->dpp_pb_configurator = true; + wpa_s->dpp_pb_announce_time.sec = 0; + wpa_s->dpp_pb_announce_time.usec = 0; + str_clear_free(wpa_s->dpp_pb_cmd); + wpa_s->dpp_pb_cmd = NULL; + if (cmd) { + wpa_s->dpp_pb_cmd = os_strdup(cmd); + if (!wpa_s->dpp_pb_cmd) + return -1; + } + eloop_register_timeout(100, 0, wpas_dpp_push_button_expire, + wpa_s, NULL); + + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS "started"); + return 0; +} + + +static void wpas_dpp_pb_scan_res_handler(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res) +{ + if (!wpa_s->dpp_pb_time.sec && !wpa_s->dpp_pb_time.usec) + return; + + os_free(wpa_s->dpp_pb_freqs); + wpa_s->dpp_pb_freqs = wpas_dpp_presence_ann_channels(wpa_s, NULL); + + wpa_printf(MSG_DEBUG, "DPP: Scan completed for PB discovery"); + if (!wpa_s->dpp_pb_freqs || + eloop_register_timeout(0, 0, wpas_dpp_pb_next, wpa_s, NULL) < 0) + wpas_dpp_push_button_stop(wpa_s); +} + + +int wpas_dpp_push_button(struct wpa_supplicant *wpa_s, const char *cmd) +{ + int res; + + if (!wpa_s->dpp) + return -1; + wpas_dpp_push_button_stop(wpa_s); + wpas_dpp_stop(wpa_s); + wpas_dpp_chirp_stop(wpa_s); + + os_get_reltime(&wpa_s->dpp_pb_time); + + if (cmd && + (os_strstr(cmd, " role=configurator") || + os_strstr(cmd, " conf="))) + return wpas_dpp_push_button_configurator(wpa_s, cmd); + + wpa_s->dpp_pb_configurator = false; + + wpa_s->dpp_pb_freq_idx = 0; + + res = dpp_bootstrap_gen(wpa_s->dpp, "type=pkex"); + if (res < 0) + return -1; + wpa_s->dpp_pb_bi = dpp_bootstrap_get_id(wpa_s->dpp, res); + if (!wpa_s->dpp_pb_bi) + return -1; + + wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; + wpa_s->dpp_netrole = DPP_NETROLE_STA; + wpa_s->dpp_qr_mutual = 0; + wpa_s->dpp_pb_announcement = + dpp_build_pb_announcement(wpa_s->dpp_pb_bi); + if (!wpa_s->dpp_pb_announcement) + return -1; + + wpa_printf(MSG_DEBUG, + "DPP: Scan to create channel list for PB discovery"); + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_s->scan_res_handler = wpas_dpp_pb_scan_res_handler; + wpa_supplicant_req_scan(wpa_s, 0, 0); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_STATUS "started"); + return 0; +} + + +void wpas_dpp_push_button_stop(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->dpp) + return; + os_free(wpa_s->dpp_pb_freqs); + wpa_s->dpp_pb_freqs = NULL; + wpabuf_free(wpa_s->dpp_pb_announcement); + wpa_s->dpp_pb_announcement = NULL; + if (wpa_s->dpp_pb_bi) { + char id[20]; + + if (wpa_s->dpp_pb_bi == wpa_s->dpp_pkex_bi) + wpa_s->dpp_pkex_bi = NULL; + os_snprintf(id, sizeof(id), "%u", wpa_s->dpp_pb_bi->id); + dpp_bootstrap_remove(wpa_s->dpp, id); + wpa_s->dpp_pb_bi = NULL; + if (!wpa_s->dpp_pb_result_indicated) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "failed"); + wpa_s->dpp_pb_result_indicated = true; + } + } + + wpa_s->dpp_pb_resp_freq = 0; + wpa_s->dpp_pb_stop_iter = 0; + wpa_s->dpp_pb_discovery_done = false; + os_free(wpa_s->dpp_pb_cmd); + wpa_s->dpp_pb_cmd = NULL; + + eloop_cancel_timeout(wpas_dpp_pb_next, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_push_button_expire, wpa_s, NULL); + if (wpas_dpp_pb_active(wpa_s)) { + wpa_printf(MSG_DEBUG, "DPP: Stop active push button mode"); + if (!wpa_s->dpp_pb_result_indicated) + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_PB_RESULT "failed"); + } + wpa_s->dpp_pb_time.sec = 0; + wpa_s->dpp_pb_time.usec = 0; + dpp_pkex_free(wpa_s->dpp_pkex); + wpa_s->dpp_pkex = NULL; + os_free(wpa_s->dpp_pkex_auth_cmd); + wpa_s->dpp_pkex_auth_cmd = NULL; + + wpa_s->dpp_pb_result_indicated = false; + + str_clear_free(wpa_s->dpp_pb_cmd); + wpa_s->dpp_pb_cmd = NULL; + + if (wpa_s->scan_res_handler == wpas_dpp_pb_scan_res_handler) { + wpas_abort_ongoing_scan(wpa_s); + wpa_s->scan_res_handler = NULL; + } +} + +#endif /* CONFIG_DPP3 */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant-2.9_standard/wpa_supplicant/dpp_supplicant.h index b0d5fcf188354a91e12c1ed1ec4486f65727e801..e2bdd9d40e5f07549f49a6d0e8f42dc53653de70 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/dpp_supplicant.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/dpp_supplicant.h @@ -2,6 +2,7 @@ * wpa_supplicant - DPP * Copyright (c) 2017, Qualcomm Atheros, Inc. * Copyright (c) 2018-2020, The Linux Foundation + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -23,6 +24,7 @@ void wpas_dpp_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq, unsigned int duration); void wpas_dpp_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, unsigned int freq); +void wpas_dpp_tx_wait_expire(struct wpa_supplicant *wpa_s); void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, const u8 *buf, size_t len, unsigned int freq); int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd); @@ -41,5 +43,8 @@ int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd); void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s); int wpas_dpp_reconfig(struct wpa_supplicant *wpa_s, const char *cmd); int wpas_dpp_ca_set(struct wpa_supplicant *wpa_s, const char *cmd); +int wpas_dpp_conf_set(struct wpa_supplicant *wpa_s, const char *cmd); +int wpas_dpp_push_button(struct wpa_supplicant *wpa_s, const char *cmd); +void wpas_dpp_push_button_stop(struct wpa_supplicant *wpa_s); #endif /* DPP_SUPPLICANT_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/driver_i.h b/wpa_supplicant-2.9_standard/wpa_supplicant/driver_i.h index 5803994913383f21c85fbe7e2e19f1d6be00dfe8..fae0defc0064d55527efd325f01908fb1ced4309 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/driver_i.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/driver_i.h @@ -13,7 +13,6 @@ #ifdef CONFIG_VENDOR_EXT #include "vendor_ext.h" #endif - /* driver_ops */ static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s, const char *ifname) @@ -63,6 +62,9 @@ static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s, struct wpa_driver_associate_params *params) { if (wpa_s->driver->associate) { + if (params) + params->freq.link_id = -1; + return wpa_s->driver->associate(wpa_s->drv_priv, params); } return -1; @@ -128,7 +130,7 @@ static inline int wpa_drv_stop_sched_scan(struct wpa_supplicant *wpa_s) } struct wpa_scan_results * -wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s); +wpa_drv_get_scan_results(struct wpa_supplicant *wpa_s, const u8 *bssid); static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid) { @@ -145,11 +147,8 @@ static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid) } return -1; } -#ifdef CONFIG_MLD_PATCH + static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, int link_id, -#else -static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, -#endif enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, @@ -173,9 +172,8 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, params.key = key; params.key_len = key_len; params.key_flag = key_flag; -#ifdef CONFIG_MLD_PATCH params.link_id = link_id; -#endif + if (alg != WPA_ALG_NONE) { /* keyidx = 1 can be either a broadcast or--with * Extended Key ID--a unicast key. Use bit 15 for @@ -200,7 +198,7 @@ static inline int wpa_drv_get_seqnum(struct wpa_supplicant *wpa_s, { if (wpa_s->driver->get_seqnum) return wpa_s->driver->get_seqnum(wpa_s->ifname, wpa_s->drv_priv, - addr, idx, seq); + addr, idx, -1, seq); return -1; } @@ -231,14 +229,13 @@ static inline int wpa_drv_set_wapi_key(struct wpa_supplicant *wpa_s, enum wpa_al return -1; } #endif - static inline int wpa_drv_sta_deauth(struct wpa_supplicant *wpa_s, const u8 *addr, u16 reason_code) { if (wpa_s->driver->sta_deauth) { return wpa_s->driver->sta_deauth(wpa_s->drv_priv, wpa_s->own_addr, addr, - reason_code); + reason_code, -1); } return -1; } @@ -364,7 +361,7 @@ static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s, if (wpa_s->driver->send_mlme) return wpa_s->driver->send_mlme(wpa_s->drv_priv, data, data_len, noack, - freq, NULL, 0, 0, wait); + freq, NULL, 0, 0, wait, -1); return -1; } @@ -378,19 +375,15 @@ static inline int wpa_drv_update_ft_ies(struct wpa_supplicant *wpa_s, return -1; } -static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s, - struct wpa_driver_ap_params *params) -{ - if (wpa_s->driver->set_ap) - return wpa_s->driver->set_ap(wpa_s->drv_priv, params); - return -1; -} - static inline int wpa_drv_sta_add(struct wpa_supplicant *wpa_s, struct hostapd_sta_add_params *params) { - if (wpa_s->driver->sta_add) + if (wpa_s->driver->sta_add) { + /* Set link_id to -1 for non-TDLS peers */ + if (!(params->flags & WPA_STA_TDLS_PEER)) + params->mld_link_id = -1; return wpa_s->driver->sta_add(wpa_s->drv_priv, params); + } return -1; } @@ -410,7 +403,7 @@ static inline int wpa_drv_tx_control_port(struct wpa_supplicant *wpa_s, if (!wpa_s->driver->tx_control_port) return -1; return wpa_s->driver->tx_control_port(wpa_s->drv_priv, dest, proto, - buf, len, no_encrypt); + buf, len, no_encrypt, -1); } static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s, @@ -421,7 +414,7 @@ static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s, if (wpa_s->driver->hapd_send_eapol) return wpa_s->driver->hapd_send_eapol(wpa_s->drv_priv, addr, data, data_len, encrypt, - own_addr, flags); + own_addr, flags, -1); return -1; } @@ -446,20 +439,10 @@ static inline int wpa_drv_set_supp_port(struct wpa_supplicant *wpa_s, return 0; } -static inline int wpa_drv_send_action(struct wpa_supplicant *wpa_s, - unsigned int freq, - unsigned int wait, - const u8 *dst, const u8 *src, - const u8 *bssid, - const u8 *data, size_t data_len, - int no_cck) -{ - if (wpa_s->driver->send_action) - return wpa_s->driver->send_action(wpa_s->drv_priv, freq, - wait, dst, src, bssid, - data, data_len, no_cck); - return -1; -} +int wpa_drv_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, + unsigned int wait, const u8 *dst, const u8 *src, + const u8 *bssid, const u8 *data, size_t data_len, + int no_cck); static inline void wpa_drv_send_action_cancel_wait(struct wpa_supplicant *wpa_s) { @@ -562,7 +545,7 @@ static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s, int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s, struct wpa_signal_info *si); -#ifdef CONFIG_MLD_PATCH_EXT + static inline int wpa_drv_mlo_signal_poll(struct wpa_supplicant *wpa_s, struct wpa_mlo_signal_info *mlo_si) { @@ -570,7 +553,7 @@ static inline int wpa_drv_mlo_signal_poll(struct wpa_supplicant *wpa_s, return wpa_s->driver->mlo_signal_poll(wpa_s->drv_priv, mlo_si); return -1; } -#endif + static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s, struct wpa_channel_info *ci) { @@ -628,13 +611,14 @@ static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, int initiator, - const u8 *buf, size_t len) + const u8 *buf, size_t len, int link_id) { if (wpa_s->driver->send_tdls_mgmt) { return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst, action_code, dialog_token, status_code, peer_capab, - initiator, buf, len); + initiator, buf, len, + link_id); } return -1; } @@ -852,6 +836,14 @@ static inline int wpa_drv_set_replay_protect(struct wpa_supplicant *wpa_s, window); } +static inline int wpa_drv_set_offload(struct wpa_supplicant *wpa_s, u8 offload) +{ + if (!wpa_s->driver->set_offload) + return -1; + return wpa_s->driver->set_offload(wpa_s->drv_priv, offload); + +} + static inline int wpa_drv_set_current_cipher_suite(struct wpa_supplicant *wpa_s, u64 cs) { @@ -1012,7 +1004,7 @@ static inline int wpa_drv_setband(struct wpa_supplicant *wpa_s, static inline int wpa_drv_get_pref_freq_list(struct wpa_supplicant *wpa_s, enum wpa_driver_if_type if_type, unsigned int *num, - unsigned int *freq_list) + struct weighted_pcl *freq_list) { #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->get_pref_freq_list_override) @@ -1136,6 +1128,10 @@ static inline int wpa_drv_update_connect_params( { if (!wpa_s->driver->update_connect_params) return -1; + + if (params) + params->freq.link_id = -1; + return wpa_s->driver->update_connect_params(wpa_s->drv_priv, params, mask); } @@ -1165,7 +1161,43 @@ static inline int wpa_drv_dpp_listen(struct wpa_supplicant *wpa_s, bool enable) return wpa_s->driver->dpp_listen(wpa_s->drv_priv, enable); } -#ifdef CONFIG_MLD_PATCH +static inline int wpa_drv_send_pasn_resp(struct wpa_supplicant *wpa_s, + struct pasn_auth *params) +{ + if (!wpa_s->driver->send_pasn_resp) + return -1; + return wpa_s->driver->send_pasn_resp(wpa_s->drv_priv, params); +} + +static inline int wpa_drv_set_secure_ranging_ctx(struct wpa_supplicant *wpa_s, + const u8 *own_addr, + const u8 *peer_addr, + u32 cipher, u8 tk_len, + const u8 *tk, + u8 ltf_keyseed_len, + const u8 *ltf_keyseed, + u32 action) +{ + struct secure_ranging_params params; + + /* Configure secure ranging context only to the drivers that support it. + */ + if (!wpa_s->driver->set_secure_ranging_ctx) + return 0; + + os_memset(¶ms, 0, sizeof(params)); + params.action = action; + params.own_addr = own_addr; + params.peer_addr = peer_addr; + params.cipher = cipher; + params.tk_len = tk_len; + params.tk = tk; + params.ltf_keyseed_len = ltf_keyseed_len; + params.ltf_keyseed = ltf_keyseed; + + return wpa_s->driver->set_secure_ranging_ctx(wpa_s->drv_priv, ¶ms); +} + static inline int wpas_drv_get_sta_mlo_info(struct wpa_supplicant *wpa_s, struct driver_sta_mlo_info *mlo_info) @@ -1175,7 +1207,6 @@ wpas_drv_get_sta_mlo_info(struct wpa_supplicant *wpa_s, return wpa_s->driver->get_sta_mlo_info(wpa_s->drv_priv, mlo_info); } -#endif #ifdef CONFIG_DRIVER_HDF static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s, @@ -1188,6 +1219,4 @@ static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s, return -1; } #endif - - #endif /* DRIVER_I_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/eapol_test.c b/wpa_supplicant-2.9_standard/wpa_supplicant/eapol_test.c index febb23644c300d393c6dfce8ef32e63743bf994e..5d9581f8deed0f4a346f3a70983f9ee23dddcc56 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/eapol_test.c @@ -15,6 +15,7 @@ #include "common.h" #include "utils/ext_password.h" #include "common/version.h" +#include "crypto/crypto.h" #include "crypto/tls.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.h" @@ -194,6 +195,9 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e, return; } + if (!radius_msg_add_msg_auth(msg)) + goto fail; + radius_msg_make_authenticator(msg); hdr = (const struct eap_hdr *) eap; @@ -669,6 +673,10 @@ static void test_eapol_clean(struct eapol_test_data *e, wpa_s->eapol = NULL; if (e->radius_conf && e->radius_conf->auth_server) { os_free(e->radius_conf->auth_server->shared_secret); + os_free(e->radius_conf->auth_server->ca_cert); + os_free(e->radius_conf->auth_server->client_cert); + os_free(e->radius_conf->auth_server->private_key); + os_free(e->radius_conf->auth_server->private_key_passwd); os_free(e->radius_conf->auth_server); } os_free(e->radius_conf); @@ -713,7 +721,7 @@ static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx) printf("Sending fake EAP-Request-Identity\n"); eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid, buf, - sizeof(*hdr) + 5); + sizeof(*hdr) + 5, FRAME_ENCRYPTION_UNKNOWN); } @@ -732,16 +740,27 @@ static char *eap_type_text(u8 type) case EAP_TYPE_IDENTITY: return "Identity"; case EAP_TYPE_NOTIFICATION: return "Notification"; case EAP_TYPE_NAK: return "Nak"; + + case EAP_TYPE_MD5: return "MD5"; + case EAP_TYPE_OTP: return "OTP"; + case EAP_TYPE_GTC: return "GTC"; case EAP_TYPE_TLS: return "TLS"; + case EAP_TYPE_LEAP: return "LEAP"; + case EAP_TYPE_SIM: return "SIM"; case EAP_TYPE_TTLS: return "TTLS"; + case EAP_TYPE_AKA: return "AKA"; case EAP_TYPE_PEAP: return "PEAP"; - case EAP_TYPE_SIM: return "SIM"; - case EAP_TYPE_GTC: return "GTC"; - case EAP_TYPE_MD5: return "MD5"; - case EAP_TYPE_OTP: return "OTP"; + case EAP_TYPE_MSCHAPV2: return "MSCHAPv2"; case EAP_TYPE_FAST: return "FAST"; - case EAP_TYPE_SAKE: return "SAKE"; + case EAP_TYPE_PAX: return "PAX"; case EAP_TYPE_PSK: return "PSK"; + case EAP_TYPE_SAKE: return "SAKE"; + case EAP_TYPE_IKEV2: return "IKEv2"; + case EAP_TYPE_AKA_PRIME: return "AKA-PRIME"; + case EAP_TYPE_GPSK: return "GPSK"; + case EAP_TYPE_PWD: return "PWD"; + case EAP_TYPE_EKE: return "EKE"; + case EAP_TYPE_TEAP: return "TEAP"; default: return "Unknown"; } } @@ -761,20 +780,20 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) msg = e->last_recv_radius; eap = radius_msg_get_eap(msg); - if (eap == NULL) { - /* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3: + if (!eap) { + /* RFC 3579, Chap. 2.6.3: * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message * attribute */ - wpa_printf(MSG_DEBUG, "could not extract " - "EAP-Message from RADIUS message"); + wpa_printf(MSG_DEBUG, + "could not extract EAP-Message from RADIUS message"); wpabuf_free(e->last_eap_radius); e->last_eap_radius = NULL; return; } if (wpabuf_len(eap) < sizeof(*hdr)) { - wpa_printf(MSG_DEBUG, "too short EAP packet " - "received from authentication server"); + wpa_printf(MSG_DEBUG, + "too short EAP packet received from authentication server"); wpabuf_free(eap); return; } @@ -810,11 +829,11 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap); break; } - wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d " - "id=%d len=%d) from RADIUS server: %s", - hdr->code, hdr->identifier, ntohs(hdr->length), buf); - - /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */ + buf[sizeof(buf) - 1] = '\0'; + wpa_printf(MSG_DEBUG, + "decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s", + hdr->code, hdr->identifier, be_to_host16(hdr->length), + buf); wpabuf_free(e->last_eap_radius); e->last_eap_radius = eap; @@ -830,7 +849,8 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) wpabuf_len(eap)); eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid, (u8 *) dot1x, - sizeof(*dot1x) + wpabuf_len(eap)); + sizeof(*dot1x) + wpabuf_len(eap), + FRAME_ENCRYPTION_UNKNOWN); os_free(dot1x); } } @@ -847,7 +867,7 @@ static void ieee802_1x_get_keys(struct eapol_test_data *e, keys = radius_msg_get_ms_keys(msg, req, shared_secret, shared_secret_len); - if (keys && keys->send == NULL && keys->recv == NULL) { + if (keys && !keys->send && !keys->recv) { os_free(keys); keys = radius_msg_get_cisco_keys(msg, req, shared_secret, shared_secret_len); @@ -908,20 +928,19 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 0) < 0 && radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { - wpa_printf(MSG_DEBUG, "Allowing RADIUS " - "Access-Reject without Message-Authenticator " - "since it does not include EAP-Message\n"); + wpa_printf(MSG_DEBUG, + "Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message"); } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 1)) { - printf("Incoming RADIUS packet did not have correct " - "Message-Authenticator - dropped\n"); - return RADIUS_RX_UNKNOWN; + wpa_printf(MSG_INFO, + "Incoming RADIUS packet did not have correct Message-Authenticator - dropped"); + return RADIUS_RX_INVALID_AUTHENTICATOR; } if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && hdr->code != RADIUS_CODE_ACCESS_REJECT && hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { - printf("Unknown RADIUS message code\n"); + wpa_printf(MSG_INFO, "Unknown RADIUS message code"); return RADIUS_RX_UNKNOWN; } @@ -995,7 +1014,10 @@ struct wpa_driver_ops eapol_test_drv_ops = { static void wpa_init_conf(struct eapol_test_data *e, struct wpa_supplicant *wpa_s, const char *authsrv, - int port, const char *secret, + int port, bool tls, const char *secret, + const char *ca_cert, const char *client_cert, + const char *private_key, + const char *private_key_passwd, const char *cli_addr, const char *ifname) { struct hostapd_radius_server *as; @@ -1033,8 +1055,17 @@ static void wpa_init_conf(struct eapol_test_data *e, } #endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ as->port = port; + as->tls = tls; as->shared_secret = (u8 *) os_strdup(secret); as->shared_secret_len = os_strlen(secret); + if (ca_cert) + as->ca_cert = os_strdup(ca_cert); + if (client_cert) + as->client_cert = os_strdup(client_cert); + if (private_key) + as->private_key = os_strdup(private_key); + if (private_key_passwd) + as->private_key_passwd = os_strdup(private_key_passwd); e->radius_conf->auth_server = as; e->radius_conf->auth_servers = as; e->radius_conf->msg_dumps = 1; @@ -1244,11 +1275,16 @@ static void usage(void) { printf("usage:\n" "eapol_test [-enWSv] -c [-a] [-p] " - "[-s]\\\n" + "[-s] \\\n" + " [-X \\\n" " [-r] [-t] [-C] \\\n" " [-M] [-o] [-R] " "[-P] \\\n" +#ifdef CONFIG_RADIUS_TLS + " [-j] [-J] \\\n" + "[-k] \\\n" +#endif /* CONFIG_RADIUS_TLS */ " [-A] [-i] [-T]\n" "eapol_test scard\n" "eapol_test sim [debug]\n" @@ -1257,10 +1293,11 @@ static void usage(void) " -c = configuration file\n" " -a = IP address of the authentication server, " "default 127.0.0.1\n" - " -p = UDP port of the authentication server, " - "default 1812\n" - " -s = shared secret with the authentication " - "server, default 'radius'\n" + " -p = Port of the authentication server,\n" + " default 1812 for RADIUS/UDP and 2083 for RADIUS/TLS\n" + " -s = shared secret with the authentication server,\n" + " default 'radius' for RADIUS/UDP and 'radsec' for RADIUS/TLS\n" + " -X = RADIUS protocol to use: UDP (default) or TLS\n" " -A = IP address of the client, default: select " "automatically\n" " -r = number of re-authentications\n" @@ -1298,8 +1335,11 @@ int main(int argc, char *argv[]) struct wpa_supplicant wpa_s; int c, ret = 1, wait_for_monitor = 0, save_config = 0; char *as_addr = "127.0.0.1"; - int as_port = 1812; - char *as_secret = "radius"; + int as_port = -1; + char *as_secret = NULL; + char *ca_cert = NULL, *client_cert = NULL; + char *private_key = NULL, *private_key_passwd = NULL; + bool tls = false; char *cli_addr = NULL; char *conf = NULL; int timeout = 30; @@ -1322,7 +1362,8 @@ int main(int argc, char *argv[]) wpa_debug_show_keys = 1; for (;;) { - c = getopt(argc, argv, "a:A:c:C:ei:M:nN:o:p:P:r:R:s:St:T:vW"); + c = getopt(argc, argv, + "a:A:c:C:ei:j:J:k:K:M:nN:o:p:P:r:R:s:St:T:vWX:"); if (c < 0) break; switch (c) { @@ -1344,6 +1385,20 @@ int main(int argc, char *argv[]) case 'i': ifname = optarg; break; +#ifdef CONFIG_RADIUS_TLS + case 'j': + ca_cert = optarg; + break; + case 'J': + client_cert = optarg; + break; + case 'k': + private_key = optarg; + break; + case 'K': + private_key_passwd = optarg; + break; +#endif /* CONFIG_RADIUS_TLS */ case 'M': if (hwaddr_aton(optarg, eapol_test.own_addr)) { usage(); @@ -1394,6 +1449,16 @@ int main(int argc, char *argv[]) case 'W': wait_for_monitor++; break; + case 'X': + if (os_strcmp(optarg, "UDP") == 0) { + tls = false; + } else if (os_strcmp(optarg, "TLS") == 0) { + tls = true; + } else { + usage(); + return -1; + } + break; case 'N': p1 = os_zalloc(sizeof(*p1)); if (p1 == NULL) @@ -1428,6 +1493,11 @@ int main(int argc, char *argv[]) } } + if (!as_secret) + as_secret = tls ? "radsec" : "radius"; + if (as_port < 0) + as_port = tls ? 2083 : 1812; + if (argc > optind && os_strcmp(argv[optind], "scard") == 0) { return scard_test(&eapol_test); } @@ -1460,7 +1530,7 @@ int main(int argc, char *argv[]) dl_list_init(&wpa_s.bss); dl_list_init(&wpa_s.bss_id); if (conf) - wpa_s.conf = wpa_config_read(conf, NULL); + wpa_s.conf = wpa_config_read(conf, NULL, false); else wpa_s.conf = wpa_config_alloc_empty(ctrl_iface, NULL); if (wpa_s.conf == NULL) { @@ -1477,7 +1547,8 @@ int main(int argc, char *argv[]) wpa_s.conf->pcsc_reader = os_strdup(eapol_test.pcsc_reader); } - wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret, + wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, tls, as_secret, + ca_cert, client_cert, private_key, private_key_passwd, cli_addr, ifname); wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s); if (wpa_s.ctrl_iface == NULL) { @@ -1549,6 +1620,7 @@ int main(int argc, char *argv[]) else printf("SUCCESS\n"); + crypto_unload(); os_program_deinit(); return ret; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/events.c b/wpa_supplicant-2.9_standard/wpa_supplicant/events.c index c43441060b9ded70900d4b2839c9d872413dc119..fb55e85825f4dd45fea9eefb849f881a62a45f65 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/events.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/events.c @@ -22,6 +22,7 @@ #include "common/wpa_ctrl.h" #include "eap_peer/eap.h" #include "ap/hostapd.h" +#include "ap/sta_info.h" #include "p2p/p2p.h" #include "fst/fst.h" #include "wnm_sta.h" @@ -49,6 +50,7 @@ #include "mesh.h" #include "mesh_mpm.h" #include "wmm_ac.h" +#include "nan_usd.h" #include "dpp_supplicant.h" #ifdef CONFIG_MAGICLINK #include "wpa_magiclink.h" @@ -79,7 +81,9 @@ extern void wpas_connect_work_done(struct wpa_supplicant *wpa_s); #ifndef CONFIG_NO_SCAN_PROCESSING static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, - int new_scan, int own_request); + int new_scan, int own_request, + bool trigger_6ghz_scan, + union wpa_event_data *data); #endif /* CONFIG_NO_SCAN_PROCESSING */ @@ -155,59 +159,95 @@ void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx) } +static struct wpa_bss * __wpa_supplicant_get_new_bss( + struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *ssid, + size_t ssid_len) +{ + if (ssid && ssid_len > 0) + return wpa_bss_get(wpa_s, bssid, ssid, ssid_len); + else + return wpa_bss_get_bssid(wpa_s, bssid); +} + + +static struct wpa_bss * _wpa_supplicant_get_new_bss( + struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *ssid, + size_t ssid_len, bool try_update_scan_results) +{ + struct wpa_bss *bss = __wpa_supplicant_get_new_bss(wpa_s, bssid, ssid, + ssid_len); + + if (bss || !try_update_scan_results) + return bss; + + wpa_supplicant_update_scan_results(wpa_s, bssid); + + return __wpa_supplicant_get_new_bss(wpa_s, bssid, ssid, ssid_len); +} + + static struct wpa_bss * wpa_supplicant_get_new_bss( struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wpa_bss *bss = NULL; struct wpa_ssid *ssid = wpa_s->current_ssid; + u8 drv_ssid[SSID_MAX_LEN]; + int res; + bool try_update_scan_results = true; - if (ssid->ssid_len > 0) - bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len); + res = wpa_drv_get_ssid(wpa_s, drv_ssid); + if (res > 0) { + bss = _wpa_supplicant_get_new_bss(wpa_s, bssid, drv_ssid, res, + try_update_scan_results); + try_update_scan_results = false; + } + if (!bss && ssid && ssid->ssid_len > 0) { + bss = _wpa_supplicant_get_new_bss(wpa_s, bssid, ssid->ssid, + ssid->ssid_len, + try_update_scan_results); + try_update_scan_results = false; + } if (!bss) - bss = wpa_bss_get_bssid(wpa_s, bssid); + bss = _wpa_supplicant_get_new_bss(wpa_s, bssid, NULL, 0, + try_update_scan_results); return bss; } -static void wpa_supplicant_update_current_bss(struct wpa_supplicant *wpa_s) +static struct wpa_bss * +wpa_supplicant_update_current_bss(struct wpa_supplicant *wpa_s, const u8 *bssid) { - struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid); - - if (!bss) { - wpa_supplicant_update_scan_results(wpa_s); - - /* Get the BSS from the new scan results */ - bss = wpa_supplicant_get_new_bss(wpa_s, wpa_s->bssid); - } + struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, bssid); if (bss) wpa_s->current_bss = bss; + + return bss; } -#ifdef CONFIG_MLD_PATCH + + static void wpa_supplicant_update_link_bss(struct wpa_supplicant *wpa_s, u8 link_id, const u8 *bssid) { struct wpa_bss *bss = wpa_supplicant_get_new_bss(wpa_s, bssid); - if (!bss) { - wpa_supplicant_update_scan_results(wpa_s); - bss = wpa_supplicant_get_new_bss(wpa_s, bssid); - } if (bss) wpa_s->links[link_id].bss = bss; } -#endif -static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) + +static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) { struct wpa_ssid *ssid, *old_ssid; + struct wpa_bss *bss; u8 drv_ssid[SSID_MAX_LEN]; size_t drv_ssid_len; int res; if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid) { - wpa_supplicant_update_current_bss(wpa_s); + wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid); if (wpa_s->current_ssid->ssid_len == 0) return 0; /* current profile still in use */ @@ -271,11 +311,19 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the " "current AP"); + bss = wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid); if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) { u8 wpa_ie[80]; size_t wpa_ie_len = sizeof(wpa_ie); - if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, - wpa_ie, &wpa_ie_len) < 0) + bool skip_default_rsne; + + /* Do not override RSNE/RSNXE with the default values if the + * driver indicated the actual values used in the + * (Re)Association Request frame. */ + skip_default_rsne = data && data->assoc_info.req_ies; + if (wpa_supplicant_set_suites(wpa_s, bss, ssid, + wpa_ie, &wpa_ie_len, + skip_default_rsne) < 0) wpa_dbg(wpa_s, MSG_DEBUG, "Could not set WPA suites"); } else { wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); @@ -286,8 +334,6 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; - wpa_supplicant_update_current_bss(wpa_s); - wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); wpa_supplicant_initiate_eapol(wpa_s); if (old_ssid != wpa_s->current_ssid) @@ -317,7 +363,8 @@ void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx) wpa_supplicant_req_scan(wpa_s, 0, 0); } } -#ifdef CONFIG_MLD_PATCH + + void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s) { if (!wpa_s->valid_links) @@ -328,7 +375,8 @@ void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s) os_memset(wpa_s->ap_mld_addr, 0, ETH_ALEN); os_memset(wpa_s->links, 0, sizeof(wpa_s->links)); } -#endif + + void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) { int bssid_changed; @@ -381,9 +429,15 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) wpa_s->current_ssid = NULL; eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_s->key_mgmt = 0; + wpa_s->allowed_key_mgmts = 0; +#ifndef CONFIG_NO_RRM wpas_rrm_reset(wpa_s); +#endif /* CONFIG_NO_RRM */ wpa_s->wnmsleep_used = 0; +#ifdef CONFIG_WNM + wpa_s->wnm_mode = 0; +#endif /* CONFIG_WNM */ wnm_clear_coloc_intf_reporting(wpa_s); wpa_s->disable_mbo_oce = 0; @@ -395,13 +449,20 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0) wpa_s->enabled_4addr_mode = 0; -#ifdef CONFIG_MLD_PATCH + + wpa_s->wps_scan_done = false; wpas_reset_mlo_info(wpa_s); -#endif + +#ifdef CONFIG_SME + wpa_s->sme.bss_max_idle_period = 0; +#endif /* CONFIG_SME */ + + wpa_s->ssid_verified = false; + wpa_s->bigtk_set = false; } -static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s) +static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s, bool authorized) { struct wpa_ie_data ie; int pmksa_set = -1; @@ -422,9 +483,12 @@ static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s) for (i = 0; i < ie.num_pmkid; i++) { pmksa_set = pmksa_cache_set_current(wpa_s->wpa, ie.pmkid + i * PMKID_LEN, - NULL, NULL, 0, NULL, 0); + NULL, NULL, 0, NULL, 0, + true); if (pmksa_set == 0) { eapol_sm_notify_pmkid_attempt(wpa_s->eapol); + if (authorized) + wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); break; } } @@ -672,10 +736,11 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, u8 wapi_ie_len; u8 wapi_type_index = 9; #endif + bool is_6ghz_bss = is_6ghz_freq(bss->freq); + ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss); if (ret >= 0) return ret; - #ifdef CONFIG_WAPI wapi_ie = wpa_bss_get_ie(bss, WLAN_EID_WAPI); if (!wapi_ie) { @@ -710,6 +775,13 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WEP */ rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); + if (is_6ghz_bss && !rsn_ie) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - 6 GHz BSS without RSNE"); + return 0; + } + while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) { proto_match++; @@ -724,6 +796,16 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, if (!ie.has_group) ie.group_cipher = wpa_default_rsn_cipher(bss->freq); + if (is_6ghz_bss || !is_zero_ether_addr(bss->mld_addr)) { + /* WEP and TKIP are not allowed on 6 GHz/MLD */ + ie.pairwise_cipher &= ~(WPA_CIPHER_WEP40 | + WPA_CIPHER_WEP104 | + WPA_CIPHER_TKIP); + ie.group_cipher &= ~(WPA_CIPHER_WEP40 | + WPA_CIPHER_WEP104 | + WPA_CIPHER_TKIP); + } + #ifdef CONFIG_WEP if (wep_ok && (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104))) @@ -765,6 +847,21 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, break; } + if (is_6ghz_bss) { + /* MFPC must be supported on 6 GHz */ + if (!(ie.capabilities & WPA_CAPABILITY_MFPC)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip RSNE - 6 GHz without MFPC"); + break; + } + + /* WPA PSK is not allowed on the 6 GHz band */ + ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256); + } + if (!(ie.key_mgmt & ssid->key_mgmt)) { if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, @@ -803,15 +900,40 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, return 1; } + if (is_6ghz_bss) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip - 6 GHz BSS without matching RSNE"); + return 0; + } + + wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); + if (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED && (!(ssid->key_mgmt & WPA_KEY_MGMT_OWE) || ssid->owe_only)) { +#ifdef CONFIG_OWE + if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && ssid->owe_only && + !wpa_ie && !rsn_ie && + wpa_s->owe_transition_select && + wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE) && + ssid->owe_transition_bss_select_count + 1 <= + MAX_OWE_TRANSITION_BSS_SELECT_COUNT) { + ssid->owe_transition_bss_select_count++; + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " skip OWE open BSS (selection count %d does not exceed %d)", + ssid->owe_transition_bss_select_count, + MAX_OWE_TRANSITION_BSS_SELECT_COUNT); + wpa_s->owe_transition_search = 1; + return 0; + } +#endif /* CONFIG_OWE */ if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, " skip - MFP Required but network not MFP Capable"); return 0; } - wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) { proto_match++; @@ -897,7 +1019,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, return 1; } #endif /* CONFIG_OWE */ - #ifdef CONFIG_WAPI if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN | WPA_PROTO_WAPI)) && wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) { @@ -915,7 +1036,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, return 0; } #endif - if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE)) { if (debug_print) @@ -1029,11 +1149,24 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, continue; } + if (flagged && ((rate_ie[j] & 0x7f) == + BSS_MEMBERSHIP_SELECTOR_HE_PHY)) { + if (!he_supported(mode, IEEE80211_MODE_INFRA)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, + " hardware does not support HE PHY"); + return 0; + } + continue; + } + #ifdef CONFIG_SAE if (flagged && ((rate_ie[j] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) { - if (wpa_s->conf->sae_pwe == 0 && + if (wpa_s->conf->sae_pwe == + SAE_PWE_HUNT_AND_PECK && !ssid->sae_password_id && + !is_6ghz_freq(bss->freq) && wpa_key_mgmt_sae(ssid->key_mgmt)) { if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, @@ -1128,7 +1261,6 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, #ifdef CONFIG_OWE const u8 *owe, *pos, *end, *bssid; u8 ssid_len; - struct wpa_bss *open_bss; owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE); if (!owe || !wpa_bss_get_ie(bss, WLAN_EID_RSN)) @@ -1171,59 +1303,30 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } } } +#endif /* CONFIG_OWE */ +} - if (bss->ssid_len > 0) - return; - open_bss = wpa_bss_get_bssid_latest(wpa_s, bssid); - if (!open_bss) - return; - if (ssid_len != open_bss->ssid_len || - os_memcmp(pos, open_bss->ssid, ssid_len) != 0) { - wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, - "OWE: transition mode SSID mismatch: %s", - wpa_ssid_txt(open_bss->ssid, open_bss->ssid_len)); - wpa_printf(MSG_DEBUG, "OWE: transition mode SSID mismatch: %s", - anonymize_ssid(wpa_ssid_txt(open_bss->ssid, open_bss->ssid_len))); - return; - } +static bool wpas_valid_ml_bss(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +{ + u16 removed_links; - owe = wpa_bss_get_vendor_ie(open_bss, OWE_IE_VENDOR_TYPE); - if (!owe || wpa_bss_get_ie(open_bss, WLAN_EID_RSN)) { - wpa_dbg(wpa_s, MSG_DEBUG, - "OWE: transition mode open BSS unexpected info"); - return; - } + if (wpa_bss_parse_basic_ml_element(wpa_s, bss, NULL, NULL, NULL, NULL)) + return true; - pos = owe + 6; - end = owe + 2 + owe[1]; + if (!bss->valid_links) + return true; - if (end - pos < ETH_ALEN + 1) - return; - if (os_memcmp(pos, bss->bssid, ETH_ALEN) != 0) { - wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, - "OWE: transition mode BSSID mismatch: " MACSTR, - MAC2STR(pos)); - wpa_printf(MSG_DEBUG, "OWE: transition mode BSSID mismatch: " MACSTR_SEC, - MAC2STR_SEC(pos)); - return; - } - pos += ETH_ALEN; - ssid_len = *pos++; - if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN) - return; - wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, "OWE: learned transition mode OWE SSID: %s", - wpa_ssid_txt(pos, ssid_len)); - wpa_printf(MSG_DEBUG, "OWE: learned transition mode OWE SSID: %s", - anonymize_ssid(wpa_ssid_txt(pos, ssid_len))); - os_memcpy(bss->ssid, pos, ssid_len); - bss->ssid_len = ssid_len; - bss->flags |= WPA_BSS_OWE_TRANSITION; -#endif /* CONFIG_OWE */ + /* Check if the current BSS is going to be removed */ + removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, bss); + if (BIT(bss->mld_link_id) & removed_links) + return false; + + return true; } -static int disabled_freq(struct wpa_supplicant *wpa_s, int freq) +int disabled_freq(struct wpa_supplicant *wpa_s, int freq) { int i, j; @@ -1367,7 +1470,7 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, #endif /* CONFIG_WPS */ if (ssid->bssid_set && ssid->ssid_len == 0 && - os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0) + ether_addr_equal(bss->bssid, ssid->bssid)) check_ssid = false; if (check_ssid && @@ -1379,7 +1482,7 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, } if (ssid->bssid_set && - os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) { + !ether_addr_equal(bss->bssid, ssid->bssid)) { if (debug_print) wpa_dbg(wpa_s, MSG_INFO, " skip - BSSID mismatch"); return false; @@ -1400,7 +1503,7 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, !addr_in_list(bss->bssid, ssid->bssid_accept, ssid->num_bssid_accept)) { if (debug_print) - wpa_dbg(wpa_s, MSG_INFO, + wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID not in list of accepted values"); return false; } @@ -1438,6 +1541,7 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, " skip - non-OSEN network not allowed"); return false; } + #ifdef CONFIG_WAPI if (((ssid->key_mgmt & WPA_KEY_MGMT_WAPI_PSK) || (ssid->key_mgmt & WPA_KEY_MGMT_WAPI_CERT)) && (wapi_ie_len == 0)) { @@ -1500,7 +1604,6 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, return false; } #endif /* CONFIG_MESH */ - #ifndef CONFIG_DRIVER_NL80211_HISI if (!rate_match(wpa_s, ssid, bss, debug_print)) { if (debug_print) @@ -1509,10 +1612,13 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, return false; } #endif - #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) && + /* When using SAE Password Identifier and when operationg on the 6 GHz + * band, only H2E is allowed. */ + if ((wpa_s->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || + is_6ghz_freq(bss->freq) || ssid->sae_password_id) && + wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK && + wpa_key_mgmt_sae(ssid->key_mgmt) && !(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) { if (debug_print) wpa_dbg(wpa_s, MSG_INFO, @@ -1579,7 +1685,7 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, } 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) { + !ether_addr_equal(dev_addr, ssid->go_p2p_dev_addr)) { if (debug_print) wpa_dbg(wpa_s, MSG_INFO, " skip - no matching GO P2P Device Address in P2P element"); @@ -1591,7 +1697,6 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, #ifdef CONFIG_MAGICLINK_PC } #endif /* CONFIG_MAGICLINK_PC */ - /* * 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 @@ -1615,7 +1720,7 @@ static bool wpa_scan_res_ok(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, 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); + assoc_disallow = wpas_mbo_check_assoc_disallow(bss); if (assoc_disallow && assoc_disallow[1] >= 1) { if (debug_print) wpa_dbg(wpa_s, MSG_INFO, @@ -1637,7 +1742,8 @@ skip_assoc_disallow: #ifdef CONFIG_DPP if ((ssid->key_mgmt & WPA_KEY_MGMT_DPP) && - !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, ssid) && + !wpa_sm_pmksa_exists(wpa_s->wpa, bss->bssid, wpa_s->own_addr, + ssid) && (!ssid->dpp_connector || !ssid->dpp_netaccesskey || !ssid->dpp_csign)) { if (debug_print) @@ -1665,12 +1771,35 @@ skip_assoc_disallow: #endif /* CONFIG_SAE_PK */ if (bss->ssid_len == 0) { +#ifdef CONFIG_OWE + const u8 *owe_ssid = NULL; + size_t owe_ssid_len = 0; + + owe_trans_ssid(wpa_s, bss, &owe_ssid, &owe_ssid_len); + if (owe_ssid && owe_ssid_len && + owe_ssid_len == ssid->ssid_len && + os_memcmp(owe_ssid, ssid->ssid, owe_ssid_len) == 0) { + if (debug_print) + wpa_dbg(wpa_s, MSG_INFO, + " skip - no SSID in BSS entry for a possible OWE transition mode BSS"); + int_array_add_unique(&wpa_s->owe_trans_scan_freq, + bss->freq); + return false; + } +#endif /* CONFIG_OWE */ if (debug_print) wpa_dbg(wpa_s, MSG_INFO, " skip - no SSID known for the BSS"); return false; } + if (!wpas_valid_ml_bss(wpa_s, bss)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_INFO, + " skip - ML BSS going to be removed"); + return false; + } + /* Matching configuration found */ return true; } @@ -1777,6 +1906,12 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, return NULL; } + if (wnm_is_bss_excluded(wpa_s, bss)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID excluded"); + return NULL; + } + for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) { if (wpa_scan_res_ok(wpa_s, ssid, match_ssid, match_ssid_len, bss, bssid_ignore_count, debug_print)) @@ -1890,10 +2025,12 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, break; } - if (selected == NULL && wpa_s->bssid_ignore && + if (!selected && + (wpa_s->bssid_ignore || wnm_active_bss_trans_mgmt(wpa_s)) && !wpa_s->countermeasures) { wpa_dbg(wpa_s, MSG_INFO, "No APs found - clear BSSID ignore list and try again"); + wnm_btm_reset(wpa_s); wpa_bssid_ignore_clear(wpa_s); wpa_s->bssid_ignore_cleared = true; } else if (selected == NULL) @@ -1945,17 +2082,128 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s, } +static bool ml_link_probe_scan(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->ml_connect_probe_ssid || !wpa_s->ml_connect_probe_bss) + return false; + + wpa_msg(wpa_s, MSG_DEBUG, + "Request association with " MACSTR " after ML probe", + MAC2STR(wpa_s->ml_connect_probe_bss->bssid)); + + wpa_supplicant_associate(wpa_s, wpa_s->ml_connect_probe_bss, + wpa_s->ml_connect_probe_ssid); + + wpa_s->ml_connect_probe_ssid = NULL; + wpa_s->ml_connect_probe_bss = NULL; + + return true; +} + + +static int wpa_supplicant_connect_ml_missing(struct wpa_supplicant *wpa_s, + struct wpa_bss *selected, + struct wpa_ssid *ssid) +{ + int *freqs; + u16 missing_links = 0, removed_links; + u8 ap_mld_id; + + if (!((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))) + return 0; + + if (wpa_bss_parse_basic_ml_element(wpa_s, selected, NULL, + &missing_links, ssid, + &ap_mld_id) || + !missing_links) + return 0; + + removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, selected); + missing_links &= ~removed_links; + + if (!missing_links) + return 0; + + wpa_dbg(wpa_s, MSG_DEBUG, + "MLD: Doing an ML probe for missing links 0x%04x", + missing_links); + + freqs = os_malloc(sizeof(int) * 2); + if (!freqs) + return 0; + + wpa_s->ml_connect_probe_ssid = ssid; + wpa_s->ml_connect_probe_bss = selected; + + freqs[0] = selected->freq; + freqs[1] = 0; + + wpa_s->manual_scan_passive = 0; + wpa_s->manual_scan_use_id = 0; + wpa_s->manual_scan_only_new = 0; + wpa_s->scan_id_count = 0; + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = freqs; + + os_memcpy(wpa_s->ml_probe_bssid, selected->bssid, ETH_ALEN); + + /* + * In case the ML probe request is intended to retrieve information from + * the transmitted BSS, the AP MLD ID should be included and should be + * set to zero. + * In case the ML probe requested is intended to retrieve information + * from a non-transmitted BSS, the AP MLD ID should not be included. + */ + if (ap_mld_id) + wpa_s->ml_probe_mld_id = -1; + else + wpa_s->ml_probe_mld_id = 0; + + if (ssid && ssid->ssid_len) { + os_free(wpa_s->ssids_from_scan_req); + wpa_s->num_ssids_from_scan_req = 0; + + wpa_s->ssids_from_scan_req = + os_zalloc(sizeof(struct wpa_ssid_value)); + if (wpa_s->ssids_from_scan_req) { + wpa_printf(MSG_DEBUG, + "MLD: ML probe: With direct SSID"); + + wpa_s->num_ssids_from_scan_req = 1; + wpa_s->ssids_from_scan_req[0].ssid_len = ssid->ssid_len; + os_memcpy(wpa_s->ssids_from_scan_req[0].ssid, + ssid->ssid, ssid->ssid_len); + } + } + + wpa_s->ml_probe_links = missing_links; + + wpa_s->normal_scans = 0; + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_s->after_wps = 0; + wpa_s->known_wps_freq = 0; + wpa_supplicant_req_scan(wpa_s, 0, 0); + + return 1; +} + + int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid) { - if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { +#ifdef IEEE8021X_EAPOL + if ((eap_is_wps_pbc_enrollee(&ssid->eap) && + wpas_wps_partner_link_overlap_detect(wpa_s)) || + wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP "PBC session overlap"); - #if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) +#if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) WpaEventReport(wpa_s->ifname, WPA_EVENT_WPS_OVERLAP, NULL); - #endif +#endif wpas_notify_wps_event_pbc_overlap(wpa_s); + wpa_s->wps_overlap = true; #ifdef CONFIG_P2P if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT || wpa_s->p2p_in_provisioning) { @@ -1971,6 +2219,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, #endif /* CONFIG_WPS */ return -1; } +#endif /* IEEE8021X_EAPOL */ wpa_msg_only_for_cb(wpa_s, MSG_EXCESSIVE, "Considering connect request: reassociate: %d selected: " @@ -1994,18 +2243,21 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, * the selected BSSID, do not trigger new attempt. */ if (wpa_s->reassociate || - (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 && + (!ether_addr_equal(selected->bssid, wpa_s->bssid) && ((wpa_s->wpa_state != WPA_ASSOCIATING && wpa_s->wpa_state != WPA_AUTHENTICATING) || (!is_zero_ether_addr(wpa_s->pending_bssid) && - os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) != - 0) || + !ether_addr_equal(selected->bssid, wpa_s->pending_bssid)) || (is_zero_ether_addr(wpa_s->pending_bssid) && ssid != wpa_s->current_ssid)))) { if (wpa_supplicant_scard_init(wpa_s, ssid)) { wpa_supplicant_req_new_scan(wpa_s, 10, 0); return 0; } + + if (wpa_supplicant_connect_ml_missing(wpa_s, selected, ssid)) + return 0; + wpa_msg(wpa_s, MSG_INFO, "Request association with " MACSTR, MAC2STR(selected->bssid)); wpa_supplicant_associate(wpa_s, selected, ssid); @@ -2084,9 +2336,15 @@ static void wpa_supplicant_rsn_preauth_scan_results( static int wpas_get_snr_signal_info(u32 frequency, int avg_signal, int noise) { - if (noise == WPA_INVALID_NOISE) - noise = IS_5GHZ(frequency) ? DEFAULT_NOISE_FLOOR_5GHZ : - DEFAULT_NOISE_FLOOR_2GHZ; + if (noise == WPA_INVALID_NOISE) { + if (IS_5GHZ(frequency)) { + noise = DEFAULT_NOISE_FLOOR_5GHZ; + } else if (is_6ghz_freq(frequency)) { + noise = DEFAULT_NOISE_FLOOR_6GHZ; + } else { + noise = DEFAULT_NOISE_FLOOR_2GHZ; + } + } return avg_signal - noise; } @@ -2098,8 +2356,20 @@ wpas_get_est_throughput_from_bss_snr(const struct wpa_supplicant *wpa_s, int rate = wpa_bss_get_max_rate(bss); const u8 *ies = wpa_bss_ie_ptr(bss); size_t ie_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; + enum chan_width max_cw = CHAN_WIDTH_UNKNOWN; - return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, bss->freq); + return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, bss->freq, + &max_cw); +} + + +static int wpas_evaluate_band_score(int frequency) +{ + if (is_6ghz_freq(frequency)) + return 2; + if (IS_5GHZ(frequency)) + return 1; + return 0; } @@ -2108,12 +2378,19 @@ int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s, struct wpa_bss *selected) { int min_diff, diff; - int to_5ghz; - int cur_level; + int cur_band_score, sel_band_score; + int to_5ghz, to_6ghz; + int cur_level, sel_level; unsigned int cur_est, sel_est; struct wpa_signal_info si; int cur_snr = 0; int ret = 0; + const u8 *cur_ies = wpa_bss_ie_ptr(current_bss); + const u8 *sel_ies = wpa_bss_ie_ptr(selected); + size_t cur_ie_len = current_bss->ie_len ? current_bss->ie_len : + current_bss->beacon_ie_len; + size_t sel_ie_len = selected->ie_len ? selected->ie_len : + selected->beacon_ie_len; wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation"); wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR @@ -2135,18 +2412,18 @@ int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s, MAC2STR_SEC(selected->bssid), selected->freq, selected->level, selected->snr, selected->est_throughput); + if (wpas_ap_link_address(wpa_s, selected->bssid)) { + wpa_dbg(wpa_s, MSG_DEBUG, "MLD: associated to selected BSS"); + return 0; + } + if (wpa_s->current_ssid->bssid_set && - os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) == - 0) { + ether_addr_equal(selected->bssid, wpa_s->current_ssid->bssid)) { wpa_dbg(wpa_s, MSG_DEBUG, "Allow reassociation - selected BSS " "has preferred BSSID"); return 1; } - cur_level = current_bss->level; - cur_est = current_bss->est_throughput; - sel_est = selected->est_throughput; - /* * Try to poll the signal from the driver since this will allow to get * more accurate values. In some cases, there can be big differences @@ -2163,9 +2440,16 @@ int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s, * information about our currently associated AP. */ if (wpa_drv_signal_poll(wpa_s, &si) == 0 && - (si.avg_beacon_signal || si.avg_signal)) { - cur_level = si.avg_beacon_signal ? si.avg_beacon_signal : - si.avg_signal; + (si.data.avg_beacon_signal || si.data.avg_signal)) { + /* + * Normalize avg_signal to the RSSI over 20 MHz, as the + * throughput is estimated based on the RSSI over 20 MHz + */ + cur_level = si.data.avg_beacon_signal ? + si.data.avg_beacon_signal : + (si.data.avg_signal - + wpas_channel_width_rssi_bump(cur_ies, cur_ie_len, + si.chanwidth)); cur_snr = wpas_get_snr_signal_info(si.frequency, cur_level, si.current_noise); @@ -2175,8 +2459,24 @@ int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "Using signal poll values for the current BSS: level=%d snr=%d est_throughput=%u", cur_level, cur_snr, cur_est); + } else { + /* Level and SNR are measured over 20 MHz channel */ + cur_level = current_bss->level; + cur_snr = current_bss->snr; + cur_est = current_bss->est_throughput; } + /* Adjust the SNR of BSSes based on the channel width. */ + cur_level += wpas_channel_width_rssi_bump(cur_ies, cur_ie_len, + current_bss->max_cw); + cur_snr = wpas_adjust_snr_by_chanwidth(cur_ies, cur_ie_len, + current_bss->max_cw, cur_snr); + + sel_est = selected->est_throughput; + sel_level = selected->level + + wpas_channel_width_rssi_bump(sel_ies, sel_ie_len, + selected->max_cw); + if (sel_est > cur_est + 5000) { wpa_dbg(wpa_s, MSG_DEBUG, "Allow reassociation - selected BSS has better estimated throughput"); @@ -2184,8 +2484,11 @@ int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s, } to_5ghz = selected->freq > 4000 && current_bss->freq < 4000; + to_6ghz = is_6ghz_freq(selected->freq) && + !is_6ghz_freq(current_bss->freq); - if (cur_level < 0 && cur_level > selected->level + to_5ghz * 2 && + if (cur_level < 0 && + cur_level > sel_level + to_5ghz * 2 + to_6ghz * 2 && sel_est < cur_est * 1.2) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better " "signal level"); @@ -2235,9 +2538,13 @@ int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s, else if (sel_est > cur_est) min_diff--; - if (to_5ghz) + cur_band_score = wpas_evaluate_band_score(current_bss->freq); + sel_band_score = wpas_evaluate_band_score(selected->freq); + min_diff += (cur_band_score - sel_band_score) * 2; + if (wpa_s->signal_threshold && cur_level <= wpa_s->signal_threshold && + sel_level > wpa_s->signal_threshold) min_diff -= 2; - diff = selected->level - cur_level; + diff = sel_level - cur_level; if (diff < min_diff) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference in signal level (%d < %d)", @@ -2256,7 +2563,7 @@ int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s, MAC2STR(current_bss->bssid), current_bss->freq, cur_level, cur_est, MAC2STR(selected->bssid), - selected->freq, selected->level, sel_est); + selected->freq, sel_level, sel_est); return ret; } @@ -2268,6 +2575,7 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { struct wpa_bss *current_bss = NULL; + const u8 *bssid; if (wpa_s->reassociate) return 1; /* explicit request to reassociate */ @@ -2281,12 +2589,17 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, if (wpas_driver_bss_selection(wpa_s)) return 0; /* Driver-based roaming */ + if (wpa_s->valid_links) + bssid = wpa_s->links[wpa_s->mlo_assoc_link_id].bssid; + else + bssid = wpa_s->bssid; + if (wpa_s->current_ssid->ssid) - current_bss = wpa_bss_get(wpa_s, wpa_s->bssid, + current_bss = wpa_bss_get(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); + current_bss = wpa_bss_get_bssid(wpa_s, bssid); if (!current_bss) return 1; /* current BSS not seen in scan results */ @@ -2322,6 +2635,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res = NULL; int ret = 0; int ap = 0; + bool trigger_6ghz_scan; #ifndef CONFIG_NO_RANDOM_POOL size_t i, num; #endif /* CONFIG_NO_RANDOM_POOL */ @@ -2331,11 +2645,16 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, ap = 1; #endif /* CONFIG_AP */ + trigger_6ghz_scan = wpa_s->crossed_6ghz_dom && + wpa_s->last_scan_all_chan; + wpa_s->crossed_6ghz_dom = false; + wpa_s->last_scan_all_chan = false; + wpa_supplicant_notify_scanning(wpa_s, 0); scan_res = wpa_supplicant_get_scan_results(wpa_s, data ? &data->scan_info : - NULL, 1); + NULL, 1, NULL); if (scan_res == NULL) { if (wpa_s->conf->ap_scan == 2 || ap || wpa_s->scan_res_handler == scan_only_handler) @@ -2403,30 +2722,28 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)", wpa_s->own_scan_running, data ? data->scan_info.external_scan : 0); - if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && - wpa_s->manual_scan_use_id && wpa_s->own_scan_running && - own_request && !(data && data->scan_info.external_scan)) { + wpa_s->manual_scan_use_id && wpa_s->own_scan_running && + own_request && !(data && data->scan_info.external_scan)) { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", wpa_s->manual_scan_id); - - #if defined(OHOS_EUPDATER) +#if defined(OHOS_EUPDATER) struct WpaRecvScanResultParam wpaRecvScanResultParam; os_memset(&wpaRecvScanResultParam, 0, sizeof(struct WpaRecvScanResultParam)); wpaRecvScanResultParam.scanId = wpa_s->manual_scan_id ; wpa_printf(MSG_ERROR, "send WPA_EVENT_RECV_SCAN_RESULT scanId = v%d", wpaRecvScanResultParam.scanId); WpaEventReport(wpa_s->ifname, WPA_EVENT_RECV_SCAN_RESULT, (void *) &wpaRecvScanResultParam); - #endif +#endif wpa_s->manual_scan_use_id = 0; } else { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); - #if defined(OHOS_EUPDATER) +#if defined(OHOS_EUPDATER) struct WpaRecvScanResultParam wpaRecvScanResultParam; os_memset(&wpaRecvScanResultParam, 0, sizeof(struct WpaRecvScanResultParam)); wpaRecvScanResultParam.scanId = 0; wpa_printf(MSG_ERROR, "send WPA_EVENT_RECV_SCAN_RESULT scanId = v%d", wpaRecvScanResultParam.scanId); WpaEventReport(wpa_s->ifname, WPA_EVENT_RECV_SCAN_RESULT, (void *) &wpaRecvScanResultParam); - #endif +#endif } wpas_notify_scan_results(wpa_s); @@ -2447,15 +2764,20 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return 0; } - if (wnm_scan_process(wpa_s, 1) > 0) + if (wnm_scan_process(wpa_s, false) > 0) goto scan_work_done; if (sme_proc_obss_scan(wpa_s) > 0) goto scan_work_done; +#ifndef CONFIG_NO_RRM if (own_request && data && wpas_beacon_rep_scan_process(wpa_s, scan_res, &data->scan_info) > 0) goto scan_work_done; +#endif /* CONFIG_NO_RRM */ + + if (ml_link_probe_scan(wpa_s)) + goto scan_work_done; if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) goto scan_work_done; @@ -2501,7 +2823,11 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, } } - return wpas_select_network_from_last_scan(wpa_s, 1, own_request); + if (wpa_s->supp_pbc_active && !wpas_wps_partner_link_scan_done(wpa_s)) + return ret; + + return wpas_select_network_from_last_scan(wpa_s, 1, own_request, + trigger_6ghz_scan, data); scan_work_done: wpa_scan_results_free(scan_res); @@ -2514,8 +2840,44 @@ scan_work_done: } +static int wpas_trigger_6ghz_scan(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + struct wpa_driver_scan_params params; + unsigned int j; + + wpa_dbg(wpa_s, MSG_INFO, "Triggering 6GHz-only scan"); + os_memset(¶ms, 0, sizeof(params)); + params.non_coloc_6ghz = wpa_s->last_scan_non_coloc_6ghz; + for (j = 0; j < data->scan_info.num_ssids; j++) + params.ssids[j] = data->scan_info.ssids[j]; + params.num_ssids = data->scan_info.num_ssids; + wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, ¶ms, + true, !wpa_s->last_scan_non_coloc_6ghz, false); + if (!wpa_supplicant_trigger_scan(wpa_s, ¶ms, true, true)) { + os_free(params.freqs); + return 1; + } + wpa_dbg(wpa_s, MSG_INFO, "Failed to trigger 6GHz-only scan"); + os_free(params.freqs); + return 0; +} + + +/** + * Select a network from the last scan + * @wpa_s: Pointer to wpa_supplicant data + * @new_scan: Whether this function was called right after a scan has finished + * @own_request: Whether the scan was requested by this interface + * @trigger_6ghz_scan: Whether to trigger a 6ghz-only scan when applicable + * @data: Scan data from scan that finished if applicable + * + * See _wpa_supplicant_event_scan_results() for return values. + */ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, - int new_scan, int own_request) + int new_scan, int own_request, + bool trigger_6ghz_scan, + union wpa_event_data *data) { struct wpa_bss *selected; struct wpa_ssid *ssid = NULL; @@ -2535,6 +2897,10 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, return 0; /* no normal connection on p2p_mgmt interface */ wpa_s->owe_transition_search = 0; +#ifdef CONFIG_OWE + os_free(wpa_s->owe_trans_scan_freq); + wpa_s->owe_trans_scan_freq = NULL; +#endif /* CONFIG_OWE */ selected = wpa_supplicant_pick_network(wpa_s, &ssid); #ifdef CONFIG_MESH @@ -2567,6 +2933,8 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_INFO, "Connect failed"); return -1; } + wpa_s->supp_pbc_active = false; + if (new_scan) wpa_supplicant_rsn_preauth_scan_results(wpa_s); /* @@ -2585,6 +2953,10 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, if (new_scan) wpa_supplicant_rsn_preauth_scan_results(wpa_s); } else if (own_request) { + if (wpa_s->support_6ghz && trigger_6ghz_scan && data && + wpas_trigger_6ghz_scan(wpa_s, data) < 0) + return 1; + /* * No SSID found. If SCAN results are as a result of * own scan request and not due to a scan request on @@ -2601,6 +2973,9 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, if (res == 1) return 0; + if (wpas_p2p_retry_limit_exceeded(wpa_s)) + return 0; + if (wpa_s->p2p_in_provisioning || wpa_s->show_group_started || wpa_s->p2p_in_invitation) { @@ -2648,6 +3023,13 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, "OWE: Use shorter wait during transition mode search"); timeout_sec = 0; timeout_usec = 500000; + if (wpa_s->owe_trans_scan_freq) { + os_free(wpa_s->next_scan_freqs); + wpa_s->next_scan_freqs = + wpa_s->owe_trans_scan_freq; + wpa_s->owe_trans_scan_freq = NULL; + timeout_usec = 100000; + } wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); return 0; @@ -2735,13 +3117,27 @@ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s) wpa_s->conf->scan_res_valid_for_connect)) { wpa_printf(MSG_DEBUG, "Fast associate: Old scan results"); return -1; + } else if (wpa_s->crossed_6ghz_dom) { + wpa_printf(MSG_DEBUG, "Fast associate: Crossed 6 GHz domain"); + return -1; } #endif /* CONFIG_OPEN_HARMONY_PATCH */ - return wpas_select_network_from_last_scan(wpa_s, 0, 1); + return wpas_select_network_from_last_scan(wpa_s, 0, 1, false, NULL); +#endif /* CONFIG_NO_SCAN_PROCESSING */ +} + + +int wpa_wps_supplicant_fast_associate(struct wpa_supplicant *wpa_s) +{ +#ifdef CONFIG_NO_SCAN_PROCESSING + return -1; +#else /* CONFIG_NO_SCAN_PROCESSING */ + return wpas_select_network_from_last_scan(wpa_s, 1, 1, false, NULL); #endif /* CONFIG_NO_SCAN_PROCESSING */ } + #ifdef CONFIG_WNM static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx) @@ -2807,6 +3203,8 @@ static void wnm_process_assoc_resp(struct wpa_supplicant *wpa_s, wnm_bss_keep_alive, wpa_s, NULL); } + } else { + wpa_s->sme.bss_max_idle_period = 0; } #endif /* CONFIG_SME */ } @@ -2822,8 +3220,6 @@ void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s) } -#ifdef CONFIG_INTERWORKING - static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map, size_t len) { @@ -2856,32 +3252,49 @@ static void interworking_process_assoc_resp(struct wpa_supplicant *wpa_s, } } -#endif /* CONFIG_INTERWORKING */ + +static void wpa_supplicant_set_4addr_mode(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->enabled_4addr_mode) { + wpa_printf(MSG_DEBUG, "4addr mode already set"); + return; + } + + if (wpa_drv_set_4addr_mode(wpa_s, 1) < 0) { + wpa_msg(wpa_s, MSG_ERROR, "Failed to set 4addr mode"); + goto fail; + } + wpa_s->enabled_4addr_mode = 1; + wpa_msg(wpa_s, MSG_INFO, "Successfully set 4addr mode"); + return; + +fail: + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); +} static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s, const u8 *ies, size_t ies_len) { struct ieee802_11_elems elems; - const u8 *map_sub_elem, *pos; - size_t len; + struct multi_ap_params multi_ap; + u16 status; wpa_s->multi_ap_ie = 0; if (!ies || ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed || - !elems.multi_ap || elems.multi_ap_len < 7) + !elems.multi_ap) return; - pos = elems.multi_ap + 4; - len = elems.multi_ap_len - 4; - - map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE); - if (!map_sub_elem || map_sub_elem[1] < 1) + status = check_multi_ap_ie(elems.multi_ap + 4, elems.multi_ap_len - 4, + &multi_ap); + if (status != WLAN_STATUS_SUCCESS) return; - wpa_s->multi_ap_backhaul = !!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS); - wpa_s->multi_ap_fronthaul = !!(map_sub_elem[2] & + wpa_s->multi_ap_backhaul = !!(multi_ap.capability & + MULTI_AP_BACKHAUL_BSS); + wpa_s->multi_ap_fronthaul = !!(multi_ap.capability & MULTI_AP_FRONTHAUL_BSS); wpa_s->multi_ap_ie = 1; } @@ -2911,11 +3324,7 @@ static void multi_ap_set_4addr_mode(struct wpa_supplicant *wpa_s) goto fail; } - if (wpa_drv_set_4addr_mode(wpa_s, 1) < 0) { - wpa_printf(MSG_ERROR, "Failed to set 4addr mode"); - goto fail; - } - wpa_s->enabled_4addr_mode = 1; + wpa_supplicant_set_4addr_mode(wpa_s); return; fail: @@ -3004,8 +3413,10 @@ static int wpa_supplicant_use_own_rsne_params(struct wpa_supplicant *wpa_s, p += len; } - if (!found || wpa_parse_wpa_ie(p, len, &ie) < 0) + if (!found || wpa_parse_wpa_ie(p, len, &ie) < 0) { + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, 0); return 0; + } wpa_hexdump(MSG_DEBUG, "WPA: Update cipher suite selection based on IEs in driver-generated WPA/RSNE in AssocReq", @@ -3022,7 +3433,6 @@ static int wpa_supplicant_use_own_rsne_params(struct wpa_supplicant *wpa_s, sel = ie.key_mgmt; if (ssid->key_mgmt) sel &= ssid->key_mgmt; - #ifdef CONFIG_DRIVER_NL80211_HISI if (!sel) { sel = ie.key_mgmt; @@ -3050,33 +3460,35 @@ static int wpa_supplicant_use_own_rsne_params(struct wpa_supplicant *wpa_s, return -1; } -#ifdef CONFIG_DRIVER_NL80211_HISI +#ifdef CONFIG_OCV + if (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) || + (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV)) && ssid->ocv) + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, + !!(ie.capabilities & WPA_CAPABILITY_OCVC)); +#endif /* CONFIG_OCV */ + /* * Update PMK in wpa_sm and the driver if roamed to WPA/WPA2 PSK from a * different AKM. */ if (wpa_s->key_mgmt != ie.key_mgmt && - wpa_key_mgmt_wpa_psk_no_sae(ie.key_mgmt)) { + wpa_key_mgmt_wpa_psk_no_sae(ie.key_mgmt)) { if (!ssid->psk_set) { wpa_dbg(wpa_s, MSG_INFO, "No PSK available for association"); - wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE"); + wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE", NULL); return -1; } wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL, NULL); if (wpa_s->conf->key_mgmt_offload && - (wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD) && -#ifdef CONFIG_MLD_PATCH - wpa_drv_set_key(wpa_s, -1, 0, NULL, 0, 0, NULL, 0, ssid->psk, -#else - wpa_drv_set_key(wpa_s, 0, NULL, 0, 0, NULL, 0, ssid->psk, -#endif - PMK_LEN, KEY_FLAG_PMK)) + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD) && + wpa_drv_set_key(wpa_s, -1, 0, NULL, 0, 0, NULL, 0, + ssid->psk, PMK_LEN, KEY_FLAG_PMK)) wpa_dbg(wpa_s, MSG_ERROR, "WPA: Cannot set PMK for key management offload"); } -#endif + wpa_s->key_mgmt = ie.key_mgmt; wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt); wpa_dbg(wpa_s, MSG_INFO, "WPA: using KEY_MGMT %s and proto %d", @@ -3220,6 +3632,16 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, bool bssid_known; wpa_dbg(wpa_s, MSG_DEBUG, "Association info event"); + wpa_s->ssid_verified = false; + wpa_s->bigtk_set = false; +#ifdef CONFIG_SAE +#ifdef CONFIG_SME + /* SAE H2E binds the SSID into PT and that verifies the SSID + * implicitly. */ + if (wpa_s->sme.sae.state == SAE_ACCEPTED && wpa_s->sme.sae.h2e) + wpa_s->ssid_verified = true; +#endif /* CONFIG_SME */ +#endif /* CONFIG_SAE */ 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, @@ -3235,10 +3657,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_WNM */ -#ifdef CONFIG_INTERWORKING interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); -#endif /* CONFIG_INTERWORKING */ if (wpa_s->hw_capab == CAPAB_VHT && get_ie(data->assoc_info.resp_ies, data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP)) @@ -3303,6 +3723,10 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, } else { wpa_s->connection_channel_bandwidth = CHAN_WIDTH_20; } + wpa_s->connection_eht = req_elems.eht_capabilities && + resp_elems.eht_capabilities; + if (req_elems.rrm_enabled) + wpa_s->rrm.rrm_used = 1; } } @@ -3326,7 +3750,8 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len)) break; found = 1; - wpa_find_assoc_pmkid(wpa_s); + wpa_find_assoc_pmkid(wpa_s, + data->assoc_info.authorized); } if (!found_x && p[0] == WLAN_EID_RSNX) { if (wpa_sm_set_assoc_rsnxe(wpa_s->wpa, p, len)) @@ -3343,14 +3768,22 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, #ifdef CONFIG_FILS #ifdef CONFIG_SME - if ((wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS || - wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS) && - (!data->assoc_info.resp_frame || - fils_process_assoc_resp(wpa_s->wpa, - data->assoc_info.resp_frame, - data->assoc_info.resp_frame_len) < 0)) { - wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED); - return -1; + if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS || + wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS_SK_PFS) { + if (!data->assoc_info.resp_frame || + fils_process_assoc_resp(wpa_s->wpa, + data->assoc_info.resp_frame, + data->assoc_info.resp_frame_len) < + 0) { + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_UNSPECIFIED); + return -1; + } + + /* FILS use of an AEAD cipher include the SSID element in + * (Re)Association Request frame in the AAD and since the AP + * accepted that, the SSID was verified. */ + wpa_s->ssid_verified = true; } #endif /* CONFIG_SME */ @@ -3362,8 +3795,11 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, #ifdef CONFIG_OWE if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE && + !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA) && (!bssid_known || - owe_process_assoc_resp(wpa_s->wpa, bssid, + owe_process_assoc_resp(wpa_s->wpa, + wpa_s->valid_links ? + wpa_s->ap_mld_addr : bssid, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len) < 0)) { wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED); @@ -3408,6 +3844,9 @@ no_pfs: wpa_s, WLAN_REASON_INVALID_IE); return -1; } + /* SSID is included in PMK-R0 derivation, so it is verified + * implicitly. */ + wpa_s->ssid_verified = true; } p = data->assoc_info.resp_ies; @@ -3469,16 +3908,21 @@ no_pfs: return -1; } wpa_dbg(wpa_s, MSG_DEBUG, "FT: Reassociation Response done"); + /* SSID is included in PMK-R0 derivation, so it is verified + * implicitly. */ + wpa_s->ssid_verified = true; } wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); #endif /* CONFIG_IEEE80211R */ +#ifndef CONFIG_NO_ROBUST_AV if (bssid_known) wpas_handle_assoc_resp_mscs(wpa_s, bssid, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); +#endif /* CONFIG_NO_ROBUST_AV */ /* WPA/RSN IE from Beacon/ProbeResp */ p = data->assoc_info.beacon_ies; @@ -3523,18 +3967,29 @@ no_pfs: if (wpa_found || rsn_found) wpa_s->ap_ies_from_associnfo = 1; - if (wpa_s->assoc_freq && data->assoc_info.freq && - wpa_s->assoc_freq != data->assoc_info.freq) { - wpa_printf(MSG_DEBUG, "Operating frequency changed from " - "%u to %u MHz", - wpa_s->assoc_freq, data->assoc_info.freq); - wpa_supplicant_update_scan_results(wpa_s); + if (wpa_s->assoc_freq && data->assoc_info.freq) { + struct wpa_bss *bss; + unsigned int freq = 0; + + if (bssid_known) { + bss = wpa_bss_get_bssid_latest(wpa_s, bssid); + if (bss) + freq = bss->freq; + } + if (freq != data->assoc_info.freq) { + wpa_printf(MSG_DEBUG, + "Operating frequency changed from %u to %u MHz", + wpa_s->assoc_freq, data->assoc_info.freq); + wpa_supplicant_update_scan_results(wpa_s, bssid); + } } wpa_s->assoc_freq = data->assoc_info.freq; +#ifndef CONFIG_NO_ROBUST_AV wpas_handle_assoc_resp_qos_mgmt(wpa_s, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len); +#endif /* CONFIG_NO_ROBUST_AV */ return 0; } @@ -3605,7 +4060,6 @@ static void wpas_fst_update_mb_assoc(struct wpa_supplicant *wpa_s, #endif /* CONFIG_FST */ } -#ifdef CONFIG_MLD_PATCH #define MLD_INFO_BUF_LEN 64 static unsigned int wpas_ml_parse_assoc(struct wpa_supplicant *wpa_s, struct ieee802_11_elems *elems, @@ -3628,7 +4082,7 @@ static unsigned int wpas_ml_parse_assoc(struct wpa_supplicant *wpa_s, if (!wpa_s->valid_links || !elems->basic_mle || !elems->basic_mle_len) return 0; - mlbuf = ieee802_11_defrag((const struct ieee802_11_elems *)elems->basic_mle, elems->basic_mle_len, true); + mlbuf = ieee802_11_defrag(elems->basic_mle, elems->basic_mle_len, true); if (!mlbuf) return 0; @@ -3684,12 +4138,12 @@ static unsigned int wpas_ml_parse_assoc(struct wpa_supplicant *wpa_s, goto out; } - wpa_printf(MSG_DEBUG, "MLD: address: " MACSTR_SEC, - MAC2STR_SEC(common_info->mld_addr)); + wpa_printf(MSG_DEBUG, "MLD: address: " MACSTR, + MAC2STR(common_info->mld_addr)); - if (os_memcmp(wpa_s->ap_mld_addr, common_info->mld_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(wpa_s->ap_mld_addr, common_info->mld_addr)) { wpa_printf(MSG_DEBUG, "MLD: Mismatching MLD address (expected " - MACSTR_SEC ")", MAC2STR_SEC(wpa_s->ap_mld_addr)); + MACSTR ")", MAC2STR(wpa_s->ap_mld_addr)); goto out; } @@ -3827,8 +4281,8 @@ static unsigned int wpas_ml_parse_assoc(struct wpa_supplicant *wpa_s, /* Get the link address */ wpa_printf(MSG_DEBUG, - "MLD: link addr: " MACSTR_SEC " nstr BM len=%u", - MAC2STR_SEC(pos + 1), nstr_bitmap_len); + "MLD: link addr: " MACSTR " nstr BM len=%u", + MAC2STR(pos + 1), nstr_bitmap_len); ml_info[i].link_id = ctrl & EHT_PER_STA_CTRL_LINK_ID_MSK; os_memcpy(ml_info[i].bssid, pos + 1, ETH_ALEN); @@ -3881,30 +4335,25 @@ static int wpa_drv_get_mlo_info(struct wpa_supplicant *wpa_s) if (!mlo.valid_links) return 0; - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(mlo.valid_links & BIT(i))) - continue; - - if (os_memcmp(wpa_s->links[i].addr, mlo.links[i].addr, - ETH_ALEN) != 0 || - os_memcmp(wpa_s->links[i].bssid, mlo.links[i].bssid, - ETH_ALEN) != 0) { + for_each_link(mlo.valid_links, i) { + if (!ether_addr_equal(wpa_s->links[i].addr, + mlo.links[i].addr) || + !ether_addr_equal(wpa_s->links[i].bssid, + mlo.links[i].bssid)) { match = false; break; } } if (match && wpa_s->mlo_assoc_link_id == mlo.assoc_link_id && - os_memcmp(wpa_s->ap_mld_addr, mlo.ap_mld_addr, ETH_ALEN) == 0) + ether_addr_equal(wpa_s->ap_mld_addr, mlo.ap_mld_addr)) return 0; } wpa_s->valid_links = mlo.valid_links; wpa_s->mlo_assoc_link_id = mlo.assoc_link_id; os_memcpy(wpa_s->ap_mld_addr, mlo.ap_mld_addr, ETH_ALEN); - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(wpa_s->valid_links & BIT(i))) - continue; + for_each_link(wpa_s->valid_links, i) { os_memcpy(wpa_s->links[i].addr, mlo.links[i].addr, ETH_ALEN); os_memcpy(wpa_s->links[i].bssid, mlo.links[i].bssid, ETH_ALEN); wpa_s->links[i].freq = mlo.links[i].freq; @@ -3914,6 +4363,7 @@ static int wpa_drv_get_mlo_info(struct wpa_supplicant *wpa_s) return 0; } + static int wpa_sm_set_ml_info(struct wpa_supplicant *wpa_s) { struct driver_sta_mlo_info drv_mlo; @@ -3936,19 +4386,10 @@ static int wpa_sm_set_ml_info(struct wpa_supplicant *wpa_s) wpa_mlo.valid_links = drv_mlo.valid_links; wpa_mlo.req_links = drv_mlo.req_links; - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + for_each_link(drv_mlo.req_links, i) { struct wpa_bss *bss; - - if (!(drv_mlo.req_links & BIT(i))) - continue; bss = wpa_supplicant_get_new_bss(wpa_s, drv_mlo.links[i].bssid); - if (!bss) { - wpa_supplicant_update_scan_results(wpa_s); - bss = wpa_supplicant_get_new_bss( - wpa_s, drv_mlo.links[i].bssid); - } - if (!bss) { wpa_dbg(wpa_s, MSG_INFO, "Failed to get MLO link %d BSS", i); @@ -3972,7 +4413,8 @@ static int wpa_sm_set_ml_info(struct wpa_supplicant *wpa_s) out: return wpa_sm_set_mlo_params(wpa_s->wpa, &wpa_mlo); } -#endif + + static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { @@ -3990,8 +4432,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, hostapd_notif_assoc(wpa_s->ap_iface->bss[0], data->assoc_info.addr, data->assoc_info.req_ies, - data->assoc_info.req_ies_len, - data->assoc_info.reassoc); + data->assoc_info.req_ies_len, NULL, 0, + NULL, data->assoc_info.reassoc); return; } #endif /* CONFIG_AP */ @@ -4062,14 +4504,26 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_s, WLAN_REASON_DEAUTH_LEAVING); return; } -#ifdef CONFIG_MLD_PATCH + if (wpa_drv_get_mlo_info(wpa_s) < 0) { wpa_dbg(wpa_s, MSG_ERROR, "Failed to get MLO connection info"); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); return; } -#endif + + if (ft_completed && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION)) { + wpa_msg(wpa_s, MSG_INFO, "Attempt to roam to " MACSTR, + MAC2STR(bssid)); + if (!wpa_supplicant_update_current_bss(wpa_s, bssid)) { + wpa_printf(MSG_ERROR, + "Can't find target AP's information!"); + return; + } + wpa_supplicant_assoc_update_ie(wpa_s); + } + if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0) return; /* @@ -4085,7 +4539,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_supplicant_upload_p2p_state(wpa_s, P2P_INTERFACE_STATE_ASSOCIATED, P2P_CHR_DEFAULT_REASON_CODE, P2P_CHR_DEFAULT_REASON_CODE); #endif - if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) { + if (!ether_addr_equal(bssid, wpa_s->bssid)) { if (os_reltime_initialized(&wpa_s->session_start)) { os_reltime_age(&wpa_s->session_start, &wpa_s->session_length); @@ -4109,7 +4563,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) { wpa_clear_keys(wpa_s, bssid); } - if (wpa_supplicant_select_config(wpa_s) < 0) { + if (wpa_supplicant_select_config(wpa_s, data) < 0) { wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); return; @@ -4132,7 +4586,6 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpas_fst_update_mb_assoc(wpa_s, data); #ifdef CONFIG_SME -#ifdef CONFIG_MLD_PATCH /* * Cache the current AP's BSSID (for non-MLO connection) or MLD address * (for MLO connection) as the previous BSSID for subsequent @@ -4140,9 +4593,6 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, */ os_memcpy(wpa_s->sme.prev_bssid, wpa_s->valid_links ? wpa_s->ap_mld_addr : bssid, ETH_ALEN); -#else - os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN); -#endif wpa_s->sme.prev_bssid_set = 1; wpa_s->sme.last_unprot_disconnect.sec = 0; #endif /* CONFIG_SME */ @@ -4156,7 +4606,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid); } wpa_sm_notify_assoc(wpa_s->wpa, bssid); -#ifdef CONFIG_MLD_PATCH + if (wpa_sm_set_ml_info(wpa_s)) { wpa_dbg(wpa_s, MSG_INFO, "Failed to set MLO connection info to wpa_sm"); @@ -4164,7 +4614,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, WLAN_REASON_DEAUTH_LEAVING); return; } -#endif + if (wpa_s->l2) l2_packet_notify_auth_start(wpa_s->l2); @@ -4222,7 +4672,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, #ifdef CONFIG_WAPI } #endif - + wpa_supplicant_cancel_scan(wpa_s); if (ft_completed) { @@ -4236,14 +4686,23 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, eapol_sm_notify_eap_success(wpa_s->eapol, true); } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) && wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { - /* - * We are done; the driver will take care of RSN 4-way - * handshake. - */ - wpa_supplicant_cancel_auth_timeout(wpa_s); - wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); - eapol_sm_notify_portValid(wpa_s->eapol, true); - eapol_sm_notify_eap_success(wpa_s->eapol, true); + if (already_authorized) { + /* + * We are done; the driver will take care of RSN 4-way + * handshake. + */ + wpa_supplicant_cancel_auth_timeout(wpa_s); + wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); + eapol_sm_notify_portValid(wpa_s->eapol, true); + eapol_sm_notify_eap_success(wpa_s->eapol, true); + } else { + /* Update port, WPA_COMPLETED state from the + * EVENT_PORT_AUTHORIZED handler when the driver is done + * with the 4-way handshake. + */ + wpa_msg(wpa_s, MSG_DEBUG, + "ASSOC INFO: wait for driver port authorized indication"); + } } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) && wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { /* @@ -4278,20 +4737,17 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, os_get_reltime(&now); os_reltime_sub(&now, &wpa_s->pending_eapol_rx_time, &age); if (age.sec == 0 && age.usec < 200000 && -#ifdef CONFIG_MLD_PATCH - os_memcmp(wpa_s->pending_eapol_rx_src, - wpa_s->valid_links ? wpa_s->ap_mld_addr : bssid, ETH_ALEN) == 0 -#else - os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) == 0 -#endif - ) { + ether_addr_equal(wpa_s->pending_eapol_rx_src, + wpa_s->valid_links ? wpa_s->ap_mld_addr : + bssid)) { wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL " "frame that was received just before " "association notification"); wpa_supplicant_rx_eapol( wpa_s, wpa_s->pending_eapol_rx_src, wpabuf_head(wpa_s->pending_eapol_rx), - wpabuf_len(wpa_s->pending_eapol_rx)); + wpabuf_len(wpa_s->pending_eapol_rx), + wpa_s->pending_eapol_encrypted); } wpabuf_free(wpa_s->pending_eapol_rx); wpa_s->pending_eapol_rx = NULL; @@ -4327,6 +4783,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpas_wps_notify_assoc(wpa_s, bssid); +#ifndef CONFIG_NO_WMM_AC if (data) { wmm_ac_notify_assoc(wpa_s, data->assoc_info.resp_ies, data->assoc_info.resp_ies_len, @@ -4335,6 +4792,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, if (wpa_s->reassoc_same_bss) wmm_ac_restore_tspecs(wpa_s); } +#endif /* CONFIG_NO_WMM_AC */ #if defined(CONFIG_FILS) || defined(CONFIG_MBO) bss = wpa_bss_get_bssid(wpa_s, bssid); @@ -4355,6 +4813,9 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, #ifdef CONFIG_DPP2 wpa_s->dpp_pfs_fallback = 0; #endif /* CONFIG_DPP2 */ + + if (wpa_s->current_ssid && wpa_s->current_ssid->enable_4addr_mode) + wpa_supplicant_set_4addr_mode(wpa_s); } @@ -4390,18 +4851,19 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s, wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR " reason=%d%s", MAC2STR(bssid), reason_code, - locally_generated ? "locally_generated=1" : ""); - #if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) + locally_generated ? " locally_generated=1" : ""); +#if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) struct WpaDisconnectParam wpaDisconnectParma; os_memcpy(wpaDisconnectParma.bssid, bssid, ETH_ALEN); wpaDisconnectParma.locallyGenerated = locally_generated; wpaDisconnectParma.reasonCode = reason_code; wpa_printf(MSG_DEBUG, "%s wpaDisconnectParmabssid[0]=%x", __func__, wpaDisconnectParma.bssid[0]); WpaEventReport(wpa_s->ifname, WPA_EVENT_DISCONNECT, (void *) &wpaDisconnectParma); - #endif +#endif } } + static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code, int locally_generated) { @@ -4431,16 +4893,10 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, int locally_generated) { const u8 *bssid; - int authenticating; - u8 prev_pending_bssid[ETH_ALEN]; struct wpa_bss *fast_reconnect = NULL; struct wpa_ssid *fast_reconnect_ssid = NULL; - struct wpa_ssid *last_ssid; struct wpa_bss *curr = NULL; - authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING; - os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN); - #ifdef CONFIG_WAPI wpa_printf(MSG_DEBUG, "wpa_s->ap_wapi_ie_len=%d\twpa_s->assoc_wapi_ie_len =%d\n", wpa_s->ap_wapi_ie_len, wpa_s->assoc_wapi_ie_len); @@ -4506,7 +4962,8 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, "pre-shared key may be incorrect"); if (wpas_p2p_4way_hs_failed(wpa_s) > 0) return; /* P2P group removed */ - wpas_auth_failed(wpa_s, "WRONG_KEY"); + wpas_auth_failed(wpa_s, "WRONG_KEY", wpa_s->pending_bssid); + wpas_notify_psk_mismatch(wpa_s); #ifdef CONFIG_DPP2 wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_AUTH_FAILURE); @@ -4568,25 +5025,18 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, if (is_zero_ether_addr(bssid)) bssid = wpa_s->pending_bssid; if (wpa_s->wpa_state >= WPA_AUTHENTICATING) -#ifdef CONFIG_MLD_PATCH wpas_connection_failed(wpa_s, bssid, NULL); -#else - wpas_connection_failed(wpa_s, bssid); -#endif wpa_sm_notify_disassoc(wpa_s->wpa); ptksa_cache_flush(wpa_s->ptksa, wpa_s->bssid, WPA_CIPHER_NONE); - #ifdef CONFIG_VENDOR_EXT if (wpa_vendor_ext_is_p2p_enhance_mode(wpa_s)) { goto skip_rewrite_reason; } #endif - if (locally_generated) wpa_s->disconnect_reason = -reason_code; else wpa_s->disconnect_reason = reason_code; - #ifdef CONFIG_VENDOR_EXT skip_rewrite_reason: #endif @@ -4595,17 +5045,11 @@ skip_rewrite_reason: wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys"); wpa_clear_keys(wpa_s, wpa_s->bssid); } - last_ssid = wpa_s->current_ssid; wpa_supplicant_mark_disassoc(wpa_s); if (curr) wpa_bss_remove(wpa_s, curr, "Connection to AP lost"); - if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) { - sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid); - wpa_s->current_ssid = last_ssid; - } - if (fast_reconnect && !wpas_network_disabled(wpa_s, fast_reconnect_ssid) && !disallowed_bssid(wpa_s, fast_reconnect->bssid) && @@ -4664,7 +5108,7 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s, #endif pairwise = (data && data->michael_mic_failure.unicast); os_get_reltime(&t); - if ((wpa_s->last_michael_mic_error.sec && + if ((os_reltime_initialized(&wpa_s->last_michael_mic_error) && !os_reltime_expired(&t, &wpa_s->last_michael_mic_error, 60)) || wpa_s->pending_mic_error_report) { if (wpa_s->pending_mic_error_report) { @@ -4971,8 +5415,7 @@ static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data, wpa_printf(MSG_DEBUG, "FT: Received FT Action Response: STA " MACSTR_SEC " TargetAP " MACSTR_SEC " status %u", MAC2STR_SEC(sta_addr), MAC2STR_SEC(target_ap_addr), status); - - if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(sta_addr, wpa_s->own_addr)) { wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, "FT: Foreign STA Address " MACSTR " in FT Action Response", MAC2STR(sta_addr)); wpa_printf(MSG_DEBUG, "FT: Foreign STA Address " MACSTR_SEC @@ -5072,7 +5515,7 @@ static void wpas_event_disconnect(struct wpa_supplicant *wpa_s, const u8 *addr, (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) && eapol_sm_failed(wpa_s->eapol))) && !wpa_s->eap_expected_failure)) - wpas_auth_failed(wpa_s, "AUTH_FAILED"); + wpas_auth_failed(wpa_s, "AUTH_FAILED", addr); #ifdef CONFIG_P2P #ifdef CONFIG_OPEN_HARMONY_PATCH @@ -5117,7 +5560,7 @@ static void wpas_event_disassoc(struct wpa_supplicant *wpa_s, reason2str(reason_code), locally_generated ? " locally_generated=1" : ""); if (addr) - wpa_dbg(wpa_s, MSG_INFO, " * address " MACSTR, + wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR, MAC2STR(addr)); wpa_hexdump(MSG_INFO, "Disassociation frame IE(s)", ie, ie_len); @@ -5227,6 +5670,20 @@ static const char * reg_type_str(enum reg_type type) } +static void wpas_beacon_hint(struct wpa_supplicant *wpa_s, const char *title, + struct frequency_attrs *attrs) +{ + if (!attrs->freq) + return; + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REGDOM_BEACON_HINT + "%s freq=%u max_tx_power=%u%s%s%s", + title, attrs->freq, attrs->max_tx_power, + attrs->disabled ? " disabled=1" : "", + attrs->no_ir ? " no_ir=1" : "", + attrs->radar ? " radar=1" : ""); +} + + void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s, struct channel_list_changed *info) { @@ -5248,6 +5705,13 @@ void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s, reg_init_str(info->initiator), reg_type_str(info->type), info->alpha2[0] ? " alpha2=" : "", info->alpha2[0] ? info->alpha2 : ""); + + if (info->initiator == REGDOM_BEACON_HINT) { + wpas_beacon_hint(ifs, "before", + &info->beacon_hint_before); + wpas_beacon_hint(ifs, "after", + &info->beacon_hint_after); + } } if (wpa_s->drv_priv == NULL) @@ -5255,12 +5719,17 @@ void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s, dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, radio_list) { + bool was_6ghz_enabled; + wpa_printf(MSG_DEBUG, "%s: Updating hw mode", ifs->ifname); free_hw_features(ifs); ifs->hw.modes = wpa_drv_get_hw_feature_data( ifs, &ifs->hw.num_modes, &ifs->hw.flags, &dfs_domain); + was_6ghz_enabled = ifs->is_6ghz_enabled; + ifs->is_6ghz_enabled = wpas_is_6ghz_supported(ifs, true); + /* Restart PNO/sched_scan with updated channel list */ if (ifs->pno) { wpas_stop_pno(ifs); @@ -5269,6 +5738,11 @@ void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s, wpa_dbg(ifs, MSG_DEBUG, "Channel list changed - restart sched_scan"); wpas_scan_restart_sched_scan(ifs); + } else if (!was_6ghz_enabled && ifs->is_6ghz_enabled) { + wpa_dbg(ifs, MSG_INFO, + "Channel list changed: 6 GHz was enabled"); + + ifs->crossed_6ghz_dom = true; } } @@ -5300,10 +5774,12 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, " Category=%u DataLen=%d freq=%d MHz", MAC2STR_SEC(mgmt->sa), category, (int) plen, freq); +#ifndef CONFIG_NO_WMM_AC if (category == WLAN_ACTION_WMM) { wmm_ac_rx_action(wpa_s, mgmt->da, mgmt->sa, payload, plen); return; } +#endif /* CONFIG_NO_WMM_AC */ #ifdef CONFIG_IEEE80211R if (category == WLAN_ACTION_FT) { @@ -5352,6 +5828,12 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, MAC2STR(mgmt->sa)); wpa_printf(MSG_DEBUG, "TDLS: Received Discovery Response from " MACSTR_SEC, MAC2STR_SEC(mgmt->sa)); + if (wpa_s->valid_links && + wpa_tdls_process_discovery_response(wpa_s->wpa, mgmt->sa, + &payload[1], plen - 1)) + wpa_dbg(wpa_s, MSG_ERROR, + "TDLS: Discovery Response process failed for " + MACSTR, MAC2STR(mgmt->sa)); return; } #endif /* CONFIG_TDLS */ @@ -5365,7 +5847,7 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, MACSTR, MAC2STR(mgmt->sa)); wpa_printf(MSG_DEBUG, "Interworking: Received QoS Map Configure frame from " MACSTR_SEC, MAC2STR_SEC(mgmt->sa)); - if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) == 0 && + if (ether_addr_equal(mgmt->sa, wpa_s->bssid) && qlen > 2 && pos[0] == WLAN_EID_QOS_MAP_SET && pos[1] <= qlen - 2 && pos[1] >= 16) wpas_qos_map_set(wpa_s, pos + 2, pos[1]); @@ -5373,6 +5855,7 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_INTERWORKING */ +#ifndef CONFIG_NO_RRM if (category == WLAN_ACTION_RADIO_MEASUREMENT && payload[0] == WLAN_RRM_RADIO_MEASUREMENT_REQUEST) { wpas_rrm_handle_radio_measurement_request(wpa_s, mgmt->sa, @@ -5395,6 +5878,7 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, rssi); return; } +#endif /* CONFIG_NO_RRM */ #ifdef CONFIG_FST if (mgmt->u.action.category == WLAN_ACTION_FST && wpa_s->fst) { @@ -5403,6 +5887,17 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_FST */ +#ifdef CONFIG_NAN_USD + if (category == WLAN_ACTION_PUBLIC && plen >= 5 && + payload[0] == WLAN_PA_VENDOR_SPECIFIC && + WPA_GET_BE32(&payload[1]) == NAN_SDF_VENDOR_TYPE) { + payload += 5; + plen -= 5; + wpas_nan_usd_rx_sdf(wpa_s, mgmt->sa, freq, payload, plen); + return; + } +#endif /* CONFIG_NAN_USD */ + #ifdef CONFIG_DPP if (category == WLAN_ACTION_PUBLIC && plen >= 5 && payload[0] == WLAN_PA_VENDOR_SPECIFIC && @@ -5415,6 +5910,7 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_DPP */ +#ifndef CONFIG_NO_ROBUST_AV if (category == WLAN_ACTION_ROBUST_AV_STREAMING && payload[0] == ROBUST_AV_SCS_RESP) { wpas_handle_robust_av_scs_recv_action(wpa_s, mgmt->sa, @@ -5435,6 +5931,7 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s, payload + 4, plen - 4); return; } +#endif /* CONFIG_NO_ROBUST_AV */ wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid, category, payload, plen, freq); @@ -5594,12 +6091,15 @@ static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s, data->assoc_info.fils_pmk, data->assoc_info.fils_pmk_len, data->assoc_info.fils_pmkid, - wpa_s->bssid, fils_cache_id); + wpa_s->valid_links ? + wpa_s->ap_mld_addr : + wpa_s->bssid, + fils_cache_id); } else if (data->assoc_info.fils_pmkid) { /* Update the current PMKSA used for this connection */ pmksa_cache_set_current(wpa_s->wpa, data->assoc_info.fils_pmkid, - NULL, NULL, 0, NULL, 0); + NULL, NULL, 0, NULL, 0, true); } } #endif /* CONFIG_FILS */ @@ -5635,11 +6135,9 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { const u8 *bssid = data->assoc_reject.bssid; -#ifdef CONFIG_MLD_PATCH struct ieee802_11_elems elems; struct ml_sta_link_info ml_info[MAX_NUM_MLD_LINKS]; const u8 *link_bssids[MAX_NUM_MLD_LINKS + 1]; -#endif #ifdef CONFIG_MBO struct wpa_bss *reject_bss; #endif /* CONFIG_MBO */ @@ -5678,13 +6176,13 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, STA_CONNECT_FAIL_REASON_UNSPECIFIED ? " qca_driver_reason=" : "", connect_fail_reason(data->assoc_reject.reason_code)); - #if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) +#if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) struct WpaAssociateRejectParam wpaAssociateRejectParma; os_memcpy(wpaAssociateRejectParma.bssid, bssid, ETH_ALEN); wpaAssociateRejectParma.statusCode = data->assoc_reject.status_code; wpaAssociateRejectParma.timeOut = data->assoc_reject.timed_out; WpaEventReport(wpa_s->ifname, WPA_EVENT_ASSOCIATE_REJECT, (void *) &wpaAssociateRejectParma); - #endif +#endif wpa_s->assoc_status_code = data->assoc_reject.status_code; wpas_notify_assoc_status_code(wpa_s); @@ -5701,11 +6199,7 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, if (!bss) { bss = wpa_supplicant_get_new_bss(wpa_s, bssid); if (!bss) { -#ifdef CONFIG_MLD_PATCH wpas_connection_failed(wpa_s, bssid, NULL); -#else - wpas_connection_failed(wpa_s, bssid); -#endif wpa_supplicant_mark_disassoc(wpa_s); return; } @@ -5740,11 +6234,7 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, if (!bss || wpa_s->dpp_pfs_fallback) { wpa_printf(MSG_DEBUG, "DPP: Updated PFS policy for next try"); -#ifdef CONFIG_MLD_PATCH wpas_connection_failed(wpa_s, bssid, NULL); -#else - wpas_connection_failed(wpa_s, bssid); -#endif wpa_supplicant_mark_disassoc(wpa_s); return; } @@ -5781,7 +6271,6 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_MBO */ -#ifdef CONFIG_MLD_PATCH /* Check for other failed links in the response */ os_memset(link_bssids, 0, sizeof(link_bssids)); if (ieee802_11_parse_elems(data->assoc_reject.resp_ies, @@ -5806,10 +6295,9 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, } } } -#endif if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) { - sme_event_assoc_reject(wpa_s, data); + sme_event_assoc_reject(wpa_s, data, link_bssids); return; } @@ -5850,21 +6338,16 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, fils_connection_failure(wpa_s); } #endif /* CONFIG_FILS */ -#ifdef CONFIG_MLD_PATCH - wpas_connection_failed(wpa_s, bssid, link_bssids); -#else - wpas_connection_failed(wpa_s, bssid); -#endif #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_p2p_state(wpa_s, P2P_INTERFACE_STATE_DISCONNECTED, DR_ASSOCIATING_REJECT, wpa_s->assoc_status_code); #endif + wpas_connection_failed(wpa_s, bssid, link_bssids); wpa_supplicant_mark_disassoc(wpa_s); } int run_mode = 0; - static void wpas_event_unprot_beacon(struct wpa_supplicant *wpa_s, struct unprot_beacon *data) { @@ -5872,7 +6355,7 @@ static void wpas_event_unprot_beacon(struct wpa_supplicant *wpa_s, int res; if (!data || wpa_s->wpa_state != WPA_COMPLETED || - os_memcmp(data->sa, wpa_s->bssid, ETH_ALEN) != 0) + !ether_addr_equal(data->sa, wpa_s->bssid)) return; wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_UNPROT_BEACON MACSTR, MAC2STR(data->sa)); @@ -5897,6 +6380,94 @@ static void wpas_event_unprot_beacon(struct wpa_supplicant *wpa_s, } +static const char * bitmap_to_str(u8 value, char *buf) +{ + char *pos = buf; + int i, k = 0; + + for (i = 7; i >= 0; i--) + pos[k++] = (value & BIT(i)) ? '1' : '0'; + + pos[8] = '\0'; + return pos; +} + + +static void wpas_tid_link_map(struct wpa_supplicant *wpa_s, + struct tid_link_map_info *info) +{ + char map_info[1000], *pos, *end; + int res, i; + + pos = map_info; + end = pos + sizeof(map_info); + res = os_snprintf(map_info, sizeof(map_info), "default=%d", + info->default_map); + if (os_snprintf_error(end - pos, res)) + return; + pos += res; + + if (!info->default_map) { + for_each_link(info->valid_links, i) { + char uplink_map_str[9]; + char downlink_map_str[9]; + + bitmap_to_str(info->t2lmap[i].uplink, uplink_map_str); + bitmap_to_str(info->t2lmap[i].downlink, + downlink_map_str); + + res = os_snprintf(pos, end - pos, + " link_id=%d up_link=%s down_link=%s", + i, uplink_map_str, + downlink_map_str); + if (os_snprintf_error(end - pos, res)) + return; + pos += res; + } + } + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_T2LM_UPDATE "%s", map_info); +} + + +static void wpas_link_reconfig(struct wpa_supplicant *wpa_s) +{ + u8 bssid[ETH_ALEN]; + + if (wpa_drv_get_bssid(wpa_s, bssid) < 0) { + wpa_printf(MSG_ERROR, "LINK_RECONFIG: Failed to get BSSID"); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + return; + } + + if (!ether_addr_equal(bssid, wpa_s->bssid)) { + os_memcpy(wpa_s->bssid, bssid, ETH_ALEN); + wpa_supplicant_update_current_bss(wpa_s, wpa_s->bssid); + wpas_notify_bssid_changed(wpa_s); + } + + if (wpa_drv_get_mlo_info(wpa_s) < 0) { + wpa_printf(MSG_ERROR, + "LINK_RECONFIG: Failed to get MLO connection info"); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + return; + } + + if (wpa_sm_set_ml_info(wpa_s)) { + wpa_printf(MSG_ERROR, + "LINK_RECONFIG: Failed to set MLO connection info to wpa_sm"); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + return; + } + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_LINK_RECONFIG "valid_links=0x%x", + wpa_s->valid_links); +} + + void set_running_hostap() { run_mode = 1; @@ -5918,7 +6489,6 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, if (run_mode == 1) { return wpa_supplicant_event_hapd(ctx, event, data); } - struct wpa_supplicant *wpa_s = ctx; int resched; struct os_reltime age, clear_at; @@ -6018,6 +6588,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpas_event_deauth(wpa_s, data ? &data->deauth_info : NULL); break; + case EVENT_LINK_RECONFIG: + wpas_link_reconfig(wpa_s); + break; case EVENT_MICHAEL_MIC_FAILURE: wpa_supplicant_event_michael_mic_failure(wpa_s, data); break; @@ -6065,6 +6638,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, os_reltime_sub(&now, &wpa_s->scan_start_time, &diff); wpa_s->scan_start_time.sec = 0; wpa_s->scan_start_time.usec = 0; + wpa_s->wps_scan_done = true; wpa_dbg(wpa_s, MSG_INFO, "Scan completed in %ld.%06ld seconds", diff.sec, diff.usec); } @@ -6146,6 +6720,13 @@ 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_WNM + if (data->tx_status.type == WLAN_FC_TYPE_MGMT && + data->tx_status.stype == WLAN_FC_STYPE_ACTION && + wnm_btm_resp_tx_status(wpa_s, data->tx_status.data, + data->tx_status.data_len) == 0) + break; +#endif /* CONFIG_WNM */ #ifdef CONFIG_PASN if (data->tx_status.type == WLAN_FC_TYPE_MGMT && data->tx_status.stype == WLAN_FC_STYPE_AUTH && @@ -6182,8 +6763,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, */ if (data->tx_status.type == WLAN_FC_TYPE_MGMT && data->tx_status.stype == WLAN_FC_STYPE_ACTION && - os_memcmp(wpa_s->p2pdev->pending_action_dst, - data->tx_status.dst, ETH_ALEN) == 0) { + ether_addr_equal(wpa_s->p2pdev->pending_action_dst, + data->tx_status.dst)) { offchannel_send_action_tx_status( wpa_s->p2pdev, data->tx_status.dst, data->tx_status.data, @@ -6228,7 +6809,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->rx_from_unknown.wds); break; #endif /* CONFIG_AP */ -#ifdef CONFIG_MLD_PATCH + case EVENT_LINK_CH_SWITCH_STARTED: case EVENT_LINK_CH_SWITCH: if (!data || !wpa_s->current_ssid || @@ -6262,6 +6843,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s->links[data->ch_switch.link_id].bss); } break; +#ifdef CONFIG_MLD_PATCH case EVENT_MLO_LINK_SWITCH: if (!data || !(wpa_s->valid_links & BIT(data->mlo_link_switch_event.link_id))) break; @@ -6338,6 +6920,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->ch_switch.ch_width, data->ch_switch.cf1, data->ch_switch.cf2, + data->ch_switch.punct_bitmap, 1); } #endif /* CONFIG_AP */ @@ -6522,6 +7105,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s, data->remain_on_channel.freq, data->remain_on_channel.duration); #endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + wpas_nan_usd_remain_on_channel_cb( + wpa_s, data->remain_on_channel.freq, + data->remain_on_channel.duration); +#endif /* CONFIG_NAN_USD */ break; case EVENT_CANCEL_REMAIN_ON_CHANNEL: #ifdef CONFIG_OFFCHANNEL @@ -6534,26 +7122,34 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpas_dpp_cancel_remain_on_channel_cb( wpa_s, data->remain_on_channel.freq); #endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + wpas_nan_usd_cancel_remain_on_channel_cb( + wpa_s, data->remain_on_channel.freq); +#endif /* CONFIG_NAN_USD */ break; case EVENT_EAPOL_RX: wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src, data->eapol_rx.data, - data->eapol_rx.data_len); + data->eapol_rx.data_len, + data->eapol_rx.encrypted); break; case EVENT_SIGNAL_CHANGE: wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SIGNAL_CHANGE - "above=%d signal=%d noise=%d txrate=%d", + "above=%d signal=%d noise=%d txrate=%lu", data->signal_change.above_threshold, - data->signal_change.current_signal, + data->signal_change.data.signal, data->signal_change.current_noise, - data->signal_change.current_txrate); + data->signal_change.data.current_tx_rate); wpa_bss_update_level(wpa_s->current_bss, - data->signal_change.current_signal); + data->signal_change.data.signal); bgscan_notify_signal_change( wpa_s, data->signal_change.above_threshold, - data->signal_change.current_signal, + data->signal_change.data.signal, data->signal_change.current_noise, - data->signal_change.current_txrate); + data->signal_change.data.current_tx_rate); + os_memcpy(&wpa_s->last_signal_info, data, + sizeof(struct wpa_signal_info)); + wpas_notify_signal_change(wpa_s); break; case EVENT_INTERFACE_MAC_CHANGED: wpa_supplicant_update_mac_addr(wpa_s); @@ -6568,7 +7164,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s, NULL); os_memcpy(addr, wpa_s->own_addr, ETH_ALEN); wpa_supplicant_update_mac_addr(wpa_s); - if (os_memcmp(addr, wpa_s->own_addr, ETH_ALEN) != 0) + if (!ether_addr_equal(addr, wpa_s->own_addr)) wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL); else wpa_sm_pmksa_cache_reconfig(wpa_s->wpa); @@ -6702,8 +7298,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, #endif /* CONFIG_IBSS_RSN */ break; case EVENT_DRIVER_GTK_REKEY: - if (os_memcmp(data->driver_gtk_rekey.bssid, - wpa_s->bssid, ETH_ALEN)) + if (!ether_addr_equal(data->driver_gtk_rekey.bssid, + wpa_s->bssid)) break; if (!wpa_s->wpa) break; @@ -6814,7 +7410,36 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, sme_external_auth_trigger(wpa_s, data); #endif /* CONFIG_SAE */ break; +#ifdef CONFIG_PASN + case EVENT_PASN_AUTH: + wpas_pasn_auth_trigger(wpa_s, &data->pasn_auth); + break; +#endif /* CONFIG_PASN */ case EVENT_PORT_AUTHORIZED: +#ifdef CONFIG_AP + if (wpa_s->ap_iface && wpa_s->ap_iface->bss[0]) { + struct sta_info *sta; + + sta = ap_get_sta(wpa_s->ap_iface->bss[0], + data->port_authorized.sta_addr); + if (sta) + ap_sta_set_authorized(wpa_s->ap_iface->bss[0], + sta, 1); + else + wpa_printf(MSG_DEBUG, + "No STA info matching port authorized event found"); + break; + } +#endif /* CONFIG_AP */ +#ifndef CONFIG_NO_WPA + if (data->port_authorized.td_bitmap_len) { + wpa_printf(MSG_DEBUG, + "WPA3: Transition Disable bitmap from the driver event: 0x%x", + data->port_authorized.td_bitmap[0]); + wpas_transition_disable( + wpa_s, data->port_authorized.td_bitmap[0]); + } +#endif /* CONFIG_NO_WPA */ wpa_supplicant_event_port_authorized(wpa_s); break; case EVENT_STATION_OPMODE_CHANGED: @@ -6832,6 +7457,18 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, case EVENT_UNPROT_BEACON: wpas_event_unprot_beacon(wpa_s, &data->unprot_beacon); break; + case EVENT_TX_WAIT_EXPIRE: +#ifdef CONFIG_DPP + wpas_dpp_tx_wait_expire(wpa_s); +#endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + wpas_nan_usd_tx_wait_expire(wpa_s); +#endif /* CONFIG_NAN_USD */ + break; + case EVENT_TID_LINK_MAP: + if (data) + wpas_tid_link_map(wpa_s, &data->t2l_map_info); + break; default: wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event); break; @@ -6846,7 +7483,6 @@ void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, if (run_mode == 1) { return wpa_supplicant_event_global_hapd(ctx, event, data); } - struct wpa_supplicant *wpa_s; if (event != EVENT_INTERFACE_STATUS) diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/60_wpa_supplicant b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/60_wpa_supplicant index 39bd8e09b5899e0f99d566e36fc1a25e83388320..81928a09a661a3bcf2843f490d713a7232d0bf4e 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/60_wpa_supplicant +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/60_wpa_supplicant @@ -1,19 +1,19 @@ -#!/bin/sh - -# /etc/pm/sleep.d/60_wpa_supplicant -# Action script to notify wpa_supplicant of pm-action events. - -PATH=/sbin:/usr/sbin:/bin:/usr/bin - -WPACLI=wpa_cli - -case "$1" in - suspend|hibernate) - $WPACLI suspend - ;; - resume|thaw) - $WPACLI resume - ;; -esac - -exit 0 +#!/bin/sh + +# /etc/pm/sleep.d/60_wpa_supplicant +# Action script to notify wpa_supplicant of pm-action events. + +PATH=/sbin:/usr/sbin:/bin:/usr/bin + +WPACLI=wpa_cli + +case "$1" in + suspend|hibernate) + $WPACLI suspend + ;; + resume|thaw) + $WPACLI resume + ;; +esac + +exit 0 diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dbus-listen-preq.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dbus-listen-preq.py index 337519f4e927133d40a1040ed06a12ae94960081..c8aa445a55214f7b7aceae981f8eb48539f2682b 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dbus-listen-preq.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dbus-listen-preq.py @@ -1,66 +1,66 @@ -#!/usr/bin/python - -from __future__ import print_function -import dbus -import sys -import time -import gobject -from dbus.mainloop.glib import DBusGMainLoop - -WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1" -WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1" -WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1" -WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface" - -def usage(): - print("Usage: %s " % sys.argv[0]) - print("Press Ctrl-C to stop") - -def ProbeRequest(args): - if 'addr' in args: - print('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']), - end=' ') - if 'dst' in args: - print('-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']), - end=' ') - if 'bssid' in args: - print('(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']), - end=' ') - if 'signal' in args: - print('signal:%d' % args['signal'], end=' ') - if 'ies' in args: - print('have IEs (%d bytes)' % len(args['ies']), end=' ') - print('') - -if __name__ == "__main__": - global bus - global wpas_obj - global if_obj - global p2p_iface - - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - - bus = dbus.SystemBus() - wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) - - # Print list of i/f if no one is specified - if (len(sys.argv) < 2) : - usage() - sys.exit(0) - - wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) - - ifname = sys.argv[1] - - path = wpas.GetInterface(ifname) - - if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) - iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE) - - bus.add_signal_receiver(ProbeRequest, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="ProbeRequest") - - iface.SubscribeProbeReq() - - gobject.MainLoop().run() +#!/usr/bin/python + +from __future__ import print_function +import dbus +import sys +import time +import gobject +from dbus.mainloop.glib import DBusGMainLoop + +WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1" +WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1" +WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1" +WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface" + +def usage(): + print("Usage: %s " % sys.argv[0]) + print("Press Ctrl-C to stop") + +def ProbeRequest(args): + if 'addr' in args: + print('%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['addr']), + end=' ') + if 'dst' in args: + print('-> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % tuple(args['dst']), + end=' ') + if 'bssid' in args: + print('(bssid %.2x:%.2x:%.2x:%.2x:%.2x:%.2x)' % tuple(args['dst']), + end=' ') + if 'signal' in args: + print('signal:%d' % args['signal'], end=' ') + if 'ies' in args: + print('have IEs (%d bytes)' % len(args['ies']), end=' ') + print('') + +if __name__ == "__main__": + global bus + global wpas_obj + global if_obj + global p2p_iface + + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + + bus = dbus.SystemBus() + wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) + + # Print list of i/f if no one is specified + if (len(sys.argv) < 2) : + usage() + sys.exit(0) + + wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) + + ifname = sys.argv[1] + + path = wpas.GetInterface(ifname) + + if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) + iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE) + + bus.add_signal_receiver(ProbeRequest, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="ProbeRequest") + + iface.SubscribeProbeReq() + + gobject.MainLoop().run() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dpp-nfc.py index 8e865f3fcd33818e363773888fbfa8fb665f25c6..6cffe71869bf95a2e7ab36858a7e09f23acfffe8 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dpp-nfc.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dpp-nfc.py @@ -359,7 +359,7 @@ def run_dpp_handover_client(handover, alt=False): summary("NFC Handover Request message for DPP: " + str(message)) if handover.peer_crn is not None and not alt: - summary("NFC handover request from peer was already received - do not send own") + summary("NFC handover request from peer was already received - do not send own[1]") return if handover.client: summary("Use already started handover client") @@ -382,7 +382,8 @@ def run_dpp_handover_client(handover, alt=False): handover.client = client if handover.peer_crn is not None and not alt: - summary("NFC handover request from peer was already received - do not send own") + summary("NFC handover request from peer was already received - do not send own[2] (except alt)") + run_client_alt(handover, alt) return summary("Sending handover request") @@ -876,6 +877,11 @@ def llcp_worker(llc, try_alt): if init_on_touch: summary("Starting handover client (init_on_touch)") dpp_handover_client(handover) + summary("llcp_worker init_on_touch processing completed: try_own={} hs_sent={} no_alt_proposal={} start_client_alt={}".format(handover.try_own, handover.hs_sent, handover.no_alt_proposal, handover.start_client_alt)) + if handover.start_client_alt and not handover.hs_sent: + summary("Try alternative handover request before exiting llcp_worker") + handover.start_client_alt = False + dpp_handover_client(handover, alt=True) summary("Exiting llcp_worker thread (init_on_touch)") return diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dpp-qrcode.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dpp-qrcode.py index b468d15cf9cde3cdf449add71371be3751fdfee3..d8faeffd8d8f43bf041662c28d6798aa2c47f825 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dpp-qrcode.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/dpp-qrcode.py @@ -1,130 +1,130 @@ -#!/usr/bin/python -# -# Example Android logcat to wpa_supplicant wrapper for QR Code scans -# Copyright (c) 2017, Qualcomm Atheros, Inc. -# -# This software may be distributed under the terms of the BSD license. -# See README for more details. - -import os -import sys -import argparse -import logging -import qrcode - -scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__)) -sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy')) - -import wpaspy - -wpas_ctrl = '/var/run/wpa_supplicant' - -def wpas_connect(): - ifaces = [] - if os.path.isdir(wpas_ctrl): - try: - ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] - except OSError as error: - print("Could not find wpa_supplicant: ", error) - return None - - if len(ifaces) < 1: - print("No wpa_supplicant control interface found") - return None - - for ctrl in ifaces: - try: - wpas = wpaspy.Ctrl(ctrl) - return wpas - except Exception as e: - pass - return None - -def dpp_logcat(): - for line in iter(sys.stdin.readline, ''): - if "ResultHandler: Launching intent: Intent" not in line: - continue - if "act=android.intent.action.VIEW" not in line: - continue - uri = None - for val in line.split(' '): - if val.startswith('dat='): - uri = val.split('=', 1)[1] - break - if not uri: - continue - if not uri.startswith('DPP:'): - continue - print("Found DPP bootstrap info URI:") - print(uri) - wpas = wpas_connect() - if not wpas: - print("Could not connect to wpa_supplicant") - print('') - continue - res = wpas.request("DPP_QR_CODE " + uri); - try: - id = int(res) - except ValueError: - print("QR Code URI rejected") - continue - print("QR Code URI accepted - ID=%d" % id) - print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id)) - del wpas - -def dpp_display(curve): - wpas = wpas_connect() - if not wpas: - print("Could not connect to wpa_supplicant") - return - res = wpas.request("STATUS") - addr = None - for line in res.splitlines(): - if line.startswith("address="): - addr = line.split('=')[1] - break - cmd = "DPP_BOOTSTRAP_GEN type=qrcode" - cmd += " chan=81/1" - if addr: - cmd += " mac=" + addr.replace(':','') - if curve: - cmd += " curve=" + curve - res = wpas.request(cmd) - try: - id = int(res) - except ValueError: - print("Failed to generate bootstrap info URI") - return - print("Bootstrap information - ID=%d" % id) - print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id)) - uri = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % id) - print(uri) - print("ID=%d" % id) - qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M, - border=3) - qr.add_data(uri, optimize=5) - qr.print_ascii(tty=True) - print("ID=%d" % id) - del wpas - -def main(): - parser = argparse.ArgumentParser(description='Android logcat to wpa_supplicant integration for DPP QR Code operations') - parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO, - action='store_const', dest='loglevel', - help='verbose debug output') - parser.add_argument('--curve', '-c', - help='set a specific curve (P-256, P-384, P-521, BP-256R1, BP-384R1, BP-512R1) for key generation') - parser.add_argument('command', choices=['logcat', - 'display'], - nargs='?') - args = parser.parse_args() - - logging.basicConfig(level=args.loglevel) - - if args.command == "logcat": - dpp_logcat() - elif args.command == "display": - dpp_display(args.curve) - -if __name__ == '__main__': - main() +#!/usr/bin/python +# +# Example Android logcat to wpa_supplicant wrapper for QR Code scans +# Copyright (c) 2017, Qualcomm Atheros, Inc. +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import sys +import argparse +import logging +import qrcode + +scriptsdir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__)) +sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy')) + +import wpaspy + +wpas_ctrl = '/var/run/wpa_supplicant' + +def wpas_connect(): + ifaces = [] + if os.path.isdir(wpas_ctrl): + try: + ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] + except OSError as error: + print("Could not find wpa_supplicant: ", error) + return None + + if len(ifaces) < 1: + print("No wpa_supplicant control interface found") + return None + + for ctrl in ifaces: + try: + wpas = wpaspy.Ctrl(ctrl) + return wpas + except Exception as e: + pass + return None + +def dpp_logcat(): + for line in iter(sys.stdin.readline, ''): + if "ResultHandler: Launching intent: Intent" not in line: + continue + if "act=android.intent.action.VIEW" not in line: + continue + uri = None + for val in line.split(' '): + if val.startswith('dat='): + uri = val.split('=', 1)[1] + break + if not uri: + continue + if not uri.startswith('DPP:'): + continue + print("Found DPP bootstrap info URI:") + print(uri) + wpas = wpas_connect() + if not wpas: + print("Could not connect to wpa_supplicant") + print('') + continue + res = wpas.request("DPP_QR_CODE " + uri); + try: + id = int(res) + except ValueError: + print("QR Code URI rejected") + continue + print("QR Code URI accepted - ID=%d" % id) + print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id)) + del wpas + +def dpp_display(curve): + wpas = wpas_connect() + if not wpas: + print("Could not connect to wpa_supplicant") + return + res = wpas.request("STATUS") + addr = None + for line in res.splitlines(): + if line.startswith("address="): + addr = line.split('=')[1] + break + cmd = "DPP_BOOTSTRAP_GEN type=qrcode" + cmd += " chan=81/1" + if addr: + cmd += " mac=" + addr.replace(':','') + if curve: + cmd += " curve=" + curve + res = wpas.request(cmd) + try: + id = int(res) + except ValueError: + print("Failed to generate bootstrap info URI") + return + print("Bootstrap information - ID=%d" % id) + print(wpas.request("DPP_BOOTSTRAP_INFO %d" % id)) + uri = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % id) + print(uri) + print("ID=%d" % id) + qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M, + border=3) + qr.add_data(uri, optimize=5) + qr.print_ascii(tty=True) + print("ID=%d" % id) + del wpas + +def main(): + parser = argparse.ArgumentParser(description='Android logcat to wpa_supplicant integration for DPP QR Code operations') + parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO, + action='store_const', dest='loglevel', + help='verbose debug output') + parser.add_argument('--curve', '-c', + help='set a specific curve (P-256, P-384, P-521, BP-256R1, BP-384R1, BP-512R1) for key generation') + parser.add_argument('command', choices=['logcat', + 'display'], + nargs='?') + args = parser.parse_args() + + logging.basicConfig(level=args.loglevel) + + if args.command == "logcat": + dpp_logcat() + elif args.command == "display": + dpp_display(args.curve) + +if __name__ == '__main__': + main() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/ieee8021x.conf b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/ieee8021x.conf index e8a5503d8359de59d01ee6f6c07dc259d03b92d8..713db2bdb69333fabc291525025ebed9400ce074 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/ieee8021x.conf +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/ieee8021x.conf @@ -1,13 +1,13 @@ -# IEEE 802.1X with dynamic WEP keys using EAP-PEAP/MSCHAPv2 - -ctrl_interface=/var/run/wpa_supplicant - -network={ - ssid="example 802.1x network" - key_mgmt=IEEE8021X - eap=PEAP - phase2="auth=MSCHAPV2" - identity="user name" - password="password" - ca_cert="/etc/cert/ca.pem" -} +# IEEE 802.1X with dynamic WEP keys using EAP-PEAP/MSCHAPv2 + +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="example 802.1x network" + key_mgmt=IEEE8021X + eap=PEAP + phase2="auth=MSCHAPV2" + identity="user name" + password="password" + ca_cert="/etc/cert/ca.pem" +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/openCryptoki.conf b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/openCryptoki.conf index e2301a61cabf15890ee490a5e5ca456eeb1d645c..e9cb8b5e5399e47b368d63d11352a0f971ef2bc8 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/openCryptoki.conf +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/openCryptoki.conf @@ -1,41 +1,41 @@ -# EAP-TLS using private key and certificates via OpenSSL PKCS#11 engine and -# openCryptoki (e.g., with TPM token) - -# This example uses following PKCS#11 objects: -# $ pkcs11-tool --module /usr/lib/opencryptoki/libopencryptoki.so -O -l -# Please enter User PIN: -# Private Key Object; RSA -# label: rsakey -# ID: 04 -# Usage: decrypt, sign, unwrap -# Certificate Object, type = X.509 cert -# label: ca -# ID: 01 -# Certificate Object, type = X.509 cert -# label: cert -# ID: 04 - -# Configure OpenSSL to load the PKCS#11 engine and openCryptoki module -pkcs11_engine_path=/usr/lib/engines/engine_pkcs11.so -pkcs11_module_path=/usr/lib/opencryptoki/libopencryptoki.so - -network={ - ssid="test network" - key_mgmt=WPA-EAP - eap=TLS - identity="User" - - # use OpenSSL PKCS#11 engine for this network - engine=1 - engine_id="pkcs11" - - # select the private key and certificates based on ID (see pkcs11-tool - # output above) - key_id="4" - cert_id="4" - ca_cert_id="1" - - # set the PIN code; leave this out to configure the PIN to be requested - # interactively when needed (e.g., via wpa_gui or wpa_cli) - pin="123456" -} +# EAP-TLS using private key and certificates via OpenSSL PKCS#11 engine and +# openCryptoki (e.g., with TPM token) + +# This example uses following PKCS#11 objects: +# $ pkcs11-tool --module /usr/lib/opencryptoki/libopencryptoki.so -O -l +# Please enter User PIN: +# Private Key Object; RSA +# label: rsakey +# ID: 04 +# Usage: decrypt, sign, unwrap +# Certificate Object, type = X.509 cert +# label: ca +# ID: 01 +# Certificate Object, type = X.509 cert +# label: cert +# ID: 04 + +# Configure OpenSSL to load the PKCS#11 engine and openCryptoki module +pkcs11_engine_path=/usr/lib/engines/engine_pkcs11.so +pkcs11_module_path=/usr/lib/opencryptoki/libopencryptoki.so + +network={ + ssid="test network" + key_mgmt=WPA-EAP + eap=TLS + identity="User" + + # use OpenSSL PKCS#11 engine for this network + engine=1 + engine_id="pkcs11" + + # select the private key and certificates based on ID (see pkcs11-tool + # output above) + key_id="4" + cert_id="4" + ca_cert_id="1" + + # set the PIN code; leave this out to configure the PIN to be requested + # interactively when needed (e.g., via wpa_gui or wpa_cli) + pin="123456" +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-action-udhcp.sh b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-action-udhcp.sh index 53d8b777cd513f20c057320ccf9f6a1c49ae2129..3057a051a0a02ecfc365d12d8e6df56f6775d3db 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-action-udhcp.sh +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-action-udhcp.sh @@ -1,69 +1,69 @@ -#!/bin/sh - -IFNAME=$1 -CMD=$2 - -kill_daemon() { - NAME=$1 - PF=$2 - - if [ ! -r $PF ]; then - return - fi - - PID=`cat $PF` - if [ $PID -gt 0 ]; then - if ps $PID | grep -q $NAME; then - kill $PID - fi - fi - rm $PF -} - -if [ "$CMD" = "P2P-GROUP-STARTED" ]; then - GIFNAME=$3 - if [ "$4" = "GO" ]; then - kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid - ifconfig $GIFNAME 192.168.42.1 up - udhcpd /etc/udhcpd-p2p.conf - fi - if [ "$4" = "client" ]; then - kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid - kill_daemon udhcpd /var/run/udhcpd-$GIFNAME.pid - udhcpc -i $GIFNAME -p /var/run/udhcpc-$GIFNAME.pid \ - -s /etc/udhcpc.script - fi -fi - -if [ "$CMD" = "P2P-GROUP-REMOVED" ]; then - GIFNAME=$3 - if [ "$4" = "GO" ]; then - kill_daemon udhcpd /var/run/udhcpd-$GIFNAME.pid - ifconfig $GIFNAME 0.0.0.0 - fi - if [ "$4" = "client" ]; then - kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid - ifconfig $GIFNAME 0.0.0.0 - fi -fi - -if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then - GIFNAME=$3 - UPLINK=$4 - # 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 - iptables -A FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT - sysctl net.ipv4.ip_forward=1 -fi - -if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then - GIFNAME=$3 - UPLINK=$4 - # 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 - iptables -D FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT -fi +#!/bin/sh + +IFNAME=$1 +CMD=$2 + +kill_daemon() { + NAME=$1 + PF=$2 + + if [ ! -r $PF ]; then + return + fi + + PID=`cat $PF` + if [ $PID -gt 0 ]; then + if ps $PID | grep -q $NAME; then + kill $PID + fi + fi + rm $PF +} + +if [ "$CMD" = "P2P-GROUP-STARTED" ]; then + GIFNAME=$3 + if [ "$4" = "GO" ]; then + kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid + ifconfig $GIFNAME 192.168.42.1 up + udhcpd /etc/udhcpd-p2p.conf + fi + if [ "$4" = "client" ]; then + kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid + kill_daemon udhcpd /var/run/udhcpd-$GIFNAME.pid + udhcpc -i $GIFNAME -p /var/run/udhcpc-$GIFNAME.pid \ + -s /etc/udhcpc.script + fi +fi + +if [ "$CMD" = "P2P-GROUP-REMOVED" ]; then + GIFNAME=$3 + if [ "$4" = "GO" ]; then + kill_daemon udhcpd /var/run/udhcpd-$GIFNAME.pid + ifconfig $GIFNAME 0.0.0.0 + fi + if [ "$4" = "client" ]; then + kill_daemon udhcpc /var/run/udhcpc-$GIFNAME.pid + ifconfig $GIFNAME 0.0.0.0 + fi +fi + +if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then + GIFNAME=$3 + UPLINK=$4 + # 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 + iptables -A FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT + sysctl net.ipv4.ip_forward=1 +fi + +if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then + GIFNAME=$3 + UPLINK=$4 + # 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 + iptables -D FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT +fi diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-action.sh b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-action.sh index 6c27b27b787eed4b325a317b20aa3d1a99c59b26..1453f0eedb7d681849c656c59312c1ec25e5b190 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-action.sh +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-action.sh @@ -1,96 +1,96 @@ -#!/bin/sh - -IFNAME=$1 -CMD=$2 - -kill_daemon() { - NAME=$1 - PF=$2 - - if [ ! -r $PF ]; then - return - fi - - PID=`cat $PF` - if [ $PID -gt 0 ]; then - if ps $PID | grep -q $NAME; then - kill $PID - fi - fi - rm $PF -} - -if [ "$CMD" = "P2P-GROUP-STARTED" ]; then - GIFNAME=$3 - if [ "$4" = "GO" ]; then - kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid - rm /var/run/dhclient.leases-$GIFNAME - kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME - ifconfig $GIFNAME 192.168.42.1 up - if ! dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \ - -i $GIFNAME \ - -F192.168.42.11,192.168.42.99; then - # another dnsmasq instance may be running and blocking us; try to - # start with -z to avoid that - dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \ - -i $GIFNAME \ - -F192.168.42.11,192.168.42.99 --listen-address 192.168.42.1 -z -p 0 - fi - fi - if [ "$4" = "client" ]; then - kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid - rm /var/run/dhclient.leases-$GIFNAME - kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME - ipaddr=`echo "$*" | sed 's/.* ip_addr=\([^ ]*\).*/\1/'` - ipmask=`echo "$*" | sed 's/.* ip_mask=\([^ ]*\).*/\1/'` - goipaddr=`echo "$*" | sed 's/.* go_ip_addr=\([^ ]*\).*/\1/'` - if echo "$ipaddr$ipmask$goipaddr" | grep -q ' '; then - ipaddr="" - ipmask="" - goipaddr="" - fi - if [ -n "$ipaddr" ]; then - sudo ifconfig $GIFNAME "$ipaddr" netmask "$ipmask" - sudo ip ro re default via "$goipaddr" - exit 0 - fi - dhclient -pf /var/run/dhclient-$GIFNAME.pid \ - -lf /var/run/dhclient.leases-$GIFNAME \ - -nw \ - $GIFNAME - fi -fi - -if [ "$CMD" = "P2P-GROUP-REMOVED" ]; then - GIFNAME=$3 - if [ "$4" = "GO" ]; then - kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME - ifconfig $GIFNAME 0.0.0.0 - fi - if [ "$4" = "client" ]; then - kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid - rm /var/run/dhclient.leases-$GIFNAME - ifconfig $GIFNAME 0.0.0.0 - fi -fi - -if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then - GIFNAME=$3 - UPLINK=$4 - # 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 - iptables -A FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT - sysctl net.ipv4.ip_forward=1 -fi - -if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then - GIFNAME=$3 - UPLINK=$4 - # 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 - iptables -D FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT -fi +#!/bin/sh + +IFNAME=$1 +CMD=$2 + +kill_daemon() { + NAME=$1 + PF=$2 + + if [ ! -r $PF ]; then + return + fi + + PID=`cat $PF` + if [ $PID -gt 0 ]; then + if ps $PID | grep -q $NAME; then + kill $PID + fi + fi + rm $PF +} + +if [ "$CMD" = "P2P-GROUP-STARTED" ]; then + GIFNAME=$3 + if [ "$4" = "GO" ]; then + kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid + rm /var/run/dhclient.leases-$GIFNAME + kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME + ifconfig $GIFNAME 192.168.42.1 up + if ! dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \ + -i $GIFNAME \ + -F192.168.42.11,192.168.42.99; then + # another dnsmasq instance may be running and blocking us; try to + # start with -z to avoid that + dnsmasq -x /var/run/dnsmasq.pid-$GIFNAME \ + -i $GIFNAME \ + -F192.168.42.11,192.168.42.99 --listen-address 192.168.42.1 -z -p 0 + fi + fi + if [ "$4" = "client" ]; then + kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid + rm /var/run/dhclient.leases-$GIFNAME + kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME + ipaddr=`echo "$*" | sed 's/.* ip_addr=\([^ ]*\).*/\1/'` + ipmask=`echo "$*" | sed 's/.* ip_mask=\([^ ]*\).*/\1/'` + goipaddr=`echo "$*" | sed 's/.* go_ip_addr=\([^ ]*\).*/\1/'` + if echo "$ipaddr$ipmask$goipaddr" | grep -q ' '; then + ipaddr="" + ipmask="" + goipaddr="" + fi + if [ -n "$ipaddr" ]; then + sudo ifconfig $GIFNAME "$ipaddr" netmask "$ipmask" + sudo ip ro re default via "$goipaddr" + exit 0 + fi + dhclient -pf /var/run/dhclient-$GIFNAME.pid \ + -lf /var/run/dhclient.leases-$GIFNAME \ + -nw \ + $GIFNAME + fi +fi + +if [ "$CMD" = "P2P-GROUP-REMOVED" ]; then + GIFNAME=$3 + if [ "$4" = "GO" ]; then + kill_daemon dnsmasq /var/run/dnsmasq.pid-$GIFNAME + ifconfig $GIFNAME 0.0.0.0 + fi + if [ "$4" = "client" ]; then + kill_daemon dhclient /var/run/dhclient-$GIFNAME.pid + rm /var/run/dhclient.leases-$GIFNAME + ifconfig $GIFNAME 0.0.0.0 + fi +fi + +if [ "$CMD" = "P2P-CROSS-CONNECT-ENABLE" ]; then + GIFNAME=$3 + UPLINK=$4 + # 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 + iptables -A FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT + sysctl net.ipv4.ip_forward=1 +fi + +if [ "$CMD" = "P2P-CROSS-CONNECT-DISABLE" ]; then + GIFNAME=$3 + UPLINK=$4 + # 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 + iptables -D FORWARD -i $GIFNAME -o $UPLINK -j ACCEPT +fi diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-nfc.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-nfc.py index 889ac8bff15574a3501fe7f3d4343d8ca1e628cf..53d7a650ecf251881f4f9135c79a7fd5cbfca62a 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-nfc.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p-nfc.py @@ -1,654 +1,654 @@ -#!/usr/bin/python -# -# Example nfcpy to wpa_supplicant wrapper for P2P NFC operations -# Copyright (c) 2012-2013, Jouni Malinen -# -# This software may be distributed under the terms of the BSD license. -# See README for more details. - -import os -import sys -import time -import random -import threading -import argparse - -import nfc -import nfc.ndef -import nfc.llcp -import nfc.handover - -import logging - -import wpaspy - -wpas_ctrl = '/var/run/wpa_supplicant' -ifname = None -init_on_touch = False -in_raw_mode = False -prev_tcgetattr = 0 -include_wps_req = True -include_p2p_req = True -no_input = False -srv = None -continue_loop = True -terminate_now = False -summary_file = None -success_file = None - -def summary(txt): - print(txt) - if summary_file: - with open(summary_file, 'a') as f: - f.write(txt + "\n") - -def success_report(txt): - summary(txt) - if success_file: - with open(success_file, 'a') as f: - f.write(txt + "\n") - -def wpas_connect(): - ifaces = [] - if os.path.isdir(wpas_ctrl): - try: - ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] - except OSError as error: - print("Could not find wpa_supplicant: ", error) - return None - - if len(ifaces) < 1: - print("No wpa_supplicant control interface found") - return None - - for ctrl in ifaces: - if ifname: - if ifname not in ctrl: - continue - try: - print("Trying to use control interface " + ctrl) - wpas = wpaspy.Ctrl(ctrl) - return wpas - except Exception as e: - pass - return None - - -def wpas_tag_read(message): - wpas = wpas_connect() - if (wpas == None): - return False - cmd = "WPS_NFC_TAG_READ " + str(message).encode("hex") - global force_freq - if force_freq: - cmd = cmd + " freq=" + force_freq - if "FAIL" in wpas.request(cmd): - return False - return True - - -def wpas_get_handover_req(): - wpas = wpas_connect() - if (wpas == None): - return None - res = wpas.request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip() - if "FAIL" in res: - return None - return res.decode("hex") - -def wpas_get_handover_req_wps(): - wpas = wpas_connect() - if (wpas == None): - return None - res = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip() - if "FAIL" in res: - return None - return res.decode("hex") - - -def wpas_get_handover_sel(tag=False): - wpas = wpas_connect() - if (wpas == None): - return None - if tag: - res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip() - else: - res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip() - if "FAIL" in res: - return None - return res.decode("hex") - - -def wpas_get_handover_sel_wps(): - wpas = wpas_connect() - if (wpas == None): - return None - res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR"); - if "FAIL" in res: - return None - return res.rstrip().decode("hex") - - -def wpas_report_handover(req, sel, type): - wpas = wpas_connect() - if (wpas == None): - return None - cmd = "NFC_REPORT_HANDOVER " + type + " P2P " + str(req).encode("hex") + " " + str(sel).encode("hex") - global force_freq - if force_freq: - cmd = cmd + " freq=" + force_freq - return wpas.request(cmd) - - -def wpas_report_handover_wsc(req, sel, type): - wpas = wpas_connect() - if (wpas == None): - return None - cmd = "NFC_REPORT_HANDOVER " + type + " WPS " + str(req).encode("hex") + " " + str(sel).encode("hex") - if force_freq: - cmd = cmd + " freq=" + force_freq - return wpas.request(cmd) - - -def p2p_handover_client(llc): - message = nfc.ndef.HandoverRequestMessage(version="1.2") - message.nonce = random.randint(0, 0xffff) - - global include_p2p_req - if include_p2p_req: - data = wpas_get_handover_req() - if (data == None): - summary("Could not get handover request carrier record from wpa_supplicant") - return - print("Handover request carrier record from wpa_supplicant: " + data.encode("hex")) - datamsg = nfc.ndef.Message(data) - message.add_carrier(datamsg[0], "active", datamsg[1:]) - - global include_wps_req - if include_wps_req: - print("Handover request (pre-WPS):") - try: - print(message.pretty()) - except Exception as e: - print(e) - - data = wpas_get_handover_req_wps() - if data: - print("Add WPS request in addition to P2P") - datamsg = nfc.ndef.Message(data) - message.add_carrier(datamsg[0], "active", datamsg[1:]) - - print("Handover request:") - try: - print(message.pretty()) - except Exception as e: - print(e) - print(str(message).encode("hex")) - - client = nfc.handover.HandoverClient(llc) - try: - summary("Trying to initiate NFC connection handover") - client.connect() - summary("Connected for handover") - except nfc.llcp.ConnectRefused: - summary("Handover connection refused") - client.close() - return - except Exception as e: - summary("Other exception: " + str(e)) - client.close() - return - - summary("Sending handover request") - - if not client.send(message): - summary("Failed to send handover request") - client.close() - return - - summary("Receiving handover response") - message = client._recv() - if message is None: - summary("No response received") - client.close() - return - if message.type != "urn:nfc:wkt:Hs": - summary("Response was not Hs - received: " + message.type) - client.close() - return - - print("Received message") - try: - print(message.pretty()) - except Exception as e: - print(e) - print(str(message).encode("hex")) - message = nfc.ndef.HandoverSelectMessage(message) - summary("Handover select received") - try: - print(message.pretty()) - except Exception as e: - print(e) - - for carrier in message.carriers: - print("Remote carrier type: " + carrier.type) - if carrier.type == "application/vnd.wfa.p2p": - print("P2P carrier type match - send to wpa_supplicant") - if "OK" in wpas_report_handover(data, carrier.record, "INIT"): - success_report("P2P handover reported successfully (initiator)") - else: - summary("P2P handover report rejected") - break - - print("Remove peer") - client.close() - print("Done with handover") - global only_one - if only_one: - print("only_one -> stop loop") - global continue_loop - continue_loop = False - - global no_wait - if no_wait: - print("Trying to exit..") - global terminate_now - terminate_now = True - - -class HandoverServer(nfc.handover.HandoverServer): - def __init__(self, llc): - super(HandoverServer, self).__init__(llc) - self.sent_carrier = None - self.ho_server_processing = False - self.success = False - - # override to avoid parser error in request/response.pretty() in nfcpy - # due to new WSC handover format - def _process_request(self, request): - summary("received handover request {}".format(request.type)) - response = nfc.ndef.Message("\xd1\x02\x01Hs\x12") - if not request.type == 'urn:nfc:wkt:Hr': - summary("not a handover request") - else: - try: - request = nfc.ndef.HandoverRequestMessage(request) - except nfc.ndef.DecodeError as e: - summary("error decoding 'Hr' message: {}".format(e)) - else: - response = self.process_request(request) - summary("send handover response {}".format(response.type)) - return response - - def process_request(self, request): - self.ho_server_processing = True - clear_raw_mode() - print("HandoverServer - request received") - try: - print("Parsed handover request: " + request.pretty()) - except Exception as e: - print(e) - - sel = nfc.ndef.HandoverSelectMessage(version="1.2") - - found = False - - for carrier in request.carriers: - print("Remote carrier type: " + carrier.type) - if carrier.type == "application/vnd.wfa.p2p": - print("P2P carrier type match - add P2P carrier record") - found = True - self.received_carrier = carrier.record - print("Carrier record:") - try: - print(carrier.record.pretty()) - except Exception as e: - print(e) - data = wpas_get_handover_sel() - if data is None: - print("Could not get handover select carrier record from wpa_supplicant") - continue - print("Handover select carrier record from wpa_supplicant:") - print(data.encode("hex")) - self.sent_carrier = data - if "OK" in wpas_report_handover(self.received_carrier, self.sent_carrier, "RESP"): - success_report("P2P handover reported successfully (responder)") - else: - summary("P2P handover report rejected") - break - - message = nfc.ndef.Message(data); - sel.add_carrier(message[0], "active", message[1:]) - break - - for carrier in request.carriers: - if found: - break - print("Remote carrier type: " + carrier.type) - if carrier.type == "application/vnd.wfa.wsc": - print("WSC carrier type match - add WSC carrier record") - found = True - self.received_carrier = carrier.record - print("Carrier record:") - try: - print(carrier.record.pretty()) - except Exception as e: - print(e) - data = wpas_get_handover_sel_wps() - if data is None: - print("Could not get handover select carrier record from wpa_supplicant") - continue - print("Handover select carrier record from wpa_supplicant:") - print(data.encode("hex")) - self.sent_carrier = data - if "OK" in wpas_report_handover_wsc(self.received_carrier, self.sent_carrier, "RESP"): - success_report("WSC handover reported successfully") - else: - summary("WSC handover report rejected") - break - - message = nfc.ndef.Message(data); - sel.add_carrier(message[0], "active", message[1:]) - found = True - break - - print("Handover select:") - try: - print(sel.pretty()) - except Exception as e: - print(e) - print(str(sel).encode("hex")) - - summary("Sending handover select") - self.success = True - return sel - - -def clear_raw_mode(): - import sys, tty, termios - global prev_tcgetattr, in_raw_mode - if not in_raw_mode: - return - fd = sys.stdin.fileno() - termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr) - in_raw_mode = False - - -def getch(): - import sys, tty, termios, select - global prev_tcgetattr, in_raw_mode - fd = sys.stdin.fileno() - prev_tcgetattr = termios.tcgetattr(fd) - ch = None - try: - tty.setraw(fd) - in_raw_mode = True - [i, o, e] = select.select([fd], [], [], 0.05) - if i: - ch = sys.stdin.read(1) - finally: - termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr) - in_raw_mode = False - return ch - - -def p2p_tag_read(tag): - success = False - if len(tag.ndef.message): - for record in tag.ndef.message: - print("record type " + record.type) - if record.type == "application/vnd.wfa.wsc": - summary("WPS tag - send to wpa_supplicant") - success = wpas_tag_read(tag.ndef.message) - break - if record.type == "application/vnd.wfa.p2p": - summary("P2P tag - send to wpa_supplicant") - success = wpas_tag_read(tag.ndef.message) - break - else: - summary("Empty tag") - - if success: - success_report("Tag read succeeded") - - return success - - -def rdwr_connected_p2p_write(tag): - summary("Tag found - writing - " + str(tag)) - global p2p_sel_data - tag.ndef.message = str(p2p_sel_data) - success_report("Tag write succeeded") - print("Done - remove tag") - global only_one - if only_one: - global continue_loop - continue_loop = False - global p2p_sel_wait_remove - return p2p_sel_wait_remove - -def wps_write_p2p_handover_sel(clf, wait_remove=True): - print("Write P2P handover select") - data = wpas_get_handover_sel(tag=True) - if (data == None): - summary("Could not get P2P handover select from wpa_supplicant") - return - - global p2p_sel_wait_remove - p2p_sel_wait_remove = wait_remove - global p2p_sel_data - p2p_sel_data = nfc.ndef.HandoverSelectMessage(version="1.2") - message = nfc.ndef.Message(data); - p2p_sel_data.add_carrier(message[0], "active", message[1:]) - print("Handover select:") - try: - print(p2p_sel_data.pretty()) - except Exception as e: - print(e) - print(str(p2p_sel_data).encode("hex")) - - print("Touch an NFC tag") - clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write}) - - -def rdwr_connected(tag): - global only_one, no_wait - summary("Tag connected: " + str(tag)) - - if tag.ndef: - print("NDEF tag: " + tag.type) - try: - print(tag.ndef.message.pretty()) - except Exception as e: - print(e) - success = p2p_tag_read(tag) - if only_one and success: - global continue_loop - continue_loop = False - else: - summary("Not an NDEF tag - remove tag") - return True - - return not no_wait - - -def llcp_worker(llc): - global init_on_touch - if init_on_touch: - print("Starting handover client") - p2p_handover_client(llc) - return - - global no_input - if no_input: - print("Wait for handover to complete") - else: - print("Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)") - global srv - global wait_connection - while not wait_connection and srv.sent_carrier is None: - if srv.ho_server_processing: - time.sleep(0.025) - elif no_input: - time.sleep(0.5) - else: - global include_wps_req, include_p2p_req - res = getch() - if res == 'i': - include_wps_req = True - include_p2p_req = True - elif res == 'p': - include_wps_req = False - include_p2p_req = True - elif res == 'w': - include_wps_req = True - include_p2p_req = False - else: - continue - clear_raw_mode() - print("Starting handover client") - p2p_handover_client(llc) - return - - clear_raw_mode() - print("Exiting llcp_worker thread") - -def llcp_startup(clf, llc): - print("Start LLCP server") - global srv - srv = HandoverServer(llc) - return llc - -def llcp_connected(llc): - print("P2P LLCP connected") - global wait_connection - wait_connection = False - global init_on_touch - if not init_on_touch: - global srv - srv.start() - if init_on_touch or not no_input: - threading.Thread(target=llcp_worker, args=(llc,)).start() - return True - -def terminate_loop(): - global terminate_now - return terminate_now - -def main(): - clf = nfc.ContactlessFrontend() - - parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for P2P and WPS NFC operations') - parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO, - action='store_const', dest='loglevel', - help='verbose debug output') - parser.add_argument('-q', const=logging.WARNING, action='store_const', - dest='loglevel', help='be quiet') - parser.add_argument('--only-one', '-1', action='store_true', - help='run only one operation and exit') - parser.add_argument('--init-on-touch', '-I', action='store_true', - help='initiate handover on touch') - parser.add_argument('--no-wait', action='store_true', - help='do not wait for tag to be removed before exiting') - parser.add_argument('--ifname', '-i', - help='network interface name') - parser.add_argument('--no-wps-req', '-N', action='store_true', - help='do not include WPS carrier record in request') - parser.add_argument('--no-input', '-a', action='store_true', - help='do not use stdout input to initiate handover') - parser.add_argument('--tag-read-only', '-t', action='store_true', - help='tag read only (do not allow connection handover)') - parser.add_argument('--handover-only', action='store_true', - help='connection handover only (do not allow tag read)') - parser.add_argument('--freq', '-f', - help='forced frequency of operating channel in MHz') - parser.add_argument('--summary', - help='summary file for writing status updates') - parser.add_argument('--success', - help='success file for writing success update') - parser.add_argument('command', choices=['write-p2p-sel'], - nargs='?') - args = parser.parse_args() - - global only_one - only_one = args.only_one - - global no_wait - no_wait = args.no_wait - - global force_freq - force_freq = args.freq - - logging.basicConfig(level=args.loglevel) - - global init_on_touch - init_on_touch = args.init_on_touch - - if args.ifname: - global ifname - ifname = args.ifname - print("Selected ifname " + ifname) - - if args.no_wps_req: - global include_wps_req - include_wps_req = False - - if args.summary: - global summary_file - summary_file = args.summary - - if args.success: - global success_file - success_file = args.success - - if args.no_input: - global no_input - no_input = True - - clf = nfc.ContactlessFrontend() - global wait_connection - - try: - if not clf.open("usb"): - print("Could not open connection with an NFC device") - raise SystemExit - - if args.command == "write-p2p-sel": - wps_write_p2p_handover_sel(clf, wait_remove=not args.no_wait) - raise SystemExit - - global continue_loop - while continue_loop: - print("Waiting for a tag or peer to be touched") - wait_connection = True - try: - if args.tag_read_only: - if not clf.connect(rdwr={'on-connect': rdwr_connected}): - break - elif args.handover_only: - if not clf.connect(llcp={'on-startup': llcp_startup, - 'on-connect': llcp_connected}, - terminate=terminate_loop): - break - else: - if not clf.connect(rdwr={'on-connect': rdwr_connected}, - llcp={'on-startup': llcp_startup, - 'on-connect': llcp_connected}, - terminate=terminate_loop): - break - except Exception as e: - print("clf.connect failed") - - global srv - if only_one and srv and srv.success: - raise SystemExit - - except KeyboardInterrupt: - raise SystemExit - finally: - clf.close() - - raise SystemExit - -if __name__ == '__main__': - main() +#!/usr/bin/python +# +# Example nfcpy to wpa_supplicant wrapper for P2P NFC operations +# Copyright (c) 2012-2013, Jouni Malinen +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import sys +import time +import random +import threading +import argparse + +import nfc +import nfc.ndef +import nfc.llcp +import nfc.handover + +import logging + +import wpaspy + +wpas_ctrl = '/var/run/wpa_supplicant' +ifname = None +init_on_touch = False +in_raw_mode = False +prev_tcgetattr = 0 +include_wps_req = True +include_p2p_req = True +no_input = False +srv = None +continue_loop = True +terminate_now = False +summary_file = None +success_file = None + +def summary(txt): + print(txt) + if summary_file: + with open(summary_file, 'a') as f: + f.write(txt + "\n") + +def success_report(txt): + summary(txt) + if success_file: + with open(success_file, 'a') as f: + f.write(txt + "\n") + +def wpas_connect(): + ifaces = [] + if os.path.isdir(wpas_ctrl): + try: + ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] + except OSError as error: + print("Could not find wpa_supplicant: ", error) + return None + + if len(ifaces) < 1: + print("No wpa_supplicant control interface found") + return None + + for ctrl in ifaces: + if ifname: + if ifname not in ctrl: + continue + try: + print("Trying to use control interface " + ctrl) + wpas = wpaspy.Ctrl(ctrl) + return wpas + except Exception as e: + pass + return None + + +def wpas_tag_read(message): + wpas = wpas_connect() + if (wpas == None): + return False + cmd = "WPS_NFC_TAG_READ " + str(message).encode("hex") + global force_freq + if force_freq: + cmd = cmd + " freq=" + force_freq + if "FAIL" in wpas.request(cmd): + return False + return True + + +def wpas_get_handover_req(): + wpas = wpas_connect() + if (wpas == None): + return None + res = wpas.request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip() + if "FAIL" in res: + return None + return res.decode("hex") + +def wpas_get_handover_req_wps(): + wpas = wpas_connect() + if (wpas == None): + return None + res = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR").rstrip() + if "FAIL" in res: + return None + return res.decode("hex") + + +def wpas_get_handover_sel(tag=False): + wpas = wpas_connect() + if (wpas == None): + return None + if tag: + res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR-TAG").rstrip() + else: + res = wpas.request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip() + if "FAIL" in res: + return None + return res.decode("hex") + + +def wpas_get_handover_sel_wps(): + wpas = wpas_connect() + if (wpas == None): + return None + res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR"); + if "FAIL" in res: + return None + return res.rstrip().decode("hex") + + +def wpas_report_handover(req, sel, type): + wpas = wpas_connect() + if (wpas == None): + return None + cmd = "NFC_REPORT_HANDOVER " + type + " P2P " + str(req).encode("hex") + " " + str(sel).encode("hex") + global force_freq + if force_freq: + cmd = cmd + " freq=" + force_freq + return wpas.request(cmd) + + +def wpas_report_handover_wsc(req, sel, type): + wpas = wpas_connect() + if (wpas == None): + return None + cmd = "NFC_REPORT_HANDOVER " + type + " WPS " + str(req).encode("hex") + " " + str(sel).encode("hex") + if force_freq: + cmd = cmd + " freq=" + force_freq + return wpas.request(cmd) + + +def p2p_handover_client(llc): + message = nfc.ndef.HandoverRequestMessage(version="1.2") + message.nonce = random.randint(0, 0xffff) + + global include_p2p_req + if include_p2p_req: + data = wpas_get_handover_req() + if (data == None): + summary("Could not get handover request carrier record from wpa_supplicant") + return + print("Handover request carrier record from wpa_supplicant: " + data.encode("hex")) + datamsg = nfc.ndef.Message(data) + message.add_carrier(datamsg[0], "active", datamsg[1:]) + + global include_wps_req + if include_wps_req: + print("Handover request (pre-WPS):") + try: + print(message.pretty()) + except Exception as e: + print(e) + + data = wpas_get_handover_req_wps() + if data: + print("Add WPS request in addition to P2P") + datamsg = nfc.ndef.Message(data) + message.add_carrier(datamsg[0], "active", datamsg[1:]) + + print("Handover request:") + try: + print(message.pretty()) + except Exception as e: + print(e) + print(str(message).encode("hex")) + + client = nfc.handover.HandoverClient(llc) + try: + summary("Trying to initiate NFC connection handover") + client.connect() + summary("Connected for handover") + except nfc.llcp.ConnectRefused: + summary("Handover connection refused") + client.close() + return + except Exception as e: + summary("Other exception: " + str(e)) + client.close() + return + + summary("Sending handover request") + + if not client.send(message): + summary("Failed to send handover request") + client.close() + return + + summary("Receiving handover response") + message = client._recv() + if message is None: + summary("No response received") + client.close() + return + if message.type != "urn:nfc:wkt:Hs": + summary("Response was not Hs - received: " + message.type) + client.close() + return + + print("Received message") + try: + print(message.pretty()) + except Exception as e: + print(e) + print(str(message).encode("hex")) + message = nfc.ndef.HandoverSelectMessage(message) + summary("Handover select received") + try: + print(message.pretty()) + except Exception as e: + print(e) + + for carrier in message.carriers: + print("Remote carrier type: " + carrier.type) + if carrier.type == "application/vnd.wfa.p2p": + print("P2P carrier type match - send to wpa_supplicant") + if "OK" in wpas_report_handover(data, carrier.record, "INIT"): + success_report("P2P handover reported successfully (initiator)") + else: + summary("P2P handover report rejected") + break + + print("Remove peer") + client.close() + print("Done with handover") + global only_one + if only_one: + print("only_one -> stop loop") + global continue_loop + continue_loop = False + + global no_wait + if no_wait: + print("Trying to exit..") + global terminate_now + terminate_now = True + + +class HandoverServer(nfc.handover.HandoverServer): + def __init__(self, llc): + super(HandoverServer, self).__init__(llc) + self.sent_carrier = None + self.ho_server_processing = False + self.success = False + + # override to avoid parser error in request/response.pretty() in nfcpy + # due to new WSC handover format + def _process_request(self, request): + summary("received handover request {}".format(request.type)) + response = nfc.ndef.Message("\xd1\x02\x01Hs\x12") + if not request.type == 'urn:nfc:wkt:Hr': + summary("not a handover request") + else: + try: + request = nfc.ndef.HandoverRequestMessage(request) + except nfc.ndef.DecodeError as e: + summary("error decoding 'Hr' message: {}".format(e)) + else: + response = self.process_request(request) + summary("send handover response {}".format(response.type)) + return response + + def process_request(self, request): + self.ho_server_processing = True + clear_raw_mode() + print("HandoverServer - request received") + try: + print("Parsed handover request: " + request.pretty()) + except Exception as e: + print(e) + + sel = nfc.ndef.HandoverSelectMessage(version="1.2") + + found = False + + for carrier in request.carriers: + print("Remote carrier type: " + carrier.type) + if carrier.type == "application/vnd.wfa.p2p": + print("P2P carrier type match - add P2P carrier record") + found = True + self.received_carrier = carrier.record + print("Carrier record:") + try: + print(carrier.record.pretty()) + except Exception as e: + print(e) + data = wpas_get_handover_sel() + if data is None: + print("Could not get handover select carrier record from wpa_supplicant") + continue + print("Handover select carrier record from wpa_supplicant:") + print(data.encode("hex")) + self.sent_carrier = data + if "OK" in wpas_report_handover(self.received_carrier, self.sent_carrier, "RESP"): + success_report("P2P handover reported successfully (responder)") + else: + summary("P2P handover report rejected") + break + + message = nfc.ndef.Message(data); + sel.add_carrier(message[0], "active", message[1:]) + break + + for carrier in request.carriers: + if found: + break + print("Remote carrier type: " + carrier.type) + if carrier.type == "application/vnd.wfa.wsc": + print("WSC carrier type match - add WSC carrier record") + found = True + self.received_carrier = carrier.record + print("Carrier record:") + try: + print(carrier.record.pretty()) + except Exception as e: + print(e) + data = wpas_get_handover_sel_wps() + if data is None: + print("Could not get handover select carrier record from wpa_supplicant") + continue + print("Handover select carrier record from wpa_supplicant:") + print(data.encode("hex")) + self.sent_carrier = data + if "OK" in wpas_report_handover_wsc(self.received_carrier, self.sent_carrier, "RESP"): + success_report("WSC handover reported successfully") + else: + summary("WSC handover report rejected") + break + + message = nfc.ndef.Message(data); + sel.add_carrier(message[0], "active", message[1:]) + found = True + break + + print("Handover select:") + try: + print(sel.pretty()) + except Exception as e: + print(e) + print(str(sel).encode("hex")) + + summary("Sending handover select") + self.success = True + return sel + + +def clear_raw_mode(): + import sys, tty, termios + global prev_tcgetattr, in_raw_mode + if not in_raw_mode: + return + fd = sys.stdin.fileno() + termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr) + in_raw_mode = False + + +def getch(): + import sys, tty, termios, select + global prev_tcgetattr, in_raw_mode + fd = sys.stdin.fileno() + prev_tcgetattr = termios.tcgetattr(fd) + ch = None + try: + tty.setraw(fd) + in_raw_mode = True + [i, o, e] = select.select([fd], [], [], 0.05) + if i: + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr) + in_raw_mode = False + return ch + + +def p2p_tag_read(tag): + success = False + if len(tag.ndef.message): + for record in tag.ndef.message: + print("record type " + record.type) + if record.type == "application/vnd.wfa.wsc": + summary("WPS tag - send to wpa_supplicant") + success = wpas_tag_read(tag.ndef.message) + break + if record.type == "application/vnd.wfa.p2p": + summary("P2P tag - send to wpa_supplicant") + success = wpas_tag_read(tag.ndef.message) + break + else: + summary("Empty tag") + + if success: + success_report("Tag read succeeded") + + return success + + +def rdwr_connected_p2p_write(tag): + summary("Tag found - writing - " + str(tag)) + global p2p_sel_data + tag.ndef.message = str(p2p_sel_data) + success_report("Tag write succeeded") + print("Done - remove tag") + global only_one + if only_one: + global continue_loop + continue_loop = False + global p2p_sel_wait_remove + return p2p_sel_wait_remove + +def wps_write_p2p_handover_sel(clf, wait_remove=True): + print("Write P2P handover select") + data = wpas_get_handover_sel(tag=True) + if (data == None): + summary("Could not get P2P handover select from wpa_supplicant") + return + + global p2p_sel_wait_remove + p2p_sel_wait_remove = wait_remove + global p2p_sel_data + p2p_sel_data = nfc.ndef.HandoverSelectMessage(version="1.2") + message = nfc.ndef.Message(data); + p2p_sel_data.add_carrier(message[0], "active", message[1:]) + print("Handover select:") + try: + print(p2p_sel_data.pretty()) + except Exception as e: + print(e) + print(str(p2p_sel_data).encode("hex")) + + print("Touch an NFC tag") + clf.connect(rdwr={'on-connect': rdwr_connected_p2p_write}) + + +def rdwr_connected(tag): + global only_one, no_wait + summary("Tag connected: " + str(tag)) + + if tag.ndef: + print("NDEF tag: " + tag.type) + try: + print(tag.ndef.message.pretty()) + except Exception as e: + print(e) + success = p2p_tag_read(tag) + if only_one and success: + global continue_loop + continue_loop = False + else: + summary("Not an NDEF tag - remove tag") + return True + + return not no_wait + + +def llcp_worker(llc): + global init_on_touch + if init_on_touch: + print("Starting handover client") + p2p_handover_client(llc) + return + + global no_input + if no_input: + print("Wait for handover to complete") + else: + print("Wait for handover to complete - press 'i' to initiate ('w' for WPS only, 'p' for P2P only)") + global srv + global wait_connection + while not wait_connection and srv.sent_carrier is None: + if srv.ho_server_processing: + time.sleep(0.025) + elif no_input: + time.sleep(0.5) + else: + global include_wps_req, include_p2p_req + res = getch() + if res == 'i': + include_wps_req = True + include_p2p_req = True + elif res == 'p': + include_wps_req = False + include_p2p_req = True + elif res == 'w': + include_wps_req = True + include_p2p_req = False + else: + continue + clear_raw_mode() + print("Starting handover client") + p2p_handover_client(llc) + return + + clear_raw_mode() + print("Exiting llcp_worker thread") + +def llcp_startup(clf, llc): + print("Start LLCP server") + global srv + srv = HandoverServer(llc) + return llc + +def llcp_connected(llc): + print("P2P LLCP connected") + global wait_connection + wait_connection = False + global init_on_touch + if not init_on_touch: + global srv + srv.start() + if init_on_touch or not no_input: + threading.Thread(target=llcp_worker, args=(llc,)).start() + return True + +def terminate_loop(): + global terminate_now + return terminate_now + +def main(): + clf = nfc.ContactlessFrontend() + + parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for P2P and WPS NFC operations') + parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO, + action='store_const', dest='loglevel', + help='verbose debug output') + parser.add_argument('-q', const=logging.WARNING, action='store_const', + dest='loglevel', help='be quiet') + parser.add_argument('--only-one', '-1', action='store_true', + help='run only one operation and exit') + parser.add_argument('--init-on-touch', '-I', action='store_true', + help='initiate handover on touch') + parser.add_argument('--no-wait', action='store_true', + help='do not wait for tag to be removed before exiting') + parser.add_argument('--ifname', '-i', + help='network interface name') + parser.add_argument('--no-wps-req', '-N', action='store_true', + help='do not include WPS carrier record in request') + parser.add_argument('--no-input', '-a', action='store_true', + help='do not use stdout input to initiate handover') + parser.add_argument('--tag-read-only', '-t', action='store_true', + help='tag read only (do not allow connection handover)') + parser.add_argument('--handover-only', action='store_true', + help='connection handover only (do not allow tag read)') + parser.add_argument('--freq', '-f', + help='forced frequency of operating channel in MHz') + parser.add_argument('--summary', + help='summary file for writing status updates') + parser.add_argument('--success', + help='success file for writing success update') + parser.add_argument('command', choices=['write-p2p-sel'], + nargs='?') + args = parser.parse_args() + + global only_one + only_one = args.only_one + + global no_wait + no_wait = args.no_wait + + global force_freq + force_freq = args.freq + + logging.basicConfig(level=args.loglevel) + + global init_on_touch + init_on_touch = args.init_on_touch + + if args.ifname: + global ifname + ifname = args.ifname + print("Selected ifname " + ifname) + + if args.no_wps_req: + global include_wps_req + include_wps_req = False + + if args.summary: + global summary_file + summary_file = args.summary + + if args.success: + global success_file + success_file = args.success + + if args.no_input: + global no_input + no_input = True + + clf = nfc.ContactlessFrontend() + global wait_connection + + try: + if not clf.open("usb"): + print("Could not open connection with an NFC device") + raise SystemExit + + if args.command == "write-p2p-sel": + wps_write_p2p_handover_sel(clf, wait_remove=not args.no_wait) + raise SystemExit + + global continue_loop + while continue_loop: + print("Waiting for a tag or peer to be touched") + wait_connection = True + try: + if args.tag_read_only: + if not clf.connect(rdwr={'on-connect': rdwr_connected}): + break + elif args.handover_only: + if not clf.connect(llcp={'on-startup': llcp_startup, + 'on-connect': llcp_connected}, + terminate=terminate_loop): + break + else: + if not clf.connect(rdwr={'on-connect': rdwr_connected}, + llcp={'on-startup': llcp_startup, + 'on-connect': llcp_connected}, + terminate=terminate_loop): + break + except Exception as e: + print("clf.connect failed") + + global srv + if only_one and srv and srv.success: + raise SystemExit + + except KeyboardInterrupt: + raise SystemExit + finally: + clf.close() + + raise SystemExit + +if __name__ == '__main__': + main() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_connect.py index bfb553341ad615f4cb36eec900c8855b752e63b4..6992ac8f685f4800c655c5649829129eab3a464b 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_connect.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_connect.py @@ -1,299 +1,299 @@ -#!/usr/bin/python -# Tests p2p_connect -# Will try to connect to another peer -# and form a group -######### MAY NEED TO RUN AS SUDO ############# - -import dbus -import sys, os -import time -import gobject -import getopt -from dbus.mainloop.glib import DBusGMainLoop - - -def usage(): - print("Usage:") - print(" %s -i -m \ " \ - % sys.argv[0]) - print(" -a [-p ] [-g ] \ ") - print(" [-w ]") - print("Options:") - print(" -i = interface name") - print(" -m = wps method") - print(" -a = peer address") - print(" -p = pin number (8 digits)") - print(" -g = group owner intent") - print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") - print("Example:") - print(" %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0]) - - -# Required Signals -def GONegotiationSuccess(status): - print("Go Negotiation Success") - -def GONegotiationFailure(status): - print('Go Negotiation Failed. Status:') - print(format(status)) - os._exit(0) - -def GroupStarted(properties): - if properties.has_key("group_object"): - print('Group Formation Complete %s' \ - % properties["group_object"]) - os._exit(0) - -def WpsFailure(status, etc): - print("WPS Authentication Failure".format(status)) - print(etc) - os._exit(0) - -class P2P_Connect(): - # Needed Variables - global bus - global wpas_object - global interface_object - global p2p_interface - global ifname - global wpas - global wpas_dbus_interface - global timeout - global path - global wps_method - global go_intent - global addr - global pin - - # Dbus Paths - global wpas_dbus_opath - global wpas_dbus_interfaces_opath - global wpas_dbus_interfaces_interface - global wpas_dbus_interfaces_p2pdevice - - # Dictionary of Arguments - global p2p_connect_arguements - - # Constructor - def __init__(self,ifname,wpas_dbus_interface,addr, - pin,wps_method,go_intent): - # Initializes variables and threads - self.ifname = ifname - self.wpas_dbus_interface = wpas_dbus_interface - self.wps_method = wps_method - self.go_intent = go_intent - self.addr = addr - self.pin = pin - - # Generating interface/object paths - self.wpas_dbus_opath = \ - "/" + self.wpas_dbus_interface.replace(".","/") - self.wpas_wpas_dbus_interfaces_opath = \ - self.wpas_dbus_opath + "/Interfaces" - self.wpas_dbus_interfaces_interface = \ - self.wpas_dbus_interface + ".Interface" - self.wpas_dbus_interfaces_p2pdevice = \ - self.wpas_dbus_interfaces_interface + ".P2PDevice" - - # Getting interfaces and objects - DBusGMainLoop(set_as_default=True) - self.bus = dbus.SystemBus() - self.wpas_object = self.bus.get_object( - self.wpas_dbus_interface, - self.wpas_dbus_opath) - self.wpas = dbus.Interface( - self.wpas_object, self.wpas_dbus_interface) - - # See if wpa_supplicant already knows about this interface - self.path = None - try: - self.path = self.wpas.GetInterface(ifname) - except dbus.DBusException as exc: - if not str(exc).startswith( - self.wpas_dbus_interface + \ - ".InterfaceUnknown:"): - raise exc - try: - path = self.wpas.CreateInterface( - {'Ifname': ifname, 'Driver': 'test'}) - time.sleep(1) - - except dbus.DBusException as exc: - if not str(exc).startswith( - self.wpas_dbus_interface + \ - ".InterfaceExists:"): - raise exc - - # Get Interface and objects - self.interface_object = self.bus.get_object( - self.wpas_dbus_interface,self.path) - self.p2p_interface = dbus.Interface( - self.interface_object, - self.wpas_dbus_interfaces_p2pdevice) - - # Add signals - self.bus.add_signal_receiver(GONegotiationSuccess, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="GONegotiationSuccess") - self.bus.add_signal_receiver(GONegotiationFailure, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="GONegotiationFailure") - self.bus.add_signal_receiver(GroupStarted, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="GroupStarted") - self.bus.add_signal_receiver(WpsFailure, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="WpsFailed") - - - #Constructing all the arguments needed to connect - def constructArguements(self): - # Adding required arguments - self.p2p_connect_arguements = {'wps_method':self.wps_method, - 'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)} - - # Display requires a pin, and a go intent of 15 - if (self.wps_method == 'display'): - if (self.pin != None): - self.p2p_connect_arguements.update({'pin':self.pin}) - else: - print("Error:\n Pin required for wps_method=display") - usage() - quit() - - if (self.go_intent != None and int(self.go_intent) != 15): - print("go_intent overwritten to 15") - - self.go_intent = '15' - - # Keypad requires a pin, and a go intent of less than 15 - elif (self.wps_method == 'keypad'): - if (self.pin != None): - self.p2p_connect_arguements.update({'pin':self.pin}) - else: - print("Error:\n Pin required for wps_method=keypad") - usage() - quit() - - if (self.go_intent != None and int(self.go_intent) == 15): - error = "Error :\n Group Owner intent cannot be" + \ - " 15 for wps_method=keypad" - print(error) - usage() - quit() - - # Doesn't require pin - # for ./wpa_cli, p2p_connect [mac] [pin#], wps_method=keypad - elif (self.wps_method == 'pin'): - if (self.pin != None): - print("pin ignored") - - # No pin is required for pbc so it is ignored - elif (self.wps_method == 'pbc'): - if (self.pin != None): - print("pin ignored") - - else: - print("Error:\n wps_method not supported or does not exist") - usage() - quit() - - # Go_intent is optional for all arguments - if (self.go_intent != None): - self.p2p_connect_arguements.update( - {'go_intent':dbus.Int32(self.go_intent)}) - - # Running p2p_connect - def run(self): - try: - result_pin = self.p2p_interface.Connect( - self.p2p_connect_arguements) - - except dbus.DBusException as exc: - raise exc - - if (self.wps_method == 'pin' and \ - not self.p2p_connect_arguements.has_key('pin') ): - print("Connect return with pin value of %d " % int(result_pin)) - gobject.MainLoop().run() - -if __name__ == "__main__": - - # Required - interface_name = None - wps_method = None - addr = None - - # Conditionally optional - pin = None - - # Optional - wpas_dbus_interface = 'fi.w1.wpa_supplicant1' - go_intent = None - - # Using getopts to handle options - try: - options, args = getopt.getopt(sys.argv[1:],"hi:m:a:p:g:w:") - - except getopt.GetoptError: - usage() - quit() - - # If there's a switch, override default option - for key, value in options: - # Help - if (key == "-h"): - usage() - quit() - # Interface Name - elif (key == "-i"): - interface_name = value - # WPS Method - elif (key == "-m"): - wps_method = value - # Address - elif (key == "-a"): - addr = value - # Pin - elif (key == "-p"): - pin = value - # Group Owner Intent - elif (key == "-g"): - go_intent = value - # Dbus interface - elif (key == "-w"): - wpas_dbus_interface = value - else: - assert False, "unhandled option" - - # Required Arguments check - if (interface_name == None or wps_method == None or addr == None): - print("Error:\n Required arguments not specified") - usage() - quit() - - # Group Owner Intent Check - if (go_intent != None and (int(go_intent) > 15 or int(go_intent) < 0) ): - print("Error:\n Group Owner Intent must be between 0 and 15 inclusive") - usage() - quit() - - # Pin Check - if (pin != None and len(pin) != 8): - print("Error:\n Pin is not 8 digits") - usage() - quit() - - try: - p2p_connect_test = P2P_Connect(interface_name,wpas_dbus_interface, - addr,pin,wps_method,go_intent) - - except: - print("Error:\n Invalid Arguments") - usage() - quit() - - p2p_connect_test.constructArguements() - p2p_connect_test.run() - - os._exit(0) +#!/usr/bin/python +# Tests p2p_connect +# Will try to connect to another peer +# and form a group +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import getopt +from dbus.mainloop.glib import DBusGMainLoop + + +def usage(): + print("Usage:") + print(" %s -i -m \ " \ + % sys.argv[0]) + print(" -a [-p ] [-g ] \ ") + print(" [-w ]") + print("Options:") + print(" -i = interface name") + print(" -m = wps method") + print(" -a = peer address") + print(" -p = pin number (8 digits)") + print(" -g = group owner intent") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0]) + + +# Required Signals +def GONegotiationSuccess(status): + print("Go Negotiation Success") + +def GONegotiationFailure(status): + print('Go Negotiation Failed. Status:') + print(format(status)) + os._exit(0) + +def GroupStarted(properties): + if properties.has_key("group_object"): + print('Group Formation Complete %s' \ + % properties["group_object"]) + os._exit(0) + +def WpsFailure(status, etc): + print("WPS Authentication Failure".format(status)) + print(etc) + os._exit(0) + +class P2P_Connect(): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global ifname + global wpas + global wpas_dbus_interface + global timeout + global path + global wps_method + global go_intent + global addr + global pin + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Dictionary of Arguments + global p2p_connect_arguements + + # Constructor + def __init__(self,ifname,wpas_dbus_interface,addr, + pin,wps_method,go_intent): + # Initializes variables and threads + self.ifname = ifname + self.wpas_dbus_interface = wpas_dbus_interface + self.wps_method = wps_method + self.go_intent = go_intent + self.addr = addr + self.pin = pin + + # Generating interface/object paths + self.wpas_dbus_opath = \ + "/" + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = \ + self.wpas_dbus_opath + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface( + self.wpas_object, self.wpas_dbus_interface) + + # See if wpa_supplicant already knows about this interface + self.path = None + try: + self.path = self.wpas.GetInterface(ifname) + except dbus.DBusException as exc: + if not str(exc).startswith( + self.wpas_dbus_interface + \ + ".InterfaceUnknown:"): + raise exc + try: + path = self.wpas.CreateInterface( + {'Ifname': ifname, 'Driver': 'test'}) + time.sleep(1) + + except dbus.DBusException as exc: + if not str(exc).startswith( + self.wpas_dbus_interface + \ + ".InterfaceExists:"): + raise exc + + # Get Interface and objects + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface,self.path) + self.p2p_interface = dbus.Interface( + self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + # Add signals + self.bus.add_signal_receiver(GONegotiationSuccess, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="GONegotiationSuccess") + self.bus.add_signal_receiver(GONegotiationFailure, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="GONegotiationFailure") + self.bus.add_signal_receiver(GroupStarted, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="GroupStarted") + self.bus.add_signal_receiver(WpsFailure, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="WpsFailed") + + + #Constructing all the arguments needed to connect + def constructArguements(self): + # Adding required arguments + self.p2p_connect_arguements = {'wps_method':self.wps_method, + 'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)} + + # Display requires a pin, and a go intent of 15 + if (self.wps_method == 'display'): + if (self.pin != None): + self.p2p_connect_arguements.update({'pin':self.pin}) + else: + print("Error:\n Pin required for wps_method=display") + usage() + quit() + + if (self.go_intent != None and int(self.go_intent) != 15): + print("go_intent overwritten to 15") + + self.go_intent = '15' + + # Keypad requires a pin, and a go intent of less than 15 + elif (self.wps_method == 'keypad'): + if (self.pin != None): + self.p2p_connect_arguements.update({'pin':self.pin}) + else: + print("Error:\n Pin required for wps_method=keypad") + usage() + quit() + + if (self.go_intent != None and int(self.go_intent) == 15): + error = "Error :\n Group Owner intent cannot be" + \ + " 15 for wps_method=keypad" + print(error) + usage() + quit() + + # Doesn't require pin + # for ./wpa_cli, p2p_connect [mac] [pin#], wps_method=keypad + elif (self.wps_method == 'pin'): + if (self.pin != None): + print("pin ignored") + + # No pin is required for pbc so it is ignored + elif (self.wps_method == 'pbc'): + if (self.pin != None): + print("pin ignored") + + else: + print("Error:\n wps_method not supported or does not exist") + usage() + quit() + + # Go_intent is optional for all arguments + if (self.go_intent != None): + self.p2p_connect_arguements.update( + {'go_intent':dbus.Int32(self.go_intent)}) + + # Running p2p_connect + def run(self): + try: + result_pin = self.p2p_interface.Connect( + self.p2p_connect_arguements) + + except dbus.DBusException as exc: + raise exc + + if (self.wps_method == 'pin' and \ + not self.p2p_connect_arguements.has_key('pin') ): + print("Connect return with pin value of %d " % int(result_pin)) + gobject.MainLoop().run() + +if __name__ == "__main__": + + # Required + interface_name = None + wps_method = None + addr = None + + # Conditionally optional + pin = None + + # Optional + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + go_intent = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:m:a:p:g:w:") + + except getopt.GetoptError: + usage() + quit() + + # If there's a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # WPS Method + elif (key == "-m"): + wps_method = value + # Address + elif (key == "-a"): + addr = value + # Pin + elif (key == "-p"): + pin = value + # Group Owner Intent + elif (key == "-g"): + go_intent = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Required Arguments check + if (interface_name == None or wps_method == None or addr == None): + print("Error:\n Required arguments not specified") + usage() + quit() + + # Group Owner Intent Check + if (go_intent != None and (int(go_intent) > 15 or int(go_intent) < 0) ): + print("Error:\n Group Owner Intent must be between 0 and 15 inclusive") + usage() + quit() + + # Pin Check + if (pin != None and len(pin) != 8): + print("Error:\n Pin is not 8 digits") + usage() + quit() + + try: + p2p_connect_test = P2P_Connect(interface_name,wpas_dbus_interface, + addr,pin,wps_method,go_intent) + + except: + print("Error:\n Invalid Arguments") + usage() + quit() + + p2p_connect_test.constructArguements() + p2p_connect_test.run() + + os._exit(0) diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_disconnect.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_disconnect.py index f04b98e667ce1b618d48017822d3a4b42700a201..fef0861ea1eae03d33226b13b79429bdbbf9c6f9 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_disconnect.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_disconnect.py @@ -1,169 +1,169 @@ -#!/usr/bin/python -# Tests P2P_Disconnect -# Will perform disconnect on interface_name -######### MAY NEED TO RUN AS SUDO ############# - -import dbus -import sys, os -import time -import gobject -import threading -import getopt -from dbus.mainloop.glib import DBusGMainLoop - -def usage(): - print("Usage:") - print(" %s -i \ " \ - % sys.argv[0]) - print(" [-w ]") - print("Options:") - print(" -i = interface name") - print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") - print("Example:") - print(" %s -i p2p-wlan0-0" % sys.argv[0]) - -# Required Signals -def GroupFinished(status, etc): - print("Disconnected") - os._exit(0) - -class P2P_Disconnect (threading.Thread): - # Needed Variables - global bus - global wpas_object - global interface_object - global p2p_interface - global interface_name - global wpas - global wpas_dbus_interface - global path - global timeout - - # Dbus Paths - global wpas_dbus_opath - global wpas_dbus_interfaces_opath - global wpas_dbus_interfaces_interface - global wpas_dbus_interfaces_p2pdevice - - # Constructor - def __init__(self,interface_name,wpas_dbus_interface,timeout): - # Initializes variables and threads - self.interface_name = interface_name - self.wpas_dbus_interface = wpas_dbus_interface - self.timeout = timeout - - # Initializes thread and daemon allows for ctrl-c kill - threading.Thread.__init__(self) - self.daemon = True - - # Generating interface/object paths - self.wpas_dbus_opath = "/" + \ - self.wpas_dbus_interface.replace(".","/") - self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ - "/Interfaces" - self.wpas_dbus_interfaces_interface = \ - self.wpas_dbus_interface + ".Interface" - self.wpas_dbus_interfaces_p2pdevice = \ - self.wpas_dbus_interfaces_interface \ - + ".P2PDevice" - - # Getting interfaces and objects - DBusGMainLoop(set_as_default=True) - self.bus = dbus.SystemBus() - self.wpas_object = self.bus.get_object( - self.wpas_dbus_interface, - self.wpas_dbus_opath) - self.wpas = dbus.Interface(self.wpas_object, - self.wpas_dbus_interface) - - # Try to see if supplicant knows about interface - # If not, throw an exception - try: - self.path = self.wpas.GetInterface( - self.interface_name) - except dbus.DBusException as exc: - error = 'Error:\n Interface ' + self.interface_name \ - + ' was not found' - print(error) - usage() - os._exit(0) - - self.interface_object = self.bus.get_object( - self.wpas_dbus_interface, self.path) - self.p2p_interface = dbus.Interface(self.interface_object, - self.wpas_dbus_interfaces_p2pdevice) - - # Signals - self.bus.add_signal_receiver(GroupFinished, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="GroupFinished") - - # Runs p2p_disconnect - def run(self): - # Allows other threads to keep working while MainLoop runs - # Required for timeout implementation - gobject.MainLoop().get_context().iteration(True) - gobject.threads_init() - self.p2p_interface.Disconnect() - gobject.MainLoop().run() - - -if __name__ == "__main__": - - timeout = 5 - # Defaults for optional inputs - wpas_dbus_interface = 'fi.w1.wpa_supplicant1' - - # interface_name is required - interface_name = None - - # Using getopts to handle options - try: - options, args = getopt.getopt(sys.argv[1:],"hi:w:") - - except getopt.GetoptError: - usage() - quit() - - # If there's a switch, override default option - for key, value in options: - # Help - if (key == "-h"): - usage() - quit() - # Interface Name - elif (key == "-i"): - interface_name = value - # Dbus interface - elif (key == "-w"): - wpas_dbus_interface = value - else: - assert False, "unhandled option" - - # Interface name is required and was not given - if (interface_name == None): - print("Error:\n interface_name is required") - usage() - quit() - - # Constructor - try: - p2p_disconnect_test = P2P_Disconnect(interface_name, - wpas_dbus_interface,timeout) - - except: - print("Error:\n Invalid wpas_dbus_interface") - usage() - quit() - - # Start P2P_Disconnect - p2p_disconnect_test.start() - - try: - time.sleep(int(p2p_disconnect_test.timeout)) - - except: - pass - - print("Disconnect timed out") - quit() +#!/usr/bin/python +# Tests P2P_Disconnect +# Will perform disconnect on interface_name +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import threading +import getopt +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print("Usage:") + print(" %s -i \ " \ + % sys.argv[0]) + print(" [-w ]") + print("Options:") + print(" -i = interface name") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i p2p-wlan0-0" % sys.argv[0]) + +# Required Signals +def GroupFinished(status, etc): + print("Disconnected") + os._exit(0) + +class P2P_Disconnect (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global timeout + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,timeout): + # Initializes variables and threads + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + self.timeout = timeout + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException as exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print(error) + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + # Signals + self.bus.add_signal_receiver(GroupFinished, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="GroupFinished") + + # Runs p2p_disconnect + def run(self): + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + self.p2p_interface.Disconnect() + gobject.MainLoop().run() + + +if __name__ == "__main__": + + timeout = 5 + # Defaults for optional inputs + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:w:") + + except getopt.GetoptError: + usage() + quit() + + # If there's a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print("Error:\n interface_name is required") + usage() + quit() + + # Constructor + try: + p2p_disconnect_test = P2P_Disconnect(interface_name, + wpas_dbus_interface,timeout) + + except: + print("Error:\n Invalid wpas_dbus_interface") + usage() + quit() + + # Start P2P_Disconnect + p2p_disconnect_test.start() + + try: + time.sleep(int(p2p_disconnect_test.timeout)) + + except: + pass + + print("Disconnect timed out") + quit() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_find.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_find.py index 412d8120031ac66cb1de701f86b2fc372acfd3d0..3b9162c78b96b6dd6a6ee81b280f7903408a8941 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_find.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_find.py @@ -1,192 +1,192 @@ -#!/usr/bin/python -# Tests p2p_find -# Will list all devices found/lost within a time frame (timeout) -# Then Program will exit -######### MAY NEED TO RUN AS SUDO ############# - -import dbus -import sys, os -import time -import gobject -import threading -import getopt -from dbus.mainloop.glib import DBusGMainLoop - -def usage(): - print("Usage:") - print(" %s -i [-t ] \ " \ - % sys.argv[0]) - print(" [-w ]") - print("Options:") - print(" -i = interface name") - print(" -t = timeout = 0s (infinite)") - print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") - print("Example:") - print(" %s -i wlan0 -t 10" % sys.argv[0]) - -# Required Signals -def deviceFound(devicepath): - print("Device found: %s" % (devicepath)) - -def deviceLost(devicepath): - print("Device lost: %s" % (devicepath)) - -class P2P_Find (threading.Thread): - # Needed Variables - global bus - global wpas_object - global interface_object - global p2p_interface - global interface_name - global wpas - global wpas_dbus_interface - global timeout - global path - - # Dbus Paths - global wpas_dbus_opath - global wpas_dbus_interfaces_opath - global wpas_dbus_interfaces_interface - global wpas_dbus_interfaces_p2pdevice - - # Constructor - def __init__(self,interface_name,wpas_dbus_interface,timeout): - # Initializes variables and threads - self.timeout = int(timeout) - self.interface_name = interface_name - self.wpas_dbus_interface = wpas_dbus_interface - - # Initializes thread and daemon allows for ctrl-c kill - threading.Thread.__init__(self) - self.daemon = True - - # Generating interface/object paths - self.wpas_dbus_opath = "/" + \ - self.wpas_dbus_interface.replace(".","/") - self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ - "/Interfaces" - self.wpas_dbus_interfaces_interface = \ - self.wpas_dbus_interface + ".Interface" - self.wpas_dbus_interfaces_p2pdevice = \ - self.wpas_dbus_interfaces_interface \ - + ".P2PDevice" - - # Getting interfaces and objects - DBusGMainLoop(set_as_default=True) - self.bus = dbus.SystemBus() - self.wpas_object = self.bus.get_object( - self.wpas_dbus_interface, - self.wpas_dbus_opath) - self.wpas = dbus.Interface(self.wpas_object, - self.wpas_dbus_interface) - - # Try to see if supplicant knows about interface - # If not, throw an exception - try: - self.path = self.wpas.GetInterface( - self.interface_name) - except dbus.DBusException as exc: - error = 'Error:\n Interface ' + self.interface_name \ - + ' was not found' - print(error) - usage() - os._exit(0) - - self.interface_object = self.bus.get_object( - self.wpas_dbus_interface, self.path) - self.p2p_interface = dbus.Interface(self.interface_object, - self.wpas_dbus_interfaces_p2pdevice) - - #Adds listeners for find and lost - self.bus.add_signal_receiver(deviceFound, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="DeviceFound") - self.bus.add_signal_receiver(deviceLost, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="DeviceLost") - - - # Sets up p2p_find - P2PFindDict = dbus.Dictionary( - {'Timeout':int(self.timeout)}) - self.p2p_interface.Find(P2PFindDict) - - # Run p2p_find - def run(self): - # Allows other threads to keep working while MainLoop runs - # Required for timeout implementation - gobject.MainLoop().get_context().iteration(True) - gobject.threads_init() - gobject.MainLoop().run() - -if __name__ == "__main__": - - # Defaults for optional inputs - timeout = 0 - wpas_dbus_interface = 'fi.w1.wpa_supplicant1' - - # interface_name is required - interface_name = None - - # Using getopts to handle options - try: - options, args = getopt.getopt(sys.argv[1:],"hi:t:w:") - - except getopt.GetoptError: - usage() - quit() - - # If there's a switch, override default option - for key, value in options: - # Help - if (key == "-h"): - usage() - quit() - # Interface Name - elif (key == "-i"): - interface_name = value - # Timeout - elif (key == "-t"): - if ( int(value) >= 0): - timeout = value - else: - print("Error:\n Timeout cannot be negative") - usage() - quit() - # Dbus interface - elif (key == "-w"): - wpas_dbus_interface = value - else: - assert False, "unhandled option" - - # Interface name is required and was not given - if (interface_name == None): - print("Error:\n interface_name is required") - usage() - quit() - - # Constructor - try: - p2p_find_test = P2P_Find(interface_name, wpas_dbus_interface, timeout) - - except: - print("Error:\n Invalid wpas_dbus_interface") - usage() - quit() - - # Start P2P_Find - p2p_find_test.start() - - try: - # If timeout is 0, then run forever - if (timeout == 0): - while(True): - pass - # Else sleep for (timeout) - else: - time.sleep(p2p_find_test.timeout) - - except: - pass - - quit() +#!/usr/bin/python +# Tests p2p_find +# Will list all devices found/lost within a time frame (timeout) +# Then Program will exit +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import threading +import getopt +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print("Usage:") + print(" %s -i [-t ] \ " \ + % sys.argv[0]) + print(" [-w ]") + print("Options:") + print(" -i = interface name") + print(" -t = timeout = 0s (infinite)") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0 -t 10" % sys.argv[0]) + +# Required Signals +def deviceFound(devicepath): + print("Device found: %s" % (devicepath)) + +def deviceLost(devicepath): + print("Device lost: %s" % (devicepath)) + +class P2P_Find (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global timeout + global path + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,timeout): + # Initializes variables and threads + self.timeout = int(timeout) + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException as exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print(error) + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + #Adds listeners for find and lost + self.bus.add_signal_receiver(deviceFound, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="DeviceFound") + self.bus.add_signal_receiver(deviceLost, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="DeviceLost") + + + # Sets up p2p_find + P2PFindDict = dbus.Dictionary( + {'Timeout':int(self.timeout)}) + self.p2p_interface.Find(P2PFindDict) + + # Run p2p_find + def run(self): + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + gobject.MainLoop().run() + +if __name__ == "__main__": + + # Defaults for optional inputs + timeout = 0 + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:t:w:") + + except getopt.GetoptError: + usage() + quit() + + # If there's a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Timeout + elif (key == "-t"): + if ( int(value) >= 0): + timeout = value + else: + print("Error:\n Timeout cannot be negative") + usage() + quit() + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print("Error:\n interface_name is required") + usage() + quit() + + # Constructor + try: + p2p_find_test = P2P_Find(interface_name, wpas_dbus_interface, timeout) + + except: + print("Error:\n Invalid wpas_dbus_interface") + usage() + quit() + + # Start P2P_Find + p2p_find_test.start() + + try: + # If timeout is 0, then run forever + if (timeout == 0): + while(True): + pass + # Else sleep for (timeout) + else: + time.sleep(p2p_find_test.timeout) + + except: + pass + + quit() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_flush.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_flush.py index 5cc3a0e18b236c8dcf2155b00c502133d2d6c755..03ac64e351e9aef90bde8ff7bd425fe7641f7cc6 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_flush.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_flush.py @@ -1,168 +1,168 @@ -#!/usr/bin/python -# Tests P2P_Flush -# Will flush the p2p interface -# Then Program will exit -######### MAY NEED TO RUN AS SUDO ############# - -import dbus -import sys, os -import time -import gobject -import threading -import getopt -from dbus.mainloop.glib import DBusGMainLoop - -def usage(): - print("Usage:") - print(" %s -i \ " \ - % sys.argv[0]) - print(" [-w ]") - print("Options:") - print(" -i = interface name") - print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") - print("Example:") - print(" %s -i wlan0" % sys.argv[0]) - -# Required Signals\ -def deviceLost(devicepath): - print("Device lost: %s" % (devicepath)) - -class P2P_Flush (threading.Thread): - # Needed Variables - global bus - global wpas_object - global interface_object - global p2p_interface - global interface_name - global wpas - global wpas_dbus_interface - global path - global timeout - - # Dbus Paths - global wpas_dbus_opath - global wpas_dbus_interfaces_opath - global wpas_dbus_interfaces_interface - global wpas_dbus_interfaces_p2pdevice - - # Constructor - def __init__(self,interface_name,wpas_dbus_interface,timeout): - # Initializes variables and threads - self.interface_name = interface_name - self.wpas_dbus_interface = wpas_dbus_interface - self.timeout = timeout - - # Initializes thread and daemon allows for ctrl-c kill - threading.Thread.__init__(self) - self.daemon = True - - # Generating interface/object paths - self.wpas_dbus_opath = "/" + \ - self.wpas_dbus_interface.replace(".","/") - self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ - "/Interfaces" - self.wpas_dbus_interfaces_interface = \ - self.wpas_dbus_interface + ".Interface" - self.wpas_dbus_interfaces_p2pdevice = \ - self.wpas_dbus_interfaces_interface \ - + ".P2PDevice" - - # Getting interfaces and objects - DBusGMainLoop(set_as_default=True) - self.bus = dbus.SystemBus() - self.wpas_object = self.bus.get_object( - self.wpas_dbus_interface, - self.wpas_dbus_opath) - self.wpas = dbus.Interface(self.wpas_object, - self.wpas_dbus_interface) - - # Try to see if supplicant knows about interface - # If not, throw an exception - try: - self.path = self.wpas.GetInterface( - self.interface_name) - except dbus.DBusException as exc: - error = 'Error:\n Interface ' + self.interface_name \ - + ' was not found' - print(error) - usage() - os._exit(0) - - self.interface_object = self.bus.get_object( - self.wpas_dbus_interface, self.path) - self.p2p_interface = dbus.Interface(self.interface_object, - self.wpas_dbus_interfaces_p2pdevice) - - # Signals - self.bus.add_signal_receiver(deviceLost, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="DeviceLost") - - # Runs p2p_flush - def run(self): - # Allows other threads to keep working while MainLoop runs - # Required for timeout implementation - gobject.MainLoop().get_context().iteration(True) - gobject.threads_init() - self.p2p_interface.Flush() - gobject.MainLoop().run() - - -if __name__ == "__main__": - # Needed to show which devices were lost - timeout = 5 - # Defaults for optional inputs - wpas_dbus_interface = 'fi.w1.wpa_supplicant1' - - # interface_name is required - interface_name = None - - # Using getopts to handle options - try: - options, args = getopt.getopt(sys.argv[1:],"hi:w:") - - except getopt.GetoptError: - usage() - quit() - - # If there's a switch, override default option - for key, value in options: - # Help - if (key == "-h"): - usage() - quit() - # Interface Name - elif (key == "-i"): - interface_name = value - # Dbus interface - elif (key == "-w"): - wpas_dbus_interface = value - else: - assert False, "unhandled option" - - # Interface name is required and was not given - if (interface_name == None): - print("Error:\n interface_name is required") - usage() - quit() - - # Constructor - try: - p2p_flush_test = P2P_Flush(interface_name, wpas_dbus_interface,timeout) - - except: - print("Error:\n Invalid wpas_dbus_interface") - usage() - quit() - - # Start P2P_Find - p2p_flush_test.start() - - try: - time.sleep(int(p2p_flush_test.timeout)) - - except: - pass - - print("p2p_flush complete") - quit() +#!/usr/bin/python +# Tests P2P_Flush +# Will flush the p2p interface +# Then Program will exit +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import threading +import getopt +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print("Usage:") + print(" %s -i \ " \ + % sys.argv[0]) + print(" [-w ]") + print("Options:") + print(" -i = interface name") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0" % sys.argv[0]) + +# Required Signals\ +def deviceLost(devicepath): + print("Device lost: %s" % (devicepath)) + +class P2P_Flush (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global timeout + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,timeout): + # Initializes variables and threads + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + self.timeout = timeout + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException as exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print(error) + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + # Signals + self.bus.add_signal_receiver(deviceLost, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="DeviceLost") + + # Runs p2p_flush + def run(self): + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + self.p2p_interface.Flush() + gobject.MainLoop().run() + + +if __name__ == "__main__": + # Needed to show which devices were lost + timeout = 5 + # Defaults for optional inputs + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:w:") + + except getopt.GetoptError: + usage() + quit() + + # If there's a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print("Error:\n interface_name is required") + usage() + quit() + + # Constructor + try: + p2p_flush_test = P2P_Flush(interface_name, wpas_dbus_interface,timeout) + + except: + print("Error:\n Invalid wpas_dbus_interface") + usage() + quit() + + # Start P2P_Find + p2p_flush_test.start() + + try: + time.sleep(int(p2p_flush_test.timeout)) + + except: + pass + + print("p2p_flush complete") + quit() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_group_add.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_group_add.py index db6d60d80c1b924edb65295429471d1677665a98..18ac1866bef82a4ac5306af01c0125d1ceac30dd 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_group_add.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_group_add.py @@ -1,222 +1,222 @@ -#!/usr/bin/python -# Tests p2p_group_add -######### MAY NEED TO RUN AS SUDO ############# - -import dbus -import sys, os -import time -import gobject -import getopt -import threading -from dbus.mainloop.glib import DBusGMainLoop - -def usage(): - print("Usage:") - print(" %s -i [-p ] \ " \ - % sys.argv[0]) - print(" [-f ] [-o ] \ ") - print(" [-w ]") - print("Options:") - print(" -i = interface name") - 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") - print("Example:") - print(" %s -i wlan0" % sys.argv[0]) - -# Required Signals -def GroupStarted(properties): - if properties.has_key("group_object"): - print('Group Formation Complete %s' \ - % properties["group_object"]) - os._exit(0) - -def WpsFailure(status, etc): - print("WPS Authentication Failure".format(status)) - print(etc) - os._exit(0) - -class P2P_Group_Add (threading.Thread): - # Needed Variables - global bus - global wpas_object - global interface_object - global p2p_interface - global interface_name - global wpas - global wpas_dbus_interface - global path - global persistent - global frequency - global persistent_group_object - - # Dbus Paths - global wpas_dbus_opath - global wpas_dbus_interfaces_opath - global wpas_dbus_interfaces_interface - global wpas_dbus_interfaces_p2pdevice - - # Arguments - global P2PDictionary - - # Constructor - def __init__(self,interface_name,wpas_dbus_interface,persistent,frequency, - persistent_group_object): - # Initializes variables and threads - self.interface_name = interface_name - self.wpas_dbus_interface = wpas_dbus_interface - self.persistent = persistent - self.frequency = frequency - self.persistent_group_object = persistent_group_object - - # Initializes thread and daemon allows for ctrl-c kill - threading.Thread.__init__(self) - self.daemon = True - - # Generating interface/object paths - self.wpas_dbus_opath = "/" + \ - self.wpas_dbus_interface.replace(".","/") - self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ - "/Interfaces" - self.wpas_dbus_interfaces_interface = \ - self.wpas_dbus_interface + ".Interface" - self.wpas_dbus_interfaces_p2pdevice = \ - self.wpas_dbus_interfaces_interface \ - + ".P2PDevice" - - # Getting interfaces and objects - DBusGMainLoop(set_as_default=True) - self.bus = dbus.SystemBus() - self.wpas_object = self.bus.get_object( - self.wpas_dbus_interface, - self.wpas_dbus_opath) - self.wpas = dbus.Interface(self.wpas_object, - self.wpas_dbus_interface) - - # Try to see if supplicant knows about interface - # If not, throw an exception - try: - self.path = self.wpas.GetInterface( - self.interface_name) - except dbus.DBusException as exc: - error = 'Error:\n Interface ' + self.interface_name \ - + ' was not found' - print(error) - usage() - os._exit(0) - - self.interface_object = self.bus.get_object( - self.wpas_dbus_interface, self.path) - self.p2p_interface = dbus.Interface(self.interface_object, - self.wpas_dbus_interfaces_p2pdevice) - - #Adds listeners - self.bus.add_signal_receiver(GroupStarted, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="GroupStarted") - self.bus.add_signal_receiver(WpsFailure, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="WpsFailed") - - # Sets up p2p_group_add dictionary - def constructArguments(self): - self.P2PDictionary = {'persistent':self.persistent} - - if (self.frequency != None): - if (int(self.frequency) > 0): - self.P2PDictionary.update({'frequency':int(self.frequency)}) - else: - print("Error:\n Frequency must be greater than 0") - usage() - os._exit(0) - - if (self.persistent_group_object != None): - self.P2PDictionary.update({'persistent_group_object': - self.persistent_group_object}) - - # Run p2p_group_remove - def run(self): - try: - self.p2p_interface.GroupAdd(self.P2PDictionary) - - except: - print("Error:\n Could not perform group add") - usage() - os._exit(0) - - # Allows other threads to keep working while MainLoop runs - # Required for timeout implementation - gobject.MainLoop().get_context().iteration(True) - gobject.threads_init() - gobject.MainLoop().run() - - -if __name__ == "__main__": - - # Defaults for optional inputs - # 0 = false, 1 = true - persistent = False - frequency = None - persistent_group_object = None - wpas_dbus_interface = 'fi.w1.wpa_supplicant1' - - # interface_name is required - interface_name = None - - # Using getopts to handle options - try: - options, args = getopt.getopt(sys.argv[1:],"hi:p:f:o:w:") - - except getopt.GetoptError: - usage() - quit() - - # If there's a switch, override default option - for key, value in options: - # Help - if (key == "-h"): - usage() - quit() - # Interface Name - elif (key == "-i"): - interface_name = value - # Timeout - elif (key == "-p"): - if (value == '0'): - persistent = False - elif (value == '1'): - persistent = True - else: - print("Error:\n Persistent can only be 1 or 0") - usage() - os._exit(0) - # Frequency - elif (key == "-f"): - frequency = value - # Persistent group object path - elif (key == "-o"): - persistent_group_object = value - # Dbus interface - elif (key == "-w"): - wpas_dbus_interface = value - else: - assert False, "unhandled option" - - # Interface name is required and was not given - if (interface_name == None): - print("Error:\n interface_name is required") - usage() - quit() - - try: - p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface, - persistent,frequency,persistent_group_object) - except: - print("Error:\n Invalid Arguments") - - p2p_group_add_test.constructArguments() - p2p_group_add_test.start() - time.sleep(5) - print("Error:\n Group formation timed out") - os._exit(0) +#!/usr/bin/python +# Tests p2p_group_add +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import getopt +import threading +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print("Usage:") + print(" %s -i [-p ] \ " \ + % sys.argv[0]) + print(" [-f ] [-o ] \ ") + print(" [-w ]") + print("Options:") + print(" -i = interface name") + 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") + print("Example:") + print(" %s -i wlan0" % sys.argv[0]) + +# Required Signals +def GroupStarted(properties): + if properties.has_key("group_object"): + print('Group Formation Complete %s' \ + % properties["group_object"]) + os._exit(0) + +def WpsFailure(status, etc): + print("WPS Authentication Failure".format(status)) + print(etc) + os._exit(0) + +class P2P_Group_Add (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global persistent + global frequency + global persistent_group_object + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Arguments + global P2PDictionary + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,persistent,frequency, + persistent_group_object): + # Initializes variables and threads + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + self.persistent = persistent + self.frequency = frequency + self.persistent_group_object = persistent_group_object + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException as exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print(error) + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + #Adds listeners + self.bus.add_signal_receiver(GroupStarted, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="GroupStarted") + self.bus.add_signal_receiver(WpsFailure, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="WpsFailed") + + # Sets up p2p_group_add dictionary + def constructArguments(self): + self.P2PDictionary = {'persistent':self.persistent} + + if (self.frequency != None): + if (int(self.frequency) > 0): + self.P2PDictionary.update({'frequency':int(self.frequency)}) + else: + print("Error:\n Frequency must be greater than 0") + usage() + os._exit(0) + + if (self.persistent_group_object != None): + self.P2PDictionary.update({'persistent_group_object': + self.persistent_group_object}) + + # Run p2p_group_remove + def run(self): + try: + self.p2p_interface.GroupAdd(self.P2PDictionary) + + except: + print("Error:\n Could not perform group add") + usage() + os._exit(0) + + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + gobject.MainLoop().run() + + +if __name__ == "__main__": + + # Defaults for optional inputs + # 0 = false, 1 = true + persistent = False + frequency = None + persistent_group_object = None + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:p:f:o:w:") + + except getopt.GetoptError: + usage() + quit() + + # If there's a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Timeout + elif (key == "-p"): + if (value == '0'): + persistent = False + elif (value == '1'): + persistent = True + else: + print("Error:\n Persistent can only be 1 or 0") + usage() + os._exit(0) + # Frequency + elif (key == "-f"): + frequency = value + # Persistent group object path + elif (key == "-o"): + persistent_group_object = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print("Error:\n interface_name is required") + usage() + quit() + + try: + p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface, + persistent,frequency,persistent_group_object) + except: + print("Error:\n Invalid Arguments") + + p2p_group_add_test.constructArguments() + p2p_group_add_test.start() + time.sleep(5) + print("Error:\n Group formation timed out") + os._exit(0) diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_invite.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_invite.py index 8944e11ed47c9c89a581f3bd66e32f957aa7b5cb..8ac31706fbcfa8322cc0cf7adec347d10a3120a9 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_invite.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_invite.py @@ -1,201 +1,201 @@ -#!/usr/bin/python -# Tests p2p_invite -######### MAY NEED TO RUN AS SUDO ############# - -import dbus -import sys, os -import time -import gobject -import getopt -import threading -from dbus.mainloop.glib import DBusGMainLoop - -def usage(): - print("Usage:") - print(" %s -i -a \ " \ - % sys.argv[0]) - print(" [-o ] [-w ]") - print("Options:") - print(" -i = interface name") - print(" -a = address of peer") - print(" -o = persistent group object path") - print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") - print("Example:") - print(" %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0]) - -# Required Signals -def InvitationResult(invite_result): - print("Invitation Result signal :") - status = invite_result['status'] - print("status = ", status) - if invite_result.has_key('BSSID'): - bssid = invite_result['BSSID'] - print("BSSID = ", hex(bssid[0]) , ":" , \ - hex(bssid[1]) , ":" , hex(bssid[2]) , ":", \ - hex(bssid[3]) , ":" , hex(bssid[4]) , ":" , \ - hex(bssid[5])) - os._exit(0) - -class P2P_Invite (threading.Thread): - # Needed Variables - global bus - global wpas_object - global interface_object - global p2p_interface - global interface_name - global wpas - global wpas_dbus_interface - global path - global addr - global persistent_group_object - - # Dbus Paths - global wpas_dbus_opath - global wpas_dbus_interfaces_opath - global wpas_dbus_interfaces_interface - global wpas_dbus_interfaces_p2pdevice - - # Arguments - global P2PDictionary - - # Constructor - def __init__(self,interface_name,wpas_dbus_interface,addr, - persistent_group_object): - # Initializes variables and threads - self.interface_name = interface_name - self.wpas_dbus_interface = wpas_dbus_interface - self.addr = addr - self.persistent_group_object = persistent_group_object - - # Initializes thread and daemon allows for ctrl-c kill - threading.Thread.__init__(self) - self.daemon = True - - # Generating interface/object paths - self.wpas_dbus_opath = "/" + \ - self.wpas_dbus_interface.replace(".","/") - self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ - "/Interfaces" - self.wpas_dbus_interfaces_interface = \ - self.wpas_dbus_interface + ".Interface" - self.wpas_dbus_interfaces_p2pdevice = \ - self.wpas_dbus_interfaces_interface \ - + ".P2PDevice" - - # Getting interfaces and objects - DBusGMainLoop(set_as_default=True) - self.bus = dbus.SystemBus() - self.wpas_object = self.bus.get_object( - self.wpas_dbus_interface, - self.wpas_dbus_opath) - self.wpas = dbus.Interface(self.wpas_object, - self.wpas_dbus_interface) - - # Try to see if supplicant knows about interface - # If not, throw an exception - try: - self.path = self.wpas.GetInterface( - self.interface_name) - except dbus.DBusException as exc: - error = 'Error:\n Interface ' + self.interface_name \ - + ' was not found' - print(error) - usage() - os._exit(0) - - self.interface_object = self.bus.get_object( - self.wpas_dbus_interface, self.path) - self.p2p_interface = dbus.Interface(self.interface_object, - self.wpas_dbus_interfaces_p2pdevice) - - #Adds listeners - self.bus.add_signal_receiver(InvitationResult, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="InvitationResult") - - # Sets up p2p_invite dictionary - def constructArguements(self): - self.P2PDictionary = \ - {'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)} - if (self.persistent_group_object != None): - self.P2PDictionary.update({"persistent_group_object": - self.persistent_group_object}) - - # Run p2p_invite - def run(self): - try: - self.p2p_interface.Invite(self.P2PDictionary) - - except: - print("Error:\n Invalid Arguments") - usage() - os._exit(0) - - # Allows other threads to keep working while MainLoop runs - # Required for timeout implementation - gobject.MainLoop().get_context().iteration(True) - gobject.threads_init() - gobject.MainLoop().run() - -if __name__ == "__main__": - # Defaults for optional inputs - addr = None - persistent_group_object = None - wpas_dbus_interface = 'fi.w1.wpa_supplicant1' - - # interface_name is required - interface_name = None - - # Using getopts to handle options - try: - options, args = getopt.getopt(sys.argv[1:],"hi:o:w:a:") - - except getopt.GetoptError: - usage() - quit() - - # If there's a switch, override default option - for key, value in options: - # Help - if (key == "-h"): - usage() - quit() - # Interface Name - elif (key == "-i"): - interface_name = value - elif (key == "-a"): - addr = value - # Persistent group object path - elif (key == "-o"): - persistent_group_object = value - # Dbus interface - elif (key == "-w"): - wpas_dbus_interface = value - else: - assert False, "unhandled option" - - # Interface name is required and was not given - if (interface_name == None): - print("Error:\n interface_name is required") - usage() - quit() - - if (addr == None): - print("Error:\n peer address is required") - usage() - quit() - - try: - p2p_invite_test = \ - P2P_Invite(interface_name,wpas_dbus_interface, - addr,persistent_group_object) - except: - print("Error:\n Invalid Arguments") - usage() - os._exit(1) - - p2p_invite_test.constructArguements() - p2p_invite_test.start() - time.sleep(10) - print("Error:\n p2p_invite timed out") - os._exit(0) +#!/usr/bin/python +# Tests p2p_invite +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import getopt +import threading +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print("Usage:") + print(" %s -i -a \ " \ + % sys.argv[0]) + print(" [-o ] [-w ]") + print("Options:") + print(" -i = interface name") + print(" -a = address of peer") + print(" -o = persistent group object path") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0]) + +# Required Signals +def InvitationResult(invite_result): + print("Invitation Result signal :") + status = invite_result['status'] + print("status = ", status) + if invite_result.has_key('BSSID'): + bssid = invite_result['BSSID'] + print("BSSID = ", hex(bssid[0]) , ":" , \ + hex(bssid[1]) , ":" , hex(bssid[2]) , ":", \ + hex(bssid[3]) , ":" , hex(bssid[4]) , ":" , \ + hex(bssid[5])) + os._exit(0) + +class P2P_Invite (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global addr + global persistent_group_object + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Arguments + global P2PDictionary + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,addr, + persistent_group_object): + # Initializes variables and threads + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + self.addr = addr + self.persistent_group_object = persistent_group_object + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException as exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print(error) + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + #Adds listeners + self.bus.add_signal_receiver(InvitationResult, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="InvitationResult") + + # Sets up p2p_invite dictionary + def constructArguements(self): + self.P2PDictionary = \ + {'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)} + if (self.persistent_group_object != None): + self.P2PDictionary.update({"persistent_group_object": + self.persistent_group_object}) + + # Run p2p_invite + def run(self): + try: + self.p2p_interface.Invite(self.P2PDictionary) + + except: + print("Error:\n Invalid Arguments") + usage() + os._exit(0) + + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + gobject.MainLoop().run() + +if __name__ == "__main__": + # Defaults for optional inputs + addr = None + persistent_group_object = None + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:o:w:a:") + + except getopt.GetoptError: + usage() + quit() + + # If there's a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + elif (key == "-a"): + addr = value + # Persistent group object path + elif (key == "-o"): + persistent_group_object = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print("Error:\n interface_name is required") + usage() + quit() + + if (addr == None): + print("Error:\n peer address is required") + usage() + quit() + + try: + p2p_invite_test = \ + P2P_Invite(interface_name,wpas_dbus_interface, + addr,persistent_group_object) + except: + print("Error:\n Invalid Arguments") + usage() + os._exit(1) + + p2p_invite_test.constructArguements() + p2p_invite_test.start() + time.sleep(10) + print("Error:\n p2p_invite timed out") + os._exit(0) diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_listen.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_listen.py index cbeda9ff43cad31ce36cf01f2d7b41d5ef54e5e2..46a47575ba4a00d4e1c028c2c2fbdcff5c1e74e5 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_listen.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_listen.py @@ -1,182 +1,182 @@ -#!/usr/bin/python -# Tests P2P_Find -# Will listen -# Then Program will exit -######### MAY NEED TO RUN AS SUDO ############# - -import dbus -import sys, os -import time -import gobject -import threading -import getopt -from dbus.mainloop.glib import DBusGMainLoop - -def usage(): - print("Usage:") - print(" %s -i [-t ] \ " \ - % sys.argv[0]) - print(" [-w ]") - print("Options:") - print(" -i = interface name") - print(" -t = timeout = 0s (infinite)") - print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") - print("Example:") - print(" %s -i wlan0 -t 5" % sys.argv[0]) - -# Required Signals -def p2pStateChange(status): - print(status) - -class P2P_Listen(threading.Thread): - # Needed Variables - global bus - global wpas_object - global interface_object - global p2p_interface - global interface_name - global wpas - global wpas_dbus_interface - global path - global timeout - - # Dbus Paths - global wpas_dbus_opath - global wpas_dbus_interfaces_opath - global wpas_dbus_interfaces_interface - global wpas_dbus_interfaces_p2pdevice - - # Constructor - def __init__(self,interface_name,wpas_dbus_interface,timeout): - # Initializes variables and threads - self.timeout = int(timeout) - self.interface_name = interface_name - self.wpas_dbus_interface = wpas_dbus_interface - - # Initializes thread and daemon allows for ctrl-c kill - threading.Thread.__init__(self) - self.daemon = True - - # Generating interface/object paths - self.wpas_dbus_opath = "/" + \ - self.wpas_dbus_interface.replace(".","/") - self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ - "/Interfaces" - self.wpas_dbus_interfaces_interface = \ - self.wpas_dbus_interface + ".Interface" - self.wpas_dbus_interfaces_p2pdevice = \ - self.wpas_dbus_interfaces_interface \ - + ".P2PDevice" - - # Getting interfaces and objects - DBusGMainLoop(set_as_default=True) - self.bus = dbus.SystemBus() - self.wpas_object = self.bus.get_object( - self.wpas_dbus_interface, - self.wpas_dbus_opath) - self.wpas = dbus.Interface(self.wpas_object, - self.wpas_dbus_interface) - - # Try to see if supplicant knows about interface - # If not, throw an exception - try: - self.path = self.wpas.GetInterface( - self.interface_name) - except dbus.DBusException as exc: - error = 'Error:\n Interface ' + self.interface_name \ - + ' was not found' - print(error) - usage() - os._exit(0) - - self.interface_object = self.bus.get_object( - self.wpas_dbus_interface, self.path) - self.p2p_interface = dbus.Interface(self.interface_object, - self.wpas_dbus_interfaces_p2pdevice) - - self.bus.add_signal_receiver(p2pStateChange, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="P2PStateChanged") - - # Run p2p_find - def run(self): - # Sets up p2p_listen - self.p2p_interface.Listen(int(self.timeout)) - - # Allows other threads to keep working while MainLoop runs - # Required for timeout implementation - gobject.MainLoop().get_context().iteration(True) - gobject.threads_init() - gobject.MainLoop().run() - -if __name__ == "__main__": - - # Defaults for optional inputs - timeout = 0 - wpas_dbus_interface = 'fi.w1.wpa_supplicant1' - - # interface_name is required - interface_name = None - - # Using getopts to handle options - try: - options, args = getopt.getopt(sys.argv[1:],"hi:t:w:") - - except getopt.GetoptError: - usage() - quit() - - # If there's a switch, override default option - for key, value in options: - # Help - if (key == "-h"): - usage() - quit() - # Interface Name - elif (key == "-i"): - interface_name = value - # Timeout - elif (key == "-t"): - if ( int(value) >= 0): - timeout = value - else: - print("Error:\n Timeout cannot be negative") - usage() - quit() - # Dbus interface - elif (key == "-w"): - wpas_dbus_interface = value - else: - assert False, "unhandled option" - - # Interface name is required and was not given - if (interface_name == None): - print("Error:\n interface_name is required") - usage() - quit() - - # Constructor - try: - p2p_listen_test = P2P_Listen(interface_name, wpas_dbus_interface, timeout) - - except: - print("Error:\n Invalid wpas_dbus_interface") - usage() - quit() - - # Start P2P_Find - p2p_listen_test.start() - - try: - # If timeout is 0, then run forever - if (int(p2p_listen_test.timeout) == 0): - while(True): - pass - # Else sleep for (timeout) - else: - time.sleep(int(p2p_listen_test.timeout)) - - except: - pass - - quit() +#!/usr/bin/python +# Tests P2P_Find +# Will listen +# Then Program will exit +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import threading +import getopt +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print("Usage:") + print(" %s -i [-t ] \ " \ + % sys.argv[0]) + print(" [-w ]") + print("Options:") + print(" -i = interface name") + print(" -t = timeout = 0s (infinite)") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0 -t 5" % sys.argv[0]) + +# Required Signals +def p2pStateChange(status): + print(status) + +class P2P_Listen(threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global timeout + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,timeout): + # Initializes variables and threads + self.timeout = int(timeout) + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException as exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print(error) + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + self.bus.add_signal_receiver(p2pStateChange, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="P2PStateChanged") + + # Run p2p_find + def run(self): + # Sets up p2p_listen + self.p2p_interface.Listen(int(self.timeout)) + + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + gobject.MainLoop().run() + +if __name__ == "__main__": + + # Defaults for optional inputs + timeout = 0 + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"hi:t:w:") + + except getopt.GetoptError: + usage() + quit() + + # If there's a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Timeout + elif (key == "-t"): + if ( int(value) >= 0): + timeout = value + else: + print("Error:\n Timeout cannot be negative") + usage() + quit() + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print("Error:\n interface_name is required") + usage() + quit() + + # Constructor + try: + p2p_listen_test = P2P_Listen(interface_name, wpas_dbus_interface, timeout) + + except: + print("Error:\n Invalid wpas_dbus_interface") + usage() + quit() + + # Start P2P_Find + p2p_listen_test.start() + + try: + # If timeout is 0, then run forever + if (int(p2p_listen_test.timeout) == 0): + while(True): + pass + # Else sleep for (timeout) + else: + time.sleep(int(p2p_listen_test.timeout)) + + except: + pass + + quit() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_stop_find.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_stop_find.py index f367196454d9a015cd118775c6eb46aa98e299d5..f70fb2ffc4d940fe45f67573f964b3667336bb59 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_stop_find.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/p2p/p2p_stop_find.py @@ -1,174 +1,174 @@ -#!/usr/bin/python -# Tests p2p_stop_find -######### MAY NEED TO RUN AS SUDO ############# - -import dbus -import sys, os -import time -import gobject -import threading -import getopt -from dbus.mainloop.glib import DBusGMainLoop - -def usage(): - print("Usage:") - print(" %s -i \ " \ - % sys.argv[0]) - print(" [-w ]") - print("Options:") - print(" -i = interface name") - print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") - print("Example:") - print(" %s -i wlan0" % sys.argv[0]) - -# Required Signals -def deviceLost(devicepath): - print("Device lost: %s" % (devicepath)) - -def p2pStateChange(status): - print(status) - os._exit(0) - -class P2P_Stop_Find (threading.Thread): - # Needed Variables - global bus - global wpas_object - global interface_object - global p2p_interface - global interface_name - global wpas - global wpas_dbus_interface - global path - global timeout - - # Dbus Paths - global wpas_dbus_opath - global wpas_dbus_interfaces_opath - global wpas_dbus_interfaces_interface - global wpas_dbus_interfaces_p2pdevice - - # Constructor - def __init__(self,interface_name,wpas_dbus_interface,timeout): - # Initializes variables and threads - self.interface_name = interface_name - self.wpas_dbus_interface = wpas_dbus_interface - self.timeout = timeout - - # Initializes thread and daemon allows for ctrl-c kill - threading.Thread.__init__(self) - self.daemon = True - - # Generating interface/object paths - self.wpas_dbus_opath = "/" + \ - self.wpas_dbus_interface.replace(".","/") - self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ - "/Interfaces" - self.wpas_dbus_interfaces_interface = \ - self.wpas_dbus_interface + ".Interface" - self.wpas_dbus_interfaces_p2pdevice = \ - self.wpas_dbus_interfaces_interface \ - + ".P2PDevice" - - # Getting interfaces and objects - DBusGMainLoop(set_as_default=True) - self.bus = dbus.SystemBus() - self.wpas_object = self.bus.get_object( - self.wpas_dbus_interface, - self.wpas_dbus_opath) - self.wpas = dbus.Interface(self.wpas_object, - self.wpas_dbus_interface) - - # Try to see if supplicant knows about interface - # If not, throw an exception - try: - self.path = self.wpas.GetInterface( - self.interface_name) - except dbus.DBusException as exc: - error = 'Error:\n Interface ' + self.interface_name \ - + ' was not found' - print(error) - usage() - os._exit(0) - - self.interface_object = self.bus.get_object( - self.wpas_dbus_interface, self.path) - self.p2p_interface = dbus.Interface(self.interface_object, - self.wpas_dbus_interfaces_p2pdevice) - - # Signals - self.bus.add_signal_receiver(deviceLost, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="DeviceLost") - self.bus.add_signal_receiver(p2pStateChange, - dbus_interface=self.wpas_dbus_interfaces_p2pdevice, - signal_name="P2PStateChanged") - - # Runs p2p_stop_find - def run(self): - # Allows other threads to keep working while MainLoop runs - # Required for timeout implementation - gobject.MainLoop().get_context().iteration(True) - gobject.threads_init() - self.p2p_interface.StopFind() - gobject.MainLoop().run() - - -if __name__ == "__main__": - # Needed because P2PStateChanged signal is not caught - timeout = 5 - # Defaults for optional inputs - wpas_dbus_interface = 'fi.w1.wpa_supplicant1' - - # interface_name is required - interface_name = None - - # Using getopts to handle options - try: - options, args = getopt.getopt(sys.argv[1:],"ht:i:w:") - - except getopt.GetoptError: - usage() - quit() - - # If there's a switch, override default option - for key, value in options: - # Help - if (key == "-h"): - usage() - quit() - # Interface Name - elif (key == "-i"): - interface_name = value - # Dbus interface - elif (key == "-w"): - wpas_dbus_interface = value - else: - assert False, "unhandled option" - - # Interface name is required and was not given - if (interface_name == None): - print("Error:\n interface_name is required") - usage() - quit() - - # Constructor - try: - p2p_stop_find_test = P2P_Stop_Find(interface_name, - wpas_dbus_interface,timeout) - - except: - print("Error:\n Invalid wpas_dbus_interface") - usage() - quit() - - # Start P2P_Find - p2p_stop_find_test.start() - - try: - time.sleep(int(p2p_stop_find_test.timeout)) - - except: - pass - - print("p2p find stopped") - quit() +#!/usr/bin/python +# Tests p2p_stop_find +######### MAY NEED TO RUN AS SUDO ############# + +import dbus +import sys, os +import time +import gobject +import threading +import getopt +from dbus.mainloop.glib import DBusGMainLoop + +def usage(): + print("Usage:") + print(" %s -i \ " \ + % sys.argv[0]) + print(" [-w ]") + print("Options:") + print(" -i = interface name") + print(" -w = wpas dbus interface = fi.w1.wpa_supplicant1") + print("Example:") + print(" %s -i wlan0" % sys.argv[0]) + +# Required Signals +def deviceLost(devicepath): + print("Device lost: %s" % (devicepath)) + +def p2pStateChange(status): + print(status) + os._exit(0) + +class P2P_Stop_Find (threading.Thread): + # Needed Variables + global bus + global wpas_object + global interface_object + global p2p_interface + global interface_name + global wpas + global wpas_dbus_interface + global path + global timeout + + # Dbus Paths + global wpas_dbus_opath + global wpas_dbus_interfaces_opath + global wpas_dbus_interfaces_interface + global wpas_dbus_interfaces_p2pdevice + + # Constructor + def __init__(self,interface_name,wpas_dbus_interface,timeout): + # Initializes variables and threads + self.interface_name = interface_name + self.wpas_dbus_interface = wpas_dbus_interface + self.timeout = timeout + + # Initializes thread and daemon allows for ctrl-c kill + threading.Thread.__init__(self) + self.daemon = True + + # Generating interface/object paths + self.wpas_dbus_opath = "/" + \ + self.wpas_dbus_interface.replace(".","/") + self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \ + "/Interfaces" + self.wpas_dbus_interfaces_interface = \ + self.wpas_dbus_interface + ".Interface" + self.wpas_dbus_interfaces_p2pdevice = \ + self.wpas_dbus_interfaces_interface \ + + ".P2PDevice" + + # Getting interfaces and objects + DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.wpas_object = self.bus.get_object( + self.wpas_dbus_interface, + self.wpas_dbus_opath) + self.wpas = dbus.Interface(self.wpas_object, + self.wpas_dbus_interface) + + # Try to see if supplicant knows about interface + # If not, throw an exception + try: + self.path = self.wpas.GetInterface( + self.interface_name) + except dbus.DBusException as exc: + error = 'Error:\n Interface ' + self.interface_name \ + + ' was not found' + print(error) + usage() + os._exit(0) + + self.interface_object = self.bus.get_object( + self.wpas_dbus_interface, self.path) + self.p2p_interface = dbus.Interface(self.interface_object, + self.wpas_dbus_interfaces_p2pdevice) + + # Signals + self.bus.add_signal_receiver(deviceLost, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="DeviceLost") + self.bus.add_signal_receiver(p2pStateChange, + dbus_interface=self.wpas_dbus_interfaces_p2pdevice, + signal_name="P2PStateChanged") + + # Runs p2p_stop_find + def run(self): + # Allows other threads to keep working while MainLoop runs + # Required for timeout implementation + gobject.MainLoop().get_context().iteration(True) + gobject.threads_init() + self.p2p_interface.StopFind() + gobject.MainLoop().run() + + +if __name__ == "__main__": + # Needed because P2PStateChanged signal is not caught + timeout = 5 + # Defaults for optional inputs + wpas_dbus_interface = 'fi.w1.wpa_supplicant1' + + # interface_name is required + interface_name = None + + # Using getopts to handle options + try: + options, args = getopt.getopt(sys.argv[1:],"ht:i:w:") + + except getopt.GetoptError: + usage() + quit() + + # If there's a switch, override default option + for key, value in options: + # Help + if (key == "-h"): + usage() + quit() + # Interface Name + elif (key == "-i"): + interface_name = value + # Dbus interface + elif (key == "-w"): + wpas_dbus_interface = value + else: + assert False, "unhandled option" + + # Interface name is required and was not given + if (interface_name == None): + print("Error:\n interface_name is required") + usage() + quit() + + # Constructor + try: + p2p_stop_find_test = P2P_Stop_Find(interface_name, + wpas_dbus_interface,timeout) + + except: + print("Error:\n Invalid wpas_dbus_interface") + usage() + quit() + + # Start P2P_Find + p2p_stop_find_test.start() + + try: + time.sleep(int(p2p_stop_find_test.timeout)) + + except: + pass + + print("p2p find stopped") + quit() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/plaintext.conf b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/plaintext.conf index 542ac1dd3b96abc9b47d07d64ced0963d66795be..089268563aa55cb337e5ee92bf62527fd85a8f69 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/plaintext.conf +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/plaintext.conf @@ -1,8 +1,8 @@ -# Plaintext (no encryption) network - -ctrl_interface=/var/run/wpa_supplicant - -network={ - ssid="example open network" - key_mgmt=NONE -} +# Plaintext (no encryption) network + +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="example open network" + key_mgmt=NONE +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/udhcpd-p2p.conf b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/udhcpd-p2p.conf index f92cc619e96282c62a512ccf14d4686fac81cab0..0cac900c49d31351ae0fbf72c6dd9d209f3c2402 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/udhcpd-p2p.conf +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/udhcpd-p2p.conf @@ -1,118 +1,118 @@ -# Sample udhcpd configuration file (/etc/udhcpd.conf) - -# The start and end of the IP lease block - -start 192.168.42.20 #default: 192.168.0.20 -end 192.168.42.254 #default: 192.168.0.254 - - -# The interface that udhcpd will use - -interface wlan2 #default: eth0 - - -# The maximum number of leases (includes addresses reserved -# by OFFER's, DECLINE's, and ARP conflicts) - -#max_leases 254 #default: 254 - - -# If remaining is true (default), udhcpd will store the time -# remaining for each lease in the udhcpd leases file. This is -# for embedded systems that cannot keep time between reboots. -# If you set remaining to no, the absolute time that the lease -# expires at will be stored in the dhcpd.leases file. - -#remaining yes #default: yes - - -# The time period at which udhcpd will write out a dhcpd.leases -# file. If this is 0, udhcpd will never automatically write a -# lease file. (specified in seconds) - -#auto_time 7200 #default: 7200 (2 hours) - - -# The amount of time that an IP will be reserved (leased) for if a -# DHCP decline message is received (seconds). - -#decline_time 3600 #default: 3600 (1 hour) - - -# The amount of time that an IP will be reserved (leased) for if an -# ARP conflct occurs. (seconds - -#conflict_time 3600 #default: 3600 (1 hour) - - -# How long an offered address is reserved (leased) in seconds - -#offer_time 60 #default: 60 (1 minute) - -# If a lease to be given is below this value, the full lease time is -# instead used (seconds). - -#min_lease 60 #default: 60 - - -# The location of the leases file - -#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 - -# Every time udhcpd writes a leases file, the below script will be called. -# Useful for writing the lease file to flash every few hours. - -#notify_file #default: (no script) - -#notify_file dumpleases # <--- useful for debugging - -# The following are bootp specific options, setable by udhcpd. - -#siaddr 192.168.0.22 #default: 0.0.0.0 - -#sname zorak #default: (none) - -#boot_file /var/nfs_root #default: (none) - -# 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'. - -#Examles -opt dns 192.168.2.1 -option subnet 255.255.255.0 -option domain atherosowl.com -option lease 864000 # 10 days of seconds - - -# Currently supported options, for more info, see options.c -#opt subnet -#opt timezone -#opt router -#opt timesvr -#opt namesvr -#opt dns -#opt logsvr -#opt cookiesvr -#opt lprsvr -#opt bootsize -#opt domain -#opt swapsvr -#opt rootpath -#opt ipttl -#opt mtu -#opt broadcast -#opt wins -#opt lease -#opt ntpsrv -#opt tftp -#opt bootfile - - -# 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 +# Sample udhcpd configuration file (/etc/udhcpd.conf) + +# The start and end of the IP lease block + +start 192.168.42.20 #default: 192.168.0.20 +end 192.168.42.254 #default: 192.168.0.254 + + +# The interface that udhcpd will use + +interface wlan2 #default: eth0 + + +# The maximum number of leases (includes addresses reserved +# by OFFER's, DECLINE's, and ARP conflicts) + +#max_leases 254 #default: 254 + + +# If remaining is true (default), udhcpd will store the time +# remaining for each lease in the udhcpd leases file. This is +# for embedded systems that cannot keep time between reboots. +# If you set remaining to no, the absolute time that the lease +# expires at will be stored in the dhcpd.leases file. + +#remaining yes #default: yes + + +# The time period at which udhcpd will write out a dhcpd.leases +# file. If this is 0, udhcpd will never automatically write a +# lease file. (specified in seconds) + +#auto_time 7200 #default: 7200 (2 hours) + + +# The amount of time that an IP will be reserved (leased) for if a +# DHCP decline message is received (seconds). + +#decline_time 3600 #default: 3600 (1 hour) + + +# The amount of time that an IP will be reserved (leased) for if an +# ARP conflct occurs. (seconds + +#conflict_time 3600 #default: 3600 (1 hour) + + +# How long an offered address is reserved (leased) in seconds + +#offer_time 60 #default: 60 (1 minute) + +# If a lease to be given is below this value, the full lease time is +# instead used (seconds). + +#min_lease 60 #default: 60 + + +# The location of the leases file + +#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 + +# Every time udhcpd writes a leases file, the below script will be called. +# Useful for writing the lease file to flash every few hours. + +#notify_file #default: (no script) + +#notify_file dumpleases # <--- useful for debugging + +# The following are bootp specific options, setable by udhcpd. + +#siaddr 192.168.0.22 #default: 0.0.0.0 + +#sname zorak #default: (none) + +#boot_file /var/nfs_root #default: (none) + +# 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'. + +#Examles +opt dns 192.168.2.1 +option subnet 255.255.255.0 +option domain atherosowl.com +option lease 864000 # 10 days of seconds + + +# Currently supported options, for more info, see options.c +#opt subnet +#opt timezone +#opt router +#opt timesvr +#opt namesvr +#opt dns +#opt logsvr +#opt cookiesvr +#opt lprsvr +#opt bootsize +#opt domain +#opt swapsvr +#opt rootpath +#opt ipttl +#opt mtu +#opt broadcast +#opt wins +#opt lease +#opt ntpsrv +#opt tftp +#opt bootfile + + +# 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-2.9_standard/wpa_supplicant/examples/wep.conf b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wep.conf index 9c7b55f2722a262574937dee262de19e2dbdfe77..4d3e8a10f6e9046617911d9b08df28ebffbce7ed 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wep.conf +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wep.conf @@ -1,11 +1,11 @@ -# Static WEP keys - -ctrl_interface=/var/run/wpa_supplicant - -network={ - ssid="example wep network" - key_mgmt=NONE - wep_key0="abcde" - wep_key1=0102030405 - wep_tx_keyidx=0 -} +# Static WEP keys + +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="example wep network" + key_mgmt=NONE + wep_key0="abcde" + wep_key1=0102030405 + wep_tx_keyidx=0 +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpa-psk-tkip.conf b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpa-psk-tkip.conf index 93d7fc2444ea4aed887c511d7ea1a6ae3c70fb8a..d670627b5d56a1f9070e9a4d8ae64d80b0597c8b 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpa-psk-tkip.conf +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpa-psk-tkip.conf @@ -1,12 +1,12 @@ -# WPA-PSK/TKIP - -ctrl_interface=/var/run/wpa_supplicant - -network={ - ssid="example wpa-psk network" - key_mgmt=WPA-PSK - proto=WPA - pairwise=TKIP - group=TKIP - psk="secret passphrase" -} +# WPA-PSK/TKIP + +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="example wpa-psk network" + key_mgmt=WPA-PSK + proto=WPA + pairwise=TKIP + group=TKIP + psk="secret passphrase" +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpa2-eap-ccmp.conf b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpa2-eap-ccmp.conf index d7a64d87b2547ccb7eeffacb5f0679bef4ac0a4f..f0410a198ed680ab20b4ace952347f0c0748fc80 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpa2-eap-ccmp.conf +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpa2-eap-ccmp.conf @@ -1,15 +1,15 @@ -# WPA2-EAP/CCMP using EAP-TLS - -ctrl_interface=/var/run/wpa_supplicant - -network={ - ssid="example wpa2-eap network" - key_mgmt=WPA-EAP - proto=WPA2 - pairwise=CCMP - group=CCMP - eap=TLS - ca_cert="/etc/cert/ca.pem" - private_key="/etc/cert/user.p12" - private_key_passwd="PKCS#12 passhrase" -} +# WPA2-EAP/CCMP using EAP-TLS + +ctrl_interface=/var/run/wpa_supplicant + +network={ + ssid="example wpa2-eap network" + key_mgmt=WPA-EAP + proto=WPA2 + pairwise=CCMP + group=CCMP + eap=TLS + ca_cert="/etc/cert/ca.pem" + private_key="/etc/cert/user.p12" + private_key_passwd="PKCS#12 passhrase" +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-getall.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-getall.py index 732f54d20f8b826f4c08cfaebc46484d4e0b55a5..9b6dcdb6c2790fa9d7ad71be8b3481209eab45f4 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-getall.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-getall.py @@ -1,58 +1,58 @@ -#!/usr/bin/python - -import dbus -import sys, os -import time -import gobject - -def main(): - bus = dbus.SystemBus() - wpas_obj = bus.get_object("fi.w1.wpa_supplicant1", - "/fi/w1/wpa_supplicant1") - props = wpas_obj.GetAll("fi.w1.wpa_supplicant1", - dbus_interface=dbus.PROPERTIES_IFACE) - print("GetAll(fi.w1.wpa_supplicant1, /fi/w1/wpa_supplicant1):") - print(props) - - if len(sys.argv) != 2: - os._exit(1) - - ifname = sys.argv[1] - - wpas = dbus.Interface(wpas_obj, "fi.w1.wpa_supplicant1") - path = wpas.GetInterface(ifname) - if_obj = bus.get_object("fi.w1.wpa_supplicant1", path) - props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface", - dbus_interface=dbus.PROPERTIES_IFACE) - print('') - print("GetAll(fi.w1.wpa_supplicant1.Interface, %s):" % (path)) - print(props) - - props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface.WPS", - dbus_interface=dbus.PROPERTIES_IFACE) - print('') - print("GetAll(fi.w1.wpa_supplicant1.Interface.WPS, %s):" % (path)) - print(props) - - res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'BSSs', - dbus_interface=dbus.PROPERTIES_IFACE) - if len(res) > 0: - bss_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0]) - props = bss_obj.GetAll("fi.w1.wpa_supplicant1.BSS", - dbus_interface=dbus.PROPERTIES_IFACE) - print('') - print("GetAll(fi.w1.wpa_supplicant1.BSS, %s):" % (res[0])) - print(props) - - res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'Networks', - dbus_interface=dbus.PROPERTIES_IFACE) - if len(res) > 0: - net_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0]) - props = net_obj.GetAll("fi.w1.wpa_supplicant1.Network", - dbus_interface=dbus.PROPERTIES_IFACE) - print('') - print("GetAll(fi.w1.wpa_supplicant1.Network, %s):" % (res[0])) - print(props) - -if __name__ == "__main__": - main() +#!/usr/bin/python + +import dbus +import sys, os +import time +import gobject + +def main(): + bus = dbus.SystemBus() + wpas_obj = bus.get_object("fi.w1.wpa_supplicant1", + "/fi/w1/wpa_supplicant1") + props = wpas_obj.GetAll("fi.w1.wpa_supplicant1", + dbus_interface=dbus.PROPERTIES_IFACE) + print("GetAll(fi.w1.wpa_supplicant1, /fi/w1/wpa_supplicant1):") + print(props) + + if len(sys.argv) != 2: + os._exit(1) + + ifname = sys.argv[1] + + wpas = dbus.Interface(wpas_obj, "fi.w1.wpa_supplicant1") + path = wpas.GetInterface(ifname) + if_obj = bus.get_object("fi.w1.wpa_supplicant1", path) + props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface", + dbus_interface=dbus.PROPERTIES_IFACE) + print('') + print("GetAll(fi.w1.wpa_supplicant1.Interface, %s):" % (path)) + print(props) + + props = if_obj.GetAll("fi.w1.wpa_supplicant1.Interface.WPS", + dbus_interface=dbus.PROPERTIES_IFACE) + print('') + print("GetAll(fi.w1.wpa_supplicant1.Interface.WPS, %s):" % (path)) + print(props) + + res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'BSSs', + dbus_interface=dbus.PROPERTIES_IFACE) + if len(res) > 0: + bss_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0]) + props = bss_obj.GetAll("fi.w1.wpa_supplicant1.BSS", + dbus_interface=dbus.PROPERTIES_IFACE) + print('') + print("GetAll(fi.w1.wpa_supplicant1.BSS, %s):" % (res[0])) + print(props) + + res = if_obj.Get("fi.w1.wpa_supplicant1.Interface", 'Networks', + dbus_interface=dbus.PROPERTIES_IFACE) + if len(res) > 0: + net_obj = bus.get_object("fi.w1.wpa_supplicant1", res[0]) + props = net_obj.GetAll("fi.w1.wpa_supplicant1.Network", + dbus_interface=dbus.PROPERTIES_IFACE) + print('') + print("GetAll(fi.w1.wpa_supplicant1.Network, %s):" % (res[0])) + print(props) + +if __name__ == "__main__": + main() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-signals.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-signals.py index 366a65546af63d4215f6325b6e52f7559d041e42..180d3b294f0a4c9bb74ace30692bd577bc1ae43a 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-signals.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-signals.py @@ -1,203 +1,203 @@ -#!/usr/bin/python - -import dbus -import sys, os -import time -import gobject -from dbus.mainloop.glib import DBusGMainLoop - -WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1" -WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1" -WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1" - -WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface" -WPAS_DBUS_INTERFACES_OPATH = "/fi/w1/wpa_supplicant1/Interfaces" -WPAS_DBUS_BSS_INTERFACE = "fi.w1.wpa_supplicant1.BSS" -WPAS_DBUS_NETWORK_INTERFACE = "fi.w1.wpa_supplicant1.Network" - -def byte_array_to_string(s): - import urllib - r = "" - for c in s: - if c >= 32 and c < 127: - r += "%c" % c - else: - r += urllib.quote(chr(c)) - return r - -def list_interfaces(wpas_obj): - ifaces = wpas_obj.Get(WPAS_DBUS_INTERFACE, 'Interfaces', - dbus_interface=dbus.PROPERTIES_IFACE) - for path in ifaces: - if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) - ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname', - dbus_interface=dbus.PROPERTIES_IFACE) - print(ifname) - -def interfaceAdded(interface, properties): - print("InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname'])) - -def interfaceRemoved(interface): - print("InterfaceRemoved(%s)" % (interface)) - -def propertiesChanged(properties): - for i in properties: - print("PropertiesChanged: %s=%s" % (i, properties[i])) - -def showBss(bss): - net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss) - net = dbus.Interface(net_obj, WPAS_DBUS_BSS_INTERFACE) - - # Convert the byte-array for SSID and BSSID to printable strings - val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'BSSID', - dbus_interface=dbus.PROPERTIES_IFACE) - bssid = "" - for item in val: - bssid = bssid + ":%02x" % item - bssid = bssid[1:] - val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'SSID', - dbus_interface=dbus.PROPERTIES_IFACE) - ssid = byte_array_to_string(val) - - val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'WPA', - dbus_interface=dbus.PROPERTIES_IFACE) - wpa = "no" - if val != None: - wpa = "yes" - val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'RSN', - dbus_interface=dbus.PROPERTIES_IFACE) - wpa2 = "no" - if val != None: - wpa2 = "yes" - freq = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Frequency', - dbus_interface=dbus.PROPERTIES_IFACE) - signal = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Signal', - dbus_interface=dbus.PROPERTIES_IFACE) - val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Rates', - dbus_interface=dbus.PROPERTIES_IFACE) - if len(val) > 0: - maxrate = val[0] / 1000000 - else: - maxrate = 0 - - print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)) - -def scanDone(success): - gobject.MainLoop().quit() - print("Scan done: success=%s" % success) - -def scanDone2(success, path=None): - print("Scan done: success=%s [path=%s]" % (success, path)) - -def bssAdded(bss, properties): - print("BSS added: %s" % (bss)) - showBss(bss) - -def bssRemoved(bss): - print("BSS removed: %s" % (bss)) - -def blobAdded(blob): - print("BlobAdded(%s)" % (blob)) - -def blobRemoved(blob): - print("BlobRemoved(%s)" % (blob)) - -def networkAdded(network, properties): - print("NetworkAdded(%s)" % (network)) - -def networkRemoved(network): - print("NetworkRemoved(%s)" % (network)) - -def networkSelected(network): - print("NetworkSelected(%s)" % (network)) - -def propertiesChangedInterface(properties): - for i in properties: - print("PropertiesChanged(interface): %s=%s" % (i, properties[i])) - -def propertiesChangedBss(properties): - for i in properties: - print("PropertiesChanged(BSS): %s=%s" % (i, properties[i])) - -def propertiesChangedNetwork(properties): - for i in properties: - print("PropertiesChanged(Network): %s=%s" % (i, properties[i])) - -def main(): - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - global bus - bus = dbus.SystemBus() - wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) - - if len(sys.argv) != 2: - list_interfaces(wpas_obj) - os._exit(1) - - wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) - bus.add_signal_receiver(interfaceAdded, - dbus_interface=WPAS_DBUS_INTERFACE, - signal_name="InterfaceAdded") - bus.add_signal_receiver(interfaceRemoved, - dbus_interface=WPAS_DBUS_INTERFACE, - signal_name="InterfaceRemoved") - bus.add_signal_receiver(propertiesChanged, - dbus_interface=WPAS_DBUS_INTERFACE, - signal_name="PropertiesChanged") - - ifname = sys.argv[1] - path = wpas.GetInterface(ifname) - if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) - iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE) - iface.connect_to_signal("ScanDone", scanDone2, - path_keyword='path') - - bus.add_signal_receiver(scanDone, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="ScanDone", - path=path) - bus.add_signal_receiver(bssAdded, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="BSSAdded", - path=path) - bus.add_signal_receiver(bssRemoved, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="BSSRemoved", - path=path) - bus.add_signal_receiver(blobAdded, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="BlobAdded", - path=path) - bus.add_signal_receiver(blobRemoved, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="BlobRemoved", - path=path) - bus.add_signal_receiver(networkAdded, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="NetworkAdded", - path=path) - bus.add_signal_receiver(networkRemoved, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="NetworkRemoved", - path=path) - bus.add_signal_receiver(networkSelected, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="NetworkSelected", - path=path) - bus.add_signal_receiver(propertiesChangedInterface, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="PropertiesChanged", - path=path) - - bus.add_signal_receiver(propertiesChangedBss, - dbus_interface=WPAS_DBUS_BSS_INTERFACE, - signal_name="PropertiesChanged") - - bus.add_signal_receiver(propertiesChangedNetwork, - dbus_interface=WPAS_DBUS_NETWORK_INTERFACE, - signal_name="PropertiesChanged") - - gobject.MainLoop().run() - -if __name__ == "__main__": - main() - +#!/usr/bin/python + +import dbus +import sys, os +import time +import gobject +from dbus.mainloop.glib import DBusGMainLoop + +WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1" +WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1" +WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1" + +WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface" +WPAS_DBUS_INTERFACES_OPATH = "/fi/w1/wpa_supplicant1/Interfaces" +WPAS_DBUS_BSS_INTERFACE = "fi.w1.wpa_supplicant1.BSS" +WPAS_DBUS_NETWORK_INTERFACE = "fi.w1.wpa_supplicant1.Network" + +def byte_array_to_string(s): + import urllib + r = "" + for c in s: + if c >= 32 and c < 127: + r += "%c" % c + else: + r += urllib.quote(chr(c)) + return r + +def list_interfaces(wpas_obj): + ifaces = wpas_obj.Get(WPAS_DBUS_INTERFACE, 'Interfaces', + dbus_interface=dbus.PROPERTIES_IFACE) + for path in ifaces: + if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) + ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname', + dbus_interface=dbus.PROPERTIES_IFACE) + print(ifname) + +def interfaceAdded(interface, properties): + print("InterfaceAdded(%s): Ifname=%s" % (interface, properties['Ifname'])) + +def interfaceRemoved(interface): + print("InterfaceRemoved(%s)" % (interface)) + +def propertiesChanged(properties): + for i in properties: + print("PropertiesChanged: %s=%s" % (i, properties[i])) + +def showBss(bss): + net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss) + net = dbus.Interface(net_obj, WPAS_DBUS_BSS_INTERFACE) + + # Convert the byte-array for SSID and BSSID to printable strings + val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'BSSID', + dbus_interface=dbus.PROPERTIES_IFACE) + bssid = "" + for item in val: + bssid = bssid + ":%02x" % item + bssid = bssid[1:] + val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'SSID', + dbus_interface=dbus.PROPERTIES_IFACE) + ssid = byte_array_to_string(val) + + val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'WPA', + dbus_interface=dbus.PROPERTIES_IFACE) + wpa = "no" + if val != None: + wpa = "yes" + val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'RSN', + dbus_interface=dbus.PROPERTIES_IFACE) + wpa2 = "no" + if val != None: + wpa2 = "yes" + freq = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Frequency', + dbus_interface=dbus.PROPERTIES_IFACE) + signal = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Signal', + dbus_interface=dbus.PROPERTIES_IFACE) + val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Rates', + dbus_interface=dbus.PROPERTIES_IFACE) + if len(val) > 0: + maxrate = val[0] / 1000000 + else: + maxrate = 0 + + print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)) + +def scanDone(success): + gobject.MainLoop().quit() + print("Scan done: success=%s" % success) + +def scanDone2(success, path=None): + print("Scan done: success=%s [path=%s]" % (success, path)) + +def bssAdded(bss, properties): + print("BSS added: %s" % (bss)) + showBss(bss) + +def bssRemoved(bss): + print("BSS removed: %s" % (bss)) + +def blobAdded(blob): + print("BlobAdded(%s)" % (blob)) + +def blobRemoved(blob): + print("BlobRemoved(%s)" % (blob)) + +def networkAdded(network, properties): + print("NetworkAdded(%s)" % (network)) + +def networkRemoved(network): + print("NetworkRemoved(%s)" % (network)) + +def networkSelected(network): + print("NetworkSelected(%s)" % (network)) + +def propertiesChangedInterface(properties): + for i in properties: + print("PropertiesChanged(interface): %s=%s" % (i, properties[i])) + +def propertiesChangedBss(properties): + for i in properties: + print("PropertiesChanged(BSS): %s=%s" % (i, properties[i])) + +def propertiesChangedNetwork(properties): + for i in properties: + print("PropertiesChanged(Network): %s=%s" % (i, properties[i])) + +def main(): + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + global bus + bus = dbus.SystemBus() + wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) + + if len(sys.argv) != 2: + list_interfaces(wpas_obj) + os._exit(1) + + wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) + bus.add_signal_receiver(interfaceAdded, + dbus_interface=WPAS_DBUS_INTERFACE, + signal_name="InterfaceAdded") + bus.add_signal_receiver(interfaceRemoved, + dbus_interface=WPAS_DBUS_INTERFACE, + signal_name="InterfaceRemoved") + bus.add_signal_receiver(propertiesChanged, + dbus_interface=WPAS_DBUS_INTERFACE, + signal_name="PropertiesChanged") + + ifname = sys.argv[1] + path = wpas.GetInterface(ifname) + if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) + iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE) + iface.connect_to_signal("ScanDone", scanDone2, + path_keyword='path') + + bus.add_signal_receiver(scanDone, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="ScanDone", + path=path) + bus.add_signal_receiver(bssAdded, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="BSSAdded", + path=path) + bus.add_signal_receiver(bssRemoved, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="BSSRemoved", + path=path) + bus.add_signal_receiver(blobAdded, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="BlobAdded", + path=path) + bus.add_signal_receiver(blobRemoved, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="BlobRemoved", + path=path) + bus.add_signal_receiver(networkAdded, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="NetworkAdded", + path=path) + bus.add_signal_receiver(networkRemoved, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="NetworkRemoved", + path=path) + bus.add_signal_receiver(networkSelected, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="NetworkSelected", + path=path) + bus.add_signal_receiver(propertiesChangedInterface, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="PropertiesChanged", + path=path) + + bus.add_signal_receiver(propertiesChangedBss, + dbus_interface=WPAS_DBUS_BSS_INTERFACE, + signal_name="PropertiesChanged") + + bus.add_signal_receiver(propertiesChangedNetwork, + dbus_interface=WPAS_DBUS_NETWORK_INTERFACE, + signal_name="PropertiesChanged") + + gobject.MainLoop().run() + +if __name__ == "__main__": + main() + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-wps.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-wps.py index 7d87b1efd5dc110912d799671a5b02514259d209..1b3b286ba96c174ef2de6e4437c580d02e4d9d62 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-wps.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new-wps.py @@ -1,80 +1,80 @@ -#!/usr/bin/python - -import dbus -import sys, os -import time -import gobject -from dbus.mainloop.glib import DBusGMainLoop - -WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1" -WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1" -WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1" - -WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface" -WPAS_DBUS_WPS_INTERFACE = "fi.w1.wpa_supplicant1.Interface.WPS" - -def propertiesChanged(properties): - if properties.has_key("State"): - print("PropertiesChanged: State: %s" % (properties["State"])) - -def scanDone(success): - print("Scan done: success=%s" % success) - -def bssAdded(bss, properties): - print("BSS added: %s" % (bss)) - -def bssRemoved(bss): - print("BSS removed: %s" % (bss)) - -def wpsEvent(name, args): - print("WPS event: %s" % (name)) - print(args) - -def credentials(cred): - print("WPS credentials: %s" % (cred)) - -def main(): - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - global bus - bus = dbus.SystemBus() - wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) - - if len(sys.argv) != 2: - print("Missing ifname argument") - os._exit(1) - - wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) - bus.add_signal_receiver(scanDone, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="ScanDone") - bus.add_signal_receiver(bssAdded, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="BSSAdded") - bus.add_signal_receiver(bssRemoved, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="BSSRemoved") - bus.add_signal_receiver(propertiesChanged, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="PropertiesChanged") - bus.add_signal_receiver(wpsEvent, - dbus_interface=WPAS_DBUS_WPS_INTERFACE, - signal_name="Event") - bus.add_signal_receiver(credentials, - dbus_interface=WPAS_DBUS_WPS_INTERFACE, - signal_name="Credentials") - - ifname = sys.argv[1] - - path = wpas.GetInterface(ifname) - if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) - if_obj.Set(WPAS_DBUS_WPS_INTERFACE, 'ProcessCredentials', - dbus.Boolean(1), - dbus_interface=dbus.PROPERTIES_IFACE) - wps = dbus.Interface(if_obj, WPAS_DBUS_WPS_INTERFACE) - wps.Start({'Role': 'enrollee', 'Type': 'pbc'}) - - gobject.MainLoop().run() - -if __name__ == "__main__": - main() - +#!/usr/bin/python + +import dbus +import sys, os +import time +import gobject +from dbus.mainloop.glib import DBusGMainLoop + +WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1" +WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1" +WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1" + +WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface" +WPAS_DBUS_WPS_INTERFACE = "fi.w1.wpa_supplicant1.Interface.WPS" + +def propertiesChanged(properties): + if properties.has_key("State"): + print("PropertiesChanged: State: %s" % (properties["State"])) + +def scanDone(success): + print("Scan done: success=%s" % success) + +def bssAdded(bss, properties): + print("BSS added: %s" % (bss)) + +def bssRemoved(bss): + print("BSS removed: %s" % (bss)) + +def wpsEvent(name, args): + print("WPS event: %s" % (name)) + print(args) + +def credentials(cred): + print("WPS credentials: %s" % (cred)) + +def main(): + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + global bus + bus = dbus.SystemBus() + wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) + + if len(sys.argv) != 2: + print("Missing ifname argument") + os._exit(1) + + wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) + bus.add_signal_receiver(scanDone, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="ScanDone") + bus.add_signal_receiver(bssAdded, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="BSSAdded") + bus.add_signal_receiver(bssRemoved, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="BSSRemoved") + bus.add_signal_receiver(propertiesChanged, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="PropertiesChanged") + bus.add_signal_receiver(wpsEvent, + dbus_interface=WPAS_DBUS_WPS_INTERFACE, + signal_name="Event") + bus.add_signal_receiver(credentials, + dbus_interface=WPAS_DBUS_WPS_INTERFACE, + signal_name="Credentials") + + ifname = sys.argv[1] + + path = wpas.GetInterface(ifname) + if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) + if_obj.Set(WPAS_DBUS_WPS_INTERFACE, 'ProcessCredentials', + dbus.Boolean(1), + dbus_interface=dbus.PROPERTIES_IFACE) + wps = dbus.Interface(if_obj, WPAS_DBUS_WPS_INTERFACE) + wps.Start({'Role': 'enrollee', 'Type': 'pbc'}) + + gobject.MainLoop().run() + +if __name__ == "__main__": + main() + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new.py index 6bf74ae4412229bbab271571b9c8e68ccc661c7e..7551fda6ab54be5f8848b2083ef213845cf7ce2f 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wpas-dbus-new.py @@ -1,149 +1,149 @@ -#!/usr/bin/python - -import dbus -import sys, os -import time -import gobject -from dbus.mainloop.glib import DBusGMainLoop - -WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1" -WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1" -WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1" - -WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface" -WPAS_DBUS_INTERFACES_OPATH = "/fi/w1/wpa_supplicant1/Interfaces" -WPAS_DBUS_BSS_INTERFACE = "fi.w1.wpa_supplicant1.BSS" - -def byte_array_to_string(s): - import urllib - r = "" - for c in s: - if c >= 32 and c < 127: - r += "%c" % c - else: - r += urllib.quote(chr(c)) - return r - -def list_interfaces(wpas_obj): - ifaces = wpas_obj.Get(WPAS_DBUS_INTERFACE, 'Interfaces', - dbus_interface=dbus.PROPERTIES_IFACE) - for path in ifaces: - if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) - ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname', - dbus_interface=dbus.PROPERTIES_IFACE) - print(ifname) - -def propertiesChanged(properties): - if properties.has_key("State"): - print("PropertiesChanged: State: %s" % (properties["State"])) - -def showBss(bss): - net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss) - net = dbus.Interface(net_obj, WPAS_DBUS_BSS_INTERFACE) - - # Convert the byte-array for SSID and BSSID to printable strings - val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'BSSID', - dbus_interface=dbus.PROPERTIES_IFACE) - bssid = "" - for item in val: - bssid = bssid + ":%02x" % item - bssid = bssid[1:] - val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'SSID', - dbus_interface=dbus.PROPERTIES_IFACE) - ssid = byte_array_to_string(val) - - val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'WPA', - dbus_interface=dbus.PROPERTIES_IFACE) - wpa = "no" - if len(val["KeyMgmt"]) > 0: - wpa = "yes" - val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'RSN', - dbus_interface=dbus.PROPERTIES_IFACE) - wpa2 = "no" - if len(val["KeyMgmt"]) > 0: - wpa2 = "yes" - freq = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Frequency', - dbus_interface=dbus.PROPERTIES_IFACE) - signal = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Signal', - dbus_interface=dbus.PROPERTIES_IFACE) - val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Rates', - dbus_interface=dbus.PROPERTIES_IFACE) - if len(val) > 0: - maxrate = val[0] / 1000000 - else: - maxrate = 0 - - print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)) - -def scanDone(success): - print("Scan done: success=%s" % success) - - res = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'BSSs', - dbus_interface=dbus.PROPERTIES_IFACE) - - print("Scanned wireless networks:") - for opath in res: - print(opath) - showBss(opath) - -def bssAdded(bss, properties): - print("BSS added: %s" % (bss)) - showBss(bss) - -def bssRemoved(bss): - print("BSS removed: %s" % (bss)) - -def main(): - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - global bus - bus = dbus.SystemBus() - wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) - - if len(sys.argv) != 2: - list_interfaces(wpas_obj) - os._exit(1) - - wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) - bus.add_signal_receiver(scanDone, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="ScanDone") - bus.add_signal_receiver(bssAdded, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="BSSAdded") - bus.add_signal_receiver(bssRemoved, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="BSSRemoved") - bus.add_signal_receiver(propertiesChanged, - dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, - signal_name="PropertiesChanged") - - ifname = sys.argv[1] - - # See if wpa_supplicant already knows about this interface - path = None - try: - path = wpas.GetInterface(ifname) - except dbus.DBusException as exc: - if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceUnknown:"): - raise exc - try: - path = wpas.CreateInterface({'Ifname': ifname, 'Driver': 'test'}) - time.sleep(1) - - except dbus.DBusException as exc: - if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceExists:"): - raise exc - - global if_obj - if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) - global iface - iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE) - iface.Scan({'Type': 'active'}) - - gobject.MainLoop().run() - - wpas.RemoveInterface(dbus.ObjectPath(path)) - -if __name__ == "__main__": - main() - +#!/usr/bin/python + +import dbus +import sys, os +import time +import gobject +from dbus.mainloop.glib import DBusGMainLoop + +WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1" +WPAS_DBUS_INTERFACE = "fi.w1.wpa_supplicant1" +WPAS_DBUS_OPATH = "/fi/w1/wpa_supplicant1" + +WPAS_DBUS_INTERFACES_INTERFACE = "fi.w1.wpa_supplicant1.Interface" +WPAS_DBUS_INTERFACES_OPATH = "/fi/w1/wpa_supplicant1/Interfaces" +WPAS_DBUS_BSS_INTERFACE = "fi.w1.wpa_supplicant1.BSS" + +def byte_array_to_string(s): + import urllib + r = "" + for c in s: + if c >= 32 and c < 127: + r += "%c" % c + else: + r += urllib.quote(chr(c)) + return r + +def list_interfaces(wpas_obj): + ifaces = wpas_obj.Get(WPAS_DBUS_INTERFACE, 'Interfaces', + dbus_interface=dbus.PROPERTIES_IFACE) + for path in ifaces: + if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) + ifname = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'Ifname', + dbus_interface=dbus.PROPERTIES_IFACE) + print(ifname) + +def propertiesChanged(properties): + if properties.has_key("State"): + print("PropertiesChanged: State: %s" % (properties["State"])) + +def showBss(bss): + net_obj = bus.get_object(WPAS_DBUS_SERVICE, bss) + net = dbus.Interface(net_obj, WPAS_DBUS_BSS_INTERFACE) + + # Convert the byte-array for SSID and BSSID to printable strings + val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'BSSID', + dbus_interface=dbus.PROPERTIES_IFACE) + bssid = "" + for item in val: + bssid = bssid + ":%02x" % item + bssid = bssid[1:] + val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'SSID', + dbus_interface=dbus.PROPERTIES_IFACE) + ssid = byte_array_to_string(val) + + val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'WPA', + dbus_interface=dbus.PROPERTIES_IFACE) + wpa = "no" + if len(val["KeyMgmt"]) > 0: + wpa = "yes" + val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'RSN', + dbus_interface=dbus.PROPERTIES_IFACE) + wpa2 = "no" + if len(val["KeyMgmt"]) > 0: + wpa2 = "yes" + freq = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Frequency', + dbus_interface=dbus.PROPERTIES_IFACE) + signal = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Signal', + dbus_interface=dbus.PROPERTIES_IFACE) + val = net_obj.Get(WPAS_DBUS_BSS_INTERFACE, 'Rates', + dbus_interface=dbus.PROPERTIES_IFACE) + if len(val) > 0: + maxrate = val[0] / 1000000 + else: + maxrate = 0 + + print(" %s :: ssid='%s' wpa=%s wpa2=%s signal=%d rate=%d freq=%d" % (bssid, ssid, wpa, wpa2, signal, maxrate, freq)) + +def scanDone(success): + print("Scan done: success=%s" % success) + + res = if_obj.Get(WPAS_DBUS_INTERFACES_INTERFACE, 'BSSs', + dbus_interface=dbus.PROPERTIES_IFACE) + + print("Scanned wireless networks:") + for opath in res: + print(opath) + showBss(opath) + +def bssAdded(bss, properties): + print("BSS added: %s" % (bss)) + showBss(bss) + +def bssRemoved(bss): + print("BSS removed: %s" % (bss)) + +def main(): + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + global bus + bus = dbus.SystemBus() + wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_OPATH) + + if len(sys.argv) != 2: + list_interfaces(wpas_obj) + os._exit(1) + + wpas = dbus.Interface(wpas_obj, WPAS_DBUS_INTERFACE) + bus.add_signal_receiver(scanDone, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="ScanDone") + bus.add_signal_receiver(bssAdded, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="BSSAdded") + bus.add_signal_receiver(bssRemoved, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="BSSRemoved") + bus.add_signal_receiver(propertiesChanged, + dbus_interface=WPAS_DBUS_INTERFACES_INTERFACE, + signal_name="PropertiesChanged") + + ifname = sys.argv[1] + + # See if wpa_supplicant already knows about this interface + path = None + try: + path = wpas.GetInterface(ifname) + except dbus.DBusException as exc: + if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceUnknown:"): + raise exc + try: + path = wpas.CreateInterface({'Ifname': ifname, 'Driver': 'test'}) + time.sleep(1) + + except dbus.DBusException as exc: + if not str(exc).startswith("fi.w1.wpa_supplicant1.InterfaceExists:"): + raise exc + + global if_obj + if_obj = bus.get_object(WPAS_DBUS_SERVICE, path) + global iface + iface = dbus.Interface(if_obj, WPAS_DBUS_INTERFACES_INTERFACE) + iface.Scan({'Type': 'active'}) + + gobject.MainLoop().run() + + wpas.RemoveInterface(dbus.ObjectPath(path)) + +if __name__ == "__main__": + main() + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wps-ap-cli b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wps-ap-cli index 15d913ef1fae6b82426781969f48f103cd263644..77d7b172e709c0cccec3f134ef1212bbd8cade27 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wps-ap-cli +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wps-ap-cli @@ -1,81 +1,81 @@ -#!/bin/sh - -CLI=wpa_cli - -pbc() -{ - echo "Starting PBC mode" - echo "Push button on the station within two minutes" - if ! $CLI wps_pbc | grep -q OK; then - echo "Failed to enable PBC mode" - fi -} - -enter_pin() -{ - echo "Enter a PIN from a station to be enrolled to the network." - printf "Enrollee PIN: " - read pin - cpin=`$CLI wps_check_pin "$pin" | tail -1` - if [ "$cpin" = "FAIL-CHECKSUM" ]; then - echo "Checksum digit is not valid" - printf "Do you want to use this PIN (y/n)? " - read resp - case "$resp" in - y*) - cpin=`echo "$pin" | sed "s/[^1234567890]//g"` - ;; - *) - return 1 - ;; - esac - fi - if [ "$cpin" = "FAIL" ]; then - echo "Invalid PIN: $pin" - return 1 - fi - echo "Enabling Enrollee PIN: $cpin" - $CLI wps_pin any "$cpin" -} - -show_config() -{ - $CLI status wps -} - -main_menu() -{ - echo "WPS AP" - echo "------" - echo "1: Push button (activate PBC)" - echo "2: Enter Enrollee PIN" - echo "3: Show current configuration" - echo "0: Exit wps-ap-cli" - - printf "Command: " - read cmd - - case "$cmd" in - 1) - pbc - ;; - 2) - enter_pin - ;; - 3) - show_config - ;; - 0) - exit 0 - ;; - *) - echo "Unknown command: $cmd" - ;; - esac - - echo - main_menu -} - - -main_menu +#!/bin/sh + +CLI=wpa_cli + +pbc() +{ + echo "Starting PBC mode" + echo "Push button on the station within two minutes" + if ! $CLI wps_pbc | grep -q OK; then + echo "Failed to enable PBC mode" + fi +} + +enter_pin() +{ + echo "Enter a PIN from a station to be enrolled to the network." + printf "Enrollee PIN: " + read pin + cpin=`$CLI wps_check_pin "$pin" | tail -1` + if [ "$cpin" = "FAIL-CHECKSUM" ]; then + echo "Checksum digit is not valid" + printf "Do you want to use this PIN (y/n)? " + read resp + case "$resp" in + y*) + cpin=`echo "$pin" | sed "s/[^1234567890]//g"` + ;; + *) + return 1 + ;; + esac + fi + if [ "$cpin" = "FAIL" ]; then + echo "Invalid PIN: $pin" + return 1 + fi + echo "Enabling Enrollee PIN: $cpin" + $CLI wps_pin any "$cpin" +} + +show_config() +{ + $CLI status wps +} + +main_menu() +{ + echo "WPS AP" + echo "------" + echo "1: Push button (activate PBC)" + echo "2: Enter Enrollee PIN" + echo "3: Show current configuration" + echo "0: Exit wps-ap-cli" + + printf "Command: " + read cmd + + case "$cmd" in + 1) + pbc + ;; + 2) + enter_pin + ;; + 3) + show_config + ;; + 0) + exit 0 + ;; + *) + echo "Unknown command: $cmd" + ;; + esac + + echo + main_menu +} + + +main_menu diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wps-nfc.py b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wps-nfc.py index bb458fb37a845dff9c943958e0b0f773c84e28d7..d8229cb16b81ab22c118d829af8cdfa8df4cd7d8 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wps-nfc.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/examples/wps-nfc.py @@ -1,525 +1,525 @@ -#!/usr/bin/python -# -# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations -# Copyright (c) 2012-2013, Jouni Malinen -# -# This software may be distributed under the terms of the BSD license. -# See README for more details. - -import os -import sys -import time -import random -import threading -import argparse - -import nfc -import nfc.ndef -import nfc.llcp -import nfc.handover - -import logging - -import wpaspy - -wpas_ctrl = '/var/run/wpa_supplicant' -srv = None -continue_loop = True -terminate_now = False -summary_file = None -success_file = None - -def summary(txt): - print(txt) - if summary_file: - with open(summary_file, 'a') as f: - f.write(txt + "\n") - -def success_report(txt): - summary(txt) - if success_file: - with open(success_file, 'a') as f: - f.write(txt + "\n") - -def wpas_connect(): - ifaces = [] - if os.path.isdir(wpas_ctrl): - try: - ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] - except OSError as error: - print("Could not find wpa_supplicant: ", error) - return None - - if len(ifaces) < 1: - print("No wpa_supplicant control interface found") - return None - - for ctrl in ifaces: - try: - wpas = wpaspy.Ctrl(ctrl) - return wpas - except Exception as e: - pass - return None - - -def wpas_tag_read(message): - wpas = wpas_connect() - if (wpas == None): - return False - if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")): - return False - return True - -def wpas_get_config_token(id=None): - wpas = wpas_connect() - if (wpas == None): - return None - if id: - ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id) - else: - ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF") - if "FAIL" in ret: - return None - return ret.rstrip().decode("hex") - - -def wpas_get_er_config_token(uuid): - wpas = wpas_connect() - if (wpas == None): - return None - ret = wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid) - if "FAIL" in ret: - return None - return ret.rstrip().decode("hex") - - -def wpas_get_password_token(): - wpas = wpas_connect() - if (wpas == None): - return None - ret = wpas.request("WPS_NFC_TOKEN NDEF") - if "FAIL" in ret: - return None - return ret.rstrip().decode("hex") - -def wpas_get_handover_req(): - wpas = wpas_connect() - if (wpas == None): - return None - ret = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR") - if "FAIL" in ret: - return None - return ret.rstrip().decode("hex") - - -def wpas_get_handover_sel(uuid): - wpas = wpas_connect() - if (wpas == None): - return None - if uuid is None: - res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip() - else: - res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip() - if "FAIL" in res: - return None - return res.decode("hex") - - -def wpas_report_handover(req, sel, type): - wpas = wpas_connect() - if (wpas == None): - return None - return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " + - str(req).encode("hex") + " " + - str(sel).encode("hex")) - - -class HandoverServer(nfc.handover.HandoverServer): - def __init__(self, llc): - super(HandoverServer, self).__init__(llc) - self.sent_carrier = None - self.ho_server_processing = False - self.success = False - - # override to avoid parser error in request/response.pretty() in nfcpy - # due to new WSC handover format - def _process_request(self, request): - summary("received handover request {}".format(request.type)) - response = nfc.ndef.Message("\xd1\x02\x01Hs\x12") - if not request.type == 'urn:nfc:wkt:Hr': - summary("not a handover request") - else: - try: - request = nfc.ndef.HandoverRequestMessage(request) - except nfc.ndef.DecodeError as e: - summary("error decoding 'Hr' message: {}".format(e)) - else: - response = self.process_request(request) - summary("send handover response {}".format(response.type)) - return response - - def process_request(self, request): - self.ho_server_processing = True - summary("HandoverServer - request received") - try: - print("Parsed handover request: " + request.pretty()) - except Exception as e: - print(e) - - sel = nfc.ndef.HandoverSelectMessage(version="1.2") - - for carrier in request.carriers: - print("Remote carrier type: " + carrier.type) - if carrier.type == "application/vnd.wfa.wsc": - summary("WPS carrier type match - add WPS carrier record") - data = wpas_get_handover_sel(self.uuid) - if data is None: - summary("Could not get handover select carrier record from wpa_supplicant") - continue - print("Handover select carrier record from wpa_supplicant:") - print(data.encode("hex")) - self.sent_carrier = data - if "OK" in wpas_report_handover(carrier.record, self.sent_carrier, "RESP"): - success_report("Handover reported successfully (responder)") - else: - summary("Handover report rejected (responder)") - - message = nfc.ndef.Message(data); - sel.add_carrier(message[0], "active", message[1:]) - - print("Handover select:") - try: - print(sel.pretty()) - except Exception as e: - print(e) - print(str(sel).encode("hex")) - - summary("Sending handover select") - self.success = True - return sel - - -def wps_handover_init(llc): - summary("Trying to initiate WPS handover") - - data = wpas_get_handover_req() - if (data == None): - summary("Could not get handover request carrier record from wpa_supplicant") - return - print("Handover request carrier record from wpa_supplicant: " + data.encode("hex")) - - message = nfc.ndef.HandoverRequestMessage(version="1.2") - message.nonce = random.randint(0, 0xffff) - datamsg = nfc.ndef.Message(data) - message.add_carrier(datamsg[0], "active", datamsg[1:]) - - print("Handover request:") - try: - print(message.pretty()) - except Exception as e: - print(e) - print(str(message).encode("hex")) - - client = nfc.handover.HandoverClient(llc) - try: - summary("Trying to initiate NFC connection handover") - client.connect() - summary("Connected for handover") - except nfc.llcp.ConnectRefused: - summary("Handover connection refused") - client.close() - return - except Exception as e: - summary("Other exception: " + str(e)) - client.close() - return - - summary("Sending handover request") - - if not client.send(message): - summary("Failed to send handover request") - client.close() - return - - summary("Receiving handover response") - message = client._recv() - if message is None: - summary("No response received") - client.close() - return - if message.type != "urn:nfc:wkt:Hs": - summary("Response was not Hs - received: " + message.type) - client.close() - return - - print("Received message") - try: - print(message.pretty()) - except Exception as e: - print(e) - print(str(message).encode("hex")) - message = nfc.ndef.HandoverSelectMessage(message) - summary("Handover select received") - try: - print(message.pretty()) - except Exception as e: - print(e) - - for carrier in message.carriers: - print("Remote carrier type: " + carrier.type) - if carrier.type == "application/vnd.wfa.wsc": - print("WPS carrier type match - send to wpa_supplicant") - if "OK" in wpas_report_handover(data, carrier.record, "INIT"): - success_report("Handover reported successfully (initiator)") - else: - summary("Handover report rejected (initiator)") - # nfcpy does not support the new format.. - #wifi = nfc.ndef.WifiConfigRecord(carrier.record) - #print wifi.pretty() - - print("Remove peer") - client.close() - print("Done with handover") - global only_one - if only_one: - global continue_loop - continue_loop = False - - global no_wait - if no_wait: - print("Trying to exit..") - global terminate_now - terminate_now = True - -def wps_tag_read(tag, wait_remove=True): - success = False - if len(tag.ndef.message): - for record in tag.ndef.message: - print("record type " + record.type) - if record.type == "application/vnd.wfa.wsc": - summary("WPS tag - send to wpa_supplicant") - success = wpas_tag_read(tag.ndef.message) - break - else: - summary("Empty tag") - - if success: - success_report("Tag read succeeded") - - if wait_remove: - print("Remove tag") - while tag.is_present: - time.sleep(0.1) - - return success - - -def rdwr_connected_write(tag): - summary("Tag found - writing - " + str(tag)) - global write_data - tag.ndef.message = str(write_data) - success_report("Tag write succeeded") - print("Done - remove tag") - global only_one - if only_one: - global continue_loop - continue_loop = False - global write_wait_remove - while write_wait_remove and tag.is_present: - time.sleep(0.1) - -def wps_write_config_tag(clf, id=None, wait_remove=True): - print("Write WPS config token") - global write_data, write_wait_remove - write_wait_remove = wait_remove - write_data = wpas_get_config_token(id) - if write_data == None: - print("Could not get WPS config token from wpa_supplicant") - sys.exit(1) - return - print("Touch an NFC tag") - clf.connect(rdwr={'on-connect': rdwr_connected_write}) - - -def wps_write_er_config_tag(clf, uuid, wait_remove=True): - print("Write WPS ER config token") - global write_data, write_wait_remove - write_wait_remove = wait_remove - write_data = wpas_get_er_config_token(uuid) - if write_data == None: - print("Could not get WPS config token from wpa_supplicant") - return - - print("Touch an NFC tag") - clf.connect(rdwr={'on-connect': rdwr_connected_write}) - - -def wps_write_password_tag(clf, wait_remove=True): - print("Write WPS password token") - global write_data, write_wait_remove - write_wait_remove = wait_remove - write_data = wpas_get_password_token() - if write_data == None: - print("Could not get WPS password token from wpa_supplicant") - return - - print("Touch an NFC tag") - clf.connect(rdwr={'on-connect': rdwr_connected_write}) - - -def rdwr_connected(tag): - global only_one, no_wait - summary("Tag connected: " + str(tag)) - - if tag.ndef: - print("NDEF tag: " + tag.type) - try: - print(tag.ndef.message.pretty()) - except Exception as e: - print(e) - success = wps_tag_read(tag, not only_one) - if only_one and success: - global continue_loop - continue_loop = False - else: - summary("Not an NDEF tag - remove tag") - return True - - return not no_wait - - -def llcp_worker(llc): - global arg_uuid - if arg_uuid is None: - wps_handover_init(llc) - print("Exiting llcp_worker thread") - return - - global srv - global wait_connection - while not wait_connection and srv.sent_carrier is None: - if srv.ho_server_processing: - time.sleep(0.025) - -def llcp_startup(clf, llc): - global arg_uuid - if arg_uuid: - print("Start LLCP server") - global srv - srv = HandoverServer(llc) - if arg_uuid is "ap": - print("Trying to handle WPS handover") - srv.uuid = None - else: - print("Trying to handle WPS handover with AP " + arg_uuid) - srv.uuid = arg_uuid - return llc - -def llcp_connected(llc): - print("P2P LLCP connected") - global wait_connection - wait_connection = False - global arg_uuid - if arg_uuid: - global srv - srv.start() - else: - threading.Thread(target=llcp_worker, args=(llc,)).start() - print("llcp_connected returning") - return True - - -def terminate_loop(): - global terminate_now - return terminate_now - -def main(): - clf = nfc.ContactlessFrontend() - - parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for WPS NFC operations') - parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO, - action='store_const', dest='loglevel', - help='verbose debug output') - parser.add_argument('-q', const=logging.WARNING, action='store_const', - dest='loglevel', help='be quiet') - parser.add_argument('--only-one', '-1', action='store_true', - help='run only one operation and exit') - parser.add_argument('--no-wait', action='store_true', - help='do not wait for tag to be removed before exiting') - parser.add_argument('--uuid', - help='UUID of an AP (used for WPS ER operations)') - parser.add_argument('--id', - help='network id (used for WPS ER operations)') - parser.add_argument('--summary', - help='summary file for writing status updates') - parser.add_argument('--success', - help='success file for writing success update') - parser.add_argument('command', choices=['write-config', - 'write-er-config', - 'write-password'], - nargs='?') - args = parser.parse_args() - - global arg_uuid - arg_uuid = args.uuid - - global only_one - only_one = args.only_one - - global no_wait - no_wait = args.no_wait - - if args.summary: - global summary_file - summary_file = args.summary - - if args.success: - global success_file - success_file = args.success - - logging.basicConfig(level=args.loglevel) - - try: - if not clf.open("usb"): - print("Could not open connection with an NFC device") - raise SystemExit - - if args.command == "write-config": - wps_write_config_tag(clf, id=args.id, wait_remove=not args.no_wait) - raise SystemExit - - if args.command == "write-er-config": - wps_write_er_config_tag(clf, args.uuid, wait_remove=not args.no_wait) - raise SystemExit - - if args.command == "write-password": - wps_write_password_tag(clf, wait_remove=not args.no_wait) - raise SystemExit - - global continue_loop - while continue_loop: - print("Waiting for a tag or peer to be touched") - wait_connection = True - try: - if not clf.connect(rdwr={'on-connect': rdwr_connected}, - llcp={'on-startup': llcp_startup, - 'on-connect': llcp_connected}, - terminate=terminate_loop): - break - except Exception as e: - print("clf.connect failed") - - global srv - if only_one and srv and srv.success: - raise SystemExit - - except KeyboardInterrupt: - raise SystemExit - finally: - clf.close() - - raise SystemExit - -if __name__ == '__main__': - main() +#!/usr/bin/python +# +# Example nfcpy to wpa_supplicant wrapper for WPS NFC operations +# Copyright (c) 2012-2013, Jouni Malinen +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import sys +import time +import random +import threading +import argparse + +import nfc +import nfc.ndef +import nfc.llcp +import nfc.handover + +import logging + +import wpaspy + +wpas_ctrl = '/var/run/wpa_supplicant' +srv = None +continue_loop = True +terminate_now = False +summary_file = None +success_file = None + +def summary(txt): + print(txt) + if summary_file: + with open(summary_file, 'a') as f: + f.write(txt + "\n") + +def success_report(txt): + summary(txt) + if success_file: + with open(success_file, 'a') as f: + f.write(txt + "\n") + +def wpas_connect(): + ifaces = [] + if os.path.isdir(wpas_ctrl): + try: + ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] + except OSError as error: + print("Could not find wpa_supplicant: ", error) + return None + + if len(ifaces) < 1: + print("No wpa_supplicant control interface found") + return None + + for ctrl in ifaces: + try: + wpas = wpaspy.Ctrl(ctrl) + return wpas + except Exception as e: + pass + return None + + +def wpas_tag_read(message): + wpas = wpas_connect() + if (wpas == None): + return False + if "FAIL" in wpas.request("WPS_NFC_TAG_READ " + str(message).encode("hex")): + return False + return True + +def wpas_get_config_token(id=None): + wpas = wpas_connect() + if (wpas == None): + return None + if id: + ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF " + id) + else: + ret = wpas.request("WPS_NFC_CONFIG_TOKEN NDEF") + if "FAIL" in ret: + return None + return ret.rstrip().decode("hex") + + +def wpas_get_er_config_token(uuid): + wpas = wpas_connect() + if (wpas == None): + return None + ret = wpas.request("WPS_ER_NFC_CONFIG_TOKEN NDEF " + uuid) + if "FAIL" in ret: + return None + return ret.rstrip().decode("hex") + + +def wpas_get_password_token(): + wpas = wpas_connect() + if (wpas == None): + return None + ret = wpas.request("WPS_NFC_TOKEN NDEF") + if "FAIL" in ret: + return None + return ret.rstrip().decode("hex") + +def wpas_get_handover_req(): + wpas = wpas_connect() + if (wpas == None): + return None + ret = wpas.request("NFC_GET_HANDOVER_REQ NDEF WPS-CR") + if "FAIL" in ret: + return None + return ret.rstrip().decode("hex") + + +def wpas_get_handover_sel(uuid): + wpas = wpas_connect() + if (wpas == None): + return None + if uuid is None: + res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR").rstrip() + else: + res = wpas.request("NFC_GET_HANDOVER_SEL NDEF WPS-CR " + uuid).rstrip() + if "FAIL" in res: + return None + return res.decode("hex") + + +def wpas_report_handover(req, sel, type): + wpas = wpas_connect() + if (wpas == None): + return None + return wpas.request("NFC_REPORT_HANDOVER " + type + " WPS " + + str(req).encode("hex") + " " + + str(sel).encode("hex")) + + +class HandoverServer(nfc.handover.HandoverServer): + def __init__(self, llc): + super(HandoverServer, self).__init__(llc) + self.sent_carrier = None + self.ho_server_processing = False + self.success = False + + # override to avoid parser error in request/response.pretty() in nfcpy + # due to new WSC handover format + def _process_request(self, request): + summary("received handover request {}".format(request.type)) + response = nfc.ndef.Message("\xd1\x02\x01Hs\x12") + if not request.type == 'urn:nfc:wkt:Hr': + summary("not a handover request") + else: + try: + request = nfc.ndef.HandoverRequestMessage(request) + except nfc.ndef.DecodeError as e: + summary("error decoding 'Hr' message: {}".format(e)) + else: + response = self.process_request(request) + summary("send handover response {}".format(response.type)) + return response + + def process_request(self, request): + self.ho_server_processing = True + summary("HandoverServer - request received") + try: + print("Parsed handover request: " + request.pretty()) + except Exception as e: + print(e) + + sel = nfc.ndef.HandoverSelectMessage(version="1.2") + + for carrier in request.carriers: + print("Remote carrier type: " + carrier.type) + if carrier.type == "application/vnd.wfa.wsc": + summary("WPS carrier type match - add WPS carrier record") + data = wpas_get_handover_sel(self.uuid) + if data is None: + summary("Could not get handover select carrier record from wpa_supplicant") + continue + print("Handover select carrier record from wpa_supplicant:") + print(data.encode("hex")) + self.sent_carrier = data + if "OK" in wpas_report_handover(carrier.record, self.sent_carrier, "RESP"): + success_report("Handover reported successfully (responder)") + else: + summary("Handover report rejected (responder)") + + message = nfc.ndef.Message(data); + sel.add_carrier(message[0], "active", message[1:]) + + print("Handover select:") + try: + print(sel.pretty()) + except Exception as e: + print(e) + print(str(sel).encode("hex")) + + summary("Sending handover select") + self.success = True + return sel + + +def wps_handover_init(llc): + summary("Trying to initiate WPS handover") + + data = wpas_get_handover_req() + if (data == None): + summary("Could not get handover request carrier record from wpa_supplicant") + return + print("Handover request carrier record from wpa_supplicant: " + data.encode("hex")) + + message = nfc.ndef.HandoverRequestMessage(version="1.2") + message.nonce = random.randint(0, 0xffff) + datamsg = nfc.ndef.Message(data) + message.add_carrier(datamsg[0], "active", datamsg[1:]) + + print("Handover request:") + try: + print(message.pretty()) + except Exception as e: + print(e) + print(str(message).encode("hex")) + + client = nfc.handover.HandoverClient(llc) + try: + summary("Trying to initiate NFC connection handover") + client.connect() + summary("Connected for handover") + except nfc.llcp.ConnectRefused: + summary("Handover connection refused") + client.close() + return + except Exception as e: + summary("Other exception: " + str(e)) + client.close() + return + + summary("Sending handover request") + + if not client.send(message): + summary("Failed to send handover request") + client.close() + return + + summary("Receiving handover response") + message = client._recv() + if message is None: + summary("No response received") + client.close() + return + if message.type != "urn:nfc:wkt:Hs": + summary("Response was not Hs - received: " + message.type) + client.close() + return + + print("Received message") + try: + print(message.pretty()) + except Exception as e: + print(e) + print(str(message).encode("hex")) + message = nfc.ndef.HandoverSelectMessage(message) + summary("Handover select received") + try: + print(message.pretty()) + except Exception as e: + print(e) + + for carrier in message.carriers: + print("Remote carrier type: " + carrier.type) + if carrier.type == "application/vnd.wfa.wsc": + print("WPS carrier type match - send to wpa_supplicant") + if "OK" in wpas_report_handover(data, carrier.record, "INIT"): + success_report("Handover reported successfully (initiator)") + else: + summary("Handover report rejected (initiator)") + # nfcpy does not support the new format.. + #wifi = nfc.ndef.WifiConfigRecord(carrier.record) + #print wifi.pretty() + + print("Remove peer") + client.close() + print("Done with handover") + global only_one + if only_one: + global continue_loop + continue_loop = False + + global no_wait + if no_wait: + print("Trying to exit..") + global terminate_now + terminate_now = True + +def wps_tag_read(tag, wait_remove=True): + success = False + if len(tag.ndef.message): + for record in tag.ndef.message: + print("record type " + record.type) + if record.type == "application/vnd.wfa.wsc": + summary("WPS tag - send to wpa_supplicant") + success = wpas_tag_read(tag.ndef.message) + break + else: + summary("Empty tag") + + if success: + success_report("Tag read succeeded") + + if wait_remove: + print("Remove tag") + while tag.is_present: + time.sleep(0.1) + + return success + + +def rdwr_connected_write(tag): + summary("Tag found - writing - " + str(tag)) + global write_data + tag.ndef.message = str(write_data) + success_report("Tag write succeeded") + print("Done - remove tag") + global only_one + if only_one: + global continue_loop + continue_loop = False + global write_wait_remove + while write_wait_remove and tag.is_present: + time.sleep(0.1) + +def wps_write_config_tag(clf, id=None, wait_remove=True): + print("Write WPS config token") + global write_data, write_wait_remove + write_wait_remove = wait_remove + write_data = wpas_get_config_token(id) + if write_data == None: + print("Could not get WPS config token from wpa_supplicant") + sys.exit(1) + return + print("Touch an NFC tag") + clf.connect(rdwr={'on-connect': rdwr_connected_write}) + + +def wps_write_er_config_tag(clf, uuid, wait_remove=True): + print("Write WPS ER config token") + global write_data, write_wait_remove + write_wait_remove = wait_remove + write_data = wpas_get_er_config_token(uuid) + if write_data == None: + print("Could not get WPS config token from wpa_supplicant") + return + + print("Touch an NFC tag") + clf.connect(rdwr={'on-connect': rdwr_connected_write}) + + +def wps_write_password_tag(clf, wait_remove=True): + print("Write WPS password token") + global write_data, write_wait_remove + write_wait_remove = wait_remove + write_data = wpas_get_password_token() + if write_data == None: + print("Could not get WPS password token from wpa_supplicant") + return + + print("Touch an NFC tag") + clf.connect(rdwr={'on-connect': rdwr_connected_write}) + + +def rdwr_connected(tag): + global only_one, no_wait + summary("Tag connected: " + str(tag)) + + if tag.ndef: + print("NDEF tag: " + tag.type) + try: + print(tag.ndef.message.pretty()) + except Exception as e: + print(e) + success = wps_tag_read(tag, not only_one) + if only_one and success: + global continue_loop + continue_loop = False + else: + summary("Not an NDEF tag - remove tag") + return True + + return not no_wait + + +def llcp_worker(llc): + global arg_uuid + if arg_uuid is None: + wps_handover_init(llc) + print("Exiting llcp_worker thread") + return + + global srv + global wait_connection + while not wait_connection and srv.sent_carrier is None: + if srv.ho_server_processing: + time.sleep(0.025) + +def llcp_startup(clf, llc): + global arg_uuid + if arg_uuid: + print("Start LLCP server") + global srv + srv = HandoverServer(llc) + if arg_uuid is "ap": + print("Trying to handle WPS handover") + srv.uuid = None + else: + print("Trying to handle WPS handover with AP " + arg_uuid) + srv.uuid = arg_uuid + return llc + +def llcp_connected(llc): + print("P2P LLCP connected") + global wait_connection + wait_connection = False + global arg_uuid + if arg_uuid: + global srv + srv.start() + else: + threading.Thread(target=llcp_worker, args=(llc,)).start() + print("llcp_connected returning") + return True + + +def terminate_loop(): + global terminate_now + return terminate_now + +def main(): + clf = nfc.ContactlessFrontend() + + parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for WPS NFC operations') + parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO, + action='store_const', dest='loglevel', + help='verbose debug output') + parser.add_argument('-q', const=logging.WARNING, action='store_const', + dest='loglevel', help='be quiet') + parser.add_argument('--only-one', '-1', action='store_true', + help='run only one operation and exit') + parser.add_argument('--no-wait', action='store_true', + help='do not wait for tag to be removed before exiting') + parser.add_argument('--uuid', + help='UUID of an AP (used for WPS ER operations)') + parser.add_argument('--id', + help='network id (used for WPS ER operations)') + parser.add_argument('--summary', + help='summary file for writing status updates') + parser.add_argument('--success', + help='success file for writing success update') + parser.add_argument('command', choices=['write-config', + 'write-er-config', + 'write-password'], + nargs='?') + args = parser.parse_args() + + global arg_uuid + arg_uuid = args.uuid + + global only_one + only_one = args.only_one + + global no_wait + no_wait = args.no_wait + + if args.summary: + global summary_file + summary_file = args.summary + + if args.success: + global success_file + success_file = args.success + + logging.basicConfig(level=args.loglevel) + + try: + if not clf.open("usb"): + print("Could not open connection with an NFC device") + raise SystemExit + + if args.command == "write-config": + wps_write_config_tag(clf, id=args.id, wait_remove=not args.no_wait) + raise SystemExit + + if args.command == "write-er-config": + wps_write_er_config_tag(clf, args.uuid, wait_remove=not args.no_wait) + raise SystemExit + + if args.command == "write-password": + wps_write_password_tag(clf, wait_remove=not args.no_wait) + raise SystemExit + + global continue_loop + while continue_loop: + print("Waiting for a tag or peer to be touched") + wait_connection = True + try: + if not clf.connect(rdwr={'on-connect': rdwr_connected}, + llcp={'on-startup': llcp_startup, + 'on-connect': llcp_connected}, + terminate=terminate_loop): + break + except Exception as e: + print("clf.connect failed") + + global srv + if only_one and srv and srv.success: + raise SystemExit + + except KeyboardInterrupt: + raise SystemExit + finally: + clf.close() + + raise SystemExit + +if __name__ == '__main__': + main() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/gas_query.c b/wpa_supplicant-2.9_standard/wpa_supplicant/gas_query.c index 216701450952b4f4cf0e574e3e3079e1a9d36c4d..2a21158be0820f4fec7075f3dbb7b733b2139bcb 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/gas_query.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/gas_query.c @@ -30,6 +30,8 @@ #define GAS_QUERY_WAIT_TIME_INITIAL 1000 #define GAS_QUERY_WAIT_TIME_COMEBACK 150 +#define GAS_QUERY_MAX_COMEBACK_DELAY 60000 + /** * struct gas_query_pending - Pending GAS query */ @@ -156,9 +158,9 @@ static void gas_query_done(struct gas_query *gas, struct gas_query_pending *query, enum gas_query_result result) { - wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR + wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_DONE "addr=" MACSTR_SEC " dialog_token=%u freq=%d status_code=%u result=%s", - MAC2STR(query->addr), query->dialog_token, query->freq, + MAC2STR_SEC(query->addr), query->dialog_token, query->freq, query->status_code, gas_result_txt(result)); if (gas->current == query) gas->current = NULL; @@ -197,10 +199,16 @@ static struct gas_query_pending * gas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token) { struct gas_query_pending *q; + struct wpa_supplicant *wpa_s = gas->wpa_s; + dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { - if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 && + if (ether_addr_equal(q->addr, addr) && q->dialog_token == dialog_token) return q; + if (wpa_s->valid_links && + ether_addr_equal(wpa_s->ap_mld_addr, addr) && + wpas_ap_link_address(wpa_s, q->addr)) + return q; } return NULL; } @@ -241,7 +249,7 @@ static void gas_query_tx_status(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR_SEC " result=%d query=%p dialog_token=%u dur=%d ms", freq, MAC2STR_SEC(dst), result, query, query->dialog_token, dur); - if (os_memcmp(dst, query->addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(dst, query->addr)) { wpa_printf(MSG_DEBUG, "GAS: TX status for unexpected destination"); return; } @@ -298,7 +306,7 @@ static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query, (!gas->wpa_s->conf->gas_address3 || (gas->wpa_s->current_ssid && gas->wpa_s->wpa_state >= WPA_ASSOCIATED && - os_memcmp(query->addr, gas->wpa_s->bssid, ETH_ALEN) == 0))) + ether_addr_equal(query->addr, gas->wpa_s->bssid)))) bssid = query->addr; else bssid = wildcard_bssid; @@ -402,14 +410,14 @@ static void gas_query_tx_comeback_req_delay(struct gas_query *gas, static void gas_query_rx_initial(struct gas_query *gas, struct gas_query_pending *query, - const u8 *adv_proto, const u8 *resp, - size_t len, u16 comeback_delay) + const u8 *adv_proto, size_t adv_proto_len, + const u8 *resp, size_t len, u16 comeback_delay) { wpa_printf(MSG_DEBUG, "GAS: Received initial response from " MACSTR_SEC " (dialog_token=%u comeback_delay=%u)", MAC2STR_SEC(query->addr), query->dialog_token, comeback_delay); - query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]); + query->adv_proto = wpabuf_alloc_copy(adv_proto, adv_proto_len); if (query->adv_proto == NULL) { gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR); return; @@ -434,9 +442,9 @@ static void gas_query_rx_initial(struct gas_query *gas, static void gas_query_rx_comeback(struct gas_query *gas, struct gas_query_pending *query, - const u8 *adv_proto, const u8 *resp, - size_t len, u8 frag_id, u8 more_frags, - u16 comeback_delay) + const u8 *adv_proto, size_t adv_proto_len, + const u8 *resp, size_t len, u8 frag_id, + u8 more_frags, u16 comeback_delay) { wpa_printf(MSG_DEBUG, "GAS: Received comeback response from " MACSTR_SEC " (dialog_token=%u frag_id=%u more_frags=%u " @@ -445,7 +453,7 @@ static void gas_query_rx_comeback(struct gas_query *gas, more_frags, comeback_delay); eloop_cancel_timeout(gas_query_rx_comeback_timeout, gas, query); - if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) || + if (adv_proto_len != wpabuf_len(query->adv_proto) || os_memcmp(adv_proto, wpabuf_head(query->adv_proto), wpabuf_len(query->adv_proto)) != 0) { wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed " @@ -514,6 +522,7 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, u8 action, dialog_token, frag_id = 0, more_frags = 0; u16 comeback_delay, resp_len; const u8 *pos, *adv_proto; + size_t adv_proto_len; int prot, pmf; unsigned int left; @@ -589,25 +598,31 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, if (pos + 2 > data + len) return 0; comeback_delay = WPA_GET_LE16(pos); + if (comeback_delay > GAS_QUERY_MAX_COMEBACK_DELAY) + comeback_delay = GAS_QUERY_MAX_COMEBACK_DELAY; pos += 2; /* Advertisement Protocol element */ - if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) { + adv_proto = pos; + left = data + len - adv_proto; + if (left < 2 || adv_proto[1] > left - 2) { wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement " "Protocol element in the response from " MACSTR_SEC, MAC2STR_SEC(sa)); return 0; } - if (*pos != WLAN_EID_ADV_PROTO) { + if (*adv_proto != WLAN_EID_ADV_PROTO) { wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement " "Protocol element ID %u in response from " MACSTR_SEC, - *pos, MAC2STR_SEC(sa)); + *adv_proto, MAC2STR_SEC(sa)); return 0; } + adv_proto_len = 2 + adv_proto[1]; + if (adv_proto_len > (size_t) (data + len - pos)) + return 0; /* unreachable due to an earlier check */ - adv_proto = pos; - pos += 2 + pos[1]; + pos += adv_proto_len; /* Query Response Length */ if (pos + 2 > data + len) { @@ -631,11 +646,12 @@ int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa, } if (action == WLAN_PA_GAS_COMEBACK_RESP) - gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len, - frag_id, more_frags, comeback_delay); + gas_query_rx_comeback(gas, query, adv_proto, adv_proto_len, + pos, resp_len, frag_id, more_frags, + comeback_delay); else - gas_query_rx_initial(gas, query, adv_proto, pos, resp_len, - comeback_delay); + gas_query_rx_initial(gas, query, adv_proto, adv_proto_len, + pos, resp_len, comeback_delay); return 0; } @@ -658,7 +674,7 @@ static int gas_query_dialog_token_available(struct gas_query *gas, { struct gas_query_pending *q; dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) { - if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 && + if (ether_addr_equal(dst, q->addr) && dialog_token == q->dialog_token) return 0; } @@ -858,9 +874,9 @@ int gas_query_req(struct gas_query *gas, const u8 *dst, int freq, *(wpabuf_mhead_u8(req) + 2) = dialog_token; - wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR + wpa_msg(gas->wpa_s, MSG_INFO, GAS_QUERY_START "addr=" MACSTR_SEC " dialog_token=%u freq=%d", - MAC2STR(query->addr), query->dialog_token, query->freq); + MAC2STR_SEC(query->addr), query->dialog_token, query->freq); if (radio_add_work(gas->wpa_s, freq, "gas-query", 0, gas_query_start_cb, query) < 0) { diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant-2.9_standard/wpa_supplicant/hs20_supplicant.c index 7db4ccdb2d88682d3319b8d1ff5fa3488f3c83b6..3df1dc516b72fc01d1dcacce0d03525c1b7e7af9 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/hs20_supplicant.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/hs20_supplicant.c @@ -26,6 +26,7 @@ #include "interworking.h" #include "hs20_supplicant.h" #include "base64.h" +#include "notify.h" #define OSU_MAX_ITEMS 10 @@ -67,15 +68,13 @@ struct osu_provider { void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss = wpa_s->current_bss; - u8 *bssid = wpa_s->bssid; const u8 *ie; const u8 *ext_capa; u32 filter = 0; if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)) { - wpa_printf(MSG_DEBUG, - "Not configuring frame filtering - BSS " MACSTR_SEC - " is not a Hotspot 2.0 network", MAC2STR_SEC(bssid)); + /* Not configuring frame filtering - BSS is not a Hotspot 2.0 + * network */ return; } @@ -326,7 +325,7 @@ static struct icon_entry * hs20_find_icon(struct wpa_supplicant *wpa_s, struct icon_entry *icon; dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) { - if (os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0 && + if (ether_addr_equal(icon->bssid, bssid) && os_strcmp(icon->file_name, file_name) == 0 && icon->image) return icon; } @@ -402,7 +401,7 @@ int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid, dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry, list) { - if ((!bssid || os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0) && + if ((!bssid || ether_addr_equal(icon->bssid, bssid)) && (!file_name || os_strcmp(icon->file_name, file_name) == 0)) { dl_list_del(&icon->list); @@ -448,7 +447,7 @@ static void hs20_remove_duplicate_icons(struct wpa_supplicant *wpa_s, list) { if (icon == new_icon) continue; - if (os_memcmp(icon->bssid, new_icon->bssid, ETH_ALEN) == 0 && + if (ether_addr_equal(icon->bssid, new_icon->bssid) && os_strcmp(icon->file_name, new_icon->file_name) == 0) { dl_list_del(&icon->list); hs20_free_icon_entry(icon); @@ -469,22 +468,22 @@ static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) { if (icon->dialog_token == dialog_token && !icon->image && - os_memcmp(icon->bssid, sa, ETH_ALEN) == 0) { + ether_addr_equal(icon->bssid, sa)) { icon->image = os_memdup(pos, slen); if (!icon->image) return -1; icon->image_len = slen; hs20_remove_duplicate_icons(wpa_s, icon); wpa_msg(wpa_s, MSG_INFO, - RX_HS20_ICON MACSTR " %s %u", - MAC2STR(sa), icon->file_name, + RX_HS20_ICON MACSTR_SEC " %s %u", + MAC2STR_SEC(sa), icon->file_name, (unsigned int) icon->image_len); return 0; } } - wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File", - MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR_SEC " Icon Binary File", + MAC2STR_SEC(sa)); if (slen < 4) { wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " @@ -618,8 +617,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, switch (subtype) { case HS20_STYPE_CAPABILITY_LIST: - wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR - " HS Capability List", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR_SEC + " HS Capability List", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_capability_list); @@ -628,8 +627,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OPERATOR_FRIENDLY_NAME: - wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR - " Operator Friendly Name", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR_SEC + " Operator Friendly Name", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_operator_friendly_name); @@ -660,8 +659,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_CONNECTION_CAPABILITY: - wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR - " Connection Capability", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR_SEC + " Connection Capability", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_connection_capability); @@ -670,8 +669,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OPERATING_CLASS: - wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR - " Operating Class", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR_SEC + " Operating Class", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_operating_class); @@ -680,8 +679,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OSU_PROVIDERS_LIST: - wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR - " OSU Providers list", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR_SEC + " OSU Providers list", MAC2STR_SEC(sa)); wpa_s->num_prov_found++; if (anqp) { wpabuf_free(anqp->hs20_osu_providers_list); @@ -701,8 +700,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OPERATOR_ICON_METADATA: - wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR - " Operator Icon Metadata", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR_SEC + " Operator Icon Metadata", MAC2STR_SEC(sa)); wpa_hexdump(MSG_DEBUG, "Operator Icon Metadata", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_operator_icon_metadata); @@ -711,8 +710,8 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, } break; case HS20_STYPE_OSU_PROVIDERS_NAI_LIST: - wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR - " OSU Providers NAI List", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR_SEC + " OSU Providers NAI List", MAC2STR_SEC(sa)); if (anqp) { wpabuf_free(anqp->hs20_osu_providers_nai_list); anqp->hs20_osu_providers_nai_list = @@ -789,10 +788,10 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s) struct osu_provider *osu = &wpa_s->osu_prov[i]; if (i > 0) fprintf(f, "\n"); - fprintf(f, "OSU-PROVIDER " MACSTR "\n" + fprintf(f, "OSU-PROVIDER " MACSTR_SEC "\n" "uri=%s\n" "methods=%08x\n", - MAC2STR(osu->bssid), osu->server_uri, osu->osu_methods); + MAC2STR_SEC(osu->bssid), osu->server_uri, osu->osu_methods); if (osu->osu_ssid_len) { fprintf(f, "osu_ssid=%s\n", wpa_ssid_txt(osu->osu_ssid, @@ -1352,7 +1351,7 @@ void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url) return; } - wpa_msg(wpa_s, MSG_INFO, HS20_T_C_ACCEPTANCE "%s", url); + wpas_notify_hs20_t_c_acceptance(wpa_s, url); } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/ibss_rsn.c b/wpa_supplicant-2.9_standard/wpa_supplicant/ibss_rsn.c index c13bf2d64237b976f4ba463894a0d3b1ee01a4eb..869994b5329c074f687a3c5c69fea2c7887371a6 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/ibss_rsn.c @@ -30,7 +30,7 @@ static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn, struct ibss_rsn_peer *peer; for (peer = ibss_rsn->peers; peer; peer = peer->next) - if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0) + if (ether_addr_equal(addr, peer->addr)) break; return peer; } @@ -138,15 +138,12 @@ static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer) if (peer->authentication_status & IBSS_RSN_REPORTED_PTK) return; peer->authentication_status |= IBSS_RSN_REPORTED_PTK; - wpa_msg(wpa_s, MSG_INFO, IBSS_RSN_COMPLETED MACSTR, - MAC2STR(peer->addr)); + wpa_msg(wpa_s, MSG_INFO, IBSS_RSN_COMPLETED MACSTR_SEC, + MAC2STR_SEC(peer->addr)); } -static int supp_set_key(void *ctx, -#ifdef CONFIG_MLD_PATCH - int link_id, -#endif - enum wpa_alg alg, + +static int supp_set_key(void *ctx, int link_id, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len, enum key_flag key_flag) @@ -175,12 +172,8 @@ static int supp_set_key(void *ctx, if (is_broadcast_ether_addr(addr)) addr = peer->addr; - return wpa_drv_set_key(peer->ibss_rsn->wpa_s, -#ifdef CONFIG_MLD_PATCH - link_id, -#endif - alg, addr, key_idx, - set_tx, seq, seq_len, key, key_len, + return wpa_drv_set_key(peer->ibss_rsn->wpa_s, link_id, alg, addr, + key_idx, set_tx, seq, seq_len, key, key_len, key_flag); } @@ -360,11 +353,7 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, } } - return wpa_drv_set_key(ibss_rsn->wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif - alg, addr, idx, + return wpa_drv_set_key(ibss_rsn->wpa_s, -1, alg, addr, idx, 1, seq, 6, key, key_len, key_flag); } @@ -495,8 +484,8 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, "\x00\x0f\xac\x04" "\x01\x00\x00\x0f\xac\x04" "\x01\x00\x00\x0f\xac\x02" - "\x00\x00", 22, NULL, 0, NULL, 0, NULL, 0) != - WPA_IE_OK) { + "\x00\x00", 22, NULL, 0, NULL, 0, NULL, 0, + NULL) != WPA_IE_OK) { wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); return -1; } @@ -683,7 +672,7 @@ void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac) for (prev = NULL, peer = ibss_rsn->peers; peer != NULL; prev = peer, peer = peer->next) { - if (os_memcmp(peermac, peer->addr, ETH_ALEN) == 0) { + if (ether_addr_equal(peermac, peer->addr)) { if (prev == NULL) ibss_rsn->peers = peer->next; else @@ -784,7 +773,8 @@ static int ibss_rsn_eapol_dst_supp(const u8 *buf, size_t len) static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, struct ibss_rsn_peer *peer, - const u8 *buf, size_t len) + const u8 *buf, size_t len, + enum frame_encryption encrypted) { int supp; u8 *tmp; @@ -800,7 +790,7 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER; wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from " MACSTR_SEC, MAC2STR_SEC(peer->addr)); - wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len); + wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len, encrypted); } else { if (ibss_rsn_is_auth_started(peer) == 0) { wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for " @@ -821,7 +811,8 @@ static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, - const u8 *buf, size_t len) + const u8 *buf, size_t len, + enum frame_encryption encrypted) { struct ibss_rsn_peer *peer; @@ -830,7 +821,8 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, peer = ibss_rsn_get_peer(ibss_rsn, src_addr); if (peer) - return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len); + return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len, + encrypted); if (ibss_rsn_eapol_dst_supp(buf, len) > 0) { /* @@ -848,7 +840,7 @@ int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, IBSS_RSN_AUTH_EAPOL_BY_US); return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers, - buf, len); + buf, len, encrypted); } return 0; @@ -877,11 +869,7 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn, * still have a pairwise key configured. */ wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer " MACSTR_SEC, MAC2STR_SEC(addr)); - wpa_drv_set_key(ibss_rsn->wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif - WPA_ALG_NONE, addr, 0, 0, + wpa_drv_set_key(ibss_rsn->wpa_s, -1, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE); } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/ibss_rsn.h b/wpa_supplicant-2.9_standard/wpa_supplicant/ibss_rsn.h index 626c543546c8573581ef026b5db493fbd2edbfb2..cff45a79cec5e32fe70a37a825f8352110ff4ee1 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/ibss_rsn.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/ibss_rsn.h @@ -57,7 +57,8 @@ void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn); int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr); void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac); int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, - const u8 *buf, size_t len); + const u8 *buf, size_t len, + enum frame_encryption encrypted); void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk); void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame, size_t len); diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/interworking.c b/wpa_supplicant-2.9_standard/wpa_supplicant/interworking.c index f9c483c15b2341dbe86892f721fd1df83c6de72b..08dd3e0cc6fc895612c4c5cace3b4976b6fcce99 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/interworking.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/interworking.c @@ -144,9 +144,9 @@ static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s) struct wpa_cred *cred; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { - if (cred->roaming_consortium_len) + if (cred->num_home_ois) return 1; - if (cred->required_roaming_consortium_len) + if (cred->num_required_home_ois) return 1; if (cred->num_roaming_consortiums) return 1; @@ -259,7 +259,6 @@ static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s, MAC2STR(bss->bssid)); wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR_SEC, MAC2STR_SEC(bss->bssid)); - wpa_s->interworking_gas_bss = bss; info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST; @@ -424,6 +423,11 @@ static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos, case NAI_REALM_INNER_NON_EAP_MSCHAPV2: wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2"); break; + default: + wpa_printf(MSG_DEBUG, + "Unsupported EAP-TTLS inner method %u", + *pos); + break; } break; case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD: @@ -993,8 +997,8 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, " (3GPP)", MAC2STR_SEC(bss->bssid)); if (already_connected(wpa_s, cred, bss)) { - wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, - MAC2STR(bss->bssid)); + wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR_SEC, + MAC2STR_SEC(bss->bssid)); return wpa_s->current_ssid->id; } @@ -1070,6 +1074,18 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, goto fail; } + if (cred->imsi_privacy_cert && cred->imsi_privacy_cert[0]) { + if (wpa_config_set_quoted(ssid, "imsi_privacy_cert", + cred->imsi_privacy_cert) < 0) + goto fail; + } + + if (cred->imsi_privacy_attr && cred->imsi_privacy_attr[0]) { + if (wpa_config_set_quoted(ssid, "imsi_privacy_attr", + cred->imsi_privacy_attr) < 0) + goto fail; + } + wpa_s->next_ssid = ssid; wpa_config_update_prio_list(wpa_s->conf); if (!only_add) @@ -1085,8 +1101,7 @@ fail: } -static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, - size_t rc_len) +static int oi_element_match(const u8 *ie, const u8 *oi, size_t oi_len) { const u8 *pos, *end; u8 lens; @@ -1111,24 +1126,24 @@ static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id, if ((lens & 0x0f) + (lens >> 4) > end - pos) return 0; - if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + if ((lens & 0x0f) == oi_len && os_memcmp(pos, oi, oi_len) == 0) return 1; pos += lens & 0x0f; - if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + if ((lens >> 4) == oi_len && os_memcmp(pos, oi, oi_len) == 0) return 1; pos += lens >> 4; - if (pos < end && (size_t) (end - pos) == rc_len && - os_memcmp(pos, rc_id, rc_len) == 0) + if (pos < end && (size_t) (end - pos) == oi_len && + os_memcmp(pos, oi, oi_len) == 0) return 1; return 0; } -static int roaming_consortium_anqp_match(const struct wpabuf *anqp, - const u8 *rc_id, size_t rc_len) +static int oi_anqp_match(const struct wpabuf *anqp, const u8 *oi, + size_t oi_len) { const u8 *pos, *end; u8 len; @@ -1144,7 +1159,7 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp, len = *pos++; if (len > end - pos) break; - if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0) + if (len == oi_len && os_memcmp(pos, oi, oi_len) == 0) return 1; pos += len; } @@ -1153,11 +1168,26 @@ static int roaming_consortium_anqp_match(const struct wpabuf *anqp, } -static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp, - const u8 *rc_id, size_t rc_len) +static int oi_match(const u8 *ie, const struct wpabuf *anqp, + const u8 *oi, size_t oi_len) { - return roaming_consortium_element_match(ie, rc_id, rc_len) || - roaming_consortium_anqp_match(anqp, rc_id, rc_len); + return oi_element_match(ie, oi, oi_len) || + oi_anqp_match(anqp, oi, oi_len); +} + + +static int cred_home_ois_match(const u8 *ie, const struct wpabuf *anqp, + const struct wpa_cred *cred) { + unsigned int i; + + /* There's a match if at least one of the home OI matches. */ + for (i = 0; i < cred->num_home_ois; i++) { + if (oi_match(ie, anqp, cred->home_ois[i], + cred->home_ois_len[i])) + return 1; + } + + return 0; } @@ -1168,9 +1198,8 @@ static int cred_roaming_consortiums_match(const u8 *ie, unsigned int i; for (i = 0; i < cred->num_roaming_consortiums; i++) { - if (roaming_consortium_match(ie, anqp, - cred->roaming_consortiums[i], - cred->roaming_consortiums_len[i])) + if (oi_match(ie, anqp, cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i])) return 1; } @@ -1181,8 +1210,9 @@ static int cred_roaming_consortiums_match(const u8 *ie, static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss) { const u8 *ie; + unsigned int i; - if (cred->required_roaming_consortium_len == 0) + if (cred->num_required_home_ois == 0) return 0; ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); @@ -1191,11 +1221,16 @@ static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss) (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL)) return 1; - return !roaming_consortium_match(ie, - bss->anqp ? - bss->anqp->roaming_consortium : NULL, - cred->required_roaming_consortium, - cred->required_roaming_consortium_len); + /* According to Passpoint specification, there must be a match for + * each required home OI provided. */ + for (i = 0; i < cred->num_required_home_ois; i++) { + if (!oi_match(ie, bss->anqp ? + bss->anqp->roaming_consortium : NULL, + cred->required_home_ois[i], + cred->required_home_ois_len[i])) + return 1; + } + return 0; } @@ -1395,26 +1430,24 @@ static struct wpa_cred * interworking_credentials_available_roaming_consortium( return NULL; for (cred = wpa_s->conf->cred; cred; cred = cred->next) { - if (cred->roaming_consortium_len == 0 && + if (cred->num_home_ois == 0 && + cred->num_required_home_ois == 0 && cred->num_roaming_consortiums == 0) continue; if (!cred->eap_method) continue; - if ((cred->roaming_consortium_len == 0 || - !roaming_consortium_match(ie, anqp, - cred->roaming_consortium, - cred->roaming_consortium_len)) && - !cred_roaming_consortiums_match(ie, anqp, cred) && - (cred->required_roaming_consortium_len == 0 || - !roaming_consortium_match( - ie, anqp, cred->required_roaming_consortium, - cred->required_roaming_consortium_len))) + /* If there's required home OIs, there must be a match for each + * required OI (see Passpoint v3.2 - 9.1.2 - RequiredHomeOI). */ + if (cred->num_required_home_ois > 0 && + cred_no_required_oi_match(cred, bss)) continue; - if (cred_no_required_oi_match(cred, bss)) + if (!cred_home_ois_match(ie, anqp, cred) && + !cred_roaming_consortiums_match(ie, anqp, cred)) continue; + if (!ignore_bw && cred_below_min_backhaul(wpa_s, cred, bss)) continue; if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss)) @@ -1598,12 +1631,12 @@ static int interworking_connect_roaming_consortium( const struct wpabuf *anqp; unsigned int i; - wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR - " based on roaming consortium match", MAC2STR(bss->bssid)); + wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR_SEC + " based on roaming consortium match", MAC2STR_SEC(bss->bssid)); if (already_connected(wpa_s, cred, bss)) { - wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, - MAC2STR(bss->bssid)); + wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR_SEC, + MAC2STR_SEC(bss->bssid)); return wpa_s->current_ssid->id; } @@ -1629,9 +1662,8 @@ static int interworking_connect_roaming_consortium( ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM); anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL; for (i = 0; (ie || anqp) && i < cred->num_roaming_consortiums; i++) { - if (!roaming_consortium_match( - ie, anqp, cred->roaming_consortiums[i], - cred->roaming_consortiums_len[i])) + if (!oi_match(ie, anqp, cred->roaming_consortiums[i], + cred->roaming_consortiums_len[i])) continue; ssid->roaming_consortium_selection = @@ -1829,8 +1861,8 @@ int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, MAC2STR_SEC(bss->bssid)); if (already_connected(wpa_s, cred, bss)) { - wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR, - MAC2STR(bss->bssid)); + wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR_SEC, + MAC2STR_SEC(bss->bssid)); nai_realm_free(realm, count); return 0; } @@ -2051,8 +2083,8 @@ static struct wpa_cred * interworking_credentials_available_3gpp( compare: #endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */ wpa_msg(wpa_s, MSG_DEBUG, - "Interworking: Parsing 3GPP info from " MACSTR, - MAC2STR(bss->bssid)); + "Interworking: Parsing 3GPP info from " MACSTR_SEC, + MAC2STR_SEC(bss->bssid)); ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len); wpa_msg(wpa_s, MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not "); @@ -2378,8 +2410,8 @@ static int roaming_partner_match(struct wpa_supplicant *wpa_s, struct wpabuf *domain_names) { wpa_printf(MSG_DEBUG, "Interworking: Comparing roaming_partner info " - "fqdn='%s' exact_match=%d priority=%u country='**'", - partner->fqdn, partner->exact_match, partner->priority); + "fqdn='%s' exact_match=%d priority=%u country='**'", + partner->fqdn, partner->exact_match, partner->priority); wpa_hexdump_ascii(MSG_DEBUG, "Interworking: Domain names", wpabuf_head(domain_names), wpabuf_len(domain_names)); @@ -2627,8 +2659,8 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR_SEC " (after best roaming partner selection)", MAC2STR_SEC(selected->bssid)); - wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR, - MAC2STR(selected->bssid)); + wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR_SEC, + MAC2STR_SEC(selected->bssid)); interworking_connect(wpa_s, selected, 0); } else if (wpa_s->wpa_state == WPA_SCANNING) wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); @@ -2655,7 +2687,7 @@ interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) continue; if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED)) continue; - if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0) + if (!ether_addr_equal(bss->hessid, other->hessid)) continue; if (bss->ssid_len != other->ssid_len || os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0) @@ -2807,7 +2839,7 @@ int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, int freq, struct wpa_bss *bss; int res; - bss = wpa_bss_get_bssid(wpa_s, dst); + bss = wpa_bss_get_bssid_latest(wpa_s, dst); if (!bss && !freq) { wpa_printf(MSG_WARNING, "ANQP: Cannot send query without BSS freq info"); @@ -2956,8 +2988,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, switch (info_id) { case ANQP_CAPABILITY_LIST: - wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR - " ANQP Capability list", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR_SEC + " ANQP Capability list", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list", pos, slen); if (anqp) { @@ -2966,8 +2998,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_VENUE_NAME: - wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR - " Venue Name", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR_SEC + " Venue Name", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen); if (anqp) { wpabuf_free(anqp->venue_name); @@ -2975,9 +3007,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_NETWORK_AUTH_TYPE: - wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR_SEC " Network Authentication Type information", - MAC2STR(sa)); + MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication " "Type", pos, slen); if (anqp) { @@ -2986,8 +3018,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_ROAMING_CONSORTIUM: - wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR - " Roaming Consortium list", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR_SEC + " Roaming Consortium list", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium", pos, slen); if (anqp) { @@ -2996,9 +3028,9 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_IP_ADDR_TYPE_AVAILABILITY: - wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR_SEC " IP Address Type Availability information", - MAC2STR(sa)); + MAC2STR_SEC(sa)); wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability", pos, slen); if (anqp) { @@ -3008,8 +3040,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_NAI_REALM: - wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR - " NAI Realm list", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR_SEC + " NAI Realm list", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen); if (anqp) { wpabuf_free(anqp->nai_realm); @@ -3017,8 +3049,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_3GPP_CELLULAR_NETWORK: - wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR - " 3GPP Cellular Network information", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR_SEC + " 3GPP Cellular Network information", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network", pos, slen); if (anqp) { @@ -3027,8 +3059,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, } break; case ANQP_DOMAIN_NAME: - wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR - " Domain Name list", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR_SEC + " Domain Name list", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen); if (anqp) { wpabuf_free(anqp->domain_name); @@ -3037,8 +3069,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, break; #ifdef CONFIG_FILS case ANQP_FILS_REALM_INFO: - wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR - " FILS Realm Information", MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR_SEC + " FILS Realm Information", MAC2STR_SEC(sa)); wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: FILS Realm Information", pos, slen); if (anqp) { @@ -3048,8 +3080,8 @@ static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, break; #endif /* CONFIG_FILS */ case ANQP_VENUE_URL: - wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue URL", - MAC2STR(sa)); + wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR_SEC " Venue URL", + MAC2STR_SEC(sa)); protected_response = pmf_in_use(wpa_s, sa); anqp_add_extra(wpa_s, anqp, info_id, pos, slen, protected_response); @@ -3158,13 +3190,13 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, */ dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) { if (tmp == wpa_s->interworking_gas_bss && - os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) { + ether_addr_equal(tmp->bssid, dst)) { bss = tmp; break; } } if (bss == NULL) - bss = wpa_bss_get_bssid(wpa_s, dst); + bss = wpa_bss_get_bssid_latest(wpa_s, dst); pos = wpabuf_head(resp); end = pos + wpabuf_len(resp); @@ -3195,12 +3227,13 @@ void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, } out_parse_done: + if (bss) + wpas_notify_bss_anqp_changed(wpa_s, bss->id); #ifdef CONFIG_HS20 hs20_notify_parse_done(wpa_s); #endif /* CONFIG_HS20 */ out: - wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s", - MAC2STR(dst), anqp_result); + wpas_notify_anqp_query_done(wpa_s, dst, anqp_result); } @@ -3245,9 +3278,9 @@ static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, struct wpa_supplicant *wpa_s = ctx; struct wpabuf *n; - wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR + wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR_SEC " dialog_token=%d status_code=%d resp_len=%d", - MAC2STR(addr), dialog_token, status_code, + MAC2STR_SEC(addr), dialog_token, status_code, resp ? (int) wpabuf_len(resp) : -1); if (!resp) return; @@ -3278,14 +3311,14 @@ int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst, u8 query_resp_len_limit = 0; freq = wpa_s->assoc_freq; - bss = wpa_bss_get_bssid(wpa_s, dst); + bss = wpa_bss_get_bssid_latest(wpa_s, dst); if (bss) freq = bss->freq; if (freq <= 0) return -1; - wpa_msg(wpa_s, MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)", - MAC2STR(dst), freq); + wpa_msg(wpa_s, MSG_DEBUG, "GAS request to " MACSTR_SEC " (freq %d MHz)", + MAC2STR_SEC(dst), freq); wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto); wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query); diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/main.c b/wpa_supplicant-2.9_standard/wpa_supplicant/main.c index a4be796a0f7c25a93109fd0ecb802fce2cb5bec2..6c32075e93e3038c5abcab59674e9b8629115697 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/main.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/main.c @@ -12,6 +12,7 @@ #endif /* __linux__ */ #include "common.h" +#include "crypto/crypto.h" #include "fst/fst.h" #include "wpa_supplicant_i.h" #include "driver_i.h" @@ -181,6 +182,7 @@ static int wpa_supplicant_init_match(struct wpa_global *global) } #endif /* CONFIG_MATCH_IFACE */ + void set_running_wpa(); __attribute__ ((visibility ("default"))) int wpa_main(int argc, char *argv[]) @@ -189,7 +191,6 @@ __attribute__ ((visibility ("default"))) int wpa_main(int argc, char *argv[]) struct wpa_interface *ifaces, *iface; int iface_count, exitcode = -1; struct wpa_params params; - for (i = 0; i < argc; i++) { wpa_printf(MSG_DEBUG, "wpa_main argv[%d]: %s", i, argv[i]); } @@ -401,6 +402,7 @@ __attribute__ ((visibility ("default"))) int wpa_main(int argc, char *argv[]) if (exitcode == 0) exitcode = wpa_supplicant_run(global); + #ifdef DFR_HANDLER dev_excp_handler_deinit(); #endif @@ -416,6 +418,7 @@ out: #endif /* CONFIG_MATCH_IFACE */ os_free(params.pid_file); + crypto_unload(); os_program_deinit(); return exitcode; @@ -423,4 +426,4 @@ out: struct wpa_global* getWpaGlobal() { return global; -} +} \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/mbo.c b/wpa_supplicant-2.9_standard/wpa_supplicant/mbo.c index 464700dc0fecf2df0059f5fcb392455dd9582542..5b495014866724dada758df4e53740ada8ffa990 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/mbo.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/mbo.c @@ -65,14 +65,18 @@ const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len, } -const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr) +static const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, + enum mbo_attr_id attr, bool beacon) { const u8 *mbo, *end; if (!bss) return NULL; - mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); + if (beacon) + mbo = wpa_bss_get_vendor_ie_beacon(bss, MBO_IE_VENDOR_TYPE); + else + mbo = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE); if (!mbo) return NULL; @@ -83,6 +87,19 @@ const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr) } +const u8 * wpas_mbo_check_assoc_disallow(struct wpa_bss *bss) +{ + const u8 *assoc_disallow; + + assoc_disallow = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_ASSOC_DISALLOW, + bss->beacon_newer); + if (assoc_disallow && assoc_disallow[1] >= 1) + return assoc_disallow; + + return NULL; +} + + void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid) { @@ -92,8 +109,8 @@ void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, wpa_s->disable_mbo_oce = 0; if (!bss) return; - mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND); - oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND); + mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND, false); + oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND, false); if (!mbo && !oce) return; if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON)) diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/mesh.c b/wpa_supplicant-2.9_standard/wpa_supplicant/mesh.c index d887af70142b47721837d0948852e7b2a332ed9f..24bb2126f0c106e602a780c13517aa1d18231b2c 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/mesh.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/mesh.c @@ -225,12 +225,13 @@ static int wpas_mesh_update_freq_params(struct wpa_supplicant *wpa_s) ifmsh->conf->ieee80211n, ifmsh->conf->ieee80211ac, ifmsh->conf->ieee80211ax, + ifmsh->conf->ieee80211be, 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)) { + he_capab, NULL, 0)) { wpa_printf(MSG_ERROR, "Error updating mesh frequency params"); wpa_supplicant_mesh_deinit(wpa_s, true); return -1; @@ -639,6 +640,7 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, wpa_s->mesh_ht_enabled = !!params->freq.ht_enabled; wpa_s->mesh_vht_enabled = !!params->freq.vht_enabled; wpa_s->mesh_he_enabled = !!params->freq.he_enabled; + wpa_s->mesh_eht_enabled = !!params->freq.eht_enabled; if (params->freq.ht_enabled && params->freq.sec_channel_offset) ssid->ht40 = params->freq.sec_channel_offset; @@ -648,23 +650,27 @@ int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s, switch (params->freq.bandwidth) { case 80: if (params->freq.center_freq2) { - ssid->max_oper_chwidth = CHANWIDTH_80P80MHZ; + ssid->max_oper_chwidth = + CONF_OPER_CHWIDTH_80P80MHZ; ssid->vht_center_freq2 = params->freq.center_freq2; } else { - ssid->max_oper_chwidth = CHANWIDTH_80MHZ; + ssid->max_oper_chwidth = + CONF_OPER_CHWIDTH_80MHZ; } break; case 160: - ssid->max_oper_chwidth = CHANWIDTH_160MHZ; + ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_160MHZ; break; default: - ssid->max_oper_chwidth = CHANWIDTH_USE_HT; + ssid->max_oper_chwidth = CONF_OPER_CHWIDTH_USE_HT; break; } } if (wpa_s->mesh_he_enabled) ssid->he = 1; + if (wpa_s->mesh_eht_enabled) + ssid->eht = 1; if (ssid->beacon_int > 0) params->beacon_int = ssid->beacon_int; else if (wpa_s->conf->beacon_int > 0) diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/mesh_mpm.c b/wpa_supplicant-2.9_standard/wpa_supplicant/mesh_mpm.c index f49814ec3e9d0001bf23239af6f7ec1667fb7cf2..598fc41e085590f7fe51ed8ae22d0dfdf4422f09 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/mesh_mpm.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/mesh_mpm.c @@ -16,6 +16,7 @@ #include "ap/hostapd.h" #include "ap/sta_info.h" #include "ap/ieee802_11.h" +#include "ap/beacon.h" #include "ap/wpa_auth.h" #include "wpa_supplicant_i.h" #include "driver_i.h" @@ -263,6 +264,13 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, if (type != PLINK_CLOSE && conf->ocv) buf_len += OCV_OCI_EXTENDED_LEN; #endif /* CONFIG_OCV */ +#ifdef CONFIG_IEEE80211BE + if (type != PLINK_CLOSE && wpa_s->mesh_eht_enabled) { + buf_len += 3 + 2 + EHT_PHY_CAPAB_LEN + EHT_MCS_NSS_CAPAB_LEN + + EHT_PPE_THRESH_CAPAB_LEN; + buf_len += 3 + sizeof(struct ieee80211_eht_operation); +} +#endif /* CONFIG_IEEE80211BE */ buf = wpabuf_alloc(buf_len); if (!buf) @@ -390,7 +398,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, wpabuf_put_data(buf, he_capa_oper, pos - he_capa_oper); } #endif /* CONFIG_IEEE80211AX */ - #ifdef CONFIG_OCV if (type != PLINK_CLOSE && conf->ocv) { struct wpa_channel_info ci; @@ -407,6 +414,21 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_OCV */ +#ifdef CONFIG_IEEE80211BE + if (type != PLINK_CLOSE && wpa_s->mesh_eht_enabled) { + u8 eht_capa_oper[3 + + 2 + + EHT_PHY_CAPAB_LEN + + EHT_MCS_NSS_CAPAB_LEN + + EHT_PPE_THRESH_CAPAB_LEN + + 3 + sizeof(struct ieee80211_eht_operation)]; + pos = hostapd_eid_eht_capab(bss, eht_capa_oper, + IEEE80211_MODE_MESH); + pos = hostapd_eid_eht_operation(bss, pos); + wpabuf_put_data(buf, eht_capa_oper, pos - eht_capa_oper); + } +#endif /* CONFIG_IEEE80211BE */ + if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) { wpa_msg(wpa_s, MSG_INFO, "Mesh MPM: failed to add AMPE and MIC IE"); @@ -449,6 +471,7 @@ void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, params.plink_state = state; params.peer_aid = sta->peer_aid; params.set = 1; + params.mld_link_id = -1; ret = wpa_drv_sta_add(wpa_s, ¶ms); if (ret) { @@ -493,7 +516,7 @@ static void plink_timer(void *eloop_ctx, void *user_data) break; } reason = WLAN_REASON_MESH_MAX_RETRIES; - /* fall through */ + __attribute__((fallthrough)); case PLINK_CNF_RCVD: /* confirm timer */ @@ -545,8 +568,11 @@ 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) + if (sta->plink_state == PLINK_ESTAB) { hapd->num_plinks--; + wpas_notify_mesh_peer_disconnected( + wpa_s, sta->addr, WLAN_REASON_UNSPECIFIED); + } 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_SEC, @@ -677,6 +703,7 @@ void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr) params.addr = sta->addr; params.flags = WPA_STA_AUTHENTICATED | WPA_STA_AUTHORIZED; params.set = 1; + params.mld_link_id = -1; wpa_msg(wpa_s, MSG_DEBUG, "MPM authenticating " MACSTR, MAC2STR(sta->addr)); @@ -754,12 +781,13 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, set_disable_ht40(sta->ht_capabilities, 1); } - update_ht_state(data, sta); + if (update_ht_state(data, sta) > 0) + ieee802_11_update_beacons(data->iface); #ifdef CONFIG_IEEE80211AC copy_sta_vht_capab(data, sta, elems->vht_capabilities); copy_sta_vht_oper(data, sta, elems->vht_operation); - set_sta_vht_opmode(data, sta, elems->vht_opmode_notif); + set_sta_vht_opmode(data, sta, elems->opmode_notif); #endif /* CONFIG_IEEE80211AC */ #ifdef CONFIG_IEEE80211AX @@ -767,6 +795,13 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, elems->he_capabilities, elems->he_capabilities_len); copy_sta_he_6ghz_capab(data, sta, elems->he_6ghz_band_cap); #endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211BE + copy_sta_eht_capab(data, sta, IEEE80211_MODE_MESH, + elems->he_capabilities, + elems->he_capabilities_len, + elems->eht_capabilities, + elems->eht_capabilities_len); +#endif /*CONFIG_IEEE80211BE */ if (hostapd_get_aid(data, sta) < 0) { wpa_msg(wpa_s, MSG_ERROR, "No AIDs available"); @@ -788,8 +823,11 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, params.he_capab = sta->he_capab; params.he_capab_len = sta->he_capab_len; params.he_6ghz_capab = sta->he_6ghz_capab; + params.eht_capab = sta->eht_capab; + params.eht_capab_len = sta->eht_capab_len; params.flags |= WPA_STA_WMM; params.flags_mask |= WPA_STA_AUTHENTICATED; + params.mld_link_id = -1; if (conf->security == MESH_CONF_SEC_NONE) { params.flags |= WPA_STA_AUTHORIZED; params.flags |= WPA_STA_AUTHENTICATED; @@ -827,7 +865,7 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr, if (ssid && ssid->no_auto_peer && (is_zero_ether_addr(data->mesh_required_peer) || - os_memcmp(data->mesh_required_peer, addr, ETH_ALEN) != 0)) { + !ether_addr_equal(data->mesh_required_peer, addr))) { wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with " MACSTR " because of no_auto_peer", MAC2STR(addr)); if (data->mesh_pending_auth) { @@ -838,7 +876,7 @@ void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr, mgmt = wpabuf_head(data->mesh_pending_auth); os_reltime_age(&data->mesh_pending_auth_time, &age); if (age.sec < 2 && - os_memcmp(mgmt->sa, addr, ETH_ALEN) == 0) { + ether_addr_equal(mgmt->sa, addr)) { wpa_printf(MSG_DEBUG, "mesh: Process pending Authentication frame from %u.%06u seconds ago", (unsigned int) age.sec, @@ -890,10 +928,7 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s, if (conf->security & MESH_CONF_SEC_AMPE) { wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len); - wpa_drv_set_key(wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif + wpa_drv_set_key(wpa_s, -1, wpa_cipher_to_alg(conf->pairwise_cipher), sta->addr, 0, 0, seq, sizeof(seq), sta->mtk, sta->mtk_len, @@ -903,10 +938,7 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s, sta->mgtk_rsc, sizeof(sta->mgtk_rsc)); wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK", sta->mgtk, sta->mgtk_len); - wpa_drv_set_key(wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif + wpa_drv_set_key(wpa_s, -1, wpa_cipher_to_alg(conf->group_cipher), sta->addr, sta->mgtk_key_id, 0, sta->mgtk_rsc, sizeof(sta->mgtk_rsc), @@ -919,10 +951,7 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s, wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK", sta->igtk, sta->igtk_len); wpa_drv_set_key( - wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif + wpa_s, -1, wpa_cipher_to_alg(conf->mgmt_group_cipher), sta->addr, sta->igtk_key_id, 0, sta->igtk_rsc, sizeof(sta->igtk_rsc), @@ -941,11 +970,6 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s, peer_add_timer(wpa_s, NULL); eloop_cancel_timeout(plink_timer, wpa_s, sta); - /* Send ctrl event */ - wpa_msg(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR, - MAC2STR(sta->addr)); - - /* Send D-Bus event */ wpas_notify_mesh_peer_connected(wpa_s, sta->addr); } @@ -1096,10 +1120,6 @@ static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta, " closed with reason %d", MAC2STR(sta->addr), reason); - wpa_msg(wpa_s, MSG_INFO, MESH_PEER_DISCONNECTED MACSTR, - MAC2STR(sta->addr)); - - /* Send D-Bus event */ wpas_notify_mesh_peer_disconnected(wpa_s, sta->addr, reason); @@ -1418,8 +1438,13 @@ void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s, /* called by ap_free_sta */ void mesh_mpm_free_sta(struct hostapd_data *hapd, struct sta_info *sta) { - if (sta->plink_state == PLINK_ESTAB) + struct wpa_supplicant *wpa_s = hapd->iface->owner; + + if (sta->plink_state == PLINK_ESTAB) { hapd->num_plinks--; + wpas_notify_mesh_peer_disconnected( + wpa_s, sta->addr, WLAN_REASON_UNSPECIFIED); + } eloop_cancel_timeout(plink_timer, ELOOP_ALL_CTX, sta); eloop_cancel_timeout(mesh_auth_timer, ELOOP_ALL_CTX, sta); } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/mesh_rsn.c b/wpa_supplicant-2.9_standard/wpa_supplicant/mesh_rsn.c index fa56484c1443c63ae54e65eb07ed228047a91254..f167b34da852dc4c573ffe3fd1b0c1c9f0529825 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/mesh_rsn.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/mesh_rsn.c @@ -38,8 +38,8 @@ void mesh_auth_timer(void *eloop_ctx, void *user_data) wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR_SEC " (attempt %d) ", MAC2STR_SEC(sta->addr), sta->sae_auth_retry); - wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_FAILURE "addr=" MACSTR, - MAC2STR(sta->addr)); + wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_FAILURE "addr=" MACSTR_SEC, + MAC2STR_SEC(sta->addr)); if (sta->sae_auth_retry < MESH_AUTH_RETRY) { mesh_rsn_auth_sae_sta(wpa_s, sta); } else { @@ -54,8 +54,8 @@ void mesh_auth_timer(void *eloop_ctx, void *user_data) wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED); sta->sae->state = SAE_NOTHING; wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr=" - MACSTR " duration=%d", - MAC2STR(sta->addr), + MACSTR_SEC " duration=%d", + MAC2STR_SEC(sta->addr), hapd->conf->ap_max_inactivity); } sta->sae_auth_retry++; @@ -118,11 +118,7 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, } wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len); - return wpa_drv_set_key(mesh_rsn->wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif - alg, addr, idx, + return wpa_drv_set_key(mesh_rsn->wpa_s, -1, alg, addr, idx, 1, seq, 6, key, key_len, key_flag); } @@ -146,6 +142,23 @@ static int auth_start_ampe(void *ctx, const u8 *addr) } +static int auth_for_each_sta( + void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx), + void *cb_ctx) +{ + struct mesh_rsn *rsn = ctx; + struct hostapd_data *hapd; + struct sta_info *sta; + + hapd = rsn->wpa_s->ifmsh->bss[0]; + for (sta = hapd->sta_list; sta; sta = sta->next) { + if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx)) + return 1; + } + return 0; +} + + static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, enum mfp_options ieee80211w, int ocv) { @@ -155,6 +168,7 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, .get_psk = auth_get_psk, .set_key = auth_set_key, .start_ampe = auth_start_ampe, + .for_each_sta = auth_for_each_sta, }; u8 seq[6] = {}; @@ -198,10 +212,7 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, /* group mgmt */ wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK", rsn->igtk, rsn->igtk_len); - wpa_drv_set_key(rsn->wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif + wpa_drv_set_key(rsn->wpa_s, -1, wpa_cipher_to_alg(rsn->mgmt_group_cipher), broadcast_ether_addr, rsn->igtk_key_id, 1, @@ -212,11 +223,7 @@ 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, -#ifdef CONFIG_MLD_PATCH - -1, -#endif - wpa_cipher_to_alg(rsn->group_cipher), + wpa_drv_set_key(rsn->wpa_s, -1, 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); @@ -397,7 +404,8 @@ int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, " - try to use PMKSA caching instead of new SAE authentication", MAC2STR_SEC(sta->addr)); wpa_auth_pmksa_set_to_sm(pmksa, sta->wpa_sm, hapd->wpa_auth, - sta->sae->pmkid, sta->sae->pmk); + sta->sae->pmkid, sta->sae->pmk, + &sta->sae->pmk_len); sae_accept_sta(hapd, sta); sta->mesh_sae_pmksa_caching = 1; return 0; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/nan_usd.c b/wpa_supplicant-2.9_standard/wpa_supplicant/nan_usd.c new file mode 100644 index 0000000000000000000000000000000000000000..da0a87abb3292838f636ee12e83c91d39cff2a2c --- /dev/null +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/nan_usd.c @@ -0,0 +1,513 @@ +/* + * NAN unsynchronized service discovery (USD) + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/nan_de.h" +#include "wpa_supplicant_i.h" +#include "offchannel.h" +#include "driver_i.h" +#include "nan_usd.h" + + +static const char * +tx_status_result_txt(enum offchannel_send_action_result result) +{ + switch (result) { + case OFFCHANNEL_SEND_ACTION_SUCCESS: + return "success"; + case OFFCHANNEL_SEND_ACTION_NO_ACK: + return "no-ack"; + case OFFCHANNEL_SEND_ACTION_FAILED: + return "failed"; + } + + return "?"; +} + + +static void wpas_nan_de_tx_status(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, + const u8 *data, size_t data_len, + enum offchannel_send_action_result result) +{ + if (!wpa_s->nan_de) + return; + + wpa_printf(MSG_DEBUG, "NAN: TX status A1=" MACSTR " A2=" MACSTR + " A3=" MACSTR " freq=%d len=%zu result=%s", + MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), freq, + data_len, tx_status_result_txt(result)); + + nan_de_tx_status(wpa_s->nan_de, freq, dst); +} + + +struct wpas_nan_usd_tx_work { + unsigned int freq; + unsigned int wait_time; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + struct wpabuf *buf; +}; + + +static void wpas_nan_usd_tx_work_free(struct wpas_nan_usd_tx_work *twork) +{ + if (!twork) + return; + wpabuf_free(twork->buf); + os_free(twork); +} + + +static void wpas_nan_usd_tx_work_done(struct wpa_supplicant *wpa_s) +{ + struct wpas_nan_usd_tx_work *twork; + + if (!wpa_s->nan_usd_tx_work) + return; + + twork = wpa_s->nan_usd_tx_work->ctx; + wpas_nan_usd_tx_work_free(twork); + radio_work_done(wpa_s->nan_usd_tx_work); + wpa_s->nan_usd_tx_work = NULL; +} + + +static int wpas_nan_de_tx_send(struct wpa_supplicant *wpa_s, unsigned int freq, + unsigned int wait_time, const u8 *dst, + const u8 *src, const u8 *bssid, + const struct wpabuf *buf) +{ + wpa_printf(MSG_DEBUG, "NAN: TX NAN SDF A1=" MACSTR " A2=" MACSTR + " A3=" MACSTR " freq=%d len=%zu", + MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), freq, + wpabuf_len(buf)); + + return offchannel_send_action(wpa_s, freq, dst, src, bssid, + wpabuf_head(buf), wpabuf_len(buf), + wait_time, wpas_nan_de_tx_status, 1); +} + + +static void wpas_nan_usd_start_tx_cb(struct wpa_radio_work *work, int deinit) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpas_nan_usd_tx_work *twork = work->ctx; + + if (deinit) { + if (work->started) { + wpa_s->nan_usd_tx_work = NULL; + offchannel_send_action_done(wpa_s); + } + wpas_nan_usd_tx_work_free(twork); + return; + } + + wpa_s->nan_usd_tx_work = work; + + if (wpas_nan_de_tx_send(wpa_s, twork->freq, twork->wait_time, + twork->dst, twork->src, twork->bssid, + twork->buf) < 0) + wpas_nan_usd_tx_work_done(wpa_s); +} + + +static int wpas_nan_de_tx(void *ctx, unsigned int freq, unsigned int wait_time, + const u8 *dst, const u8 *src, const u8 *bssid, + const struct wpabuf *buf) +{ + struct wpa_supplicant *wpa_s = ctx; + struct wpas_nan_usd_tx_work *twork; + + if (wpa_s->nan_usd_tx_work || wpa_s->nan_usd_listen_work) { + /* Reuse ongoing radio work */ + return wpas_nan_de_tx_send(wpa_s, freq, wait_time, dst, src, + bssid, buf); + } + + twork = os_zalloc(sizeof(*twork)); + if (!twork) + return -1; + twork->freq = freq; + twork->wait_time = wait_time; + os_memcpy(twork->dst, dst, ETH_ALEN); + os_memcpy(twork->src, src, ETH_ALEN); + os_memcpy(twork->bssid, bssid, ETH_ALEN); + twork->buf = wpabuf_dup(buf); + if (!twork->buf) { + wpas_nan_usd_tx_work_free(twork); + return -1; + } + + if (radio_add_work(wpa_s, freq, "nan-usd-tx", 0, + wpas_nan_usd_start_tx_cb, twork) < 0) { + wpas_nan_usd_tx_work_free(twork); + return -1; + } + + return 0; +} + + +struct wpas_nan_usd_listen_work { + unsigned int freq; + unsigned int duration; +}; + + +static void wpas_nan_usd_listen_work_done(struct wpa_supplicant *wpa_s) +{ + struct wpas_nan_usd_listen_work *lwork; + + if (!wpa_s->nan_usd_listen_work) + return; + + lwork = wpa_s->nan_usd_listen_work->ctx; + os_free(lwork); + radio_work_done(wpa_s->nan_usd_listen_work); + wpa_s->nan_usd_listen_work = NULL; +} + + +static void wpas_nan_usd_start_listen_cb(struct wpa_radio_work *work, + int deinit) +{ + struct wpa_supplicant *wpa_s = work->wpa_s; + struct wpas_nan_usd_listen_work *lwork = work->ctx; + unsigned int duration; + + if (deinit) { + if (work->started) { + wpa_s->nan_usd_listen_work = NULL; + wpa_drv_cancel_remain_on_channel(wpa_s); + } + os_free(lwork); + return; + } + + wpa_s->nan_usd_listen_work = work; + + duration = lwork->duration; + if (duration > wpa_s->max_remain_on_chan) + duration = wpa_s->max_remain_on_chan; + wpa_printf(MSG_DEBUG, "NAN: Start listen on %u MHz for %u ms", + lwork->freq, duration); + if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) { + wpa_printf(MSG_DEBUG, + "NAN: Failed to request the driver to remain on channel (%u MHz) for listen", + lwork->freq); + wpas_nan_usd_listen_work_done(wpa_s); + return; + } +} + + +static int wpas_nan_de_listen(void *ctx, unsigned int freq, + unsigned int duration) +{ + struct wpa_supplicant *wpa_s = ctx; + struct wpas_nan_usd_listen_work *lwork; + + lwork = os_zalloc(sizeof(*lwork)); + if (!lwork) + return -1; + lwork->freq = freq; + lwork->duration = duration; + + if (radio_add_work(wpa_s, freq, "nan-usd-listen", 0, + wpas_nan_usd_start_listen_cb, lwork) < 0) { + os_free(lwork); + return -1; + } + + return 0; +} + + +static void +wpas_nan_de_discovery_result(void *ctx, int subscribe_id, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len, int peer_publish_id, + const u8 *peer_addr, bool fsd, bool fsd_gas) +{ + struct wpa_supplicant *wpa_s = ctx; + char *ssi_hex; + + ssi_hex = os_zalloc(2 * ssi_len + 1); + if (!ssi_hex) + return; + if (ssi) + wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len); + wpa_msg(wpa_s, MSG_INFO, NAN_DISCOVERY_RESULT + "subscribe_id=%d publish_id=%d address=" MACSTR + " fsd=%d fsd_gas=%d srv_proto_type=%u ssi=%s", + subscribe_id, peer_publish_id, MAC2STR(peer_addr), + fsd, fsd_gas, srv_proto_type, ssi_hex); + os_free(ssi_hex); +} + + +static void wpas_nan_de_replied(void *ctx, int publish_id, const u8 *peer_addr, + int peer_subscribe_id, + enum nan_service_protocol_type srv_proto_type, + const u8 *ssi, size_t ssi_len) +{ + struct wpa_supplicant *wpa_s = ctx; + char *ssi_hex; + + ssi_hex = os_zalloc(2 * ssi_len + 1); + if (!ssi_hex) + return; + if (ssi) + wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len); + wpa_msg(wpa_s, MSG_DEBUG, NAN_REPLIED + "publish_id=%d address=" MACSTR + " subscribe_id=%d srv_proto_type=%u ssi=%s", + publish_id, MAC2STR(peer_addr), peer_subscribe_id, + srv_proto_type, ssi_hex); + os_free(ssi_hex); +} + + +static const char * nan_reason_txt(enum nan_de_reason reason) +{ + switch (reason) { + case NAN_DE_REASON_TIMEOUT: + return "timeout"; + case NAN_DE_REASON_USER_REQUEST: + return "user-request"; + case NAN_DE_REASON_FAILURE: + return "failure"; + } + + return "unknown"; +} + + +static void wpas_nan_de_publish_terminated(void *ctx, int publish_id, + enum nan_de_reason reason) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpa_msg(wpa_s, MSG_INFO, NAN_PUBLISH_TERMINATED + "publish_id=%d reason=%s", + publish_id, nan_reason_txt(reason)); +} + + +static void wpas_nan_de_subscribe_terminated(void *ctx, int subscribe_id, + enum nan_de_reason reason) +{ + struct wpa_supplicant *wpa_s = ctx; + + wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED + "subscribe_id=%d reason=%s", + subscribe_id, nan_reason_txt(reason)); +} + + +static void wpas_nan_de_receive(void *ctx, int id, int peer_instance_id, + const u8 *ssi, size_t ssi_len, + const u8 *peer_addr) +{ + struct wpa_supplicant *wpa_s = ctx; + char *ssi_hex; + + ssi_hex = os_zalloc(2 * ssi_len + 1); + if (!ssi_hex) + return; + if (ssi) + wpa_snprintf_hex(ssi_hex, 2 * ssi_len + 1, ssi, ssi_len); + wpa_msg(wpa_s, MSG_INFO, NAN_RECEIVE + "id=%d peer_instance_id=%d address=" MACSTR " ssi=%s", + id, peer_instance_id, MAC2STR(peer_addr), ssi_hex); + os_free(ssi_hex); +} + + +int wpas_nan_usd_init(struct wpa_supplicant *wpa_s) +{ + struct nan_callbacks cb; + + os_memset(&cb, 0, sizeof(cb)); + cb.ctx = wpa_s; + cb.tx = wpas_nan_de_tx; + cb.listen = wpas_nan_de_listen; + cb.discovery_result = wpas_nan_de_discovery_result; + cb.replied = wpas_nan_de_replied; + cb.publish_terminated = wpas_nan_de_publish_terminated; + cb.subscribe_terminated = wpas_nan_de_subscribe_terminated; + cb.receive = wpas_nan_de_receive; + + wpa_s->nan_de = nan_de_init(wpa_s->own_addr, false, &cb); + if (!wpa_s->nan_de) + return -1; + return 0; +} + + +void wpas_nan_usd_deinit(struct wpa_supplicant *wpa_s) +{ + nan_de_deinit(wpa_s->nan_de); + wpa_s->nan_de = NULL; +} + + +void wpas_nan_usd_rx_sdf(struct wpa_supplicant *wpa_s, const u8 *src, + unsigned int freq, const u8 *buf, size_t len) +{ + if (!wpa_s->nan_de) + return; + nan_de_rx_sdf(wpa_s->nan_de, src, freq, buf, len); +} + + +void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->nan_de) + return; + nan_de_flush(wpa_s->nan_de); +} + + +int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, + struct nan_publish_params *params) +{ + int publish_id; + struct wpabuf *elems = NULL; + + if (!wpa_s->nan_de) + return -1; + + publish_id = nan_de_publish(wpa_s->nan_de, service_name, srv_proto_type, + ssi, elems, params); + wpabuf_free(elems); + return publish_id; +} + + +void wpas_nan_usd_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id) +{ + if (!wpa_s->nan_de) + return; + nan_de_cancel_publish(wpa_s->nan_de, publish_id); +} + + +int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id, + const struct wpabuf *ssi) +{ + if (!wpa_s->nan_de) + return -1; + return nan_de_update_publish(wpa_s->nan_de, publish_id, ssi); +} + + +int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s, + const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, + struct nan_subscribe_params *params) +{ + int subscribe_id; + struct wpabuf *elems = NULL; + + if (!wpa_s->nan_de) + return -1; + + subscribe_id = nan_de_subscribe(wpa_s->nan_de, service_name, + srv_proto_type, ssi, elems, params); + wpabuf_free(elems); + return subscribe_id; +} + + +void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s, + int subscribe_id) +{ + if (!wpa_s->nan_de) + return; + nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id); +} + + +int wpas_nan_usd_transmit(struct wpa_supplicant *wpa_s, int handle, + const struct wpabuf *ssi, const struct wpabuf *elems, + const u8 *peer_addr, u8 req_instance_id) +{ + if (!wpa_s->nan_de) + return -1; + return nan_de_transmit(wpa_s->nan_de, handle, ssi, elems, peer_addr, + req_instance_id); +} + + +void wpas_nan_usd_remain_on_channel_cb(struct wpa_supplicant *wpa_s, + unsigned int freq, unsigned int duration) +{ + wpas_nan_usd_listen_work_done(wpa_s); + + if (wpa_s->nan_de) + nan_de_listen_started(wpa_s->nan_de, freq, duration); +} + + +void wpas_nan_usd_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, + unsigned int freq) +{ + if (wpa_s->nan_de) + nan_de_listen_ended(wpa_s->nan_de, freq); +} + + +void wpas_nan_usd_tx_wait_expire(struct wpa_supplicant *wpa_s) +{ + wpas_nan_usd_tx_work_done(wpa_s); + + if (wpa_s->nan_de) + nan_de_tx_wait_ended(wpa_s->nan_de); +} + + +int * wpas_nan_usd_all_freqs(struct wpa_supplicant *wpa_s) +{ + int i, j; + int *freqs = NULL; + + if (!wpa_s->hw.modes) + return NULL; + + for (i = 0; i < wpa_s->hw.num_modes; i++) { + struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; + + for (j = 0; j < mode->num_channels; j++) { + struct hostapd_channel_data *chan = &mode->channels[j]; + + /* All 20 MHz channels on 2.4 and 5 GHz band */ + if (chan->freq < 2412 || chan->freq > 5900) + continue; + + /* that allow frames to be transmitted */ + if (chan->flag & (HOSTAPD_CHAN_DISABLED | + HOSTAPD_CHAN_NO_IR | + HOSTAPD_CHAN_RADAR)) + continue; + + int_array_add_unique(&freqs, chan->freq); + } + } + + return freqs; +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/nan_usd.h b/wpa_supplicant-2.9_standard/wpa_supplicant/nan_usd.h new file mode 100644 index 0000000000000000000000000000000000000000..149ac9e60adf9eb60afb91f04f172ee4c443c4da --- /dev/null +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/nan_usd.h @@ -0,0 +1,46 @@ +/* + * NAN unsynchronized service discovery (USD) + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef NAN_USD_H +#define NAN_USD_H + +struct nan_subscribe_params; +struct nan_publish_params; +enum nan_service_protocol_type; + +int wpas_nan_usd_init(struct wpa_supplicant *wpa_s); +void wpas_nan_usd_deinit(struct wpa_supplicant *wpa_s); +void wpas_nan_usd_rx_sdf(struct wpa_supplicant *wpa_s, const u8 *src, + unsigned int freq, const u8 *buf, size_t len); +void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s); +int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, + struct nan_publish_params *params); +void wpas_nan_usd_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id); +int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id, + const struct wpabuf *ssi); +int wpas_nan_usd_subscribe(struct wpa_supplicant *wpa_s, + const char *service_name, + enum nan_service_protocol_type srv_proto_type, + const struct wpabuf *ssi, + struct nan_subscribe_params *params); +void wpas_nan_usd_cancel_subscribe(struct wpa_supplicant *wpa_s, + int subscribe_id); +int wpas_nan_usd_transmit(struct wpa_supplicant *wpa_s, int handle, + const struct wpabuf *ssi, const struct wpabuf *elems, + const u8 *peer_addr, u8 req_instance_id); +void wpas_nan_usd_remain_on_channel_cb(struct wpa_supplicant *wpa_s, + unsigned int freq, + unsigned int duration); +void wpas_nan_usd_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, + unsigned int freq); +void wpas_nan_usd_tx_wait_expire(struct wpa_supplicant *wpa_s); +int * wpas_nan_usd_all_freqs(struct wpa_supplicant *wpa_s); + +#endif /* NAN_USD_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/notify.c b/wpa_supplicant-2.9_standard/wpa_supplicant/notify.c index b77294fd2151ca01567aff337166f77b6a46b4ed..b17ba56580177af34eea971dd6d8cad6b9d66a15 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/notify.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/notify.c @@ -17,6 +17,7 @@ #include "dbus/dbus_common.h" #include "dbus/dbus_new.h" #include "rsn_supp/wpa.h" +#include "rsn_supp/pmksa_cache.h" #include "fst/fst.h" #include "crypto/tls.h" #include "bss.h" @@ -144,18 +145,17 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, sme_state_changed(wpa_s); #ifdef ANDROID - wpa_msg_ctrl(wpa_s, MSG_INFO, - WPA_EVENT_STATE_CHANGE - "id=%d state=%d BSSID=" MACSTR " SSID=%s", - wpa_s->current_ssid ? wpa_s->current_ssid->id : -1, - new_state, - MAC2STR(wpa_s->bssid), - wpa_s->current_ssid && wpa_s->current_ssid->ssid ? - wpa_ssid_txt(wpa_s->current_ssid->ssid, - wpa_s->current_ssid->ssid_len) : ""); + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE + "id=%d state=%d BSSID=" MACSTR " SSID=%s", + wpa_s->current_ssid ? wpa_s->current_ssid->id : -1, + new_state, + MAC2STR(wpa_s->bssid), + wpa_s->current_ssid && wpa_s->current_ssid->ssid ? + wpa_ssid_txt(wpa_s->current_ssid->ssid, + wpa_s->current_ssid->ssid_len) : ""); #endif /* ANDROID */ wpa_printf(MSG_DEBUG, "prepare call onEventStateChanged"); - #if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) +#if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) struct WpaStateChangedParam wpaStateChangedParma; os_memset(&wpaStateChangedParma, 0, sizeof(struct WpaStateChangedParam)); os_memcpy(wpaStateChangedParma.bssid, wpa_s->bssid, ETH_ALEN); @@ -169,9 +169,9 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, wpa_printf(MSG_EXCESSIVE, "wpaStateChangedParma.ssid = NULL"); } WpaEventReport(wpa_s->ifname, WPA_EVENT_STATE_CHANGED, (void *) &wpaStateChangedParma); - #endif +#endif - #ifdef CONFIG_VENDOR_EXT +#ifdef CONFIG_VENDOR_EXT if (new_state == WPA_ASSOCIATING) { char old_ap_vendor_info[MAX_AP_VENDOR_INFO_LEN] = {0}; strcpy_s(old_ap_vendor_info, sizeof(old_ap_vendor_info), wpa_s->ap_vendor_info); @@ -191,7 +191,7 @@ void wpas_notify_state_changed(struct wpa_supplicant *wpa_s, notify_ap_vendor_info(wpa_s->ap_vendor_info); } } - #endif /* CONFIG_VENDOR_EXT */ +#endif /* CONFIG_VENDOR_EXT */ } @@ -302,12 +302,12 @@ void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s) return; } wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSSID_CHANGED " REASON=%s BSSID=" MACSTR, reason, MAC2STR(bssid)); - #if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) +#if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) struct WpaBssidChangedParam wpaBssidChangedParma; os_memcpy(wpaBssidChangedParma.bssid, wpa_s->bssid, ETH_ALEN); os_memcpy(wpaBssidChangedParma.reason, reason, strlen(reason)); WpaEventReport(wpa_s->ifname, WPA_EVENT_BSSID_CHANGE, (void *) &wpaBssidChangedParma); - #endif +#endif #endif // CONFIG_OPEN_HARMONY_PATCH } @@ -331,14 +331,21 @@ void wpas_notify_bssid_changed_ext(struct wpa_supplicant *wpa_s, char *reason) } #endif +void wpas_notify_mac_address_changed(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_MAC_ADDRESS); +} + void wpas_notify_mlo_work_state_changed(struct wpa_supplicant *wpa_s, struct mlo_work_state_event *mlo_event) { if (wpa_s->p2p_mgmt) return; #ifdef CONFIG_OPEN_HARMONY_PATCH - const u8 *bssid = wpa_s->bssid; - wpa_msg_ctrl(wpa_s, MSG_INFO, "BSSID=" MACSTR " feature=%d state=%d reason_code=%d", MAC2STR(bssid), + wpa_msg_ctrl(wpa_s, MSG_INFO, "notify_mlo_work_state feature=%d state=%d reason_code=%d", mlo_event->feature, mlo_event->state, mlo_event->reason_code); wpa_printf(MSG_INFO, "notify_mlo_work_state feature=%d state=%d reason_code=%d", @@ -539,7 +546,6 @@ void wpas_notify_network_request(struct wpa_supplicant *wpa_s, return; wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt); - if (wpas_hdi_notify_network_request(wpa_s, ssid, rtype, default_txt) == 0) { return; } @@ -558,6 +564,7 @@ void wpas_notify_network_request(struct wpa_supplicant *wpa_s, #endif } + void wpas_notify_scanning(struct wpa_supplicant *wpa_s) { if (wpa_s->p2p_mgmt) @@ -687,8 +694,35 @@ void wpas_notify_network_removed(struct wpa_supplicant *wpa_s, { if (wpa_s->next_ssid == ssid) wpa_s->next_ssid = NULL; - if (wpa_s->wpa) + if (wpa_s->last_ssid == ssid) + wpa_s->last_ssid = NULL; + if (wpa_s->current_ssid == ssid) + wpa_s->current_ssid = NULL; + if (wpa_s->ml_connect_probe_ssid == ssid) { + wpa_s->ml_connect_probe_ssid = NULL; + wpa_s->ml_connect_probe_bss = NULL; + } + if (wpa_s->connect_without_scan == ssid) + wpa_s->connect_without_scan = NULL; +#if defined(CONFIG_SME) && defined(CONFIG_SAE) + if (wpa_s->sme.ext_auth_wpa_ssid == ssid) + wpa_s->sme.ext_auth_wpa_ssid = NULL; +#endif /* CONFIG_SME && CONFIG_SAE */ + if (wpa_s->wpa) { + if ((wpa_key_mgmt_sae(ssid->key_mgmt) && + (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA)) || + ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) && + (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA))) { + /* For cases when PMK is generated at the driver */ + struct wpa_pmkid_params params; + + os_memset(¶ms, 0, sizeof(params)); + params.ssid = ssid->ssid; + params.ssid_len = ssid->ssid_len; + wpa_drv_remove_pmkid(wpa_s, ¶ms); + } wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); + } if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s && !wpa_s->p2p_mgmt) { wpas_dbus_unregister_network(wpa_s, ssid->id); @@ -699,11 +733,6 @@ 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 */ } @@ -715,7 +744,7 @@ void wpas_notify_bss_added(struct wpa_supplicant *wpa_s, wpas_dbus_register_bss(wpa_s, bssid, id); wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_ADDED "%u " MACSTR, - id, MAC2STR(bssid)); + id, MAC2STR(bssid)); wpa_printf(MSG_DEBUG, WPA_EVENT_BSS_ADDED "%u " MACSTR_SEC, id, MAC2STR_SEC(bssid)); } @@ -835,6 +864,15 @@ void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id) } +void wpas_notify_bss_anqp_changed(struct wpa_supplicant *wpa_s, unsigned int id) +{ + if (wpa_s->p2p_mgmt) + return; + + wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_ANQP, id); +} + + void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name) { if (wpa_s->p2p_mgmt) @@ -961,7 +999,6 @@ void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s, if (wpa_s && (wpa_s->p2p_business == MIRACAST_BUSINESS) && res && res->status) wpa_s->p2p_business = 0; #endif - wpas_dbus_signal_p2p_go_neg_resp(wpa_s, res); } @@ -975,7 +1012,6 @@ void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s, status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) wpa_s->p2p_business = 0; #endif - wpas_dbus_signal_p2p_invitation_result(wpa_s, status, bssid); } @@ -1064,7 +1100,7 @@ void wpas_notify_p2p_invitation_received(struct wpa_supplicant *wpa_s, static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *sta, - const u8 *p2p_dev_addr) + const u8 *p2p_dev_addr, const u8 *ip) { #ifdef CONFIG_P2P wpas_p2p_notify_ap_sta_authorized(wpa_s, p2p_dev_addr); @@ -1082,7 +1118,6 @@ static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, /* Notify listeners a new station has been authorized */ wpas_dbus_signal_sta_authorized(wpa_s, sta); - #ifdef CONFIG_VENDOR_EXT /* Vendor notify connected */ wpa_vendor_ext_notify_connected(wpa_s, sta); @@ -1105,12 +1140,10 @@ static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s, /* Notify listeners a station has been deauthorized */ wpas_dbus_signal_sta_deauthorized(wpa_s, sta); - #ifdef CONFIG_VENDOR_EXT /* Vendor notify deauthorized */ wpa_vendor_ext_notify_deauthorized(wpa_s, sta, p2p_dev_addr); #endif - /* Unregister the station */ wpas_dbus_unregister_sta(wpa_s, sta); } @@ -1118,10 +1151,11 @@ static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s, void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *mac_addr, int authorized, - const u8 *p2p_dev_addr) + const u8 *p2p_dev_addr, const u8 *ip) { if (authorized) - wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr); + wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr, + ip); else wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr, p2p_dev_addr); } @@ -1192,6 +1226,12 @@ void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code) } +void wpas_notify_psk_mismatch(struct wpa_supplicant *wpa_s) +{ + wpas_dbus_signal_psk_mismatch(wpa_s); +} + + void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { @@ -1258,6 +1298,8 @@ void wpas_notify_mesh_peer_connected(struct wpa_supplicant *wpa_s, if (wpa_s->p2p_mgmt) return; + wpa_msg(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR, + MAC2STR(peer_addr)); wpas_dbus_signal_mesh_peer_connected(wpa_s, peer_addr); } @@ -1268,6 +1310,8 @@ void wpas_notify_mesh_peer_disconnected(struct wpa_supplicant *wpa_s, if (wpa_s->p2p_mgmt) return; + wpa_msg(wpa_s, MSG_INFO, MESH_PEER_DISCONNECTED MACSTR, + MAC2STR(peer_addr)); wpas_dbus_signal_mesh_peer_disconnected(wpa_s, peer_addr, reason_code); } @@ -1307,11 +1351,21 @@ void wpas_notify_interworking_ap_added(struct wpa_supplicant *wpa_s, bh, bss_load, conn_capab); } + void wpas_notify_interworking_select_done(struct wpa_supplicant *wpa_s) { wpas_dbus_signal_interworking_select_done(wpa_s); } +void wpas_notify_anqp_query_done(struct wpa_supplicant *wpa_s, + const u8 *dst, const char *result) +{ + wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s", + MAC2STR(dst), result); + + wpas_dbus_signal_anqp_query_done(wpa_s, dst, result); +} + #endif /* CONFIG_INTERWORKING */ int wpas_set_external_sim(struct wpa_supplicant* wpa_s, char *params) @@ -1356,3 +1410,26 @@ int wpas_eap_sim_auth_rsp(struct wpa_supplicant *wpa_s, char *params) os_free(auth_rsp_params); return 0; } + + +void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s, + struct rsn_pmksa_cache_entry *entry) +{ + /* TODO: Notify external entities of the added PMKSA cache entry */ +} + + +void wpas_notify_signal_change(struct wpa_supplicant *wpa_s) +{ + wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SIGNAL_CHANGE); +} + + +#ifdef CONFIG_HS20 +void wpas_notify_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s, + const char *url) +{ + wpa_msg(wpa_s, MSG_INFO, HS20_T_C_ACCEPTANCE "%s", url); + wpas_dbus_signal_hs20_t_c_acceptance(wpa_s, url); +} +#endif /* CONFIG_HS20 */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/notify.h b/wpa_supplicant-2.9_standard/wpa_supplicant/notify.h index 970114b19b09aeb2fa624c148453dcc1cf0faa0a..aaea046e1fc061c7bc9b31584ee1bf3e651ecfd8 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/notify.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/notify.h @@ -19,6 +19,7 @@ struct wps_event_m2d; struct wps_event_fail; struct tls_cert_data; struct wpa_cred; +struct rsn_pmksa_cache_entry; #define RSP_PARAM_SIZE 120 #define GSM_AUTH_PREFIX "GSM-AUTH" @@ -89,6 +90,7 @@ void wpas_notify_bssid_changed_ext(struct wpa_supplicant *wpa_s, char *reason); #endif void wpas_notify_mlo_work_state_changed(struct wpa_supplicant *wpa_s, struct mlo_work_state_event *mlo_event); +void wpas_notify_mac_address_changed(struct wpa_supplicant *wpa_s); void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s); void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); @@ -136,6 +138,8 @@ void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s, void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s, unsigned int id); void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id); +void wpas_notify_bss_anqp_changed(struct wpa_supplicant *wpa_s, + unsigned int id); void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name); void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name); @@ -147,7 +151,7 @@ void wpas_notify_resume(struct wpa_global *global); void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *mac_addr, int authorized, - const u8 *p2p_dev_addr); + const u8 *p2p_dev_addr, const u8 *ip); void wpas_notify_p2p_find_stopped(struct wpa_supplicant *wpa_s); void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s, const u8 *dev_addr, int new_device); @@ -196,6 +200,7 @@ void wpas_notify_preq(struct wpa_supplicant *wpa_s, void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status, const char *parameter); void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code); +void wpas_notify_psk_mismatch(struct wpa_supplicant *wpa_s); void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s, @@ -224,4 +229,12 @@ void wpas_notify_interworking_select_done(struct wpa_supplicant *wpa_s); int wpas_set_external_sim(struct wpa_supplicant *wpa_s, char *params); int wpas_eap_sim_auth_rsp(struct wpa_supplicant *wpa_s, char *params); +void wpas_notify_anqp_query_done(struct wpa_supplicant *wpa_s, + const u8 *dst, const char *result); +void wpas_notify_pmk_cache_added(struct wpa_supplicant *wpa_s, + struct rsn_pmksa_cache_entry *entry); +void wpas_notify_signal_change(struct wpa_supplicant *wpa_s); +void wpas_notify_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s, + const char *url); + #endif /* NOTIFY_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/offchannel.c b/wpa_supplicant-2.9_standard/wpa_supplicant/offchannel.c index 05ad64755f8112ee758e3dd5a0718a012fc0b35f..dc1db98ef3a8768856190cd144d01d8001f5b658 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/offchannel.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/offchannel.c @@ -25,12 +25,12 @@ wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src) { struct wpa_supplicant *iface; - if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) { + if (ether_addr_equal(src, wpa_s->own_addr)) { #ifdef CONFIG_P2P if (wpa_s->p2p_mgmt && wpa_s != wpa_s->parent && wpa_s->parent->ap_iface && - os_memcmp(wpa_s->parent->own_addr, - wpa_s->own_addr, ETH_ALEN) == 0 && + ether_addr_equal(wpa_s->parent->own_addr, + wpa_s->own_addr) && wpabuf_len(wpa_s->pending_action_tx) >= 2 && *wpabuf_head_u8(wpa_s->pending_action_tx) != WLAN_ACTION_PUBLIC) { @@ -54,7 +54,7 @@ wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src) */ iface = wpa_s->global->ifaces; while (iface) { - if (os_memcmp(src, iface->own_addr, ETH_ALEN) == 0) + if (ether_addr_equal(src, iface->own_addr)) break; iface = iface->next; } @@ -188,7 +188,7 @@ void offchannel_send_action_tx_status( return; } - if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) { + if (!ether_addr_equal(dst, wpa_s->pending_action_dst)) { wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - " "unknown destination address"); return; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/op_classes.c b/wpa_supplicant-2.9_standard/wpa_supplicant/op_classes.c index bd53c5ceceafe2eeccc6d53902ccae4f18237a77..ff11d20b9903c5137356498e638fc40d891035c8 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/op_classes.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/op_classes.c @@ -22,13 +22,12 @@ static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, unsigned int *flags) { int i; - bool is_6ghz = op_class >= 131 && op_class <= 136; + bool is_6ghz = is_6ghz_op_class(op_class); for (i = 0; i < mode->num_channels; i++) { bool chan_is_6ghz; - chan_is_6ghz = mode->channels[i].freq >= 5935 && - mode->channels[i].freq <= 7115; + chan_is_6ghz = is_6ghz_freq(mode->channels[i].freq); if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan) break; } @@ -103,10 +102,7 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, NOT_ALLOWED) return NOT_ALLOWED; - if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) || - (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) || - (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) || - (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10))) + if (!(flags & HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL)) return NOT_ALLOWED; if (flags & HOSTAPD_CHAN_NO_IR) @@ -175,14 +171,8 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode, NOT_ALLOWED) return NOT_ALLOWED; - if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) || - (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) || - (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) || - (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) || - (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) || - (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) || - (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) || - (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10))) + if (!(flags & HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL) || + !(flags & HOSTAPD_CHAN_VHT_160MHZ_SUBCHANNEL)) return NOT_ALLOWED; if (flags & HOSTAPD_CHAN_NO_IR) @@ -196,6 +186,69 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode, } +static int get_center_320mhz(struct hostapd_hw_modes *mode, u8 channel, + const u8 *center_channels, size_t num_chan) +{ + unsigned int i; + + if (mode->mode != HOSTAPD_MODE_IEEE80211A || !mode->is_6ghz) + return 0; + + for (i = 0; i < num_chan; i++) { + /* + * In 320 MHz, the bandwidth "spans" 60 channels (e.g., 65-125), + * so the center channel is 30 channels away from the start/end. + */ + if (channel >= center_channels[i] - 30 && + channel <= center_channels[i] + 30) + return center_channels[i]; + } + + return 0; +} + + +static enum chan_allowed verify_320mhz(struct hostapd_hw_modes *mode, + u8 op_class, u8 channel) +{ + u8 center_chan; + unsigned int i; + bool no_ir = false; + const u8 *center_channels; + size_t num_chan; + const u8 center_channels_6ghz[] = { 31, 63, 95, 127, 159, 191 }; + + center_channels = center_channels_6ghz; + num_chan = ARRAY_SIZE(center_channels_6ghz); + + center_chan = get_center_320mhz(mode, channel, center_channels, + num_chan); + if (!center_chan) + return NOT_ALLOWED; + + /* Check all the channels are available */ + for (i = 0; i < 16; i++) { + unsigned int flags; + u8 adj_chan = center_chan - 30 + i * 4; + + if (allow_channel(mode, op_class, adj_chan, &flags) == + NOT_ALLOWED) + return NOT_ALLOWED; + + if (!(flags & HOSTAPD_CHAN_EHT_320MHZ_SUBCHANNEL)) + return NOT_ALLOWED; + + if (flags & HOSTAPD_CHAN_NO_IR) + no_ir = true; + } + + if (no_ir) + return NO_IR; + + return ALLOWED; +} + + enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class, u8 channel, u8 bw) { @@ -237,6 +290,13 @@ enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class, * result and use only the 80 MHz specific version. */ res2 = res = verify_80mhz(mode, op_class, channel); + } else if (bw == BW320) { + /* + * channel is a center channel and as such, not necessarily a + * valid 20 MHz channels. Override earlier allow_channel() + * result and use only the 320 MHz specific version. + */ + res2= res = verify_320mhz(mode, op_class, channel); } if (res == NOT_ALLOWED || res2 == NOT_ALLOWED) @@ -260,6 +320,7 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s, int z; int freq2 = 0; int freq5 = 0; + bool freq6 = false; mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode, is_6ghz_op_class(op_class->op_class)); @@ -274,7 +335,9 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s, if (f == 0) break; /* end of list */ - if (f > 4000 && f < 6000) + if (is_6ghz_freq(f)) + freq6 = true; + else if (f > 4000 && f < 6000) freq5 = 1; else if (f > 2400 && f < 2500) freq2 = 1; @@ -283,8 +346,11 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s, /* No frequencies specified, can use anything hardware supports. */ freq2 = freq5 = 1; + freq6 = true; } + if (is_6ghz_op_class(op_class->op_class) && !freq6) + return 0; if (op_class->op_class >= 115 && op_class->op_class <= 130 && !freq5) return 0; if (op_class->op_class >= 81 && op_class->op_class <= 84 && !freq2) @@ -462,6 +528,7 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, u8 op, current, chan; u8 *ie_len; size_t res; + bool op128 = false, op130 = false, op133 = false, op135 = false; /* * Determine the current operating class correct mode based on @@ -470,8 +537,9 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, * or used. */ if (wpas_sta_secondary_channel_offset(bss, ¤t, &chan) < 0 && - ieee80211_freq_to_channel_ext(bss->freq, 0, CHANWIDTH_USE_HT, - ¤t, &chan) == NUM_HOSTAPD_MODES) + ieee80211_freq_to_channel_ext(bss->freq, 0, + CONF_OPER_CHWIDTH_USE_HT, ¤t, + &chan) == NUM_HOSTAPD_MODES) return 0; /* @@ -488,8 +556,50 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, wpabuf_put_u8(buf, current); for (op = 0; global_op_class[op].op_class; op++) { - if (wpas_op_class_supported(wpa_s, ssid, &global_op_class[op])) - wpabuf_put_u8(buf, global_op_class[op].op_class); + bool supp; + u8 op_class = global_op_class[op].op_class; + + supp = wpas_op_class_supported(wpa_s, ssid, + &global_op_class[op]); + if (!supp) + continue; + switch (op_class) { + case 128: + op128 = true; + break; + case 130: + op130 = true; + break; + case 133: + op133 = true; + break; + case 135: + op135 = true; + break; + } + if (is_80plus_op_class(op_class)) + continue; + + /* Add a 1-octet operating class to the Operating Class field */ + wpabuf_put_u8(buf, global_op_class[op].op_class); + } + + /* Add the 2-octet operating classes (i.e., 80+80 MHz cases), if any */ + if ((op128 && op130) || (op133 && op135)) { + /* Operating Class Duple Sequence field */ + + /* Zero Delimiter */ + wpabuf_put_u8(buf, 0); + + /* Operating Class Duple List */ + if (op128 && op130) { + wpabuf_put_u8(buf, 130); + wpabuf_put_u8(buf, 128); + } + if (op133 && op135) { + wpabuf_put_u8(buf, 135); + wpabuf_put_u8(buf, 133); + } } *ie_len = wpabuf_len(buf) - 2; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant.c index 1cbdd339ea8da2be26b1e895f996bcbe5350580e..0104274f5fce32e7615680152d0e1277f2a1bbfa 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant.c @@ -179,7 +179,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len); static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, int *force_freq, int *pref_freq, int go, - unsigned int *pref_freq_list, + struct weighted_pcl *pref_freq_list, unsigned int *num_pref_freq); static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq, const u8 *ssid, size_t ssid_len); @@ -215,6 +215,8 @@ wpas_p2p_consider_moving_gos(struct wpa_supplicant *wpa_s, struct wpa_used_freq_data *freqs, unsigned int num, enum wpas_p2p_channel_update_trig trig); static void wpas_p2p_reconsider_moving_go(void *eloop_ctx, void *timeout_ctx); +static int wpas_p2p_disallowed_freq(struct wpa_global *global, + unsigned int freq); static int wpas_get_6ghz_he_chwidth_capab(struct hostapd_hw_modes *mode) @@ -242,7 +244,7 @@ static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s) return -1; num = get_shared_radio_freqs(wpa_s, freqs, - wpa_s->num_multichan_concurrent); + wpa_s->num_multichan_concurrent, false); os_free(freqs); unused = wpa_s->num_multichan_concurrent - num; @@ -270,7 +272,8 @@ wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s, return 0; num = get_shared_radio_freqs_data(wpa_s, freqs, - wpa_s->num_multichan_concurrent); + wpa_s->num_multichan_concurrent, + false); os_memset(p2p_freqs, 0, sizeof(struct wpa_used_freq_data) * len); @@ -395,6 +398,23 @@ static void wpas_p2p_scan_res_fail_handler(struct wpa_supplicant *wpa_s) } +void wpas_p2p_scan_freqs(struct wpa_supplicant *wpa_s, + struct wpa_driver_scan_params *params, + bool include_6ghz) +{ + wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, + params, false, false, false); + wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, + params, false, false, false); + wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211AD, + params, false, false, false); + if (!wpa_s->conf->p2p_6ghz_disable && + is_p2p_allow_6ghz(wpa_s->global->p2p) && include_6ghz) + wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, + params, true, true, false); +} + + static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit) { struct wpa_supplicant *wpa_s = work->wpa_s; @@ -417,14 +437,9 @@ static void wpas_p2p_trigger_scan_cb(struct wpa_radio_work *work, int deinit) params->only_new_results = 1; } - if (!params->p2p_include_6ghz && !params->freqs) { - wpa_printf(MSG_DEBUG, - "P2P: Exclude 6 GHz channels - 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); - } + if (!params->freqs) + wpas_p2p_scan_freqs(wpa_s, params, params->p2p_include_6ghz); + ret = wpa_drv_scan(wpa_s, params); if (ret == 0) wpa_s->curr_scan_cookie = params->scan_cookie; @@ -507,6 +522,13 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, num_req_dev_types, req_dev_types); if (wps_ie == NULL) goto fail; + + /* + * In case 6 GHz channels are requested as part of the P2P scan, only + * the PSCs would be included as P2P GOs are not expected to be + * collocated, i.e., they would not be announced in the RNR element of + * other APs. + */ if (!wpa_s->conf->p2p_6ghz_disable) params->p2p_include_6ghz = include_6ghz; switch (type) { @@ -608,9 +630,9 @@ static enum wpa_driver_if_type wpas_p2p_if_type(int p2p_group_interface) return WPA_IF_P2P_GO; case P2P_GROUP_INTERFACE_CLIENT: return WPA_IF_P2P_CLIENT; + default: + return WPA_IF_P2P_GROUP; } - - return WPA_IF_P2P_GROUP; } @@ -780,7 +802,8 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role, struct wpa_supplicant *go_wpa_s, *cli_wpa_s; struct wpa_ssid *persistent_go; int p2p_no_group_iface; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; + unsigned int size; wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role); @@ -860,7 +883,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role, !cli_wpa_s) return P2PS_SETUP_CLIENT; - /* fall through */ + __attribute__((fallthrough)); case P2PS_SETUP_NONE: case P2PS_SETUP_NEW: @@ -883,7 +906,7 @@ static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role, conncap = P2PS_SETUP_GROUP_OWNER; goto grp_owner; } - /* fall through */ + __attribute__((fallthrough)); default: return P2PS_SETUP_NONE; @@ -1118,6 +1141,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, } wpa_s->p2p_in_invitation = 0; + wpa_s->p2p_retry_limit = 0; eloop_cancel_timeout(wpas_p2p_move_go, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_reconsider_moving_go, wpa_s, NULL); @@ -1185,7 +1209,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_s->current_ssid = NULL; } - + #ifdef CONFIG_P2P_160M if (wpa_s->last_ssid == ssid){ wpa_printf(MSG_INFO, "Set wpa_s->last_ssid to NULL for SSID equals last_ssid"); @@ -1202,6 +1226,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, * Likewise, we don't send out network removed signals for such * network objects. */ + wpas_notify_network_removed(wpa_s, ssid); wpa_config_remove_network(wpa_s->conf, id); wpa_supplicant_clear_status(wpa_s); wpa_supplicant_cancel_sched_scan(wpa_s); @@ -1219,6 +1244,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, #ifdef CONFIG_VENDOR_EXT wpa_vendor_ext_p2p_enhance_mode_disable(wpa_s); #endif + wpa_s->p2p_go_no_pri_sec_switch = 0; return 0; } @@ -1316,7 +1342,7 @@ static int wpas_p2p_store_persistent_group(struct wpa_supplicant *wpa_s, "group (GO Dev Addr " MACSTR_SEC ")", MAC2STR_SEC(go_dev_addr)); for (s = wpa_s->conf->ssid; s; s = s->next) { if (s->disabled == 2 && - os_memcmp(go_dev_addr, s->bssid, ETH_ALEN) == 0 && + ether_addr_equal(go_dev_addr, s->bssid) && s->ssid_len == ssid->ssid_len && os_memcmp(ssid->ssid, s->ssid, ssid->ssid_len) == 0) break; @@ -1422,8 +1448,8 @@ static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s, return; for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) { - if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN, addr, - ETH_ALEN) != 0) + if (!ether_addr_equal(s->p2p_client_list + i * 2 * ETH_ALEN, + addr)) continue; if (i == s->num_p2p_clients - 1) @@ -1534,10 +1560,10 @@ static void wpas_p2p_group_started(struct wpa_supplicant *wpa_s, MAC2STR(go_dev_addr), persistent ? " [PERSISTENT]" : "", extra); wpa_printf(MSG_INFO, P2P_EVENT_GROUP_STARTED - "%s %s ssid=\"%s\" freq=%d go_dev_addr=" MACSTR_SEC "%s%s", - wpa_s->ifname, go ? "GO" : "client", anonymize_ssid(ssid_txt), freq, - MAC2STR_SEC(go_dev_addr), persistent ? " [PERSISTENT]" : "", - extra); + "%s %s ssid=\"%s\" freq=%d go_dev_addr=" MACSTR_SEC "%s%s", + wpa_s->ifname, go ? "GO" : "client", anonymize_ssid(ssid_txt), freq, + MAC2STR_SEC(go_dev_addr), persistent ? " [PERSISTENT]" : "", + extra); #endif #ifdef CONFIG_LIBWPA_VENDOR #ifdef CONFIG_VENDOR_EXT @@ -1608,6 +1634,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, wpa_s->p2p_in_provisioning = 0; } wpa_s->p2p_in_invitation = 0; + wpa_s->p2p_retry_limit = 0; wpa_s->group_formation_reported = 1; if (!success) { @@ -1801,8 +1828,8 @@ static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s, if (result != OFFCHANNEL_SEND_ACTION_SUCCESS && wpa_s->pending_pd_before_join && - (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 || - os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0) && + (ether_addr_equal(dst, wpa_s->pending_join_dev_addr) || + ether_addr_equal(dst, wpa_s->pending_join_iface_addr)) && wpa_s->p2p_fallback_to_go_neg) { wpa_s->pending_pd_before_join = 0; wpa_dbg(wpa_s, MSG_DEBUG, "P2P: No ACK for PD Req " @@ -2338,7 +2365,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s, ssid->auth_alg |= WPA_AUTH_ALG_SAE; ssid->key_mgmt = WPA_KEY_MGMT_SAE; ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; - ssid->sae_pwe = 1; + ssid->sae_pwe = SAE_PWE_HASH_TO_ELEMENT; wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use SAE auth_alg and key_mgmt"); } else { p2p_set_6ghz_dev_capab(wpa_s->global->p2p, false); @@ -2430,6 +2457,7 @@ do { \ d->passive_scan = s->passive_scan; d->pmf = s->pmf; d->p2p_6ghz_disable = s->p2p_6ghz_disable; + d->sae_pwe = s->sae_pwe; if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey && !d->wps_nfc_pw_from_config) { @@ -2722,6 +2750,21 @@ void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s) } +bool wpas_p2p_retry_limit_exceeded(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->p2p_in_invitation || !wpa_s->p2p_retry_limit || + wpa_s->p2p_in_invitation <= wpa_s->p2p_retry_limit) + return false; + + wpa_printf(MSG_DEBUG, "P2P: Group join retry limit exceeded"); + eloop_cancel_timeout(wpas_p2p_group_formation_timeout, + wpa_s->p2pdev, NULL); + eloop_register_timeout(0, 0, wpas_p2p_group_formation_timeout, + wpa_s->p2pdev, NULL); + return true; +} + + static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) { struct wpa_supplicant *wpa_s = ctx; @@ -2932,7 +2975,7 @@ static void wpas_dev_found(void *ctx, const u8 *addr, MAC2STR(addr), MAC2STR(info->p2p_device_addr), wps_dev_type_bin2str(info->pri_dev_type, - devtype, sizeof(devtype)), + devtype, sizeof(devtype)), info->device_name, methods, info->dev_capab, info->group_capab, id, str, @@ -2983,7 +3026,7 @@ static void wpas_dev_found(void *ctx, const u8 *addr, "dev_capab=0x%x group_capab=0x%x%s%s%s new=%d", MAC2STR(addr), MAC2STR(info->p2p_device_addr), wps_dev_type_bin2str(info->pri_dev_type, devtype, - sizeof(devtype)), + sizeof(devtype)), info->device_name, info->config_methods, info->dev_capab, info->group_capab, wfd_dev_info_hex ? " wfd_dev_info=0x" : "", @@ -3216,6 +3259,12 @@ static void wpas_stop_listen(void *ctx) wpa_drv_probe_req_report(wpa_s, 0); wpas_p2p_listen_work_done(wpa_s); + + if (radio_work_pending(wpa_s, "p2p-listen")) { + wpa_printf(MSG_DEBUG, + "P2P: p2p-listen is still pending - remove it"); + radio_remove_works(wpa_s, "p2p-listen", 0); + } } @@ -3354,8 +3403,8 @@ static void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) char params[20]; if (wpa_s->pending_pd_before_join && - (os_memcmp(peer, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 || - os_memcmp(peer, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) { + (ether_addr_equal(peer, wpa_s->pending_join_dev_addr) || + ether_addr_equal(peer, wpa_s->pending_join_iface_addr))) { wpa_s->pending_pd_before_join = 0; wpa_printf(MSG_DEBUG, "P2P: Starting pending " "join-existing-group operation"); @@ -3595,6 +3644,68 @@ static int wpas_p2p_pick_best_used_freq(struct wpa_supplicant *wpa_s, } +/** + * Pick the best frequency the driver suggests. + * + * num_pref_freq is used as both input and output + * - input: the max size of pref_freq_list, + * - output: the valid size of pref_freq_list filled with data. + */ +static int wpas_p2p_pick_best_pref_freq(struct wpa_supplicant *wpa_s, bool go, + struct weighted_pcl *pref_freq_list, + unsigned int *num_pref_freq) +{ + int best_freq = 0; + unsigned int max_pref_freq, i; + int res; + enum wpa_driver_if_type iface_type; + + max_pref_freq = *num_pref_freq; + *num_pref_freq = 0; + + if (go) + iface_type = WPA_IF_P2P_GO; + else + iface_type = WPA_IF_P2P_CLIENT; + + res = wpa_drv_get_pref_freq_list(wpa_s, iface_type, &max_pref_freq, + pref_freq_list); + if (!res && !is_p2p_allow_6ghz(wpa_s->global->p2p)) + max_pref_freq = p2p_remove_6ghz_channels(pref_freq_list, + max_pref_freq); + if (res || !max_pref_freq) { + wpa_printf(MSG_DEBUG, + "P2P: No preferred frequency list available"); + return 0; + } + + *num_pref_freq = max_pref_freq; + i = 0; + while (i < *num_pref_freq && + (!p2p_supported_freq(wpa_s->global->p2p, + pref_freq_list[i].freq) || + wpas_p2p_disallowed_freq(wpa_s->global, + pref_freq_list[i].freq) || + !p2p_pref_freq_allowed(&pref_freq_list[i], go))) { + wpa_printf(MSG_DEBUG, + "P2P: preferred_freq_list[%d]=%d is disallowed", + i, pref_freq_list[i].freq); + i++; + } + if (i != *num_pref_freq) { + best_freq = pref_freq_list[i].freq; + wpa_printf(MSG_DEBUG, "P2P: Using preferred_freq_list[%d]=%d", + i, best_freq); + } else { + wpa_printf(MSG_DEBUG, + "P2P: All driver preferred frequencies are disallowed for P2P use"); + *num_pref_freq = 0; + } + + return best_freq; +} + + static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, const u8 *go_dev_addr, const u8 *ssid, size_t ssid_len, int *go, u8 *group_bssid, @@ -3607,15 +3718,18 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, struct wpa_used_freq_data *freqs; struct wpa_supplicant *grp; int best_freq; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; + unsigned int num_pref_freq; + int res; + if (!persistent_group) { wpa_printf(MSG_DEBUG, "P2P: Invitation from " MACSTR_SEC " to join an active group (SSID: %s)", MAC2STR_SEC(sa), anonymize_ssid(wpa_ssid_txt(ssid, ssid_len))); if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) && - (os_memcmp(go_dev_addr, wpa_s->p2p_auth_invite, ETH_ALEN) - == 0 || - os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0)) { + (ether_addr_equal(go_dev_addr, wpa_s->p2p_auth_invite) || + ether_addr_equal(sa, wpa_s->p2p_auth_invite))) { wpa_printf(MSG_DEBUG, "P2P: Accept previously " "authorized invitation"); goto accept_inv; @@ -3657,7 +3771,7 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, } if (!is_zero_ether_addr(wpa_s->p2p_auth_invite) && - os_memcmp(sa, wpa_s->p2p_auth_invite, ETH_ALEN) == 0) { + ether_addr_equal(sa, wpa_s->p2p_auth_invite)) { wpa_printf(MSG_DEBUG, "P2P: Accept previously initiated " "invitation to re-invoke a persistent group"); os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); @@ -3666,7 +3780,7 @@ static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid, for (s = wpa_s->conf->ssid; s; s = s->next) { if (s->disabled == 2 && - os_memcmp(s->bssid, go_dev_addr, ETH_ALEN) == 0 && + ether_addr_equal(s->bssid, go_dev_addr) && s->ssid_len == ssid_len && os_memcmp(ssid, s->ssid, ssid_len) == 0) break; @@ -3717,6 +3831,12 @@ accept_inv: os_free(freqs); } + num_pref_freq = P2P_MAX_PREF_CHANNELS; + res = wpas_p2p_pick_best_pref_freq(wpa_s, *go, pref_freq_list, + &num_pref_freq); + if (res > 0) + best_freq = res; + /* Get one of the frequencies currently in use */ if (best_freq > 0) { wpa_printf(MSG_DEBUG, "P2P: Trying to prefer a channel already used by one of the interfaces"); @@ -3830,7 +3950,8 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, wpa_s->conf->p2p_go_he, wpa_s->conf->p2p_go_edmg, NULL, go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, - 1, is_p2p_allow_6ghz(wpa_s->global->p2p)); + 1, is_p2p_allow_6ghz(wpa_s->global->p2p), 0, + NULL); } else if (bssid) { wpa_s->user_initiated_pd = 0; wpa_msg_global(wpa_s, MSG_INFO, @@ -3970,13 +4091,13 @@ static void wpas_remove_persistent_peer(struct wpa_supplicant *wpa_s, return; for (i = 0; ssid->p2p_client_list && i < ssid->num_p2p_clients; i++) { - if (os_memcmp(ssid->p2p_client_list + i * 2 * ETH_ALEN, peer, - ETH_ALEN) == 0) + if (ether_addr_equal(ssid->p2p_client_list + i * 2 * ETH_ALEN, + peer)) break; } if (i >= ssid->num_p2p_clients || !ssid->p2p_client_list) { if (ssid->mode != WPAS_MODE_P2P_GO && - os_memcmp(ssid->bssid, peer, ETH_ALEN) == 0) { + ether_addr_equal(ssid->bssid, peer)) { wpa_printf(MSG_DEBUG, "P2P: Remove persistent group %d " "due to invitation result", ssid->id); wpas_notify_network_removed(wpa_s, ssid); @@ -4159,7 +4280,8 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, ssid->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 1, - is_p2p_allow_6ghz(wpa_s->global->p2p)); + is_p2p_allow_6ghz(wpa_s->global->p2p), 0, + NULL); #ifdef CONFIG_OPEN_HARMONY_MIRACAST_MAC if (wpa_s->p2p_business == MIRACAST_BUSINESS) wpa_s->p2p_business = 0; @@ -4367,13 +4489,7 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s, if (res == NO_IR) ret = NO_IR; if (!is_6ghz) { - if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) - return NOT_ALLOWED; - if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) - return NOT_ALLOWED; - if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) - return NOT_ALLOWED; - if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)) + if (!(flags & HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL)) return NOT_ALLOWED; } else if (is_6ghz && (!(wpas_get_6ghz_he_chwidth_capab(mode) & @@ -4458,21 +4574,8 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s, ret = NO_IR; if (!is_6ghz_op_class(op_class)) { - if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) - return NOT_ALLOWED; - if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) - return NOT_ALLOWED; - if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) - return NOT_ALLOWED; - if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) - return NOT_ALLOWED; - if (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) - return NOT_ALLOWED; - if (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) - return NOT_ALLOWED; - if (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) - return NOT_ALLOWED; - if (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)) + if (!(flags & HOSTAPD_CHAN_VHT_80MHZ_SUBCHANNEL) || + !(flags & HOSTAPD_CHAN_VHT_160MHZ_SUBCHANNEL)) return NOT_ALLOWED; } else if (is_6ghz_op_class(op_class) && (!(wpas_get_6ghz_he_chwidth_capab(mode) & @@ -4506,6 +4609,10 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s, int flag = 0; enum chan_allowed res, res2; + if (is_6ghz_op_class(op_class) && !is_6ghz_psc_frequency( + p2p_channel_to_freq(op_class, channel))) + return NOT_ALLOWED; + res2 = res = has_channel(wpa_s->global, mode, op_class, channel, &flag); if (bw == BW40MINUS) { if (!(flag & HOSTAPD_CHAN_HT40MINUS)) @@ -4653,8 +4760,7 @@ int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s, for (op = 0; global_op_class[op].op_class; op++) { const struct oper_class_map *o = &global_op_class[op]; - u16 ch; - int chan = channel; + u16 ch = 0; /* Allow DFS channels marked as NO_P2P_SUPP to be used with * driver offloaded DFS. */ @@ -4665,15 +4771,22 @@ int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s, wpa_s->conf->p2p_6ghz_disable)) continue; + /* IEEE Std 802.11ax-2021 26.17.2.3.2: "A 6 GHz-only AP should + * set up the BSS with a primary 20 MHz channel that coincides + * with a preferred scanning channel (PSC)." + * 6 GHz BW40 operation class 132 in wpa_supplicant uses the + * lowest 20 MHz channel for simplicity, so increase ch by 4 to + * match the PSC. + */ if (is_6ghz_op_class(o->op_class) && o->bw == BW40 && get_6ghz_sec_channel(channel) < 0) - chan = channel - 4; + ch = 4; - for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { + for (ch += o->min_chan; ch <= o->max_chan; ch += o->inc) { if (o->mode != HOSTAPD_MODE_IEEE80211A || (o->bw != BW40PLUS && o->bw != BW40MINUS && o->bw != BW40) || - ch != chan) + ch != channel) continue; ret = wpas_p2p_verify_channel(wpa_s, mode, o->op_class, ch, o->bw); @@ -4747,7 +4860,7 @@ static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf, struct wpa_supplicant *wpa_s = ctx; for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) { - if (os_memcmp(wpa_s->own_addr, interface_addr, ETH_ALEN) == 0) + if (ether_addr_equal(wpa_s->own_addr, interface_addr)) break; } if (wpa_s == NULL) @@ -4786,7 +4899,7 @@ struct wpa_supplicant * wpas_get_p2p_client_iface(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid = wpa_s->current_ssid; if (ssid && (ssid->mode != WPAS_MODE_INFRA || !ssid->p2p_group)) continue; - if (os_memcmp(wpa_s->go_dev_addr, peer_dev_addr, ETH_ALEN) == 0) + if (ether_addr_equal(wpa_s->go_dev_addr, peer_dev_addr)) return wpa_s; } @@ -4998,7 +5111,7 @@ static int wpas_remove_stale_groups(void *ctx, const u8 *peer, const u8 *go, while ((s = wpas_p2p_get_persistent(wpa_s, peer, NULL, 0))) { if (go && ssid && ssid_len && s->ssid_len == ssid_len && - os_memcmp(go, s->bssid, ETH_ALEN) == 0 && + ether_addr_equal(go, s->bssid) && os_memcmp(ssid, s->ssid, ssid_len) == 0) break; @@ -5014,8 +5127,8 @@ static int wpas_remove_stale_groups(void *ctx, const u8 *peer, const u8 *go, } for (i = 0; i < s->num_p2p_clients; i++) { - if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN, - peer, ETH_ALEN) != 0) + if (!ether_addr_equal(s->p2p_client_list + + i * 2 * ETH_ALEN, peer)) continue; os_memmove(s->p2p_client_list + i * 2 * ETH_ALEN, @@ -5107,7 +5220,7 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, MAC2STR(adv_mac), ses_id, MAC2STR(ses_mac), passwd_id, feat_cap_str); - wpa_printf(MSG_INFO, P2P_EVENT_P2PS_PROVISION_START MACSTR_SEC + wpa_printf(MSG_INFO, P2P_EVENT_P2PS_PROVISION_START MACSTR_SEC " adv_id=%x conncap=%x" " adv_mac=" MACSTR_SEC " session=%x mac=" MACSTR_SEC @@ -5194,7 +5307,7 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, break; if (s && s->ssid_len == stale->ssid_len && - os_memcmp(stale->bssid, s->bssid, ETH_ALEN) == 0 && + ether_addr_equal(stale->bssid, s->bssid) && os_memcmp(stale->ssid, s->ssid, s->ssid_len) == 0) break; @@ -5210,9 +5323,8 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, size_t i; for (i = 0; i < stale->num_p2p_clients; i++) { - if (os_memcmp(stale->p2p_client_list + - i * ETH_ALEN, - dev, ETH_ALEN) == 0) { + if (ether_addr_equal(stale->p2p_client_list + + i * ETH_ALEN, dev)) { os_memmove(stale->p2p_client_list + i * ETH_ALEN, stale->p2p_client_list + @@ -5311,7 +5423,7 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, persistent_go->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : - 0, 0, false); + 0, 0, false, 0, NULL); } else if (response_done) { wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0, false); @@ -5464,7 +5576,7 @@ static int wpas_prov_disc_resp_cb(void *ctx) NULL, persistent_go->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0, - is_p2p_allow_6ghz(wpa_s->global->p2p)); + is_p2p_allow_6ghz(wpa_s->global->p2p), 0, NULL); } else { wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0, is_p2p_allow_6ghz(wpa_s->global->p2p)); @@ -5476,7 +5588,7 @@ static int wpas_prov_disc_resp_cb(void *ctx) static int wpas_p2p_get_pref_freq_list(void *ctx, int go, unsigned int *len, - unsigned int *freq_list) + struct weighted_pcl *freq_list) { struct wpa_supplicant *wpa_s = ctx; @@ -5528,7 +5640,7 @@ int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s) * factory MAC. */ if (is_zero_ether_addr(wpa_s->conf->p2p_device_persistent_mac_addr)) return 0; - os_memcpy(addr, wpa_s->conf->p2p_device_persistent_mac_addr, ETH_ALEN); + os_memcpy(addr, wpa_s->conf->p2p_device_persistent_mac_addr,ETH_ALEN); wpa_msg(wpa_s, MSG_DEBUG, "Restore last used MAC address."); } @@ -6134,8 +6246,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, p2p_get_interface_addr(wpa_s->global->p2p, wpa_s->pending_join_dev_addr, iface_addr) == 0 && - os_memcmp(iface_addr, wpa_s->pending_join_dev_addr, ETH_ALEN) != 0 - && !wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr)) { + !ether_addr_equal(iface_addr, wpa_s->pending_join_dev_addr) && + !wpa_bss_get_bssid(wpa_s, wpa_s->pending_join_iface_addr)) { wpa_printf(MSG_DEBUG, "P2P: Overwrite pending interface " "address for join from " MACSTR_SEC " to " MACSTR_SEC " based on newly discovered P2P peer entry", @@ -6175,10 +6287,9 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, anonymize_ssid(wpa_ssid_txt(bss->ssid, bss->ssid_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 && - os_memcmp(dev_addr, wpa_s->pending_join_dev_addr, - ETH_ALEN) != 0) { + ether_addr_equal(wpa_s->pending_join_dev_addr, + wpa_s->pending_join_iface_addr) && + !ether_addr_equal(dev_addr, wpa_s->pending_join_dev_addr)) { wpa_printf(MSG_DEBUG, "P2P: Update target GO device address based on BSS entry: " MACSTR_SEC " (was " MACSTR_SEC ")", MAC2STR_SEC(dev_addr), @@ -6199,7 +6310,7 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s, #ifdef CONFIG_LIBWPA_VENDOR wpa_printf(MSG_INFO, "WPA_EVENT_GROUP_FORMATION_FAILURE"); WpaEventReport(wpa_s->ifname, WPA_EVENT_GROUP_FORMATION_FAILURE, "FREQ_CONFLICT"); -#endif +#endif wpas_notify_p2p_group_formation_failure( wpa_s, "FREQ_CONFLICT"); return; @@ -6318,14 +6429,8 @@ 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 || - !is_p2p_allow_6ghz(wpa_s->global->p2p)) { - wpa_printf(MSG_DEBUG, - "P2P: 6 GHz disabled - update the scan frequency list"); - wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, ¶ms, - 0); - wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, ¶ms, - 0); + } else { + wpas_p2p_scan_freqs(wpa_s, ¶ms, true); } ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); @@ -6498,7 +6603,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s, int freq, static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, int *force_freq, int *pref_freq, int go, - unsigned int *pref_freq_list, + struct weighted_pcl *pref_freq_list, unsigned int *num_pref_freq) { struct wpa_used_freq_data *freqs; @@ -6573,50 +6678,14 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, best_freq = wpas_p2p_pick_best_used_freq(wpa_s, freqs, num); if (!wpa_s->conf->num_p2p_pref_chan && *pref_freq == 0) { - enum wpa_driver_if_type iface_type; - - if (go) - iface_type = WPA_IF_P2P_GO; - else - iface_type = WPA_IF_P2P_CLIENT; - wpa_printf(MSG_DEBUG, "P2P: best_freq=%d, go=%d", best_freq, go); - res = wpa_drv_get_pref_freq_list(wpa_s, iface_type, - &max_pref_freq, - pref_freq_list); - if (!is_p2p_allow_6ghz(wpa_s->global->p2p)) - max_pref_freq = p2p_remove_6ghz_channels(pref_freq_list, - max_pref_freq); - - if (!res && max_pref_freq > 0) { - *num_pref_freq = max_pref_freq; - i = 0; - while (i < *num_pref_freq && - (!p2p_supported_freq(wpa_s->global->p2p, - pref_freq_list[i]) || - wpas_p2p_disallowed_freq(wpa_s->global, - pref_freq_list[i]))) { - wpa_printf(MSG_DEBUG, - "P2P: preferred_freq_list[%d]=%d is disallowed", - i, pref_freq_list[i]); - i++; - } - if (i != *num_pref_freq) { - best_freq = pref_freq_list[i]; - wpa_printf(MSG_DEBUG, - "P2P: Using preferred_freq_list[%d]=%d", - i, best_freq); - } else { - wpa_printf(MSG_DEBUG, - "P2P: All driver preferred frequencies are disallowed for P2P use"); - *num_pref_freq = 0; - } - } else { - wpa_printf(MSG_DEBUG, - "P2P: No preferred frequency list available"); - } + *num_pref_freq = max_pref_freq; + res = wpas_p2p_pick_best_pref_freq(wpa_s, go, pref_freq_list, + num_pref_freq); + if (res > 0) + best_freq = res; } /* We have a candidate frequency to use */ @@ -6730,7 +6799,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, enum wpa_driver_if_type iftype; const u8 *if_addr; struct wpa_ssid *ssid = NULL; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; + unsigned int size; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -7041,28 +7111,31 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq) if (!wpa_s->conf->num_p2p_pref_chan && !freq) { unsigned int i, size = P2P_MAX_PREF_CHANNELS; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS]; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; int res; res = wpa_drv_get_pref_freq_list(wpa_s, WPA_IF_P2P_GO, &size, pref_freq_list); - if (!is_p2p_allow_6ghz(wpa_s->global->p2p)) + if (!res && size > 0 && !is_p2p_allow_6ghz(wpa_s->global->p2p)) size = p2p_remove_6ghz_channels(pref_freq_list, size); if (!res && size > 0) { i = 0; while (i < size && (!p2p_supported_freq(wpa_s->global->p2p, - pref_freq_list[i]) || - wpas_p2p_disallowed_freq(wpa_s->global, - pref_freq_list[i]))) { + pref_freq_list[i].freq) || + wpas_p2p_disallowed_freq( + wpa_s->global, + pref_freq_list[i].freq) || + !p2p_pref_freq_allowed(&pref_freq_list[i], + true))) { wpa_printf(MSG_DEBUG, "P2P: preferred_freq_list[%d]=%d is disallowed", - i, pref_freq_list[i]); + i, pref_freq_list[i].freq); i++; } if (i != size) { - freq = pref_freq_list[i]; + freq = pref_freq_list[i].freq; wpa_printf(MSG_DEBUG, "P2P: Using preferred_freq_list[%d]=%d", i, freq); @@ -7301,7 +7374,8 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, return -1; num = get_shared_radio_freqs_data(wpa_s, freqs, - wpa_s->num_multichan_concurrent); + wpa_s->num_multichan_concurrent, + false); if (wpa_s->current_ssid && wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO && @@ -7536,8 +7610,8 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, if (!is_6ghz && ieee80211_freq_to_channel_ext( - cand, -1, CHANWIDTH_USE_HT, &op_class, - &chan) != NUM_HOSTAPD_MODES && + cand, -1, CONF_OPER_CHWIDTH_USE_HT, + &op_class, &chan) != NUM_HOSTAPD_MODES && wpas_p2p_verify_channel( wpa_s, hwmode, op_class, chan, BW40MINUS) == ALLOWED) @@ -7545,8 +7619,8 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, if (!supported && !is_6ghz && ieee80211_freq_to_channel_ext( - cand, 1, CHANWIDTH_USE_HT, &op_class, - &chan) != NUM_HOSTAPD_MODES && + cand, 1, CONF_OPER_CHWIDTH_USE_HT, + &op_class, &chan) != NUM_HOSTAPD_MODES && wpas_p2p_verify_channel( wpa_s, hwmode, op_class, chan, BW40PLUS) == ALLOWED) @@ -7703,6 +7777,7 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, bool allow_6ghz) { struct p2p_go_neg_results params; + int selected_freq = 0; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; @@ -7717,12 +7792,13 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, wpas_p2p_stop_find_oper(wpa_s); if (!wpa_s->p2p_go_do_acs) { - freq = wpas_p2p_select_go_freq(wpa_s, freq); - if (freq < 0) + selected_freq = wpas_p2p_select_go_freq(wpa_s, freq); + if (selected_freq < 0) return -1; } - if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, vht_center_freq2, + if (wpas_p2p_init_go_params(wpa_s, ¶ms, selected_freq, + vht_center_freq2, ht40, vht, max_oper_chwidth, he, edmg, NULL)) return -1; @@ -7745,6 +7821,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, wpa_s = wpas_p2p_get_group_iface(wpa_s, 0, 1); if (wpa_s == NULL) return -1; + if (freq > 0) + wpa_s->p2p_go_no_pri_sec_switch = 1; wpas_start_wps_go(wpa_s, ¶ms, 0); return 0; @@ -7753,9 +7831,12 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, struct wpa_ssid *params, int addr_allocated, - int freq, int force_scan) + int freq, int force_scan, int retry_limit, + const u8 *go_bssid) { struct wpa_ssid *ssid; + int other_iface_found = 0; + struct wpa_supplicant *ifs; wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 0); if (wpa_s == NULL) @@ -7778,6 +7859,16 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, WPA_CIPHER_CCMP; ssid->group_cipher = params->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP; ssid->key_mgmt = WPA_KEY_MGMT_PSK; + if (is_6ghz_freq(freq) && + is_p2p_6ghz_capable(wpa_s->global->p2p)) { + ssid->auth_alg |= WPA_AUTH_ALG_SAE; + ssid->key_mgmt |= WPA_KEY_MGMT_SAE; + ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL; + ssid->sae_pwe = SAE_PWE_HASH_TO_ELEMENT; + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Enable SAE auth_alg and key_mgmt"); + } + ssid->ssid = os_malloc(params->ssid_len); if (ssid->ssid == NULL) { wpa_config_remove_network(wpa_s->conf, ssid->id); @@ -7794,12 +7885,38 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, if (params->passphrase) ssid->passphrase = os_strdup(params->passphrase); + if (go_bssid) { + ssid->bssid_set = 1; + os_memcpy(ssid->bssid, go_bssid, ETH_ALEN); + } + wpa_s->show_group_started = 1; wpa_s->p2p_in_invitation = 1; + wpa_s->p2p_retry_limit = retry_limit; wpa_s->p2p_invite_go_freq = freq; wpa_s->p2p_go_group_formation_completed = 0; wpa_s->global->p2p_group_formation = wpa_s; + /* + * Get latest scan results from driver in case cached scan results from + * interfaces on the same wiphy allow us to skip the next scan by fast + * associating. Also update the scan time to the most recent scan result + * fetch time on the same radio so it reflects the actual time the last + * scan result event occurred. + */ + wpa_supplicant_update_scan_results(wpa_s, go_bssid); + dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant, + radio_list) { + if (ifs == wpa_s) + continue; + if (!other_iface_found || os_reltime_before(&wpa_s->last_scan, + &ifs->last_scan)) { + other_iface_found = 1; + wpa_s->last_scan.sec = ifs->last_scan.sec; + wpa_s->last_scan.usec = ifs->last_scan.usec; + } + } + eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->p2pdev, NULL); eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0, @@ -7819,7 +7936,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, int edmg, const struct p2p_channels *channels, int connection_timeout, int force_scan, - bool allow_6ghz) + bool allow_6ghz, int retry_limit, + const u8 *go_bssid) { struct p2p_go_neg_results params; int go = 0, freq; @@ -7864,6 +7982,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, freq = wpas_p2p_select_go_freq(wpa_s, force_freq); if (freq < 0) return -1; + wpa_s->p2p_go_no_pri_sec_switch = 1; } else { freq = wpas_p2p_select_go_freq(wpa_s, neg_freq); if (freq < 0 || @@ -7887,7 +8006,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, } return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq, - force_scan); + force_scan, retry_limit, go_bssid); } else { return -1; } @@ -8191,9 +8310,10 @@ int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf, } -static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s) +static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s, + bool force) { - if (!offchannel_pending_action_tx(wpa_s)) + if (!offchannel_pending_action_tx(wpa_s) && !force) return; if (wpa_s->p2p_send_action_work) { @@ -8203,6 +8323,8 @@ static void wpas_p2p_clear_pending_action_tx(struct wpa_supplicant *wpa_s) offchannel_send_action_done(wpa_s); } + if (!offchannel_pending_action_tx(wpa_s)) + return; wpa_printf(MSG_DEBUG, "P2P: Drop pending Action TX due to new " "operation request"); offchannel_clear_pending_action_tx(wpa_s); @@ -8216,7 +8338,7 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, u8 seek_cnt, const char **seek_string, int freq, bool include_6ghz) { - wpas_p2p_clear_pending_action_tx(wpa_s); + wpas_p2p_clear_pending_action_tx(wpa_s, false); wpa_s->global->p2p_long_listen = 0; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL || @@ -8262,7 +8384,7 @@ static void wpas_p2p_scan_res_ignore_search(struct wpa_supplicant *wpa_s, static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s) { - wpas_p2p_clear_pending_action_tx(wpa_s); + wpas_p2p_clear_pending_action_tx(wpa_s, true); wpa_s->global->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); @@ -8315,7 +8437,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout) } wpa_supplicant_cancel_sched_scan(wpa_s); - wpas_p2p_clear_pending_action_tx(wpa_s); + wpas_p2p_clear_pending_action_tx(wpa_s, false); if (timeout == 0) { /* @@ -8391,7 +8513,7 @@ int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr, case P2P_PREQ_NOT_P2P: wpas_notify_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal); - /* fall through */ + __attribute__((fallthrough)); case P2P_PREQ_MALFORMED: case P2P_PREQ_NOT_LISTEN: case P2P_PREQ_NOT_PROCESSED: @@ -8469,7 +8591,8 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, int force_freq = 0; int res; int no_pref_freq_given = pref_freq == 0; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; + unsigned int size; #ifdef CONFIG_OPEN_HARMONY_MIRACAST_MAC int saved_business = (wpa_s == NULL) ? 0 : wpa_s->p2p_business; @@ -8566,7 +8689,8 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, int persistent; int freq = 0, force_freq = 0, pref_freq = 0; int res; - unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS], size; + struct weighted_pcl pref_freq_list[P2P_MAX_PREF_CHANNELS]; + unsigned int size; wpa_s->p2p_persistent_go_freq = 0; wpa_s->p2p_go_ht40 = 0; @@ -8663,6 +8787,7 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) wpa_s->global->p2p_group_formation = NULL; wpa_s->p2p_in_provisioning = 0; wpa_s->p2p_in_invitation = 0; + wpa_s->p2p_retry_limit = 0; } os_memset(go_dev_addr, 0, ETH_ALEN); @@ -9197,8 +9322,8 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s) wpa_s->cross_connect_in_use = 1; wpa_msg_global(wpa_s->p2pdev, MSG_INFO, - P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s", - wpa_s->ifname, wpa_s->cross_connect_uplink); + P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s", + wpa_s->ifname, wpa_s->cross_connect_uplink); wpa_printf(MSG_INFO, P2P_EVENT_CROSS_CONNECT_ENABLE "%s %s", wpa_s->ifname, wpa_s->cross_connect_uplink); break; @@ -9206,7 +9331,7 @@ static void wpas_p2p_cross_connect_setup(struct wpa_supplicant *wpa_s) } -int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s) +static int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s) { if (wpa_s->p2p_group_interface != P2P_GROUP_INTERFACE_CLIENT && !wpa_s->p2p_in_provisioning) @@ -9242,7 +9367,7 @@ void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s, if (!freqs) return; - num = get_shared_radio_freqs_data(wpa_s, freqs, num); + num = get_shared_radio_freqs_data(wpa_s, freqs, num, false); os_memset(&chan, 0, sizeof(chan)); os_memset(&cli_chan, 0, sizeof(cli_chan)); @@ -9443,6 +9568,10 @@ int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s) "in group formation", wpa_s->global->p2p_group_formation->ifname); ret = 1; + } else if (wpa_s->global->p2p_group_formation == wpa_s) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Skip Extended Listen timeout and allow scans on current interface for group formation"); + ret = 2; } } @@ -9504,13 +9633,13 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s, return s; continue; } - if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0) + if (ether_addr_equal(s->bssid, addr)) return s; /* peer is GO in the persistent group */ if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL) continue; for (i = 0; i < s->num_p2p_clients; i++) { - if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN, - addr, ETH_ALEN) == 0) + if (ether_addr_equal(s->p2p_client_list + + i * 2 * ETH_ALEN, addr)) return s; /* peer is P2P client in persistent * group */ } @@ -9563,6 +9692,7 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, wpa_s->global->p2p_group_formation = NULL; wpa_s->p2p_in_provisioning = 0; wpa_s->p2p_in_invitation = 0; + wpa_s->p2p_retry_limit = 0; } wpa_s->global->p2p_go_wait_client.sec = 0; if (addr == NULL) @@ -9660,9 +9790,9 @@ static int wpas_p2p_remove_psk_entry(struct wpa_supplicant *wpa_s, dl_list_for_each_safe(psk, tmp, &s->psk_list, struct psk_list_entry, list) { if ((iface_addr && !psk->p2p && - os_memcmp(addr, psk->addr, ETH_ALEN) == 0) || + ether_addr_equal(addr, psk->addr)) || (!iface_addr && psk->p2p && - os_memcmp(addr, psk->addr, ETH_ALEN) == 0)) { + ether_addr_equal(addr, psk->addr))) { wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, "P2P: Remove persistent group PSK list entry for " MACSTR " p2p=%u", @@ -9816,9 +9946,9 @@ void wpas_p2p_remove_client_go(struct wpa_supplicant *wpa_s, prev = NULL; psk = hapd->conf->ssid.wpa_psk; while (psk) { - if ((iface_addr && os_memcmp(peer, psk->addr, ETH_ALEN) == 0) || + if ((iface_addr && ether_addr_equal(peer, psk->addr)) || (!iface_addr && - os_memcmp(peer, psk->p2p_dev_addr, ETH_ALEN) == 0)) { + ether_addr_equal(peer, psk->p2p_dev_addr))) { wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, "P2P: Remove operating group PSK entry for " MACSTR " iface_addr=%d", MAC2STR(peer), iface_addr); @@ -9831,7 +9961,7 @@ void wpas_p2p_remove_client_go(struct wpa_supplicant *wpa_s, hapd->conf->ssid.wpa_psk = psk->next; rem = psk; psk = psk->next; - os_free(rem); + bin_clear_free(rem, sizeof(*rem)); } else { prev = psk; psk = psk->next; @@ -10608,9 +10738,6 @@ static void wpas_p2p_optimize_listen_channel(struct wpa_supplicant *wpa_s, if (!wpa_s->conf->p2p_optimize_listen_chan) return; - if (!wpa_s->current_ssid || wpa_s->wpa_state != WPA_COMPLETED) - return; - curr_chan = p2p_get_listen_channel(wpa_s->global->p2p); for (i = 0, cand = 0; i < num; i++) { ieee80211_freq_to_chan(freqs[i].freq, &chan); @@ -10678,9 +10805,15 @@ static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s) goto out; } - if (conf->hw_mode != wpa_s->ap_iface->current_mode->mode) { - wpa_dbg(wpa_s, MSG_DEBUG, - "P2P CSA: CSA to a different band is not supported"); + if (conf->hw_mode != wpa_s->ap_iface->current_mode->mode && + (wpa_s->ap_iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A || + is_6ghz_freq(wpa_s->ap_iface->freq) || + conf->hw_mode != HOSTAPD_MODE_IEEE80211G)) { + wpa_dbg(wpa_s, MSG_INFO, + "P2P CSA: CSA from hardware mode %d%s to %d is not supported", + wpa_s->ap_iface->current_mode->mode, + is_6ghz_freq(wpa_s->ap_iface->freq) ? " (6 GHz)" : "", + conf->hw_mode); ret = -1; goto out; } @@ -10688,6 +10821,7 @@ static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s) os_memset(&csa_settings, 0, sizeof(csa_settings)); csa_settings.cs_count = P2P_GO_CSA_COUNT; csa_settings.block_tx = P2P_GO_CSA_BLOCK_TX; + csa_settings.link_id = -1; csa_settings.freq_params.freq = params.freq; csa_settings.freq_params.sec_channel_offset = conf->secondary_channel; csa_settings.freq_params.ht_enabled = conf->ieee80211n; @@ -10729,13 +10863,15 @@ static int wpas_p2p_move_go_csa(struct wpa_supplicant *wpa_s) csa_settings.freq_params.center_freq2 = freq2; switch (conf->vht_oper_chwidth) { - case CHANWIDTH_80MHZ: - case CHANWIDTH_80P80MHZ: + case CONF_OPER_CHWIDTH_80MHZ: + case CONF_OPER_CHWIDTH_80P80MHZ: csa_settings.freq_params.bandwidth = 80; break; - case CHANWIDTH_160MHZ: + case CONF_OPER_CHWIDTH_160MHZ: csa_settings.freq_params.bandwidth = 160; break; + default: + break; } } @@ -10842,7 +10978,7 @@ static void wpas_p2p_reconsider_moving_go(void *eloop_ctx, void *timeout_ctx) if (!freqs) return; - num = get_shared_radio_freqs_data(wpa_s, freqs, num); + num = get_shared_radio_freqs_data(wpa_s, freqs, num, false); /* Previous attempt to move a GO was not possible -- try again. */ wpas_p2p_consider_moving_gos(wpa_s, freqs, num, diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant.h index c8d98a00b91cffb30845d486967caaac4e32724e..7a80bfa6f3c0e82f610f80f89533ceae8ea8a76a 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant.h @@ -61,7 +61,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, int max_oper_chwidth, int he, int edmg, const struct p2p_channels *channels, int connection_timeout, int force_scan, - bool allow_6ghz); + bool allow_6ghz, int retry_limit, + const u8 *go_bssid); struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); enum wpas_p2p_prov_disc_use { @@ -155,6 +156,9 @@ struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s, void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, const u8 *addr); int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s); +void wpas_p2p_scan_freqs(struct wpa_supplicant *wpa_s, + struct wpa_driver_scan_params *params, + bool include_6ghz); int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s, struct hostapd_hw_modes *mode, u8 channel); @@ -221,9 +225,9 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s); void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s); void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s); -int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s); int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s); void wpas_p2p_ap_setup_failed(struct wpa_supplicant *wpa_s); +bool wpas_p2p_retry_limit_exceeded(struct wpa_supplicant *wpa_s); void wpas_p2p_indicate_state_change(struct wpa_supplicant *wpa_s); void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s); void wpas_p2p_ap_deinit(struct wpa_supplicant *wpa_s); @@ -321,11 +325,6 @@ static inline void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s) { } -static inline int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s) -{ - return 0; -} - static inline int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s) { return 0; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant_sd.c b/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant_sd.c index 41f3fb6c5c5d56988fa6a7200c980a8f9e60762c..59a74d932033f9a87d90ae2df7a99c2f1f551e87 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant_sd.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/p2p_supplicant_sd.c @@ -1245,12 +1245,22 @@ int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s, bsrv = os_zalloc(sizeof(*bsrv)); if (bsrv == NULL) return -1; - bsrv->query = query; - bsrv->resp = resp; + bsrv->query = wpabuf_dup(query); + if (!bsrv->query) + goto error_bsrv; + bsrv->resp = wpabuf_dup(resp); + if (!bsrv->resp) + goto error_query; dl_list_add(&wpa_s->global->p2p_srv_bonjour, &bsrv->list); wpas_p2p_sd_service_update(wpa_s); return 0; + +error_query: + wpabuf_free(bsrv->query); +error_bsrv: + os_free(bsrv); + return -1; } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant-2.9_standard/wpa_supplicant/pasn_supplicant.c index be721352f225cdb317eb97679625e1928b84651f..9bceb6fe4163e3ba9aa4592624a755573103273f 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/pasn_supplicant.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/pasn_supplicant.c @@ -23,12 +23,14 @@ #include "wpa_supplicant_i.h" #include "driver_i.h" #include "bss.h" +#include "scan.h" #include "config.h" static const int dot11RSNAConfigPMKLifetime = 43200; struct wpa_pasn_auth_work { - u8 bssid[ETH_ALEN]; + u8 own_addr[ETH_ALEN]; + u8 peer_addr[ETH_ALEN]; int akmp; int cipher; u16 group; @@ -37,6 +39,15 @@ struct wpa_pasn_auth_work { }; +static int wpas_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len, + int noack, unsigned int freq, unsigned int wait) +{ + struct wpa_supplicant *wpa_s = ctx; + + return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait); +} + + static void wpas_pasn_free_auth_work(struct wpa_pasn_auth_work *awork) { wpabuf_free(awork->comeback); @@ -52,6 +63,8 @@ static void wpas_pasn_auth_work_timeout(void *eloop_ctx, void *timeout_ctx) wpa_printf(MSG_DEBUG, "PASN: Auth work timeout - stopping auth"); wpas_pasn_auth_stop(wpa_s); + + wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE); } @@ -64,7 +77,8 @@ static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s) } -static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid, +static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int akmp, int cipher, u8 status, struct wpabuf *comeback, u16 comeback_after) @@ -78,14 +92,14 @@ static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid, wpa_snprintf_hex(comeback_txt, buflen, wpabuf_head(comeback), comeback_len); - wpa_msg_only_for_cb(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR + wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u comeback_after=%u comeback=%s", - MAC2STR(bssid), + MAC2STR(peer_addr), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN), status, comeback_after, comeback_txt); wpa_printf(MSG_INFO, PASN_AUTH_STATUS MACSTR_SEC " akmp=%s, status=%u comeback_after=%u comeback=%s", - MAC2STR_SEC(bssid), + MAC2STR_SEC(peer_addr), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN), status, comeback_after, comeback_txt); @@ -96,191 +110,36 @@ static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s, const u8 *bssid, wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u", - MAC2STR(bssid), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN), + MAC2STR(peer_addr), 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) +static struct sae_pt * +wpas_pasn_sae_derive_pt(struct wpa_ssid *ssid, int group) { - struct wpas_pasn *pasn = &wpa_s->pasn; - struct wpabuf *buf = NULL; - int ret; - - ret = sae_set_group(&pasn->sae, pasn->group); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to set SAE group"); - return NULL; - } - - ret = sae_prepare_commit_pt(&pasn->sae, pasn->ssid->pt, - wpa_s->own_addr, pasn->bssid, - NULL, NULL); - 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_SAE_HASH_TO_ELEMENT); - - 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); - - if (alg != WLAN_AUTH_SAE || seq != 1 || - status != WLAN_STATUS_SAE_HASH_TO_ELEMENT) { - wpa_printf(MSG_DEBUG, "PASN: SAE: dropping peer commit"); - return -1; - } - - res = sae_parse_commit(&pasn->sae, data + 6, len - 6, NULL, 0, groups, 1 -#ifdef CONFIG_MLD_PATCH - ,NULL -#endif - ); - 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 -#ifdef CONFIG_MLD_PATCH - ,NULL -#endif - ); - 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; -} - + const char *password = ssid->sae_password; + int groups[2] = { group, 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; + if (!password) + password = ssid->passphrase; - /* 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"); + if (!password) { + wpa_printf(MSG_DEBUG, "PASN: SAE without a password"); 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; + return sae_derive_pt(groups, ssid->ssid, ssid->ssid_len, + (const u8 *) password, os_strlen(password), + ssid->sae_password_id); } -static int wpas_pasn_sae_setup_pt(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid, int group) +static int wpas_pasn_sae_setup_pt(struct wpa_ssid *ssid, int group) { - const char *password = ssid->sae_password; - int groups[2] = { group, 0 }; - - if (!password) - password = ssid->passphrase; - - if (!password) { + if (!ssid->sae_password && !ssid->passphrase) { wpa_printf(MSG_DEBUG, "PASN: SAE without a password"); return -1; } @@ -288,9 +147,7 @@ static int wpas_pasn_sae_setup_pt(struct wpa_supplicant *wpa_s, if (ssid->pt) return 0; /* PT already derived */ - ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len, - (const u8 *) password, os_strlen(password), - ssid->sae_password_id); + ssid->pt = wpas_pasn_sae_derive_pt(ssid, group); return ssid->pt ? 0 : -1; } @@ -298,852 +155,331 @@ static int wpas_pasn_sae_setup_pt(struct wpa_supplicant *wpa_s, #endif /* CONFIG_SAE */ -#ifdef CONFIG_FILS - -static struct wpabuf * wpas_pasn_fils_build_auth(struct wpa_supplicant *wpa_s) +static int wpas_pasn_get_params_from_bss(struct wpa_supplicant *wpa_s, + struct pasn_peer *peer) { - 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; + const u8 *rsne, *rsnxe; 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; - } + int sel, key_mgmt, pairwise_cipher; + int network_id = 0, group = 19; + struct wpa_ssid *ssid = NULL; + size_t ssid_str_len = 0; + const u8 *ssid_str = NULL; + const u8 *peer_addr = peer->peer_addr; - if (!elems.rsn_ie || !elems.fils_nonce || !elems.fils_nonce || - !elems.wrapped_data) { - wpa_printf(MSG_DEBUG, "PASN: FILS: Missing IEs"); - return -1; + bss = wpa_bss_get_bssid(wpa_s, peer_addr); + if (!bss) { + wpa_supplicant_update_scan_results(wpa_s, peer_addr); + bss = wpa_bss_get_bssid(wpa_s, peer_addr); + if (!bss) { + wpa_printf(MSG_DEBUG, "PASN: BSS not found"); + 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"); + rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN); + if (!rsne) { + wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE"); return -1; } - ret = wpa_pasn_validate_rsne(&rsne_data); + ret = wpa_parse_wpa_ie(rsne, *(rsne + 1) + 2, &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"); + wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE 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; - } + rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX); - rmsk_len = ERP_MAX_KEY_LEN; - ret = eapol_sm_get_key(wpa_s->eapol, rmsk, rmsk_len); + ssid_str_len = bss->ssid_len; + ssid_str = bss->ssid; - if (ret == PMK_LEN) { - rmsk_len = PMK_LEN; - ret = eapol_sm_get_key(wpa_s->eapol, rmsk, rmsk_len); + /* Get the network configuration based on the obtained SSID */ + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (!wpas_network_disabled(wpa_s, ssid) && + ssid_str_len == ssid->ssid_len && + os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0) + break; } - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: FILS: Failed getting RMSK"); - return -1; - } + if (ssid) + network_id = ssid->id; - ret = fils_rmsk_to_pmk(pasn->akmp, rmsk, rmsk_len, - pasn->fils.nonce, anonce, NULL, 0, - pasn->pmk, &pasn->pmk_len); + sel = rsne_data.pairwise_cipher; + if (ssid && ssid->pairwise_cipher) + sel &= ssid->pairwise_cipher; - forced_memzero(rmsk, sizeof(rmsk)); + wpa_printf(MSG_DEBUG, "PASN: peer pairwise 0x%x, select 0x%x", + rsne_data.pairwise_cipher, sel); - if (ret) { - wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PMK"); + pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1); + if (pairwise_cipher < 0) { + wpa_msg(wpa_s, MSG_WARNING, + "PASN: Failed to select pairwise cipher"); 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); + sel = rsne_data.key_mgmt; + if (ssid && ssid->key_mgmt) + sel &= ssid->key_mgmt; - 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: + wpa_printf(MSG_DEBUG, "PASN: peer AKMP 0x%x, select 0x%x", + rsne_data.key_mgmt, sel); #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); + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) || !ssid) + sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY | + WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY); #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, - const struct wpabuf *comeback) -{ - 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) { +#ifdef CONFIG_IEEE80211R + if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME | + WPA_DRIVER_FLAGS_UPDATE_FT_IES))) + sel &= ~WPA_KEY_MGMT_FT; +#endif /* CONFIG_IEEE80211R */ + if (0) { +#ifdef CONFIG_IEEE80211R +#ifdef CONFIG_SHA384 + } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) && + os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) { + key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384; + wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/802.1X-SHA384"); + if (ssid && !ssid->ft_eap_pmksa_caching && + pmksa_cache_get_current(wpa_s->wpa)) { + /* PMKSA caching with FT may have interoperability + * issues, so disable that case by default for now. + */ wpa_printf(MSG_DEBUG, - "PASN: FT: Failed to derive keys"); - goto fail; + "PASN: Disable PMKSA caching for FT/802.1X connection"); + pmksa_cache_clear_current(wpa_s->wpa); } - - 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, true, comeback, -1); - - if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0) - goto fail; - - /* Add own RNSXE */ - capab = 0; - capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); - 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, false, 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; - } - -#ifdef CONFIG_TESTING_OPTIONS - if (wpa_s->conf->pasn_corrupt_mic) { - wpa_printf(MSG_DEBUG, "PASN: frame 3: Corrupt MIC"); - mic[0] = ~mic[0]; - } -#endif /* CONFIG_TESTING_OPTIONS */ - - 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; - - wpabuf_free(pasn->comeback); - pasn->comeback = NULL; - pasn->comeback_after = 0; - +#endif /* CONFIG_SHA384 */ +#endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_SAE - sae_clear_data(&pasn->sae); + } else if ((sel & WPA_KEY_MGMT_SAE_EXT_KEY) && + (ieee802_11_rsnx_capab(rsnxe, + WLAN_RSNX_CAPAB_SAE_H2E)) && + (wpas_pasn_sae_setup_pt(ssid, group) == 0)) { + key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY; + wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE (ext key)"); + } else if ((sel & WPA_KEY_MGMT_SAE) && + (ieee802_11_rsnx_capab(rsnxe, + WLAN_RSNX_CAPAB_SAE_H2E)) && + (wpas_pasn_sae_setup_pt(ssid, group) == 0)) { + key_mgmt = WPA_KEY_MGMT_SAE; + wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE"); #endif /* CONFIG_SAE */ - #ifdef CONFIG_FILS - os_memset(&pasn->fils, 0, sizeof(pasn->fils)); -#endif /* CONFIG_FILS*/ - + } else if (sel & WPA_KEY_MGMT_FILS_SHA384) { + key_mgmt = WPA_KEY_MGMT_FILS_SHA384; + wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FILS-SHA384"); + } else if (sel & WPA_KEY_MGMT_FILS_SHA256) { + key_mgmt = WPA_KEY_MGMT_FILS_SHA256; + wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FILS-SHA256"); +#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)); + } else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) && + os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) { + key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; + wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/802.1X"); + if (ssid && !ssid->ft_eap_pmksa_caching && + pmksa_cache_get_current(wpa_s->wpa)) { + /* PMKSA caching with FT may have interoperability + * issues, so disable that case by default for now. + */ + wpa_printf(MSG_DEBUG, + "PASN: Disable PMKSA caching for FT/802.1X connection"); + pmksa_cache_clear_current(wpa_s->wpa); + } + } else if (sel & WPA_KEY_MGMT_FT_PSK) { + key_mgmt = WPA_KEY_MGMT_FT_PSK; + wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/PSK"); #endif /* CONFIG_IEEE80211R */ - pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE; + } else if (sel & WPA_KEY_MGMT_PASN) { + key_mgmt = WPA_KEY_MGMT_PASN; + wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT PASN"); + } else { + wpa_printf(MSG_DEBUG, "PASN: invalid AKMP"); + return -1; + } + + peer->akmp = key_mgmt; + peer->cipher = pairwise_cipher; + peer->network_id = network_id; + peer->group = group; + return 0; } -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 int wpas_pasn_set_keys_from_cache(struct wpa_supplicant *wpa_s, + const u8 *own_addr, + const u8 *peer_addr, + int cipher, int akmp) { - 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; + struct ptksa_cache_entry *entry; - 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; + entry = ptksa_cache_get(wpa_s->ptksa, peer_addr, cipher); + if (!entry) { + wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR_SEC + " not present in PTKSA cache", MAC2STR_SEC(peer_addr)); + return -1; } - 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"); + if (!ether_addr_equal(entry->own_addr, own_addr)) { + wpa_printf(MSG_DEBUG, + "PASN: own addr " MACSTR_SEC " and PTKSA entry own addr " + MACSTR_SEC " differ", + MAC2STR_SEC(own_addr), MAC2STR_SEC(entry->own_addr)); return -1; -#endif /* CONFIG_IEEE80211R */ } - if (rsn_data->num_pmkid) { - struct rsn_pmksa_cache_entry *pmksa; + wpa_printf(MSG_DEBUG, "PASN: " MACSTR_SEC " present in PTKSA cache", + MAC2STR_SEC(peer_addr)); + wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, peer_addr, cipher, + entry->ptk.tk_len, + entry->ptk.tk, + entry->ptk.ltf_keyseed_len, + entry->ptk.ltf_keyseed, 0); + return 0; +} - 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; +static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s, + struct pasn_auth *pasn_params) +{ + struct pasn_peer *peer; + u8 comeback_len = 0; + const u8 *comeback = NULL; - return 0; - } - } + if (!pasn_params) + return; -#ifdef CONFIG_SAE - if (pasn->akmp == WPA_KEY_MGMT_SAE) { - int ret; + while (wpa_s->pasn_count < pasn_params->num_peers) { + peer = &pasn_params->peer[wpa_s->pasn_count]; - ret = wpas_pasn_wd_sae_rx(wpa_s, wrapped_data); - if (ret) { + if (ether_addr_equal(wpa_s->bssid, peer->peer_addr)) { wpa_printf(MSG_DEBUG, - "PASN: Failed processing SAE wrapped data"); - pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE; - return -1; + "PASN: Associated peer is not expected"); + peer->status = PASN_STATUS_FAILURE; + wpa_s->pasn_count++; + continue; } - 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; + if (wpas_pasn_set_keys_from_cache(wpa_s, peer->own_addr, + peer->peer_addr, + peer->cipher, + peer->akmp) == 0) { + peer->status = PASN_STATUS_SUCCESS; + wpa_s->pasn_count++; + continue; + } - 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; + if (wpas_pasn_get_params_from_bss(wpa_s, peer)) { + peer->status = PASN_STATUS_FAILURE; + wpa_s->pasn_count++; + continue; } - return 0; + if (wpas_pasn_auth_start(wpa_s, peer->own_addr, + peer->peer_addr, peer->akmp, + peer->cipher, peer->group, + peer->network_id, + comeback, comeback_len)) { + peer->status = PASN_STATUS_FAILURE; + wpa_s->pasn_count++; + continue; + } + wpa_printf(MSG_DEBUG, "PASN: Sent PASN auth start for " MACSTR, + MAC2STR(peer->peer_addr)); + return; } -#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; + if (wpa_s->pasn_count == pasn_params->num_peers) { + wpa_drv_send_pasn_resp(wpa_s, pasn_params); + wpa_printf(MSG_DEBUG, "PASN: Response sent"); + os_free(wpa_s->pasn_params); + wpa_s->pasn_params = NULL; + } } -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 wpabuf *comeback) +void wpas_pasn_auth_work_done(struct wpa_supplicant *wpa_s, int status) { - 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; - } + if (!wpa_s->pasn_params) + return; - if (!ieee802_11_rsnx_capab(beacon_rsnxe, - WLAN_RSNX_CAPAB_SAE_H2E)) { - wpa_printf(MSG_DEBUG, - "PASN: AP does not support SAE H2E"); - return -1; - } + wpa_s->pasn_params->peer[wpa_s->pasn_count].status = status; + wpa_s->pasn_count++; + wpas_pasn_configure_next_peer(wpa_s, wpa_s->pasn_params); +} - if (wpas_pasn_sae_setup_pt(wpa_s, ssid, group) < 0) { - wpa_printf(MSG_DEBUG, - "PASN: Failed to derive PT"); - 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; - } +static void wpas_pasn_delete_peers(struct wpa_supplicant *wpa_s, + struct pasn_auth *pasn_params) +{ + struct pasn_peer *peer; + unsigned int i; - pasn->ecdh = crypto_ecdh_init(group); - if (!pasn->ecdh) { - wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH"); - goto fail; - } + if (!pasn_params) + return; - 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; + for (i = 0; i < pasn_params->num_peers; i++) { + peer = &pasn_params->peer[i]; + ptksa_cache_flush(wpa_s->ptksa, peer->peer_addr, + WPA_CIPHER_NONE); } +} - 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; +#ifdef CONFIG_FILS +static void wpas_pasn_initiate_eapol(struct pasn_data *pasn, + struct wpa_ssid *ssid) +{ + struct eapol_config eapol_conf; - if (wpa_s->conf->force_kdk_derivation || - (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF && - ieee802_11_rsnx_capab(beacon_rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))) - pasn->kdk_len = WPA_KDK_MAX_LEN; - else - pasn->kdk_len = 0; - wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len); + wpa_printf(MSG_DEBUG, "PASN: FILS: Initiating EAPOL"); - os_memcpy(pasn->bssid, bssid, ETH_ALEN); + eapol_sm_notify_eap_success(pasn->eapol, false); + eapol_sm_notify_eap_fail(pasn->eapol, false); + eapol_sm_notify_portControl(pasn->eapol, Auto); - wpa_printf(MSG_DEBUG, - "PASN: Init: " MACSTR_SEC " akmp=0x%x, cipher=0x%x, group=%u", - MAC2STR_SEC(pasn->bssid), pasn->akmp, pasn->cipher, - pasn->group); + os_memset(&eapol_conf, 0, sizeof(eapol_conf)); + eapol_conf.fast_reauth = pasn->fast_reauth; + eapol_conf.workaround = ssid->eap_workaround; - frame = wpas_pasn_build_auth_1(wpa_s, comeback); - if (!frame) { - wpa_printf(MSG_DEBUG, "PASN: Failed building 1st auth frame"); - goto fail; - } + eapol_sm_notify_config(pasn->eapol, &ssid->eap, &eapol_conf); +} +#endif /* CONFIG_FILS */ - 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; - } +static void wpas_pasn_reset(struct wpa_supplicant *wpa_s) +{ + struct pasn_data *pasn = &wpa_s->pasn; - eloop_register_timeout(2, 0, wpas_pasn_auth_work_timeout, wpa_s, NULL); - return 0; + wpas_pasn_cancel_auth_work(wpa_s); + wpa_s->pasn_auth_work = NULL; + eloop_cancel_timeout(wpas_pasn_auth_work_timeout, wpa_s, NULL); -fail: - return -1; + wpa_pasn_reset(pasn); } static struct wpa_bss * wpas_pasn_allowed(struct wpa_supplicant *wpa_s, - const u8 *bssid, int akmp, int cipher) + const u8 *peer_addr, 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) { + if (ether_addr_equal(wpa_s->bssid, peer_addr)) { wpa_printf(MSG_DEBUG, "PASN: Not doing authentication with current BSS"); return NULL; } - bss = wpa_bss_get_bssid(wpa_s, bssid); + bss = wpa_bss_get_bssid_latest(wpa_s, peer_addr); if (!bss) { wpa_printf(MSG_DEBUG, "PASN: BSS not found"); return NULL; @@ -1176,8 +512,16 @@ 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 pasn_data *pasn = &wpa_s->pasn; + struct wpa_ssid *ssid; struct wpa_bss *bss; const u8 *rsne, *rsnxe; +#ifdef CONFIG_FILS + const u8 *indic; + u16 fils_info; +#endif /* CONFIG_FILS */ + u16 capab = 0; + bool derive_kdk; int ret; wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: deinit=%d", deinit); @@ -1198,7 +542,7 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) * authentication is not allowed, e.g., a connection with the AP was * established. */ - bss = wpas_pasn_allowed(wpa_s, awork->bssid, awork->akmp, + bss = wpas_pasn_allowed(wpa_s, awork->peer_addr, awork->akmp, awork->cipher); if (!bss) { wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: Not allowed"); @@ -1213,15 +557,114 @@ static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX); - ret = wpas_pasn_start(wpa_s, awork->bssid, awork->akmp, awork->cipher, + derive_kdk = (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) && + ieee802_11_rsnx_capab(rsnxe, + WLAN_RSNX_CAPAB_SECURE_LTF); +#ifdef CONFIG_TESTING_OPTIONS + if (!derive_kdk) + derive_kdk = wpa_s->conf->force_kdk_derivation; +#endif /* CONFIG_TESTING_OPTIONS */ + if (derive_kdk) + pasn_enable_kdk_derivation(pasn); + else + pasn_disable_kdk_derivation(pasn); + + wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len); + + if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) && + ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF)) + pasn->secure_ltf = true; + else + pasn->secure_ltf = false; + +#ifdef CONFIG_TESTING_OPTIONS + pasn->corrupt_mic = wpa_s->conf->pasn_corrupt_mic; +#endif /* CONFIG_TESTING_OPTIONS */ + + capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); + if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) + capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF); + if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_STA) + capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT); + if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA) + capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR); + pasn_set_rsnxe_caps(pasn, capab); + pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL); + ssid = wpa_config_get_network(wpa_s->conf, awork->network_id); + +#ifdef CONFIG_SAE + if (awork->akmp == WPA_KEY_MGMT_SAE) { + if (!ssid) { + wpa_printf(MSG_DEBUG, + "PASN: No network profile found for SAE"); + goto fail; + } + pasn_set_pt(pasn, wpas_pasn_sae_derive_pt(ssid, awork->group)); + if (!pasn->pt) { + wpa_printf(MSG_DEBUG, "PASN: Failed to derive PT"); + goto fail; + } + pasn->network_id = ssid->id; + } +#endif /* CONFIG_SAE */ + +#ifdef CONFIG_FILS + /* Prepare needed information for wpas_pasn_wd_fils_auth(). */ + if (awork->akmp == WPA_KEY_MGMT_FILS_SHA256 || + awork->akmp == WPA_KEY_MGMT_FILS_SHA384) { + indic = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION); + if (!ssid) { + wpa_printf(MSG_DEBUG, "PASN: FILS: No network block"); + } else if (!indic || indic[1] < 2) { + wpa_printf(MSG_DEBUG, + "PASN: Missing FILS Indication IE"); + } else { + fils_info = WPA_GET_LE16(indic + 2); + if ((fils_info & BIT(9)) && ssid) { + pasn->eapol = wpa_s->eapol; + pasn->network_id = ssid->id; + wpas_pasn_initiate_eapol(pasn, ssid); + pasn->fils_eapol = true; + } else { + wpa_printf(MSG_DEBUG, + "PASN: FILS auth without PFS not supported"); + } + } + pasn->fast_reauth = wpa_s->conf->fast_reauth; + } +#endif /* CONFIG_FILS */ + + pasn_set_initiator_pmksa(pasn, wpa_sm_get_pmksa_cache(wpa_s->wpa)); + + if (wpa_key_mgmt_ft(awork->akmp)) { +#ifdef CONFIG_IEEE80211R + ret = wpa_pasn_ft_derive_pmk_r1(wpa_s->wpa, awork->akmp, + awork->peer_addr, + 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; + } +#else /* CONFIG_IEEE80211R */ + goto fail; +#endif /* CONFIG_IEEE80211R */ + } + + + ret = wpas_pasn_start(pasn, awork->own_addr, awork->peer_addr, + awork->peer_addr, awork->akmp, awork->cipher, awork->group, bss->freq, rsne, *(rsne + 1) + 2, rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0, - awork->network_id, awork->comeback); + awork->comeback); if (ret) { wpa_printf(MSG_DEBUG, "PASN: Failed to start PASN authentication"); goto fail; } + eloop_register_timeout(2, 0, wpas_pasn_auth_work_timeout, wpa_s, NULL); /* comeback token is no longer needed at this stage */ wpabuf_free(awork->comeback); @@ -1236,7 +679,8 @@ fail: } -int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, +int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, + const u8 *own_addr, const u8 *peer_addr, int akmp, int cipher, u16 group, int network_id, const u8 *comeback, size_t comeback_len) { @@ -1244,7 +688,7 @@ int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, struct wpa_bss *bss; wpa_printf(MSG_DEBUG, "PASN: Start: " MACSTR_SEC " akmp=0x%x, cipher=0x%x", - MAC2STR_SEC(bssid), akmp, cipher); + MAC2STR_SEC(peer_addr), akmp, cipher); /* * TODO: Consider modifying the offchannel logic to handle additional @@ -1268,7 +712,7 @@ int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, return -1; } - bss = wpas_pasn_allowed(wpa_s, bssid, akmp, cipher); + bss = wpas_pasn_allowed(wpa_s, peer_addr, akmp, cipher); if (!bss) return -1; @@ -1278,7 +722,8 @@ int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, if (!awork) return -1; - os_memcpy(awork->bssid, bssid, ETH_ALEN); + os_memcpy(awork->own_addr, own_addr, ETH_ALEN); + os_memcpy(awork->peer_addr, peer_addr, ETH_ALEN); awork->akmp = akmp; awork->cipher = cipher; awork->group = group; @@ -1305,14 +750,15 @@ int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *bssid, void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s) { - struct wpas_pasn *pasn = &wpa_s->pasn; + struct pasn_data *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, + wpas_pasn_auth_status(wpa_s, pasn->peer_addr, pasn_get_akmp(pasn), + pasn_get_cipher(pasn), pasn->status, pasn->comeback, pasn->comeback_after); @@ -1321,282 +767,129 @@ void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s) static int wpas_pasn_immediate_retry(struct wpa_supplicant *wpa_s, - struct wpas_pasn *pasn, + struct pasn_data *pasn, struct wpa_pasn_params_data *params) { - int akmp = pasn->akmp; - int cipher = pasn->cipher; + int akmp = pasn_get_akmp(pasn); + int cipher = pasn_get_cipher(pasn); u16 group = pasn->group; - u8 bssid[ETH_ALEN]; - int network_id = pasn->ssid ? pasn->ssid->id : 0; + u8 own_addr[ETH_ALEN]; + u8 peer_addr[ETH_ALEN]; wpa_printf(MSG_DEBUG, "PASN: Immediate retry"); - os_memcpy(bssid, pasn->bssid, ETH_ALEN); + os_memcpy(own_addr, pasn->own_addr, ETH_ALEN); + os_memcpy(peer_addr, pasn->peer_addr, ETH_ALEN); wpas_pasn_reset(wpa_s); - return wpas_pasn_auth_start(wpa_s, bssid, akmp, cipher, group, - network_id, + return wpas_pasn_auth_start(wpa_s, own_addr, peer_addr, akmp, cipher, + group, pasn->network_id, params->comeback, params->comeback_len); } +static void wpas_pasn_deauth_cb(struct ptksa_cache_entry *entry) +{ + struct wpa_supplicant *wpa_s = entry->ctx; + u8 own_addr[ETH_ALEN]; + u8 peer_addr[ETH_ALEN]; + + /* Use a copy of the addresses from the entry to avoid issues with the + * entry getting freed during deauthentication processing. */ + os_memcpy(own_addr, entry->own_addr, ETH_ALEN); + os_memcpy(peer_addr, entry->addr, ETH_ALEN); + wpas_pasn_deauthenticate(wpa_s, own_addr, peer_addr); +} + + 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, inc_y; - 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; + struct pasn_data *pasn = &wpa_s->pasn; + struct wpa_pasn_params_data pasn_data; + int ret; - /* 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) + if (!wpa_s->pasn_auth_work) return -2; - /* Not PASN; do nothing */ - if (mgmt->u.auth.auth_alg != host_to_le16(WLAN_AUTH_PASN)) - return -2; + pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL); + ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len, &pasn_data); + if (ret == 0) { + ptksa_cache_add(wpa_s->ptksa, pasn->own_addr, pasn->peer_addr, + pasn_get_cipher(pasn), + dot11RSNAConfigPMKLifetime, + pasn_get_ptk(pasn), + wpa_s->pasn_params ? wpas_pasn_deauth_cb : NULL, + wpa_s->pasn_params ? wpa_s : NULL, + pasn_get_akmp(pasn)); - 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; + if (pasn->pmksa_entry) + wpa_sm_set_cur_pmksa(wpa_s->wpa, pasn->pmksa_entry); } - status = le_to_host16(mgmt->u.auth.status_code); + forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk)); - if (status != WLAN_STATUS_SUCCESS && - status != WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) { - wpa_printf(MSG_DEBUG, - "PASN: Authentication rejected - status=%u", status); - pasn->status = status; + if (ret == -1) { wpas_pasn_auth_stop(wpa_s); - return -1; + wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE); } - 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; - } + if (ret == 1) + ret = wpas_pasn_immediate_retry(wpa_s, pasn, &pasn_data); - /* 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); - } - } + return ret; +} - 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; - } +void wpas_pasn_auth_trigger(struct wpa_supplicant *wpa_s, + struct pasn_auth *pasn_auth) +{ + struct pasn_peer *src, *dst; + unsigned int i, num_peers = pasn_auth->num_peers; - if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) { + if (wpa_s->pasn_params) { wpa_printf(MSG_DEBUG, - "PASN: Authentication temporarily rejected"); - - if (pasn_params.comeback && pasn_params.comeback_len) { - wpa_printf(MSG_DEBUG, - "PASN: Comeback token available. After=%u", - pasn_params.after); - - if (!pasn_params.after) - return wpas_pasn_immediate_retry(wpa_s, pasn, - &pasn_params); - - pasn->comeback = wpabuf_alloc_copy( - pasn_params.comeback, pasn_params.comeback_len); - if (pasn->comeback) - pasn->comeback_after = pasn_params.after; - } - - pasn->status = status; - 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; + "PASN: auth_trigger: Already in progress"); + return; } - if (!pasn_params.pubkey || !pasn_params.pubkey_len) { - wpa_printf(MSG_DEBUG, "PASN: Invalid public key"); - goto fail; + if (!num_peers || num_peers > WPAS_MAX_PASN_PEERS) { + wpa_printf(MSG_DEBUG, + "PASN: auth trigger: Invalid number of peers"); + return; } - if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_UNCOMPRESSED) { - inc_y = 1; - } else if (pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_0 || - pasn_params.pubkey[0] == WPA_PASN_PUBKEY_COMPRESSED_1) { - inc_y = 0; - } else { + wpa_s->pasn_params = os_zalloc(sizeof(struct pasn_auth)); + if (!wpa_s->pasn_params) { wpa_printf(MSG_DEBUG, - "PASN: Invalid first octet in pubkey=0x%x", - pasn_params.pubkey[0]); - goto fail; + "PASN: auth trigger: Failed to allocate a buffer"); + return; } - secret = crypto_ecdh_set_peerkey(pasn->ecdh, inc_y, - pasn_params.pubkey + 1, - pasn_params.pubkey_len - 1); - - if (!secret) { - wpa_printf(MSG_DEBUG, "PASN: Failed to derive shared secret"); - goto fail; - } + wpa_s->pasn_count = 0; + wpa_s->pasn_params->num_peers = num_peers; - 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); + for (i = 0; i < num_peers; i++) { + dst = &wpa_s->pasn_params->peer[i]; + src = &pasn_auth->peer[i]; + os_memcpy(dst->own_addr, wpa_s->own_addr, ETH_ALEN); + os_memcpy(dst->peer_addr, src->peer_addr, ETH_ALEN); + dst->ltf_keyseed_required = src->ltf_keyseed_required; + dst->status = PASN_STATUS_SUCCESS; - if (!wrapped_data) { - wpa_printf(MSG_DEBUG, "PASN: Missing wrapped data"); - goto fail; + if (!is_zero_ether_addr(src->own_addr)) { + os_memcpy(dst->own_addr, src->own_addr, ETH_ALEN); + wpa_printf(MSG_DEBUG, "PASN: Own (source) MAC addr: " + MACSTR, MAC2STR(dst->own_addr)); } } - 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, - pasn->kdk_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; + if (pasn_auth->action == PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT) { + wpas_pasn_delete_peers(wpa_s, wpa_s->pasn_params); + os_free(wpa_s->pasn_params); + wpa_s->pasn_params = NULL; + } else if (pasn_auth->action == PASN_ACTION_AUTH) { + wpas_pasn_configure_next_peer(wpa_s, wpa_s->pasn_params); } - - 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. - */ - if (status == WLAN_STATUS_SUCCESS) - pasn->status = WLAN_STATUS_UNSPECIFIED_FAILURE; - else - pasn->status = status; - - wpas_pasn_auth_stop(wpa_s); - return -1; } @@ -1604,12 +897,8 @@ 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); + struct pasn_data *pasn = &wpa_s->pasn; + int ret; if (!wpa_s->pasn_auth_work) { wpa_printf(MSG_DEBUG, @@ -1617,73 +906,47 @@ int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, 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; + ret = wpa_pasn_auth_tx_status(pasn, data, data_len, acked); + if (ret != 1) + return ret; - 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)); + if (!wpa_s->pasn_params) { + wpas_pasn_auth_stop(wpa_s); 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_SEC, - MAC2STR_SEC(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); - } + wpas_pasn_set_keys_from_cache(wpa_s, pasn->own_addr, pasn->peer_addr, + pasn_get_cipher(pasn), + pasn_get_akmp(pasn)); + wpas_pasn_auth_stop(wpa_s); + wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_SUCCESS); return 0; } -int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *bssid) +int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *own_addr, + const u8 *peer_addr) { struct wpa_bss *bss; struct wpabuf *buf; struct ieee80211_mgmt *deauth; int ret; - if (os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) == 0) { + if (ether_addr_equal(wpa_s->bssid, peer_addr)) { wpa_printf(MSG_DEBUG, "PASN: Cannot deauthenticate from current BSS"); return -1; } + wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, peer_addr, 0, 0, NULL, + 0, NULL, 1); + wpa_printf(MSG_DEBUG, "PASN: deauth: Flushing all PTKSA entries for " - MACSTR_SEC, MAC2STR_SEC(bssid)); - ptksa_cache_flush(wpa_s->ptksa, bssid, WPA_CIPHER_NONE); + MACSTR_SEC, MAC2STR_SEC(peer_addr)); + ptksa_cache_flush(wpa_s->ptksa, peer_addr, WPA_CIPHER_NONE); - bss = wpa_bss_get_bssid(wpa_s, bssid); + bss = wpa_bss_get_bssid(wpa_s, peer_addr); if (!bss) { wpa_printf(MSG_DEBUG, "PASN: deauth: BSS not found"); return -1; @@ -1701,9 +964,9 @@ int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *bssid) deauth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_DEAUTH << 4)); - os_memcpy(deauth->da, bssid, ETH_ALEN); - os_memcpy(deauth->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(deauth->bssid, bssid, ETH_ALEN); + os_memcpy(deauth->da, peer_addr, ETH_ALEN); + os_memcpy(deauth->sa, own_addr, ETH_ALEN); + os_memcpy(deauth->bssid, peer_addr, ETH_ALEN); deauth->u.deauth.reason_code = host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/preauth_test.c b/wpa_supplicant-2.9_standard/wpa_supplicant/preauth_test.c index 31b55325f7f7d668934173fb586f3707770f6b6c..f266ce4f409ac53d5c62a8cc4d902115db9ffaf6 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/preauth_test.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/preauth_test.c @@ -13,6 +13,7 @@ #include #include "common.h" +#include "crypto/crypto.h" #include "config.h" #include "eapol_supp/eapol_supp_sm.h" #include "eloop.h" @@ -130,7 +131,7 @@ static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid) } -static int wpa_supplicant_set_key(void *wpa_s, enum wpa_alg alg, +static int wpa_supplicant_set_key(void *wpa_s, int link_id, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len, @@ -317,7 +318,7 @@ int main(int argc, char *argv[]) } os_memset(&wpa_s, 0, sizeof(wpa_s)); - wpa_s.conf = wpa_config_read(argv[1], NULL); + wpa_s.conf = wpa_config_read(argv[1], NULL, false); if (wpa_s.conf == NULL) { printf("Failed to parse configuration file '%s'.\n", argv[1]); return -1; @@ -356,7 +357,7 @@ int main(int argc, char *argv[]) ret = -2; else { ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0, - NULL, 0) ? 0 : -3; + NULL, 0, false) ? 0 : -3; } test_eapol_clean(&wpa_s); @@ -365,6 +366,7 @@ int main(int argc, char *argv[]) eloop_destroy(); + crypto_unload(); os_program_deinit(); return ret; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/robust_av.c b/wpa_supplicant-2.9_standard/wpa_supplicant/robust_av.c index 770c8fcab1895c2595b3087deecc4d357d5b37e6..a3edf3bee80e691c563702afeb069b6c31df6193 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/robust_av.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/robust_av.c @@ -97,12 +97,27 @@ static int wpas_populate_type10_classifier(struct type10_params *type10_param, } +static bool tclas_elem_required(const struct qos_characteristics *qos_elem) +{ + if (!qos_elem || !qos_elem->available) + return true; + + if (qos_elem->direction == SCS_DIRECTION_DOWN) + return true; + + return false; +} + + static int wpas_populate_scs_descriptor_ie(struct scs_desc_elem *desc_elem, - struct wpabuf *buf) + struct wpabuf *buf, + bool allow_scs_traffic_desc) { u8 *len, *len1; struct tclas_element *tclas_elem; unsigned int i; + struct qos_characteristics *qos_elem; + u32 control_info = 0; /* SCS Descriptor element */ wpabuf_put_u8(buf, WLAN_EID_SCS_DESCRIPTOR); @@ -112,6 +127,9 @@ static int wpas_populate_scs_descriptor_ie(struct scs_desc_elem *desc_elem, if (desc_elem->request_type == SCS_REQ_REMOVE) goto end; + if (!tclas_elem_required(&desc_elem->qos_char_elem)) + goto skip_tclas_elem; + if (desc_elem->intra_access_priority || desc_elem->scs_up_avail) { wpabuf_put_u8(buf, WLAN_EID_INTRA_ACCESS_CATEGORY_PRIORITY); wpabuf_put_u8(buf, 1); @@ -164,6 +182,81 @@ static int wpas_populate_scs_descriptor_ie(struct scs_desc_elem *desc_elem, wpabuf_put_u8(buf, desc_elem->tclas_processing); } +skip_tclas_elem: + if (allow_scs_traffic_desc && desc_elem->qos_char_elem.available) { + qos_elem = &desc_elem->qos_char_elem; + /* Element ID, Length, and Element ID Extension */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + len1 = wpabuf_put(buf, 1); + wpabuf_put_u8(buf, WLAN_EID_EXT_QOS_CHARACTERISTICS); + + /* Remove invalid mask bits */ + + /* Medium Time is applicable only for direct link */ + if ((qos_elem->mask & SCS_QOS_BIT_MEDIUM_TIME) && + qos_elem->direction != SCS_DIRECTION_DIRECT) + qos_elem->mask &= ~SCS_QOS_BIT_MEDIUM_TIME; + + /* Service Start Time LinkID is valid only when Service Start + * Time is present. + */ + if ((qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME_LINKID) && + !(qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME)) + qos_elem->mask &= + ~SCS_QOS_BIT_SERVICE_START_TIME_LINKID; + + /* IEEE P802.11be/D4.0, 9.4.2.316 QoS Characteristics element, + * Figure 9-1001av (Control Info field format) + */ + control_info = ((u32) qos_elem->direction << + EHT_QOS_CONTROL_INFO_DIRECTION_OFFSET); + control_info |= ((u32) desc_elem->intra_access_priority << + EHT_QOS_CONTROL_INFO_TID_OFFSET); + control_info |= ((u32) desc_elem->intra_access_priority << + EHT_QOS_CONTROL_INFO_USER_PRIORITY_OFFSET); + control_info |= ((u32) qos_elem->mask << + EHT_QOS_CONTROL_INFO_PRESENCE_MASK_OFFSET); + + /* Control Info */ + wpabuf_put_le32(buf, control_info); + /* Minimum Service Interval */ + wpabuf_put_le32(buf, qos_elem->min_si); + /* Maximum Service Interval */ + wpabuf_put_le32(buf, qos_elem->max_si); + /* Minimum Data Rate */ + wpabuf_put_le24(buf, qos_elem->min_data_rate); + /* Delay Bound */ + wpabuf_put_le24(buf, qos_elem->delay_bound); + + /* Maximum MSDU Size */ + if (qos_elem->mask & SCS_QOS_BIT_MAX_MSDU_SIZE) + wpabuf_put_le16(buf, qos_elem->max_msdu_size); + /* Start Service Time */ + if (qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME) + wpabuf_put_le32(buf, qos_elem->service_start_time); + /* Service Start Time LinkID */ + if (qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME_LINKID) + wpabuf_put_u8(buf, + qos_elem->service_start_time_link_id); + /* Mean Data Rate */ + if (qos_elem->mask & SCS_QOS_BIT_MEAN_DATA_RATE) + wpabuf_put_le24(buf, qos_elem->mean_data_rate); + /* Delayed Bounded Burst Size */ + if (qos_elem->mask & SCS_QOS_BIT_DELAYED_BOUNDED_BURST_SIZE) + wpabuf_put_le32(buf, qos_elem->burst_size); + /* MSDU Lifetime */ + if (qos_elem->mask & SCS_QOS_BIT_MSDU_LIFETIME) + wpabuf_put_le16(buf, qos_elem->msdu_lifetime); + /* MSDU Delivery Info */ + if (qos_elem->mask & SCS_QOS_BIT_MSDU_DELIVERY_INFO) + wpabuf_put_u8(buf, qos_elem->msdu_delivery_info); + /* Medium Time */ + if (qos_elem->mask & SCS_QOS_BIT_MEDIUM_TIME) + wpabuf_put_le16(buf, qos_elem->medium_time); + + *len1 = (u8 *) wpabuf_put(buf, 0) - len1 - 1; + } + end: *len = (u8 *) wpabuf_put(buf, 0) - len - 1; return 0; @@ -273,8 +366,51 @@ static size_t tclas_elem_len(const struct tclas_element *elem) } +static size_t qos_char_len(const struct qos_characteristics *qos_elem) +{ + size_t buf_len = 0; + + buf_len += 1 + /* Element ID */ + 1 + /* Length */ + 1 + /* Element ID Extension */ + 4 + /* Control Info */ + 4 + /* Minimum Service Interval */ + 4 + /* Maximum Service Interval */ + 3 + /* Minimum Data Rate */ + 3; /* Delay Bound */ + + if (qos_elem->mask & SCS_QOS_BIT_MAX_MSDU_SIZE) + buf_len += 2; /* Maximum MSDU Size */ + + if (qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME) { + buf_len += 4; /* Service Start Time */ + if (qos_elem->mask & SCS_QOS_BIT_SERVICE_START_TIME_LINKID) + buf_len++; /* Service Start Time LinkID */ + } + + if (qos_elem->mask & SCS_QOS_BIT_MEAN_DATA_RATE) + buf_len += 3; /* Mean Data Rate */ + + if (qos_elem->mask & SCS_QOS_BIT_DELAYED_BOUNDED_BURST_SIZE) + buf_len += 4; /* Delayed Bounded Burst Size */ + + if (qos_elem->mask & SCS_QOS_BIT_MSDU_LIFETIME) + buf_len += 2; /* MSDU Lifetime */ + + if (qos_elem->mask & SCS_QOS_BIT_MSDU_DELIVERY_INFO) + buf_len++; /* MSDU Delivery Info */ + + if (qos_elem->mask & SCS_QOS_BIT_MEDIUM_TIME && + qos_elem->direction == SCS_DIRECTION_DIRECT) + buf_len += 2; /* Medium Time */ + + return buf_len; +} + + static struct wpabuf * allocate_scs_buf(struct scs_desc_elem *desc_elem, - unsigned int num_scs_desc) + unsigned int num_scs_desc, + bool allow_scs_traffic_desc) { struct wpabuf *buf; size_t buf_len = 0; @@ -292,6 +428,13 @@ static struct wpabuf * allocate_scs_buf(struct scs_desc_elem *desc_elem, if (desc_elem->request_type == SCS_REQ_REMOVE) continue; + if (allow_scs_traffic_desc && + desc_elem->qos_char_elem.available) + buf_len += qos_char_len(&desc_elem->qos_char_elem); + + if (!tclas_elem_required(&desc_elem->qos_char_elem)) + continue; + if (desc_elem->intra_access_priority || desc_elem->scs_up_avail) buf_len += 3; @@ -369,8 +512,11 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s) { struct wpabuf *buf = NULL; struct scs_desc_elem *desc_elem = NULL; + const struct ieee80211_eht_capabilities *eht; + const u8 *eht_ie; int ret = -1; unsigned int i; + bool allow_scs_traffic_desc = false; if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid) return -1; @@ -385,8 +531,28 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s) if (!desc_elem) return -1; + if (wpa_is_non_eht_scs_traffic_desc_supported(wpa_s->current_bss)) + allow_scs_traffic_desc = true; + + /* Allow SCS Traffic descriptor support for EHT connection */ + eht_ie = wpa_bss_get_ie_ext(wpa_s->current_bss, + WLAN_EID_EXT_EHT_CAPABILITIES); + if (wpa_s->connection_eht && eht_ie && + eht_ie[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN) { + eht = (const struct ieee80211_eht_capabilities *) &eht_ie[3]; + if (eht->mac_cap & EHT_MACCAP_SCS_TRAFFIC_DESC) + allow_scs_traffic_desc = true; + } + + if (!allow_scs_traffic_desc && desc_elem->qos_char_elem.available) { + wpa_dbg(wpa_s, MSG_INFO, + "Connection does not support EHT/non-EHT SCS Traffic Description - could not send SCS Request with QoS Characteristics"); + return -1; + } + buf = allocate_scs_buf(desc_elem, - wpa_s->scs_robust_av_req.num_scs_desc); + wpa_s->scs_robust_av_req.num_scs_desc, + allow_scs_traffic_desc); if (!buf) return -1; @@ -400,7 +566,8 @@ int wpas_send_scs_req(struct wpa_supplicant *wpa_s) for (i = 0; i < wpa_s->scs_robust_av_req.num_scs_desc; i++, desc_elem++) { /* SCS Descriptor element */ - if (wpas_populate_scs_descriptor_ie(desc_elem, buf) < 0) + if (wpas_populate_scs_descriptor_ie(desc_elem, buf, + allow_scs_traffic_desc) < 0) goto end; } @@ -497,17 +664,91 @@ void free_up_scs_desc(struct scs_robust_av_data *data) } +/* Element ID Extension(1) + Request Type(1) + User Priority Control(2) + + * Stream Timeout(4) */ +#define MSCS_DESCRIPTOR_FIXED_LEN 8 + +static void wpas_parse_mscs_resp(struct wpa_supplicant *wpa_s, + u16 status, const u8 *bssid, + const u8 *mscs_desc_ie) +{ + struct robust_av_data robust_av; + const u8 *pos; + + /* The MSCS Descriptor element is optional in the MSCS Response frame */ + if (!mscs_desc_ie) + goto event_mscs_result; + + if (mscs_desc_ie[1] < MSCS_DESCRIPTOR_FIXED_LEN) { + wpa_printf(MSG_INFO, + "MSCS: Drop received frame: invalid MSCS Descriptor element length: %d", + mscs_desc_ie[1]); + return; + } + + os_memset(&robust_av, 0, sizeof(struct robust_av_data)); + + /* Skip Element ID, Length, and Element ID Extension */ + pos = &mscs_desc_ie[3]; + + robust_av.request_type = *pos++; + + switch (robust_av.request_type) { + case SCS_REQ_CHANGE: + /* + * Inform the suggested set of parameters that could be accepted + * by the AP in response to a subsequent request by the station. + */ + robust_av.up_bitmap = *pos++; + robust_av.up_limit = *pos++ & 0x07; + robust_av.stream_timeout = WPA_GET_LE32(pos); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_MSCS_RESULT "bssid=" MACSTR + " status_code=%u change up_bitmap=%u up_limit=%u stream_timeout=%u", + MAC2STR(bssid), status, robust_av.up_bitmap, + robust_av.up_limit, robust_av.stream_timeout); + wpa_s->mscs_setup_done = false; + return; + case SCS_REQ_ADD: + /* + * This type is used in (Re)Association Response frame MSCS + * Descriptor element if no change is required. + */ + break; + default: + wpa_printf(MSG_INFO, + "MSCS: Drop received frame with unknown Request Type: %u", + robust_av.request_type); + return; + } + +event_mscs_result: + 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; +} + + 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; + const u8 *mscs_desc_ie; if (len < 3) return; dialog_token = *buf++; - if (dialog_token != wpa_s->robust_av.dialog_token) { + len--; + + /* AP sets dialog token to 0 for unsolicited response */ + if (!dialog_token && !wpa_s->mscs_setup_done) { + wpa_printf(MSG_INFO, + "MSCS: Drop unsolicited received frame: inactive"); + return; + } + + if (dialog_token && 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); @@ -515,9 +756,11 @@ void wpas_handle_robust_av_recv_action(struct wpa_supplicant *wpa_s, } status_code = WPA_GET_LE16(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; + buf += 2; + len -= 2; + + mscs_desc_ie = get_ie_ext(buf, len, WLAN_EID_EXT_MSCS_DESCRIPTOR); + wpas_parse_mscs_resp(wpa_s, status_code, src, mscs_desc_ie); } @@ -533,21 +776,19 @@ void wpas_handle_assoc_resp_mscs(struct wpa_supplicant *wpa_s, const u8 *bssid, return; mscs_desc_ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_MSCS_DESCRIPTOR); - if (!mscs_desc_ie || mscs_desc_ie[1] <= 8) + if (!mscs_desc_ie || mscs_desc_ie[1] <= MSCS_DESCRIPTOR_FIXED_LEN) 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, + /* Subelements start after element header and fixed fields */ + mscs_status = get_ie(&mscs_desc_ie[2 + MSCS_DESCRIPTOR_FIXED_LEN], + mscs_desc_ie[1] - MSCS_DESCRIPTOR_FIXED_LEN, 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; + + wpas_parse_mscs_resp(wpa_s, status, bssid, mscs_desc_ie); } @@ -705,14 +946,15 @@ void wpas_scs_deinit(struct wpa_supplicant *wpa_s) static int write_ipv4_info(char *pos, int total_len, - const struct ipv4_params *v4) + const struct ipv4_params *v4, + u8 classifier_mask) { int res, rem_len; char addr[INET_ADDRSTRLEN]; rem_len = total_len; - if (v4->param_mask & BIT(1)) { + if (classifier_mask & BIT(1)) { if (!inet_ntop(AF_INET, &v4->src_ip, addr, INET_ADDRSTRLEN)) { wpa_printf(MSG_ERROR, "QM: Failed to set IPv4 source address"); @@ -727,7 +969,7 @@ static int write_ipv4_info(char *pos, int total_len, rem_len -= res; } - if (v4->param_mask & BIT(2)) { + if (classifier_mask & BIT(2)) { if (!inet_ntop(AF_INET, &v4->dst_ip, addr, INET_ADDRSTRLEN)) { wpa_printf(MSG_ERROR, "QM: Failed to set IPv4 destination address"); @@ -742,7 +984,7 @@ static int write_ipv4_info(char *pos, int total_len, rem_len -= res; } - if (v4->param_mask & BIT(3)) { + if (classifier_mask & BIT(3)) { res = os_snprintf(pos, rem_len, " src_port=%d", v4->src_port); if (os_snprintf_error(rem_len, res)) return -1; @@ -751,7 +993,7 @@ static int write_ipv4_info(char *pos, int total_len, rem_len -= res; } - if (v4->param_mask & BIT(4)) { + if (classifier_mask & BIT(4)) { res = os_snprintf(pos, rem_len, " dst_port=%d", v4->dst_port); if (os_snprintf_error(rem_len, res)) return -1; @@ -760,7 +1002,7 @@ static int write_ipv4_info(char *pos, int total_len, rem_len -= res; } - if (v4->param_mask & BIT(6)) { + if (classifier_mask & BIT(6)) { res = os_snprintf(pos, rem_len, " protocol=%d", v4->protocol); if (os_snprintf_error(rem_len, res)) return -1; @@ -774,14 +1016,15 @@ static int write_ipv4_info(char *pos, int total_len, static int write_ipv6_info(char *pos, int total_len, - const struct ipv6_params *v6) + const struct ipv6_params *v6, + u8 classifier_mask) { int res, rem_len; char addr[INET6_ADDRSTRLEN]; rem_len = total_len; - if (v6->param_mask & BIT(1)) { + if (classifier_mask & BIT(1)) { if (!inet_ntop(AF_INET6, &v6->src_ip, addr, INET6_ADDRSTRLEN)) { wpa_printf(MSG_ERROR, "QM: Failed to set IPv6 source addr"); @@ -796,7 +1039,7 @@ static int write_ipv6_info(char *pos, int total_len, rem_len -= res; } - if (v6->param_mask & BIT(2)) { + if (classifier_mask & BIT(2)) { if (!inet_ntop(AF_INET6, &v6->dst_ip, addr, INET6_ADDRSTRLEN)) { wpa_printf(MSG_ERROR, "QM: Failed to set IPv6 destination addr"); @@ -811,7 +1054,7 @@ static int write_ipv6_info(char *pos, int total_len, rem_len -= res; } - if (v6->param_mask & BIT(3)) { + if (classifier_mask & BIT(3)) { res = os_snprintf(pos, rem_len, " src_port=%d", v6->src_port); if (os_snprintf_error(rem_len, res)) return -1; @@ -820,7 +1063,7 @@ static int write_ipv6_info(char *pos, int total_len, rem_len -= res; } - if (v6->param_mask & BIT(4)) { + if (classifier_mask & BIT(4)) { res = os_snprintf(pos, rem_len, " dst_port=%d", v6->dst_port); if (os_snprintf_error(rem_len, res)) return -1; @@ -829,7 +1072,7 @@ static int write_ipv6_info(char *pos, int total_len, rem_len -= res; } - if (v6->param_mask & BIT(6)) { + if (classifier_mask & BIT(6)) { res = os_snprintf(pos, rem_len, " protocol=%d", v6->next_header); if (os_snprintf_error(rem_len, res)) @@ -876,7 +1119,7 @@ static int set_frame_classifier_type4_ipv4(struct dscp_policy_data *policy) /* Classifier Mask - bit 1 = Source IP Address */ if (classifier_mask & BIT(1)) { - type4_param->ip_params.v4.param_mask |= BIT(1); + type4_param->classifier_mask |= BIT(1); os_memcpy(&type4_param->ip_params.v4.src_ip, &frame_classifier[3], 4); } @@ -889,14 +1132,14 @@ static int set_frame_classifier_type4_ipv4(struct dscp_policy_data *policy) return -1; } - type4_param->ip_params.v4.param_mask |= BIT(2); + type4_param->classifier_mask |= BIT(2); os_memcpy(&type4_param->ip_params.v4.dst_ip, &frame_classifier[7], 4); } /* Classifier Mask - bit 3 = Source Port */ if (classifier_mask & BIT(3)) { - type4_param->ip_params.v4.param_mask |= BIT(3); + type4_param->classifier_mask |= BIT(3); type4_param->ip_params.v4.src_port = WPA_GET_BE16(&frame_classifier[11]); } @@ -909,7 +1152,7 @@ static int set_frame_classifier_type4_ipv4(struct dscp_policy_data *policy) return -1; } - type4_param->ip_params.v4.param_mask |= BIT(4); + type4_param->classifier_mask |= BIT(4); type4_param->ip_params.v4.dst_port = WPA_GET_BE16(&frame_classifier[13]); } @@ -918,7 +1161,7 @@ static int set_frame_classifier_type4_ipv4(struct dscp_policy_data *policy) /* Classifier Mask - bit 6 = Protocol */ if (classifier_mask & BIT(6)) { - type4_param->ip_params.v4.param_mask |= BIT(6); + type4_param->classifier_mask |= BIT(6); type4_param->ip_params.v4.protocol = frame_classifier[16]; } @@ -943,7 +1186,7 @@ static int set_frame_classifier_type4_ipv6(struct dscp_policy_data *policy) /* Classifier Mask - bit 1 = Source IP Address */ if (classifier_mask & BIT(1)) { - type4_param->ip_params.v6.param_mask |= BIT(1); + type4_param->classifier_mask |= BIT(1); os_memcpy(&type4_param->ip_params.v6.src_ip, &frame_classifier[3], 16); } @@ -955,14 +1198,14 @@ static int set_frame_classifier_type4_ipv6(struct dscp_policy_data *policy) "QM: IPv6: Both domain name and destination IP address not expected"); return -1; } - type4_param->ip_params.v6.param_mask |= BIT(2); + type4_param->classifier_mask |= BIT(2); os_memcpy(&type4_param->ip_params.v6.dst_ip, &frame_classifier[19], 16); } /* Classifier Mask - bit 3 = Source Port */ if (classifier_mask & BIT(3)) { - type4_param->ip_params.v6.param_mask |= BIT(3); + type4_param->classifier_mask |= BIT(3); type4_param->ip_params.v6.src_port = WPA_GET_BE16(&frame_classifier[35]); } @@ -975,7 +1218,7 @@ static int set_frame_classifier_type4_ipv6(struct dscp_policy_data *policy) return -1; } - type4_param->ip_params.v6.param_mask |= BIT(4); + type4_param->classifier_mask |= BIT(4); type4_param->ip_params.v6.dst_port = WPA_GET_BE16(&frame_classifier[37]); } @@ -984,7 +1227,7 @@ static int set_frame_classifier_type4_ipv6(struct dscp_policy_data *policy) /* Classifier Mask - bit 6 = Next Header */ if (classifier_mask & BIT(6)) { - type4_param->ip_params.v6.param_mask |= BIT(6); + type4_param->classifier_mask |= BIT(6); type4_param->ip_params.v6.next_header = frame_classifier[40]; } @@ -1090,9 +1333,11 @@ static void wpas_add_dscp_policy(struct wpa_supplicant *wpa_s, } if (type4->ip_version == IPV4) - res = write_ipv4_info(pos, len, &type4->ip_params.v4); + res = write_ipv4_info(pos, len, &type4->ip_params.v4, + type4->classifier_mask); else - res = write_ipv6_info(pos, len, &type4->ip_params.v6); + res = write_ipv6_info(pos, len, &type4->ip_params.v6, + type4->classifier_mask); if (res <= 0) { wpa_printf(MSG_ERROR, @@ -1301,11 +1546,17 @@ void wpas_handle_qos_mgmt_recv_action(struct wpa_supplicant *wpa_s, attr = qos_ie + 6; rem_attrs_len = qos_ie[1] - 4; - while (rem_attrs_len > 2 && rem_attrs_len >= 2 + attr[1]) { - wpas_fill_dscp_policy(&policy, attr[0], attr[1], - &attr[2]); - rem_attrs_len -= 2 + attr[1]; - attr += 2 + attr[1]; + while (rem_attrs_len > 2) { + u8 attr_id, attr_len; + + attr_id = *attr++; + attr_len = *attr++; + rem_attrs_len -= 2; + if (attr_len > rem_attrs_len) + break; + wpas_fill_dscp_policy(&policy, attr_id, attr_len, attr); + rem_attrs_len -= attr_len; + attr += attr_len; } rem_len -= ie_len; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/rrm.c b/wpa_supplicant-2.9_standard/wpa_supplicant/rrm.c index a4f4f268db04c8ca5d7f2508d421aa9d77c0b9ab..72f7de09e3d9d6c944ef45b7c9e7cf4903ede84b 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/rrm.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/rrm.c @@ -504,7 +504,7 @@ static int wpas_add_channel(u8 op_class, u8 chan, u8 num_primary_channels, static int * wpas_add_channels(const struct oper_class_map *op, - struct hostapd_hw_modes *mode, int active, + struct hostapd_hw_modes *mode, const u8 *channels, const u8 size) { int *freqs, *next_freq; @@ -518,6 +518,8 @@ static int * wpas_add_channels(const struct oper_class_map *op, num_primary_channels = 4; else if (op->bw == BW160) num_primary_channels = 8; + else if (op->bw == BW320) + num_primary_channels = 16; else num_primary_channels = 1; @@ -535,7 +537,7 @@ static int * wpas_add_channels(const struct oper_class_map *op, enum chan_allowed res = verify_channel(mode, op->op_class, chan, op->bw); - if (res == NOT_ALLOWED || (res == NO_IR && active)) + if (res == NOT_ALLOWED) continue; if (wpas_add_channel(op->op_class, chan, num_primary_channels, @@ -557,13 +559,14 @@ 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) + struct hostapd_hw_modes *mode) { 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 }; + u8 channels_320mhz_6ghz[] = { 31, 63, 95, 127, 159, 191 }; const u8 *channels = NULL; size_t num_chan = 0; bool is_6ghz = is_6ghz_op_class(op->op_class); @@ -582,13 +585,16 @@ static int * wpas_op_class_freqs(const struct oper_class_map *op, channels_160mhz_5ghz; num_chan = is_6ghz ? ARRAY_SIZE(channels_160mhz_6ghz) : ARRAY_SIZE(channels_160mhz_5ghz); + } else if (op->bw == BW320) { + channels = channels_320mhz_6ghz; + num_chan = ARRAY_SIZE(channels_320mhz_6ghz); } - return wpas_add_channels(op, mode, active, channels, num_chan); + return wpas_add_channels(op, mode, channels, num_chan); } -static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active, +static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, const char *country, const u8 *subelems, size_t len) { @@ -636,7 +642,7 @@ static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active, * by a corresponding AP Channel Report element as specified in * IEEE Std 802.11-2016, 11.11.9.1. */ - new_freqs = wpas_add_channels(op, mode, active, pos, left); + new_freqs = wpas_add_channels(op, mode, pos, left); if (new_freqs) int_array_concat(&freqs, new_freqs); @@ -651,7 +657,7 @@ out: static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, - u8 op_class, u8 chan, int active, + u8 op_class, u8 chan, const u8 *subelems, size_t len) { int *freqs = NULL, *ext_freqs = NULL; @@ -681,7 +687,7 @@ static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, switch (chan) { case 0: - freqs = wpas_op_class_freqs(op, mode, active); + freqs = wpas_op_class_freqs(op, mode); if (!freqs) return NULL; break; @@ -689,14 +695,13 @@ static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, /* freqs will be added from AP channel subelements */ break; default: - freqs = wpas_add_channels(op, mode, active, &chan, 1); + freqs = wpas_add_channels(op, mode, &chan, 1); if (!freqs) return NULL; break; } - ext_freqs = wpas_channel_report_freqs(wpa_s, active, country, subelems, - len); + ext_freqs = wpas_channel_report_freqs(wpa_s, country, subelems, len); if (ext_freqs) { int_array_concat(&freqs, ext_freqs); os_free(ext_freqs); @@ -735,24 +740,24 @@ int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len, vht_oper = (struct ieee80211_vht_operation *) (ie + 2); switch (vht_oper->vht_op_info_chwidth) { - case 1: + case CHANWIDTH_80MHZ: seg0 = vht_oper->vht_op_info_chan_center_freq_seg0_idx; seg1 = vht_oper->vht_op_info_chan_center_freq_seg1_idx; if (seg1 && abs(seg1 - seg0) == 8) - vht = CHANWIDTH_160MHZ; + vht = CONF_OPER_CHWIDTH_160MHZ; else if (seg1) - vht = CHANWIDTH_80P80MHZ; + vht = CONF_OPER_CHWIDTH_80P80MHZ; else - vht = CHANWIDTH_80MHZ; + vht = CONF_OPER_CHWIDTH_80MHZ; break; - case 2: - vht = CHANWIDTH_160MHZ; + case CHANWIDTH_160MHZ: + vht = CONF_OPER_CHWIDTH_160MHZ; break; - case 3: - vht = CHANWIDTH_80P80MHZ; + case CHANWIDTH_80P80MHZ: + vht = CONF_OPER_CHWIDTH_80P80MHZ; break; default: - vht = CHANWIDTH_USE_HT; + vht = CONF_OPER_CHWIDTH_USE_HT; break; } } @@ -776,6 +781,7 @@ 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, + struct bitfield *ext_eids, enum beacon_report_detail detail, struct wpa_bss *bss, u8 *buf, size_t buf_len, const u8 **ies_buf, @@ -832,7 +838,9 @@ static int wpas_beacon_rep_add_frame_body(struct bitfield *eids, */ while (ies_len > 2 && 2U + ies[1] <= ies_len && rem_len > 0) { if (detail == BEACON_REPORT_DETAIL_ALL_FIELDS_AND_ELEMENTS || - (eids && bitfield_is_set(eids, ies[0]))) { + (eids && bitfield_is_set(eids, ies[0])) || + (ext_eids && ies[0] == WLAN_EID_EXTENSION && ies[1] && + bitfield_is_set(ext_eids, ies[2]))) { u8 elen = ies[1]; if (2 + elen > buf + buf_len - pos || @@ -880,7 +888,8 @@ static int wpas_add_beacon_rep_elem(struct beacon_rep_data *data, os_memcpy(buf, rep, sizeof(*rep)); - ret = wpas_beacon_rep_add_frame_body(data->eids, data->report_detail, + ret = wpas_beacon_rep_add_frame_body(data->eids, data->ext_eids, + data->report_detail, bss, buf + sizeof(*rep), 14 + *ie_len, ie, ie_len, idx == 0); @@ -936,8 +945,8 @@ static int wpas_add_beacon_rep(struct wpa_supplicant *wpa_s, struct rrm_measurement_beacon_report rep; u8 idx = 0; - if (os_memcmp(data->bssid, broadcast_ether_addr, ETH_ALEN) != 0 && - os_memcmp(data->bssid, bss->bssid, ETH_ALEN) != 0) + if (!ether_addr_equal(data->bssid, broadcast_ether_addr) && + !ether_addr_equal(data->bssid, bss->bssid)) return 0; if (data->ssid_len && @@ -1037,7 +1046,7 @@ static void wpas_rrm_scan_timeout(void *eloop_ctx, void *timeout_ctx) } os_get_reltime(&wpa_s->beacon_rep_scan); if (wpa_s->scanning || wpas_p2p_in_progress(wpa_s) || - wpa_supplicant_trigger_scan(wpa_s, params)) + wpa_supplicant_trigger_scan(wpa_s, params, true, false)) wpas_rrm_refuse_request(wpa_s); params->duration = prev_duration; } @@ -1047,6 +1056,7 @@ static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s, struct beacon_rep_data *data, u8 sid, u8 slen, const u8 *subelem) { + struct bitfield *eids; u8 report_info, i; switch (sid) { @@ -1100,6 +1110,7 @@ static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s, break; case WLAN_BEACON_REQUEST_SUBELEM_REQUEST: + case WLAN_BEACON_REQUEST_SUBELEM_EXT_REQUEST: if (data->report_detail != BEACON_REPORT_DETAIL_REQUESTED_ONLY) { wpa_printf(MSG_DEBUG, @@ -1115,20 +1126,46 @@ static int wpas_rm_handle_beacon_req_subelem(struct wpa_supplicant *wpa_s, return -1; } - if (data->eids) { + if (sid == WLAN_BEACON_REQUEST_SUBELEM_EXT_REQUEST) { + if (slen < 2) { + wpa_printf(MSG_DEBUG, + "Invalid extended request"); + return -1; + } + if (subelem[0] != WLAN_EID_EXTENSION) { + wpa_printf(MSG_DEBUG, + "Skip unknown Requested Element ID %u in Extended Request subelement", + subelem[0]); + break; + } + + /* Skip the Requested Element ID field */ + subelem++; + slen--; + } + + if ((sid == WLAN_BEACON_REQUEST_SUBELEM_REQUEST && + data->eids) || + (sid == WLAN_BEACON_REQUEST_SUBELEM_EXT_REQUEST && + data->ext_eids)) { wpa_printf(MSG_DEBUG, - "Beacon Request: Request subelement appears more than once"); + "Beacon Request: Request sub elements appear more than once"); return -1; } - data->eids = bitfield_alloc(255); - if (!data->eids) { + eids = bitfield_alloc(255); + if (!eids) { wpa_printf(MSG_DEBUG, "Failed to allocate EIDs bitmap"); return -1; } + if (sid == WLAN_BEACON_REQUEST_SUBELEM_REQUEST) + data->eids = eids; + else + data->ext_eids = eids; + for (i = 0; i < slen; i++) - bitfield_set(data->eids, subelem[i]); + bitfield_set(eids, subelem[i]); break; case WLAN_BEACON_REQUEST_SUBELEM_AP_CHANNEL: /* Skip - it will be processed when freqs are added */ @@ -1223,10 +1260,9 @@ wpas_rm_handle_beacon_req(struct wpa_supplicant *wpa_s, goto out; } - params->freqs = wpas_beacon_request_freqs( - wpa_s, req->oper_class, req->channel, - req->mode == BEACON_REPORT_MODE_ACTIVE, - req->variable, len - sizeof(*req)); + params->freqs = wpas_beacon_request_freqs(wpa_s, req->oper_class, + req->channel, req->variable, + len - sizeof(*req)); if (!params->freqs) { wpa_printf(MSG_DEBUG, "Beacon request: No valid channels"); reject_mode = MEASUREMENT_REPORT_MODE_REJECT_REFUSED; @@ -1485,6 +1521,26 @@ void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s, } +static bool wpas_beacon_rep_scan_match(struct wpa_supplicant *wpa_s, + const u8 *bssid) +{ + u8 i; + + if (!wpa_s->valid_links) + return ether_addr_equal(wpa_s->current_bss->bssid, bssid); + + for_each_link(wpa_s->valid_links, i) { + if (ether_addr_equal(wpa_s->links[i].bssid, bssid)) + return true; + } + + wpa_printf(MSG_DEBUG, "RRM: MLD: no match for TSF BSSID=" MACSTR, + MAC2STR(bssid)); + + return false; +} + + int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res, struct scan_info *info) @@ -1506,8 +1562,7 @@ int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s, MAC2STR_SEC(info->scan_start_tsf_bssid), MAC2STR_SEC(wpa_s->current_bss->bssid)); if ((wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) && - os_memcmp(info->scan_start_tsf_bssid, wpa_s->current_bss->bssid, - ETH_ALEN) != 0) { + !wpas_beacon_rep_scan_match(wpa_s, info->scan_start_tsf_bssid)) { wpa_printf(MSG_DEBUG, "RRM: Ignore scan results due to mismatching TSF BSSID"); goto out; @@ -1522,8 +1577,8 @@ int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s, if ((wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT) && - os_memcmp(scan_res->res[i]->tsf_bssid, - wpa_s->current_bss->bssid, ETH_ALEN) != 0) { + !wpas_beacon_rep_scan_match(wpa_s, + scan_res->res[i]->tsf_bssid)) { wpa_printf(MSG_DEBUG, "RRM: Ignore scan result for " MACSTR_SEC " due to mismatching TSF BSSID" MACSTR_SEC, @@ -1592,6 +1647,7 @@ void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_rrm_scan_timeout, wpa_s, NULL); bitfield_free(data->eids); + bitfield_free(data->ext_eids); os_free(data->scan_params.freqs); os_memset(data, 0, sizeof(*data)); } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/scan.c b/wpa_supplicant-2.9_standard/wpa_supplicant/scan.c index 140cab72a09dc92fd5bd2e296d4816d32fb73687..2fe787fbe99b96d793a93bba5881b8dce4a7e68b 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/scan.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/scan.c @@ -44,6 +44,8 @@ #ifdef CONFIG_P2P_CHR #include "wpa_hw_p2p_chr.h" #endif +static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s); + static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) { @@ -293,8 +295,10 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit) wpa_s->scan_res_handler = NULL; } +#ifndef CONFIG_NO_RRM if (wpa_s->beacon_rep_data.token) wpas_rrm_refuse_request(wpa_s); +#endif /* CONFIG_NO_RRM */ return; } @@ -312,27 +316,62 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit) * wpa_supplicant_trigger_scan - Request driver to start a scan * @wpa_s: Pointer to wpa_supplicant data * @params: Scan parameters + * @default_ies: Whether or not to use the default IEs in the Probe Request + * frames. Note that this will free any existing IEs set in @params, so this + * shouldn't be set if the IEs have already been set with + * wpa_supplicant_extra_ies(). Otherwise, wpabuf_free() will lead to a + * double-free. + * @next: Whether or not to perform this scan as the next radio work * Returns: 0 on success, -1 on failure */ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *params) + struct wpa_driver_scan_params *params, + bool default_ies, bool next) { struct wpa_driver_scan_params *ctx; + struct wpabuf *ies = NULL; if (wpa_s->scan_work) { wpa_dbg(wpa_s, MSG_INFO, "Reject scan trigger since one is already pending"); return -1; } + if (default_ies) { + if (params->extra_ies_len) { + os_free((u8 *) params->extra_ies); + params->extra_ies = NULL; + params->extra_ies_len = 0; + } + ies = wpa_supplicant_extra_ies(wpa_s); + if (ies) { + params->extra_ies = wpabuf_head(ies); + params->extra_ies_len = wpabuf_len(ies); + } + } ctx = wpa_scan_clone_params(params); + if (ies) { + wpabuf_free(ies); + params->extra_ies = NULL; + params->extra_ies_len = 0; + } + wpa_s->last_scan_all_chan = !params->freqs; + wpa_s->last_scan_non_coloc_6ghz = params->non_coloc_6ghz; + + if (wpa_s->crossed_6ghz_dom) { + wpa_printf(MSG_DEBUG, "First scan after crossing 6 GHz domain"); + wpa_s->crossed_6ghz_dom = false; + } + if (!ctx || - radio_add_work(wpa_s, 0, "scan", 0, wpas_trigger_scan_cb, ctx) < 0) - { + radio_add_work(wpa_s, 0, "scan", next, wpas_trigger_scan_cb, + ctx) < 0) { wpa_scan_free_params(ctx); wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=-1"); return -1; } + wpa_s->wps_scan_done = false; + return 0; } @@ -384,7 +423,7 @@ static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s) ret = wpa_drv_stop_sched_scan(wpa_s); if (ret) { - wpa_dbg(wpa_s, MSG_INFO, "stopping sched_scan failed, ret=%d", ret); + wpa_dbg(wpa_s, MSG_INFO, "stopping sched_scan failed!"); /* TODO: what to do if stopping fails? */ return -1; } @@ -426,29 +465,6 @@ wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids) } -#ifdef CONFIG_P2P -static bool is_6ghz_supported(struct wpa_supplicant *wpa_s) -{ - struct hostapd_channel_data *chnl; - int i, j; - - for (i = 0; i < wpa_s->hw.num_modes; i++) { - if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211A) { - chnl = wpa_s->hw.modes[i].channels; - for (j = 0; j < wpa_s->hw.modes[i].num_channels; j++) { - if (chnl[j].flag & HOSTAPD_CHAN_DISABLED) - continue; - if (is_6ghz_freq(chnl[j].freq)) - return true; - } - } - } - - return false; -} -#endif /* CONFIG_P2P */ - - static void wpa_supplicant_optimize_freqs( struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { @@ -477,17 +493,74 @@ static void wpa_supplicant_optimize_freqs( } if (params->freqs == NULL && wpa_s->p2p_in_invitation) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + + /* + * Perform a single-channel scan if the GO has already been + * discovered on another non-P2P interface. Note that a scan + * initiated by a P2P interface (e.g., the device interface) + * should already have sufficient IEs and scan results will be + * fetched on interface creation in that case. + */ + if (wpa_s->p2p_in_invitation == 1 && ssid) { + struct wpa_supplicant *ifs; + struct wpa_bss *bss = NULL; + const u8 *bssid = ssid->bssid_set ? ssid->bssid : NULL; + + dl_list_for_each(ifs, &wpa_s->radio->ifaces, + struct wpa_supplicant, radio_list) { + bss = wpa_bss_get(ifs, bssid, ssid->ssid, + ssid->ssid_len); + if (bss) + break; + } + if (bss && !disabled_freq(wpa_s, bss->freq)) { + params->freqs = os_calloc(2, sizeof(int)); + if (params->freqs) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Scan only the known GO frequency %d MHz during invitation", + bss->freq); + params->freqs[0] = bss->freq; + } + } + } + /* * Optimize scan based on GO information during persistent * group reinvocation */ - if (wpa_s->p2p_in_invitation < 5 && + if (!params->freqs && wpa_s->p2p_in_invitation < 5 && wpa_s->p2p_invite_go_freq > 0) { - wpa_dbg(wpa_s, MSG_WARNING, "P2P: Scan only GO preferred frequency %d MHz during invitation", - wpa_s->p2p_invite_go_freq); - params->freqs = os_calloc(2, sizeof(int)); - if (params->freqs) - params->freqs[0] = wpa_s->p2p_invite_go_freq; + if (wpa_s->p2p_invite_go_freq == 2 || + wpa_s->p2p_invite_go_freq == 5) { + enum hostapd_hw_mode mode; + + wpa_dbg(wpa_s, MSG_WARNING, + "P2P: Scan only GO preferred band %d GHz during invitation", + wpa_s->p2p_invite_go_freq); + + if (!wpa_s->hw.modes) + return; + mode = wpa_s->p2p_invite_go_freq == 5 ? + HOSTAPD_MODE_IEEE80211A : + HOSTAPD_MODE_IEEE80211G; + if (wpa_s->p2p_in_invitation <= 2) + wpa_add_scan_freqs_list(wpa_s, mode, + params, false, + false, true); + if (!params->freqs || params->freqs[0] == 0) + wpa_add_scan_freqs_list(wpa_s, mode, + params, false, + false, false); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Scan only GO preferred frequency %d MHz during invitation", + wpa_s->p2p_invite_go_freq); + params->freqs = os_calloc(2, sizeof(int)); + if (params->freqs) + params->freqs[0] = + wpa_s->p2p_invite_go_freq; + } } wpa_s->p2p_in_invitation++; if (wpa_s->p2p_in_invitation > 20) { @@ -499,6 +572,7 @@ static void wpa_supplicant_optimize_freqs( */ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Clear p2p_in_invitation"); wpa_s->p2p_in_invitation = 0; + wpa_s->p2p_retry_limit = 0; } } #endif /* CONFIG_P2P */ @@ -589,7 +663,7 @@ void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s) wpa_drv_get_ext_capa(wpa_s, type); ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, - sizeof(ext_capab)); + sizeof(ext_capab), NULL); if (ext_capab_len > 0 && wpabuf_resize(&default_ies, ext_capab_len) == 0) wpabuf_put_data(default_ies, ext_capab, ext_capab_len); @@ -623,6 +697,64 @@ void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s) } +static struct wpabuf * wpa_supplicant_ml_probe_ie(int mld_id, u16 links) +{ + struct wpabuf *extra_ie; + u16 control = MULTI_LINK_CONTROL_TYPE_PROBE_REQ; + size_t len = 3 + 4 + 4 * MAX_NUM_MLD_LINKS; + u8 link_id; + u8 *len_pos; + + if (mld_id >= 0) { + control |= EHT_ML_PRES_BM_PROBE_REQ_AP_MLD_ID; + len++; + } + + extra_ie = wpabuf_alloc(len); + if (!extra_ie) + return NULL; + + wpabuf_put_u8(extra_ie, WLAN_EID_EXTENSION); + len_pos = wpabuf_put(extra_ie, 1); + wpabuf_put_u8(extra_ie, WLAN_EID_EXT_MULTI_LINK); + + wpabuf_put_le16(extra_ie, control); + + /* common info length and MLD ID (if requested) */ + if (mld_id >= 0) { + wpabuf_put_u8(extra_ie, 2); + wpabuf_put_u8(extra_ie, mld_id); + + wpa_printf(MSG_DEBUG, "MLD: ML probe targeted at MLD ID %d", + mld_id); + } else { + wpabuf_put_u8(extra_ie, 1); + + wpa_printf(MSG_DEBUG, "MLD: ML probe targeted at receiving AP"); + } + + if (!links) + wpa_printf(MSG_DEBUG, "MLD: Probing all links"); + else + wpa_printf(MSG_DEBUG, "MLD: Probing links 0x%04x", links); + + for_each_link(links, link_id) { + wpabuf_put_u8(extra_ie, EHT_ML_SUB_ELEM_PER_STA_PROFILE); + + /* Subelement length includes only the control */ + wpabuf_put_u8(extra_ie, 2); + + control = link_id | EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK; + + wpabuf_put_le16(extra_ie, control); + } + + *len_pos = (u8 *) wpabuf_put(extra_ie, 0) - len_pos - 1; + + return extra_ie; +} + + static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) { struct wpabuf *extra_ie = NULL; @@ -633,6 +765,15 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; #endif /* CONFIG_WPS */ + if (!is_zero_ether_addr(wpa_s->ml_probe_bssid)) { + extra_ie = wpa_supplicant_ml_probe_ie(wpa_s->ml_probe_mld_id, + wpa_s->ml_probe_links); + + /* No other elements should be included in the probe request */ + wpa_printf(MSG_DEBUG, "MLD: Scan including only ML element"); + return extra_ie; + } + #ifdef CONFIG_P2P if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT); @@ -641,7 +782,7 @@ static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s) wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION); ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, - sizeof(ext_capab)); + sizeof(ext_capab), NULL); if (ext_capab_len > 0 && wpabuf_resize(&extra_ie, ext_capab_len) == 0) wpabuf_put_data(extra_ie, ext_capab, ext_capab_len); @@ -746,7 +887,9 @@ static int non_p2p_network_enabled(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) + struct wpa_driver_scan_params *params, + bool is_6ghz, bool only_6ghz_psc, + bool exclude_radar) { /* Include only supported channels for the specified band */ struct hostapd_hw_modes *mode; @@ -754,7 +897,7 @@ int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s, int *freqs, i; mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, is_6ghz); - if (!mode) + if (!mode || !mode->num_channels) return -1; if (params->freqs) { @@ -771,6 +914,14 @@ int wpa_add_scan_freqs_list(struct wpa_supplicant *wpa_s, for (i = 0; i < mode->num_channels; i++) { if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED) continue; + if (exclude_radar && + (mode->channels[i].flag & HOSTAPD_CHAN_RADAR)) + continue; + + if (is_6ghz && only_6ghz_psc && + !is_6ghz_psc_frequency(mode->channels[i].freq)) + continue; + params->freqs[num_chans++] = mode->channels[i].freq; } params->freqs[num_chans] = 0; @@ -789,13 +940,13 @@ static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s, if (wpa_s->setband_mask & WPA_SETBAND_5G) wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params, - false); + false, false, false); if (wpa_s->setband_mask & WPA_SETBAND_2G) wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, params, - false); + false, false, false); if (wpa_s->setband_mask & WPA_SETBAND_6G) wpa_add_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, params, - true); + true, false, false); } @@ -1093,7 +1244,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) wpa_supplicant_upload_p2p_state(wpa_s, P2P_INTERFACE_STATE_SCANNING, P2P_CHR_DEFAULT_REASON_CODE, P2P_CHR_DEFAULT_REASON_CODE); #endif - } + } /* * If autoscan has set its own scanning parameters */ @@ -1117,6 +1268,10 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) params.ssids[0].ssid = wpa_s->go_params->ssid; params.ssids[0].ssid_len = wpa_s->go_params->ssid_len; params.num_ssids = 1; + params.bssid = wpa_s->go_params->peer_interface_addr; + wpa_printf(MSG_DEBUG, "P2P: Use specific BSSID " MACSTR + " (peer interface address) for scan", + MAC2STR(params.bssid)); goto ssid_list_set; } @@ -1127,6 +1282,12 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) params.ssids[0].ssid_len = wpa_s->current_ssid->ssid_len; params.num_ssids = 1; + if (wpa_s->current_ssid->bssid_set) { + params.bssid = wpa_s->current_ssid->bssid; + wpa_printf(MSG_DEBUG, "P2P: Use specific BSSID " + MACSTR " for scan", + MAC2STR(params.bssid)); + } } else { wpa_printf(MSG_DEBUG, "P2P: No specific SSID known for scan during invitation"); } @@ -1342,7 +1503,8 @@ ssid_list_set: params.freqs = os_calloc(num + 1, sizeof(int)); if (params.freqs) { - num = get_shared_radio_freqs(wpa_s, params.freqs, num); + num = get_shared_radio_freqs(wpa_s, params.freqs, num, + false); if (num > 0) { wpa_dbg(wpa_s, MSG_INFO, "Scan only the " "current operating channels since " @@ -1405,6 +1567,17 @@ ssid_list_set: "Scan a previously specified BSSID " MACSTR, MAC2STR(params.bssid)); } + } else if (!is_zero_ether_addr(wpa_s->ml_probe_bssid)) { + wpa_printf(MSG_DEBUG, "Scanning for ML probe request"); + params.bssid = wpa_s->ml_probe_bssid; + params.min_probe_req_content = true; + } + + + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && + wpa_s->manual_non_coloc_6ghz) { + wpa_dbg(wpa_s, MSG_DEBUG, "Collocated 6 GHz logic is disabled"); + params.non_coloc_6ghz = 1; } scan_params = ¶ms; @@ -1430,7 +1603,13 @@ scan: params.freqs = os_calloc(num + 1, sizeof(int)); if (params.freqs) { - num = get_shared_radio_freqs(wpa_s, params.freqs, num); + /* + * Exclude the operating frequency of the current + * interface since we're looking to transition off of + * it. + */ + num = get_shared_radio_freqs(wpa_s, params.freqs, num, + true); if (num > 0 && num == wpa_s->num_multichan_concurrent) { wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used"); } else { @@ -1440,36 +1619,12 @@ scan: } } - if (!params.freqs && - (wpa_s->p2p_in_invitation || wpa_s->p2p_in_provisioning) && - !is_p2p_allow_6ghz(wpa_s->global->p2p) && - is_6ghz_supported(wpa_s)) { - int i; - - /* Exclude 5 GHz channels from the full scan for P2P connection - * since the 6 GHz band is disabled for P2P uses. */ - wpa_printf(MSG_DEBUG, - "P2P: 6 GHz disabled - update the scan frequency list"); - for (i = 0; i < wpa_s->hw.num_modes; i++) { - if (wpa_s->hw.modes[i].num_channels == 0) - continue; - if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211G) - wpa_add_scan_freqs_list( - wpa_s, HOSTAPD_MODE_IEEE80211G, - ¶ms, false); - if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211A) - wpa_add_scan_freqs_list( - wpa_s, HOSTAPD_MODE_IEEE80211A, - ¶ms, false); - if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211AD) - wpa_add_scan_freqs_list( - wpa_s, HOSTAPD_MODE_IEEE80211AD, - ¶ms, false); - } - } + if (!params.freqs && wpas_is_6ghz_supported(wpa_s, true) && + (wpa_s->p2p_in_invitation || wpa_s->p2p_in_provisioning)) + wpas_p2p_scan_freqs(wpa_s, ¶ms, true); #endif /* CONFIG_P2P */ - ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); + ret = wpa_supplicant_trigger_scan(wpa_s, scan_params, false, false); if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs && !wpa_s->manual_scan_freqs) { @@ -1506,6 +1661,10 @@ scan: if (params.bssid) os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN); } + + wpa_s->ml_probe_mld_id = -1; + wpa_s->ml_probe_links = 0; + os_memset(wpa_s->ml_probe_bssid, 0, sizeof(wpa_s->ml_probe_bssid)); } @@ -2027,7 +2186,7 @@ const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie) return get_ie((const u8 *) (res + 1), ie_len, ie); } -#ifdef CONFIG_MLD_PATCH + const u8 * wpa_scan_get_ml_ie(const struct wpa_scan_res *res, u8 type) { size_t ie_len = res->ie_len; @@ -2038,7 +2197,7 @@ const u8 * wpa_scan_get_ml_ie(const struct wpa_scan_res *res, u8 type) return get_ml_ie((const u8 *) (res + 1), ie_len, type); } -#endif + /** * wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result @@ -2148,17 +2307,170 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, } +static int wpas_channel_width_offset(enum chan_width cw) +{ + switch (cw) { + case CHAN_WIDTH_40: + return 1; + case CHAN_WIDTH_80: + return 2; + case CHAN_WIDTH_80P80: + case CHAN_WIDTH_160: + return 3; + case CHAN_WIDTH_320: + return 4; + default: + return 0; + } +} + + +/** + * wpas_channel_width_tx_pwr - Calculate the max transmit power at the channel + * width + * @ies: Information elements + * @ies_len: Length of elements + * @cw: The channel width + * Returns: The max transmit power at the channel width, TX_POWER_NO_CONSTRAINT + * if it is not constrained. + * + * This function is only used to estimate the actual signal RSSI when associated + * based on the beacon RSSI at the STA. Beacon frames are transmitted on 20 MHz + * channels, while the Data frames usually use higher channel width. Therefore + * their RSSIs may be different. Assuming there is a fixed gap between the TX + * power limit of the STA defined by the Transmit Power Envelope element and the + * TX power of the AP, the difference in the TX power of X MHz and Y MHz at the + * STA equals to the difference at the AP, and the difference in the signal RSSI + * at the STA. tx_pwr is a floating point number in the standard, but the error + * of casting to int is trivial in comparing two BSSes. + */ +static int wpas_channel_width_tx_pwr(const u8 *ies, size_t ies_len, + enum chan_width cw) +{ + int offset = wpas_channel_width_offset(cw); + const struct element *elem; + int max_tx_power = TX_POWER_NO_CONSTRAINT, tx_pwr = 0; + + for_each_element_id(elem, WLAN_EID_TRANSMIT_POWER_ENVELOPE, ies, + ies_len) { + int max_tx_pwr_count; + enum max_tx_pwr_interpretation tx_pwr_intrpn; + enum reg_6g_client_type client_type; + + if (elem->datalen < 1) + continue; + + /* + * IEEE Std 802.11ax-2021, 9.4.2.161 (Transmit Power Envelope + * element) defines Maximum Transmit Power Count (B0-B2), + * Maximum Transmit Power Interpretation (B3-B5), and Maximum + * Transmit Power Category (B6-B7). + */ + max_tx_pwr_count = elem->data[0] & 0x07; + tx_pwr_intrpn = (elem->data[0] >> 3) & 0x07; + client_type = (elem->data[0] >> 6) & 0x03; + + if (client_type != REG_DEFAULT_CLIENT) + continue; + + if (tx_pwr_intrpn == LOCAL_EIRP || + tx_pwr_intrpn == REGULATORY_CLIENT_EIRP) { + int offs; + + max_tx_pwr_count = MIN(max_tx_pwr_count, 3); + offs = MIN(offset, max_tx_pwr_count) + 1; + if (elem->datalen <= offs) + continue; + tx_pwr = (signed char) elem->data[offs]; + /* + * Maximum Transmit Power subfield is encoded as an + * 8-bit 2s complement signed integer in the range -64 + * dBm to 63 dBm with a 0.5 dB step. 63.5 dBm means no + * local maximum transmit power constraint. + */ + if (tx_pwr == 127) + continue; + tx_pwr /= 2; + max_tx_power = MIN(max_tx_power, tx_pwr); + } else if (tx_pwr_intrpn == LOCAL_EIRP_PSD || + tx_pwr_intrpn == REGULATORY_CLIENT_EIRP_PSD) { + if (elem->datalen < 2) + continue; + + tx_pwr = (signed char) elem->data[1]; + /* + * Maximum Transmit PSD subfield is encoded as an 8-bit + * 2s complement signed integer. -128 indicates that the + * corresponding 20 MHz channel cannot be used for + * transmission. +127 indicates that no maximum PSD + * limit is specified for the corresponding 20 MHz + * channel. + */ + if (tx_pwr == 127 || tx_pwr == -128) + continue; + + /* + * The Maximum Transmit PSD subfield indicates the + * maximum transmit PSD for the 20 MHz channel. Suppose + * the PSD value is X dBm/MHz, the TX power of N MHz is + * X + 10*log10(N) = X + 10*log10(20) + 10*log10(N/20) = + * X + 13 + 3*log2(N/20) + */ + tx_pwr = tx_pwr / 2 + 13 + offset * 3; + max_tx_power = MIN(max_tx_power, tx_pwr); + } + } + + return max_tx_power; +} + + +/** + * Estimate the RSSI bump of channel width |cw| with respect to 20 MHz channel. + * If the TX power has no constraint, it is unable to estimate the RSSI bump. + */ +int wpas_channel_width_rssi_bump(const u8 *ies, size_t ies_len, + enum chan_width cw) +{ + int max_20mhz_tx_pwr = wpas_channel_width_tx_pwr(ies, ies_len, + CHAN_WIDTH_20); + int max_cw_tx_pwr = wpas_channel_width_tx_pwr(ies, ies_len, cw); + + return (max_20mhz_tx_pwr == TX_POWER_NO_CONSTRAINT || + max_cw_tx_pwr == TX_POWER_NO_CONSTRAINT) ? + 0 : (max_cw_tx_pwr - max_20mhz_tx_pwr); +} + + +int wpas_adjust_snr_by_chanwidth(const u8 *ies, size_t ies_len, + enum chan_width max_cw, int snr) +{ + int rssi_bump = wpas_channel_width_rssi_bump(ies, ies_len, max_cw); + /* + * The noise has uniform power spectral density (PSD) across the + * frequency band, its power is proportional to the channel width. + * Suppose the PSD of noise is X dBm/MHz, the noise power of N MHz is + * X + 10*log10(N), and the noise power bump with respect to 20 MHz is + * 10*log10(N) - 10*log10(20) = 10*log10(N/20) = 3*log2(N/20) + */ + int noise_bump = 3 * wpas_channel_width_offset(max_cw); + + return snr + rssi_bump - noise_bump; +} + + /* Compare function for sorting scan results. Return >0 if @b is considered * better. */ static int wpa_scan_result_compar(const void *a, const void *b) { -#define MIN(a,b) a < b ? a : b struct wpa_scan_res **_wa = (void *) a; struct wpa_scan_res **_wb = (void *) b; struct wpa_scan_res *wa = *_wa; struct wpa_scan_res *wb = *_wb; int wpa_a, wpa_b; int snr_a, snr_b, snr_a_full, snr_b_full; + size_t ies_len; + const u8 *rsne_a, *rsne_b; /* WPA/WPA2 support preferred */ wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || @@ -2180,10 +2492,21 @@ static int wpa_scan_result_compar(const void *a, const void *b) return -1; if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) { - snr_a_full = wa->snr; - snr_a = MIN(wa->snr, GREAT_SNR); - snr_b_full = wb->snr; - snr_b = MIN(wb->snr, GREAT_SNR); + /* + * The scan result estimates SNR over 20 MHz, while Data frames + * usually use wider channel width. The TX power and noise power + * are both affected by the channel width. + */ + ies_len = wa->ie_len ? wa->ie_len : wa->beacon_ie_len; + snr_a_full = wpas_adjust_snr_by_chanwidth((const u8 *) (wa + 1), + ies_len, wa->max_cw, + wa->snr); + snr_a = MIN(snr_a_full, GREAT_SNR); + ies_len = wb->ie_len ? wb->ie_len : wb->beacon_ie_len; + snr_b_full = wpas_adjust_snr_by_chanwidth((const u8 *) (wb + 1), + ies_len, wb->max_cw, + wb->snr); + snr_b = MIN(snr_b_full, GREAT_SNR); } else { /* Level is not in dBm, so we can't calculate * SNR. Just use raw level (units unknown). */ @@ -2191,6 +2514,32 @@ static int wpa_scan_result_compar(const void *a, const void *b) snr_b = snr_b_full = wb->level; } + /* If SNR of a SAE BSS is good or at least as high as the PSK BSS, + * prefer SAE over PSK for mixed WPA3-Personal transition mode and + * WPA2-Personal deployments */ + rsne_a = wpa_scan_get_ie(wa, WLAN_EID_RSN); + rsne_b = wpa_scan_get_ie(wb, WLAN_EID_RSN); + if (rsne_a && rsne_b) { + struct wpa_ie_data data; + bool psk_a = false, psk_b = false, sae_a = false, sae_b = false; + + if (wpa_parse_wpa_ie_rsn(rsne_a, 2 + rsne_a[1], &data) == 0) { + psk_a = wpa_key_mgmt_wpa_psk_no_sae(data.key_mgmt); + sae_a = wpa_key_mgmt_sae(data.key_mgmt); + } + if (wpa_parse_wpa_ie_rsn(rsne_b, 2 + rsne_b[1], &data) == 0) { + psk_b = wpa_key_mgmt_wpa_psk_no_sae(data.key_mgmt); + sae_b = wpa_key_mgmt_sae(data.key_mgmt); + } + + if (sae_a && !sae_b && psk_b && + (snr_a >= GREAT_SNR || snr_a >= snr_b)) + return -1; + if (sae_b && !sae_a && psk_a && + (snr_b >= GREAT_SNR || snr_b >= snr_a)) + return 1; + } + /* If SNR is close, decide by max rate or frequency band. For cases * involving the 6 GHz band, use the throughput estimate irrespective * of the SNR difference since the LPI/VLP rules may result in @@ -2217,7 +2566,6 @@ static int wpa_scan_result_compar(const void *a, const void *b) if (snr_b_full == snr_a_full) return wb->qual - wa->qual; return snr_b_full - snr_a_full; -#undef MIN } @@ -2282,20 +2630,33 @@ static void dump_scan_res(struct wpa_scan_results *scan_res) for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *r = scan_res->res[i]; u8 *pos; + const u8 *ssid_ie, *ssid = NULL; + size_t ssid_len = 0; + + ssid_ie = wpa_scan_get_ie(r, WLAN_EID_SSID); + if (ssid_ie) { + ssid = ssid_ie + 2; + ssid_len = ssid_ie[1]; + } + if (r->flags & WPA_SCAN_LEVEL_DBM) { int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID); - wpa_printf(MSG_EXCESSIVE, MACSTR_SEC " freq=%d qual=%d " - "noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u", - MAC2STR_SEC(r->bssid), r->freq, r->qual, + wpa_printf(MSG_EXCESSIVE, MACSTR_SEC + " ssid=%s freq=%d qual=%d noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u", + MAC2STR_SEC(r->bssid), + wpa_ssid_txt(ssid, ssid_len), + r->freq, r->qual, r->noise, noise_valid ? "" : "~", r->level, r->snr, r->snr >= GREAT_SNR ? "*" : "", r->flags, r->age, r->est_throughput); } else { - wpa_printf(MSG_EXCESSIVE, MACSTR_SEC " freq=%d qual=%d " - "noise=%d level=%d flags=0x%x age=%u est=%u", - MAC2STR_SEC(r->bssid), r->freq, r->qual, + wpa_printf(MSG_EXCESSIVE, MACSTR_SEC + " ssid=%s freq=%d qual=%d noise=%d level=%d flags=0x%x age=%u est=%u", + MAC2STR_SEC(r->bssid), + wpa_ssid_txt(ssid, ssid_len), + r->freq, r->qual, r->noise, r->level, r->flags, r->age, r->est_throughput); } @@ -2329,8 +2690,7 @@ int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s, return 1; for (i = 0; i < wpa_s->bssid_filter_count; i++) { - if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid, - ETH_ALEN) == 0) + if (ether_addr_equal(wpa_s->bssid_filter + i * ETH_ALEN, bssid)) return 1; } @@ -2338,8 +2698,8 @@ int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s, } -void filter_scan_res(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *res) +static void filter_scan_res(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *res) { size_t i, j; @@ -2452,6 +2812,8 @@ static const struct minsnr_bitrate_entry vht160_table[] = { { -1, 780000 } /* SNR > 37 */ }; +/* EHT needs to be enabled in order to achieve MCS12 and MCS13 rates. */ +#define EHT_MCS 12 static const struct minsnr_bitrate_entry he20_table[] = { { 0, 0 }, @@ -2467,7 +2829,9 @@ static const struct minsnr_bitrate_entry he20_table[] = { { 31, 114700 }, /* HE20 MCS9 */ { 34, 129000 }, /* HE20 MCS10 */ { 36, 143400 }, /* HE20 MCS11 */ - { -1, 143400 } /* SNR > 29 */ + { 39, 154900 }, /* EHT20 MCS12 */ + { 42, 172100 }, /* EHT20 MCS13 */ + { -1, 172100 } /* SNR > 42 */ }; static const struct minsnr_bitrate_entry he40_table[] = { @@ -2484,7 +2848,9 @@ static const struct minsnr_bitrate_entry he40_table[] = { { 34, 229400 }, /* HE40 MCS9 */ { 37, 258100 }, /* HE40 MCS10 */ { 39, 286800 }, /* HE40 MCS11 */ - { -1, 286800 } /* SNR > 34 */ + { 42, 309500 }, /* EHT40 MCS12 */ + { 45, 344100 }, /* EHT40 MCS13 */ + { -1, 344100 } /* SNR > 45 */ }; static const struct minsnr_bitrate_entry he80_table[] = { @@ -2501,7 +2867,9 @@ static const struct minsnr_bitrate_entry he80_table[] = { { 37, 480400 }, /* HE80 MCS9 */ { 40, 540400 }, /* HE80 MCS10 */ { 42, 600500 }, /* HE80 MCS11 */ - { -1, 600500 } /* SNR > 37 */ + { 45, 648500 }, /* EHT80 MCS12 */ + { 48, 720600 }, /* EHT80 MCS13 */ + { -1, 720600 } /* SNR > 48 */ }; @@ -2519,9 +2887,31 @@ static const struct minsnr_bitrate_entry he160_table[] = { { 40, 960800 }, /* HE160 MCS9 */ { 43, 1080900 }, /* HE160 MCS10 */ { 45, 1201000 }, /* HE160 MCS11 */ - { -1, 1201000 } /* SNR > 37 */ + { 48, 1297100 }, /* EHT160 MCS12 */ + { 51, 1441200 }, /* EHT160 MCS13 */ + { -1, 1441200 } /* SNR > 51 */ }; +/* See IEEE P802.11be/D2.0, Table 36-86: EHT-MCSs for 4x996-tone RU, NSS,u = 1 + */ +static const struct minsnr_bitrate_entry eht320_table[] = { + { 0, 0 }, + { 14, 144100 }, /* EHT320 MCS0 */ + { 17, 288200 }, /* EHT320 MCS1 */ + { 21, 432400 }, /* EHT320 MCS2 */ + { 23, 576500 }, /* EHT320 MCS3 */ + { 27, 864700 }, /* EHT320 MCS4 */ + { 30, 1152900 }, /* EHT320 MCS5 */ + { 32, 1297100 }, /* EHT320 MCS6 */ + { 37, 1441200 }, /* EHT320 MCS7 */ + { 41, 1729400 }, /* EHT320 MCS8 */ + { 43, 1921500 }, /* EHT320 MCS9 */ + { 46, 2161800 }, /* EHT320 MCS10 */ + { 48, 2401900 }, /* EHT320 MCS11 */ + { 51, 2594100 }, /* EHT320 MCS12 */ + { 54, 2882400 }, /* EHT320 MCS13 */ + { -1, 2882400 } /* SNR > 54 */ +}; static unsigned int interpolate_rate(int snr, int snr0, int snr1, int rate0, int rate1) @@ -2573,17 +2963,18 @@ static unsigned int max_vht160_rate(int snr) } -static unsigned int max_he_rate(const struct minsnr_bitrate_entry table[], - int snr) +static unsigned int max_he_eht_rate(const struct minsnr_bitrate_entry table[], + int snr, bool eht) { const struct minsnr_bitrate_entry *prev, *entry = table; - while (entry->minsnr != -1 && snr >= entry->minsnr) + while (entry->minsnr != -1 && snr >= entry->minsnr && + (eht || entry - table <= EHT_MCS)) entry++; if (entry == table) return 0; prev = entry - 1; - if (entry->minsnr == -1) + if (entry->minsnr == -1 || (!eht && entry - table > EHT_MCS)) return prev->bitrate; return interpolate_rate(snr, prev->minsnr, entry->minsnr, prev->bitrate, entry->bitrate); @@ -2592,11 +2983,18 @@ static unsigned int max_he_rate(const struct minsnr_bitrate_entry table[], unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, const u8 *ies, size_t ies_len, int rate, - int snr, int freq) + int snr, int freq, enum chan_width *max_cw) { struct hostapd_hw_modes *hw_mode; unsigned int est, tmp; const u8 *ie; + /* + * No need to apply a bump to the noise here because the + * minsnr_bitrate_entry tables are based on MCS tables where this has + * been taken into account. + */ + int adjusted_snr; + bool ht40 = false, vht80 = false, vht160 = false; /* Limit based on estimated SNR */ if (rate > 1 * 2 && snr < 1) @@ -2645,64 +3043,76 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, if (hw_mode && hw_mode->ht_capab) { ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP); if (ie) { + *max_cw = CHAN_WIDTH_20; tmp = max_ht20_rate(snr, false); if (tmp > est) est = tmp; } } + 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)) + ht40 = true; + if (hw_mode && (hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) { - 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, false); + if (ht40) { + *max_cw = CHAN_WIDTH_40; + adjusted_snr = snr + + wpas_channel_width_rssi_bump(ies, ies_len, + CHAN_WIDTH_40); + tmp = max_ht40_rate(adjusted_snr, false); if (tmp > est) est = tmp; } } + /* Determine VHT BSS bandwidth based on IEEE Std 802.11-2020, + * Table 11-23 (VHT BSS bandwidth) */ + ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION); + if (ie && ie[1] >= 3) { + u8 cw = ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK; + u8 seg0 = ie[3]; + u8 seg1 = ie[4]; + + if (cw) + vht80 = true; + if (cw == 2 || + (cw == 3 && (seg1 > 0 && abs(seg1 - seg0) == 16))) + vht160 = true; + if (cw == 1 && + ((seg1 > 0 && abs(seg1 - seg0) == 8) || + (seg1 > 0 && abs(seg1 - seg0) == 16))) + vht160 = true; + } + if (hw_mode && hw_mode->vht_capab) { /* Use +1 to assume VHT is always faster than HT */ ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP); if (ie) { - bool vht80 = false, vht160 = false; - + if (*max_cw == CHAN_WIDTH_UNKNOWN) + *max_cw = CHAN_WIDTH_20; tmp = max_ht20_rate(snr, true) + 1; if (tmp > est) est = tmp; - 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, true) + 1; + if (ht40) { + *max_cw = CHAN_WIDTH_40; + adjusted_snr = snr + + wpas_channel_width_rssi_bump( + ies, ies_len, CHAN_WIDTH_40); + tmp = max_ht40_rate(adjusted_snr, true) + 1; if (tmp > est) est = tmp; } - /* Determine VHT BSS bandwidth based on IEEE Std - * 802.11-2020, Table 11-23 (VHT BSs bandwidth) */ - ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION); - if (ie && ie[1] >= 3) { - u8 cw = ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK; - u8 seg0 = ie[3]; - u8 seg1 = ie[4]; - - if (cw) - vht80 = true; - if (cw == 2 || - (cw == 3 && - (seg1 > 0 && abs(seg1 - seg0) == 16))) - vht160 = true; - if (cw == 1 && - ((seg1 > 0 && abs(seg1 - seg0) == 8) || - (seg1 > 0 && abs(seg1 - seg0) == 16))) - vht160 = true; - } - if (vht80) { - tmp = max_vht80_rate(snr) + 1; + *max_cw = CHAN_WIDTH_80; + adjusted_snr = snr + + wpas_channel_width_rssi_bump( + ies, ies_len, CHAN_WIDTH_80); + tmp = max_vht80_rate(adjusted_snr) + 1; if (tmp > est) est = tmp; } @@ -2711,7 +3121,11 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, (hw_mode->vht_capab & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { - tmp = max_vht160_rate(snr) + 1; + *max_cw = CHAN_WIDTH_160; + adjusted_snr = snr + + wpas_channel_width_rssi_bump( + ies, ies_len, CHAN_WIDTH_160); + tmp = max_vht160_rate(adjusted_snr) + 1; if (tmp > est) est = tmp; } @@ -2721,8 +3135,11 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, if (hw_mode && hw_mode->he_capab[IEEE80211_MODE_INFRA].he_supported) { /* Use +2 to assume HE is always faster than HT/VHT */ struct ieee80211_he_capabilities *he; + struct ieee80211_eht_capabilities *eht; struct he_capabilities *own_he; - u8 cw; + u8 cw, boost = 2; + const u8 *eht_ie; + bool is_eht = false; ie = get_ie_ext(ies, ies_len, WLAN_EID_EXT_HE_CAPABILITIES); if (!ie || (ie[1] < 1 + IEEE80211_HE_CAPAB_MIN_LEN)) @@ -2730,31 +3147,83 @@ unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, he = (struct ieee80211_he_capabilities *) &ie[3]; own_he = &hw_mode->he_capab[IEEE80211_MODE_INFRA]; - tmp = max_he_rate(he20_table, snr) + 2; + /* Use +3 to assume EHT is always faster than HE */ + if (hw_mode->eht_capab[IEEE80211_MODE_INFRA].eht_supported) { + eht_ie = get_ie_ext(ies, ies_len, + WLAN_EID_EXT_EHT_CAPABILITIES); + if (eht_ie && + (eht_ie[1] >= 1 + IEEE80211_EHT_CAPAB_MIN_LEN)) { + is_eht = true; + boost = 3; + } + } + + if (*max_cw == CHAN_WIDTH_UNKNOWN) + *max_cw = CHAN_WIDTH_20; + tmp = max_he_eht_rate(he20_table, snr, is_eht) + boost; if (tmp > est) est = tmp; cw = he->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & own_he->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX]; - if (cw & - (IS_2P4GHZ(freq) ? HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G : - HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) { - tmp = max_he_rate(he40_table, snr) + 2; + if ((cw & + (IS_2P4GHZ(freq) ? + HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G : + HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) && ht40) { + if (*max_cw == CHAN_WIDTH_UNKNOWN || + *max_cw < CHAN_WIDTH_40) + *max_cw = CHAN_WIDTH_40; + adjusted_snr = snr + wpas_channel_width_rssi_bump( + ies, ies_len, CHAN_WIDTH_40); + tmp = max_he_eht_rate(he40_table, adjusted_snr, + is_eht) + boost; if (tmp > est) est = tmp; } if (!IS_2P4GHZ(freq) && - (cw & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) { - tmp = max_he_rate(he80_table, snr) + 2; + (cw & HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G) && + (!IS_5GHZ(freq) || vht80)) { + if (*max_cw == CHAN_WIDTH_UNKNOWN || + *max_cw < CHAN_WIDTH_80) + *max_cw = CHAN_WIDTH_80; + adjusted_snr = snr + wpas_channel_width_rssi_bump( + ies, ies_len, CHAN_WIDTH_80); + tmp = max_he_eht_rate(he80_table, adjusted_snr, + is_eht) + boost; if (tmp > est) est = tmp; } if (!IS_2P4GHZ(freq) && (cw & (HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G | - HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G))) { - tmp = max_he_rate(he160_table, snr) + 2; + HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) && + (!IS_5GHZ(freq) || vht160)) { + if (*max_cw == CHAN_WIDTH_UNKNOWN || + *max_cw < CHAN_WIDTH_160) + *max_cw = CHAN_WIDTH_160; + adjusted_snr = snr + wpas_channel_width_rssi_bump( + ies, ies_len, CHAN_WIDTH_160); + tmp = max_he_eht_rate(he160_table, adjusted_snr, + is_eht) + boost; + if (tmp > est) + est = tmp; + } + + if (!is_eht) + return est; + + eht = (struct ieee80211_eht_capabilities *) &eht_ie[3]; + + if (is_6ghz_freq(freq) && + (eht->phy_cap[EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] & + EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK)) { + if (*max_cw == CHAN_WIDTH_UNKNOWN || + *max_cw < CHAN_WIDTH_320) + *max_cw = CHAN_WIDTH_320; + adjusted_snr = snr + wpas_channel_width_rssi_bump( + ies, ies_len, CHAN_WIDTH_320); + tmp = max_he_eht_rate(eht320_table, adjusted_snr, true); if (tmp > est) est = tmp; } @@ -2780,8 +3249,8 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s, if (!ie_len) ie_len = res->beacon_ie_len; - res->est_throughput = - wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, res->freq); + res->est_throughput = wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr, + res->freq, &res->max_cw); /* TODO: channel utilization and AP load (e.g., from AP Beacon) */ } @@ -2792,6 +3261,7 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s, * @wpa_s: Pointer to wpa_supplicant data * @info: Information about what was scanned or %NULL if not available * @new_scan: Whether a new scan was performed + * @bssid: Return BSS entries only for a single BSSID, %NULL for all * Returns: Scan results, %NULL on failure * * This function request the current scan results from the driver and updates @@ -2800,7 +3270,8 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s, */ struct wpa_scan_results * wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, - struct scan_info *info, int new_scan) + struct scan_info *info, int new_scan, + const u8 *bssid) { struct wpa_scan_results *scan_res; size_t i; @@ -2812,7 +3283,7 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, return NULL; } #endif - scan_res = wpa_drv_get_scan_results2(wpa_s); + scan_res = wpa_drv_get_scan_results(wpa_s, bssid); if (scan_res == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results"); return NULL; @@ -2873,6 +3344,7 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, /** * wpa_supplicant_update_scan_results - Update scan results from the driver * @wpa_s: Pointer to wpa_supplicant data + * @bssid: Update BSS entries only for a single BSSID, %NULL for all * Returns: 0 on success, -1 on failure * * This function updates the BSS table within wpa_supplicant based on the @@ -2882,10 +3354,11 @@ wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, * needed information to complete the connection (e.g., to perform validation * steps in 4-way handshake). */ -int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s) +int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s, + const u8 *bssid) { struct wpa_scan_results *scan_res; - scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); + scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0, bssid); if (scan_res == NULL) return -1; wpa_scan_results_free(scan_res); @@ -2905,24 +3378,24 @@ void scan_only_handler(struct wpa_supplicant *wpa_s, wpa_s->manual_scan_use_id && wpa_s->own_scan_running) { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS "id=%u", wpa_s->manual_scan_id); - #if defined(OHOS_EUPDATER) +#if defined(OHOS_EUPDATER) struct WpaRecvScanResultParam wpaRecvScanResultParam; os_memset(&wpaRecvScanResultParam, 0, sizeof(struct WpaRecvScanResultParam)); wpaRecvScanResultParam.scanId = wpa_s->manual_scan_id ; wpa_printf(MSG_DEBUG, "send WPA_EVENT_RECV_SCAN_RESULT scanId = v%d", wpaRecvScanResultParam.scanId); WpaEventReport(wpa_s->ifname, WPA_EVENT_RECV_SCAN_RESULT, (void *) &wpaRecvScanResultParam); - #endif +#endif wpa_s->manual_scan_use_id = 0; } else { wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); - #if defined(OHOS_EUPDATER) +#if defined(OHOS_EUPDATER) struct WpaRecvScanResultParam wpaRecvScanResultParam; os_memset(&wpaRecvScanResultParam, 0, sizeof(struct WpaRecvScanResultParam)); wpaRecvScanResultParam.scanId = 0 ; wpa_printf(MSG_DEBUG, "send WPA_EVENT_RECV_SCAN_RESULT scanId = v%d", wpaRecvScanResultParam.scanId); WpaEventReport(wpa_s->ifname, WPA_EVENT_RECV_SCAN_RESULT, (void *) &wpaRecvScanResultParam); - #endif +#endif } wpas_notify_scan_results(wpa_s); wpas_notify_scan_done(wpa_s, 1); @@ -2997,6 +3470,7 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) params->duration = src->duration; params->duration_mandatory = src->duration_mandatory; params->oce_scan = src->oce_scan; + params->link_id = src->link_id; if (src->sched_scan_plans_num > 0) { params->sched_scan_plans = @@ -3027,6 +3501,8 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src) params->relative_adjust_band = src->relative_adjust_band; params->relative_adjust_rssi = src->relative_adjust_rssi; params->p2p_include_6ghz = src->p2p_include_6ghz; + params->non_coloc_6ghz = src->non_coloc_6ghz; + params->min_probe_req_content = src->min_probe_req_content; return params; failed: diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/scan.h b/wpa_supplicant-2.9_standard/wpa_supplicant/scan.h index bab0019c2cfd8dc6af1e2c7552f4af205bdfc5d7..d4c06c1aed4034b0e746c01d6aec5b2fed4df347 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/scan.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/scan.h @@ -30,8 +30,13 @@ */ #define GREAT_SNR 25 -#define IS_2P4GHZ(n) (n >= 2412 && n <= 2484) -#define IS_5GHZ(n) (n > 4000 && n < 5895) +/* + * IEEE Sts 802.11ax-2021, 9.4.2.161 (Transmit Power Envelope element) indicates + * no max TX power limit if Maximum Transmit Power field is 63.5 dBm. + * The default TX power if it is not constrained by Transmit Power Envelope + * element. + */ +#define TX_POWER_NO_CONSTRAINT 64 int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s); void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec); @@ -45,15 +50,16 @@ void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s, int scanning); struct wpa_driver_scan_params; int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *params); + struct wpa_driver_scan_params *params, + bool default_ies, bool next); struct wpa_scan_results * wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s, - struct scan_info *info, int new_scan); -int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s); + struct scan_info *info, int new_scan, + const u8 *bssid); +int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s, + const u8 *bssid); const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie); -#ifdef CONFIG_MLD_PATCH const u8 * wpa_scan_get_ml_ie(const struct wpa_scan_res *res, u8 type); -#endif const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res, u32 vendor_type); const u8 * wpa_scan_get_vendor_ie_beacon(const struct wpa_scan_res *res, @@ -82,18 +88,21 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s, int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s, unsigned int type, u8 *mask); int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s); -void filter_scan_res(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *res); void scan_snr(struct wpa_scan_res *res); void scan_est_throughput(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res); unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, const u8 *ies, size_t ies_len, int rate, - int snr, int freq); + int snr, int freq, enum chan_width *max_cw); 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); + bool is_6ghz, bool only_6ghz_psc, + bool exclude_radar); +int wpas_channel_width_rssi_bump(const u8 *ies, size_t ies_len, + enum chan_width cw); +int wpas_adjust_snr_by_chanwidth(const u8 *ies, size_t ies_len, + enum chan_width max_cw, int snr); #endif /* SCAN_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/sme.c b/wpa_supplicant-2.9_standard/wpa_supplicant/sme.c index 406d98c82eedcbd9fa611bb16c70fd7e31b4b32c..4020f9eca4099acde1d4fded4d9e04a9e2da0a25 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/sme.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/sme.c @@ -1,6 +1,6 @@ /* * wpa_supplicant - SME - * Copyright (c) 2009-2014, Jouni Malinen + * Copyright (c) 2009-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -10,6 +10,7 @@ #include "common.h" #include "utils/eloop.h" +#include "utils/ext_password.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/ocv.h" @@ -27,6 +28,7 @@ #include "p2p_supplicant.h" #include "notify.h" #include "bss.h" +#include "bssid_ignore.h" #include "scan.h" #include "sme.h" #include "hs20_supplicant.h" @@ -56,11 +58,7 @@ static int index_within_array(const int *array, int idx) } -static int sme_set_sae_group(struct wpa_supplicant *wpa_s -#ifdef CONFIG_MLD_PATCH - , bool external -#endif -) +static int sme_set_sae_group(struct wpa_supplicant *wpa_s, bool external) { int *groups = wpa_s->conf->sae_groups; int default_groups[] = { 19, 20, 21, 0 }; @@ -76,15 +74,13 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s int group = groups[wpa_s->sme.sae_group_index]; if (group <= 0) break; - if (sae_set_group(&wpa_s->sme.sae, group) == 0) { + if (!int_array_includes(wpa_s->sme.sae_rejected_groups, + group) && + sae_set_group(&wpa_s->sme.sae, group) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d", wpa_s->sme.sae.group); -#ifdef CONFIG_MLD_PATCH wpa_s->sme.sae.akmp = external ? - wpa_s->sme.ext_auth_key_mgmt : wpa_s->key_mgmt; -#else - wpa_s->sme.sae.akmp = wpa_s->key_mgmt; -#endif + wpa_s->sme.ext_auth_key_mgmt : wpa_s->key_mgmt; return 0; } wpa_s->sme.sae_group_index++; @@ -96,26 +92,23 @@ 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, -#ifdef CONFIG_MLD_PATCH + const u8 *bssid, const u8 *mld_addr, -#endif int external, int reuse, int *ret_use_pt, bool *ret_use_pk) { struct wpabuf *buf; size_t len; - const char *password; + char *password = NULL; struct wpa_bss *bss; int use_pt = 0; bool use_pk = false; u8 rsnxe_capa = 0; -#ifdef CONFIG_MLD_PATCH int key_mgmt = external ? wpa_s->sme.ext_auth_key_mgmt : wpa_s->key_mgmt; const u8 *addr = mld_addr ? mld_addr : bssid; -#endif + if (ret_use_pt) *ret_use_pt = 0; if (ret_use_pk) @@ -126,7 +119,7 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override"); buf = wpabuf_alloc(4 + wpabuf_len(wpa_s->sae_commit_override)); if (!buf) - return NULL; + goto fail; if (!external) { wpabuf_put_le16(buf, 1); /* Transaction seq# */ wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS); @@ -136,41 +129,65 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_TESTING_OPTIONS */ - password = ssid->sae_password; - if (!password) - password = ssid->passphrase; + if (ssid->sae_password) { + password = os_strdup(ssid->sae_password); + if (!password) { + wpa_dbg(wpa_s, MSG_INFO, + "SAE: Failed to allocate password"); + goto fail; + } + } + if (!password && ssid->passphrase) { + password = os_strdup(ssid->passphrase); + if (!password) { + wpa_dbg(wpa_s, MSG_INFO, + "SAE: Failed to allocate password"); + goto fail; + } + } + if (!password && ssid->ext_psk) { + struct wpabuf *pw = ext_password_get(wpa_s->ext_pw, + ssid->ext_psk); + + if (!pw) { + wpa_msg(wpa_s, MSG_INFO, + "SAE: No password found from external storage"); + goto fail; + } + + password = os_malloc(wpabuf_len(pw) + 1); + if (!password) { + wpa_dbg(wpa_s, MSG_INFO, + "SAE: Failed to allocate password"); + goto fail; + } + os_memcpy(password, wpabuf_head(pw), wpabuf_len(pw)); + password[wpabuf_len(pw)] = '\0'; + ext_password_free(pw); + } if (!password) { wpa_printf(MSG_DEBUG, "SAE: No password available"); - return NULL; + goto fail; } if (reuse && wpa_s->sme.sae.tmp && -#ifdef CONFIG_MLD_PATCH - os_memcmp(addr, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) -#else - os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) -#endif - { + ether_addr_equal(addr, wpa_s->sme.sae.tmp->bssid)) { wpa_printf(MSG_DEBUG, "SAE: Reuse previously generated PWE on a retry with the same AP"); use_pt = wpa_s->sme.sae.h2e; use_pk = wpa_s->sme.sae.pk; goto reuse_data; } -#ifdef CONFIG_MLD_PATCH if (sme_set_sae_group(wpa_s, external) < 0) { -#else - if (sme_set_sae_group(wpa_s) < 0) { -#endif wpa_printf(MSG_DEBUG, "SAE: Failed to select group"); - return NULL; + goto fail; } bss = wpa_bss_get_bssid_latest(wpa_s, bssid); if (!bss) { wpa_printf(MSG_DEBUG, "SAE: BSS not available, update scan result to get BSS"); - wpa_supplicant_update_scan_results(wpa_s); + wpa_supplicant_update_scan_results(wpa_s, bssid); bss = wpa_bss_get_bssid_latest(wpa_s, bssid); } if (bss) { @@ -181,16 +198,15 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, rsnxe_capa = rsnxe[2]; } - if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3) + if (ssid->sae_password_id && + wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) use_pt = 1; -#ifdef CONFIG_MLD_PATCH if (wpa_key_mgmt_sae_ext_key(key_mgmt) && -#else - if (wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt) && -#endif wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) use_pt = 1; - + if (bss && is_6ghz_freq(bss->freq) && + wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) + use_pt = 1; #ifdef CONFIG_SAE_PK if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) && ssid->sae_pk != SAE_PK_MODE_DISABLED && @@ -205,67 +221,47 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, if (ssid->sae_pk == SAE_PK_MODE_ONLY && !use_pk) { wpa_printf(MSG_DEBUG, "SAE: Cannot use PK with the selected AP"); - return NULL; + goto fail; } #endif /* CONFIG_SAE_PK */ - if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) { + if (use_pt || wpa_s->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || + wpa_s->conf->sae_pwe == SAE_PWE_BOTH) { use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E)); - if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id || -#ifdef CONFIG_MLD_PATCH - wpa_key_mgmt_sae_ext_key(key_mgmt)) && -#else - wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) && -#endif - wpa_s->conf->sae_pwe != 3 && + if ((wpa_s->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT || + ssid->sae_password_id || + wpa_key_mgmt_sae_ext_key(key_mgmt)) && + wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK && !use_pt) { wpa_printf(MSG_DEBUG, "SAE: Cannot use H2E with the selected AP"); - return NULL; + goto fail; } } if (use_pt && !ssid->pt) - wpa_s_setup_sae_pt(wpa_s->conf, ssid); + wpa_s_setup_sae_pt(wpa_s->conf, ssid, true); if (use_pt && sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt, - wpa_s->own_addr, -#ifdef CONFIG_MLD_PATCH - addr, -#else - bssid, -#endif + wpa_s->own_addr, addr, wpa_s->sme.sae_rejected_groups, NULL) < 0) - return NULL; + goto fail; if (!use_pt && - sae_prepare_commit(wpa_s->own_addr, -#ifdef CONFIG_MLD_PATCH - addr, -#else - bssid, -#endif + sae_prepare_commit(wpa_s->own_addr, addr, (u8 *) password, os_strlen(password), &wpa_s->sme.sae) < 0) { wpa_printf(MSG_DEBUG, "SAE: Could not pick PWE"); - return NULL; + goto fail; } if (wpa_s->sme.sae.tmp) { -#ifdef CONFIG_MLD_PATCH os_memcpy(wpa_s->sme.sae.tmp->bssid, addr, ETH_ALEN); -#else - os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN); -#endif 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); -#ifdef CONFIG_MLD_PATCH os_memcpy(wpa_s->sme.sae.tmp->peer_addr, addr, ETH_ALEN); -#else - os_memcpy(wpa_s->sme.sae.tmp->peer_addr, bssid, ETH_ALEN); -#endif sae_pk_set_password(&wpa_s->sme.sae, password); #endif /* CONFIG_SAE_PK */ } @@ -276,7 +272,7 @@ reuse_data: len += 4 + os_strlen(ssid->sae_password_id); buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len); if (buf == NULL) - return NULL; + goto fail; if (!external) { wpabuf_put_le16(buf, 1); /* Transaction seq# */ if (use_pk) @@ -289,14 +285,19 @@ reuse_data: if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token, ssid->sae_password_id) < 0) { wpabuf_free(buf); - return NULL; + goto fail; } if (ret_use_pt) *ret_use_pt = use_pt; if (ret_use_pk) *ret_use_pk = use_pk; + str_clear_free(password); return buf; + +fail: + str_clear_free(password); + return NULL; } @@ -382,146 +383,96 @@ static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s, wpa_s->rrm.rrm_used = 1; } -#ifdef CONFIG_MLD_PATCH -static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) + +static void wpas_ml_handle_removed_links(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss) { - struct wpabuf *mlbuf; - const u8 *rnr_ie, *pos; - u8 ml_ie_len, rnr_ie_len; - const struct ieee80211_eht_ml *eht_ml; - const struct eht_ml_basic_common_info *ml_basic_common_info; - u8 i; - const u16 control = - host_to_le16(MULTI_LINK_CONTROL_TYPE_BASIC | - BASIC_MULTI_LINK_CTRL_PRES_LINK_ID | - BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT | - BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA); - bool ret = false; - - if (!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO)) - return false; - - mlbuf = wpa_bss_defrag_mle(bss, MULTI_LINK_CONTROL_TYPE_BASIC); + u16 removed_links = wpa_bss_parse_reconf_ml_element(wpa_s, bss); - if (!mlbuf) { - wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No ML element"); - return false; - } - - ml_ie_len = wpabuf_len(mlbuf); - - /* control + common info len + MLD address + MLD link inform ation */ - if (ml_ie_len < 2 + 1 + ETH_ALEN + 1) - goto out; - - eht_ml = wpabuf_head(mlbuf); - if ((eht_ml->ml_control & control) != control) { - wpa_printf(MSG_DEBUG, "MLD: Unexpected ML element control=0x%x", eht_ml->ml_control); - goto out; - } - - ml_basic_common_info = - (const struct eht_ml_basic_common_info *)eht_ml->variable; - - /* common info length should be valid (self, mld_addr, link_id) */ - if (ml_basic_common_info->len < 1 + ETH_ALEN + 1) - goto out; - - /* get the MLD address and MLD link ID */ - os_memcpy(wpa_s->ap_mld_addr, ml_basic_common_info->mld_addr, - ETH_ALEN); - wpa_s->mlo_assoc_link_id = ml_basic_common_info->variable[0] & - EHT_ML_LINK_ID_MSK; - - os_memcpy(wpa_s->links[wpa_s->mlo_assoc_link_id].bssid, bss->bssid, - ETH_ALEN); - wpa_s->links[wpa_s->mlo_assoc_link_id].freq = bss->freq; - - wpa_printf(MSG_DEBUG, "MLD: address="MACSTR_SEC ", link ID=%u", - MAC2STR_SEC(wpa_s->ap_mld_addr), wpa_s->mlo_assoc_link_id); - - wpa_s->valid_links = BIT(wpa_s->mlo_assoc_link_id); - - rnr_ie = wpa_bss_get_ie(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT); - - if (!rnr_ie) { - wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RNR element"); - ret = true; - goto out; - } - - - rnr_ie_len = rnr_ie[1]; - pos = rnr_ie + 2; - - while (rnr_ie_len > sizeof(struct ieee80211_neighbor_ap_info)) { - const struct ieee80211_neighbor_ap_info *ap_info = - (const struct ieee80211_neighbor_ap_info *)pos; - const u8 *data = ap_info->data; - size_t len = sizeof(struct ieee80211_neighbor_ap_info) + - ap_info->tbtt_info_len; - - wpa_printf(MSG_DEBUG, "MLD: op_class=%u, channel=%u", - ap_info->op_class, ap_info->channel); - - if (len > rnr_ie_len) - break; - - if (ap_info->tbtt_info_len < 16) { - rnr_ie_len -= len; - pos += len; - continue; - } - - data += 13; - - wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u", - *data, *(data + 1) & 0xF); - - if (*data) { - wpa_printf(MSG_DEBUG, "MLD: Reported link not part of MLD"); - } else { - struct wpa_bss *neigh_bss = - wpa_bss_get_bssid(wpa_s, ap_info->data + 1); - u8 link_id = *(data + 1) & 0xF; - - if (neigh_bss) { - if (wpa_scan_res_match(wpa_s, 0, neigh_bss, - wpa_s->current_ssid, - 1, 0)) { - wpa_s->valid_links |= BIT(link_id); - os_memcpy(wpa_s->links[link_id].bssid, - ap_info->data + 1, ETH_ALEN); - wpa_s->links[link_id].freq = neigh_bss->freq; - } else { - wpa_printf(MSG_DEBUG, - "MLD: Neighbor doesn't match current SSID - skip link"); - } - } else { - wpa_printf(MSG_DEBUG, - "MLD: Neighbor not found in scan"); - } + wpa_s->valid_links &= ~removed_links; +} + + +#ifdef CONFIG_TESTING_OPTIONS +static struct wpa_bss * wpas_ml_connect_pref(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, + struct wpa_ssid *ssid) +{ + unsigned int low, high, i; + + wpa_printf(MSG_DEBUG, + "MLD: valid_links=%d, band_pref=%u, bssid_pref=" MACSTR, + wpa_s->valid_links, + wpa_s->conf->mld_connect_band_pref, + MAC2STR(wpa_s->conf->mld_connect_bssid_pref)); + + /* Check if there are more than one link */ + if (!(wpa_s->valid_links & (wpa_s->valid_links - 1))) + return bss; + + if (!is_zero_ether_addr(wpa_s->conf->mld_connect_bssid_pref)) { + for_each_link(wpa_s->valid_links, i) { + if (wpa_s->mlo_assoc_link_id == i) + continue; + + if (ether_addr_equal( + wpa_s->links[i].bssid, + wpa_s->conf->mld_connect_bssid_pref)) + goto found; } + } - rnr_ie_len -= len; - pos += len; + if (wpa_s->conf->mld_connect_band_pref == MLD_CONNECT_BAND_PREF_AUTO) + return bss; + + switch (wpa_s->conf->mld_connect_band_pref) { + case MLD_CONNECT_BAND_PREF_2GHZ: + low = 2412; + high = 2472; + break; + case MLD_CONNECT_BAND_PREF_5GHZ: + low = 5180; + high = 5985; + break; + case MLD_CONNECT_BAND_PREF_6GHZ: + low = 5955; + high = 7125; + break; + default: + return bss; } - - wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%x", wpa_s->valid_links); - - for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { - if (!(wpa_s->valid_links & BIT(i))) + + for_each_link(wpa_s->valid_links, i) { + if (wpa_s->mlo_assoc_link_id == i) continue; - - wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid="MACSTR_SEC, - i, MAC2STR_SEC(wpa_s->links[i].bssid)); - } - - ret = true; -out: - wpabuf_free(mlbuf); - return ret; + + if (wpa_s->links[i].freq >= low && wpa_s->links[i].freq <= high) + goto found; + } + +found: + if (i == MAX_NUM_MLD_LINKS) { + wpa_printf(MSG_DEBUG, "MLD: No match for connect/band pref"); + return bss; + } + + wpa_printf(MSG_DEBUG, + "MLD: Change BSS for connect: " MACSTR " -> " MACSTR, + MAC2STR(wpa_s->links[wpa_s->mlo_assoc_link_id].bssid), + MAC2STR(wpa_s->links[i].bssid)); + + /* Get the BSS entry and do the switch */ + if (ssid && ssid->ssid_len) + bss = wpa_bss_get(wpa_s, wpa_s->links[i].bssid, ssid->ssid, + ssid->ssid_len); + else + bss = wpa_bss_get_bssid(wpa_s, wpa_s->links[i].bssid); + wpa_s->mlo_assoc_link_id = i; + + return bss; } +#endif /* CONFIG_TESTING_OPTIONS */ + static int wpas_sme_ml_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data, @@ -557,17 +508,45 @@ static int wpas_sme_ml_auth(struct wpa_supplicant *wpa_s, if (!mld_addr) return -1; - wpa_printf(MSG_DEBUG, "MLD: mld_address=" MACSTR_SEC, MAC2STR_SEC(mld_addr)); + wpa_printf(MSG_DEBUG, "MLD: mld_address=" MACSTR, MAC2STR(mld_addr)); - if (os_memcmp(wpa_s->ap_mld_addr, mld_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(wpa_s->ap_mld_addr, mld_addr)) { wpa_printf(MSG_DEBUG, "MLD: Unexpected MLD address (expected " - MACSTR_SEC ")", MAC2STR_SEC(wpa_s->ap_mld_addr)); + MACSTR ")", MAC2STR(wpa_s->ap_mld_addr)); return -1; } return 0; } -#endif + + +static void wpas_sme_set_mlo_links(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, struct wpa_ssid *ssid) +{ + u8 i; + + wpa_s->valid_links = 0; + wpa_s->mlo_assoc_link_id = bss->mld_link_id; + + for_each_link(bss->valid_links, i) { + const u8 *bssid = bss->mld_links[i].bssid; + + wpa_s->valid_links |= BIT(i); + os_memcpy(wpa_s->links[i].bssid, bssid, ETH_ALEN); + wpa_s->links[i].freq = bss->mld_links[i].freq; + wpa_s->links[i].disabled = bss->mld_links[i].disabled; + + if (bss->mld_link_id == i) + wpa_s->links[i].bss = bss; + else if (ssid && ssid->ssid_len) + wpa_s->links[i].bss = wpa_bss_get(wpa_s, bssid, + ssid->ssid, + ssid->ssid_len); + else + wpa_s->links[i].bss = wpa_bss_get_bssid(wpa_s, bssid); + } +} + static void sme_send_authentication(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid, @@ -600,11 +579,33 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, return; } + os_memset(¶ms, 0, sizeof(params)); + + if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) && + !wpa_bss_parse_basic_ml_element(wpa_s, bss, wpa_s->ap_mld_addr, + NULL, ssid, NULL) && + bss->valid_links) { + wpa_printf(MSG_DEBUG, "MLD: In authentication"); + wpas_sme_set_mlo_links(wpa_s, bss, ssid); + +#ifdef CONFIG_TESTING_OPTIONS + bss = wpas_ml_connect_pref(wpa_s, bss, ssid); + + if (wpa_s->conf->mld_force_single_link) { + wpa_printf(MSG_DEBUG, "MLD: Force single link"); + wpa_s->valid_links = BIT(wpa_s->mlo_assoc_link_id); + } +#endif /* CONFIG_TESTING_OPTIONS */ + params.mld = true; + params.mld_link_id = wpa_s->mlo_assoc_link_id; + params.ap_mld_addr = wpa_s->ap_mld_addr; + wpas_ml_handle_removed_links(wpa_s, bss); + } + skip_auth = wpa_s->conf->reassoc_same_bss_optim && wpa_s->reassoc_same_bss; wpa_s->current_bss = bss; - os_memset(¶ms, 0, sizeof(params)); wpa_s->reassociate = 0; params.freq = bss->freq; @@ -612,14 +613,6 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, params.ssid = bss->ssid; params.ssid_len = bss->ssid_len; params.p2p = ssid->p2p_group; -#ifdef CONFIG_MLD_PATCH - if (wpas_ml_element(wpa_s, bss)) { - wpa_printf(MSG_DEBUG, "MLD: In authentication"); - params.mld = true; - params.mld_link_id = wpa_s->mlo_assoc_link_id; - params.ap_mld_addr = wpa_s->ap_mld_addr; - } -#endif if (wpa_s->sme.ssid_len != params.ssid_len || os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0) @@ -665,8 +658,13 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #endif /* CONFIG_DPP */ } else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 && wpa_key_mgmt_sae(ied.key_mgmt)) { - wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg"); - params.auth_alg = WPA_AUTH_ALG_SAE; + if (wpas_is_sae_avoided(wpa_s, ssid, &ied)) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SAE enabled, but disallowing SAE auth_alg without PMF"); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg"); + params.auth_alg = WPA_AUTH_ALG_SAE; + } } else { wpa_dbg(wpa_s, MSG_DEBUG, "SAE enabled, but target BSS does not advertise SAE AKM for RSN"); @@ -701,19 +699,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (wpa_key_mgmt_fils(ssid->key_mgmt)) cache_id = wpa_bss_get_fils_cache_id(bss); #endif /* CONFIG_FILS */ - if (pmksa_cache_set_current(wpa_s->wpa, NULL, -#ifdef CONFIG_MLD_PATCH + if (pmksa_cache_set_current(wpa_s->wpa, NULL, params.mld ? params.ap_mld_addr : -#endif - bss->bssid, + bss->bssid, wpa_s->current_ssid, try_opportunistic, cache_id, - 0) == 0) + 0, false) == 0) eapol_sm_notify_pmkid_attempt(wpa_s->eapol); wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); if (wpa_supplicant_set_suites(wpa_s, bss, ssid, wpa_s->sme.assoc_req_ie, - &wpa_s->sme.assoc_req_ie_len)) { + &wpa_s->sme.assoc_req_ie_len, + false)) { wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA " "key management and encryption suites"); wpas_connect_work_done(wpa_s); @@ -726,7 +723,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); if (wpa_supplicant_set_suites(wpa_s, bss, ssid, wpa_s->sme.assoc_req_ie, - &wpa_s->sme.assoc_req_ie_len)) { + &wpa_s->sme.assoc_req_ie_len, + false)) { wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA " "key management and encryption suites"); wpas_connect_work_done(wpa_s); @@ -746,7 +744,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie); if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, wpa_s->sme.assoc_req_ie, - &wpa_s->sme.assoc_req_ie_len)) { + &wpa_s->sme.assoc_req_ie_len, + false)) { wpa_msg(wpa_s, MSG_WARNING, "SME: Failed to set WPA " "key management and encryption suites (no " "scan results)"); @@ -828,7 +827,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (wpa_s->sme.prev_bssid_set && wpa_s->sme.ft_used && os_memcmp(md, wpa_s->sme.mobility_domain, 2) == 0 && - wpa_sm_has_ptk(wpa_s->wpa)) { + wpa_sm_has_ft_keys(wpa_s->wpa, md)) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT " "over-the-air"); params.auth_alg = WPA_AUTH_ALG_FT; @@ -883,10 +882,12 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, sme_auth_handle_rrm(wpa_s, bss); +#ifndef CONFIG_NO_RRM wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie( wpa_s, ssid, bss, wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len); +#endif /* CONFIG_NO_RRM */ if (params.p2p) wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT); @@ -894,7 +895,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION); ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, - sizeof(ext_capab)); + sizeof(ext_capab), bss); if (ext_capab_len > 0) { u8 *pos = wpa_s->sme.assoc_req_ie; if (wpa_s->sme.assoc_req_ie_len > 0 && pos[0] == WLAN_EID_RSN) @@ -906,6 +907,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, os_memcpy(pos, ext_capab, ext_capab_len); } + if (ssid->max_idle && wpa_s->sme.assoc_req_ie_len + 5 <= + sizeof(wpa_s->sme.assoc_req_ie)) { + u8 *pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len; + + *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD; + *pos++ = 3; + WPA_PUT_LE16(pos, ssid->max_idle); + pos += 2; + *pos = 0; /* Idle Options */ + wpa_s->sme.assoc_req_ie_len += 5; + } + #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->rsnxe_override_assoc && wpabuf_len(wpa_s->rsnxe_override_assoc) <= @@ -1004,16 +1017,14 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #ifdef CONFIG_SAE if (!skip_auth && params.auth_alg == WPA_AUTH_ALG_SAE && - pmksa_cache_set_current(wpa_s->wpa, NULL, -#ifdef CONFIG_MLD_PATCH + pmksa_cache_set_current(wpa_s->wpa, NULL, params.mld ? params.ap_mld_addr : -#endif - bss->bssid, - ssid, 0, + bss->bssid, + ssid, 0, NULL, wpa_key_mgmt_sae(wpa_s->key_mgmt) ? wpa_s->key_mgmt : - (int) WPA_KEY_MGMT_SAE) == 0) { + (int) WPA_KEY_MGMT_SAE, false) == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication"); wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); @@ -1025,20 +1036,15 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, if (start) resp = sme_auth_build_sae_commit(wpa_s, ssid, bss->bssid, -#ifdef CONFIG_MLD_PATCH - params.mld ? params.ap_mld_addr : NULL, -#endif - 0, + params.mld ? + params.ap_mld_addr : + NULL, 0, start == 2, NULL, NULL); else resp = sme_auth_build_sae_confirm(wpa_s, 0); if (resp == NULL) { -#ifdef CONFIG_MLD_PATCH wpas_connection_failed(wpa_s, bss->bssid, NULL); -#else - wpas_connection_failed(wpa_s, bss->bssid); -#endif return; } params.auth_data = wpabuf_head(resp); @@ -1056,6 +1062,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); + wpa_sm_set_ssid(wpa_s->wpa, bss->ssid, bss->ssid_len); wpa_supplicant_initiate_eapol(wpa_s); #ifdef CONFIG_FILS @@ -1111,14 +1118,12 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, goto no_fils; } - if (pmksa_cache_set_current(wpa_s->wpa, NULL, -#ifdef CONFIG_MLD_PATCH + if (pmksa_cache_set_current(wpa_s->wpa, NULL, params.mld ? params.ap_mld_addr : -#endif - bss->bssid, + bss->bssid, ssid, 0, wpa_bss_get_fils_cache_id(bss), - 0) == 0) + 0, false) == 0) wpa_printf(MSG_DEBUG, "SME: Try to use FILS with PMKSA caching"); resp = fils_build_auth(wpa_s->wpa, ssid->fils_dh_group, md); @@ -1171,7 +1176,7 @@ no_fils: */ if (wpa_s->num_multichan_concurrent < 2) { int freq, num; - num = get_shared_radio_freqs(wpa_s, &freq, 1); + num = get_shared_radio_freqs(wpa_s, &freq, 1, false); if (num > 0 && freq > 0 && freq != params.freq) { wpa_printf(MSG_DEBUG, "Conflicting frequency found (%d != %d)", @@ -1179,11 +1184,7 @@ no_fils: if (wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq, ssid) < 0) { -#ifdef CONFIG_MLD_PATCH wpas_connection_failed(wpa_s, bss->bssid, NULL); -#else - wpas_connection_failed(wpa_s, bss->bssid); -#endif wpa_supplicant_mark_disassoc(wpa_s); wpabuf_free(resp); wpas_connect_work_done(wpa_s); @@ -1206,11 +1207,7 @@ no_fils: if (wpa_drv_authenticate(wpa_s, ¶ms) < 0) { wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the " "driver failed"); -#ifdef CONFIG_MLD_PATCH wpas_connection_failed(wpa_s, bss->bssid, NULL); -#else - wpas_connection_failed(wpa_s, bss->bssid); -#endif wpa_supplicant_mark_disassoc(wpa_s); wpabuf_free(resp); wpas_connect_work_done(wpa_s); @@ -1264,6 +1261,7 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit) wpa_s->rsnxe_len = 0; sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1); + wpas_notify_auth_changed(wpa_s); } @@ -1324,11 +1322,12 @@ void sme_authenticate(struct wpa_supplicant *wpa_s, #ifdef CONFIG_SAE -#ifdef CONFIG_MLD_PATCH + #define WPA_AUTH_FRAME_ML_IE_LEN (6 + ETH_ALEN) static void wpa_auth_ml_ie(struct wpabuf *buf, const u8 *mld_addr) { + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); wpabuf_put_u8(buf, 4 + ETH_ALEN); wpabuf_put_u8(buf, WLAN_EID_EXT_MULTI_LINK); @@ -1341,17 +1340,13 @@ static void wpa_auth_ml_ie(struct wpabuf *buf, const u8 *mld_addr) wpabuf_put_u8(buf, 0x7); /* length = Length field + MLD MAC address */ wpabuf_put_data(buf, mld_addr, ETH_ALEN); } -#endif + static int sme_external_auth_build_buf(struct wpabuf *buf, struct wpabuf *params, const u8 *sa, const u8 *da, u16 auth_transaction, u16 seq_num, - u16 status_code -#ifdef CONFIG_MLD_PATCH - , const u8 *mld_addr -#endif - ) + u16 status_code, const u8 *mld_addr) { struct ieee80211_mgmt *resp; @@ -1369,10 +1364,10 @@ static int sme_external_auth_build_buf(struct wpabuf *buf, resp->u.auth.status_code = host_to_le16(status_code); if (params) wpabuf_put_buf(buf, params); -#ifdef CONFIG_MLD_PATCH + if (mld_addr) wpa_auth_ml_ie(buf, mld_addr); -#endif + return 0; } @@ -1387,23 +1382,18 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, u16 status; resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, -#ifdef CONFIG_MLD_PATCH wpa_s->sme.ext_ml_auth ? wpa_s->sme.ext_auth_ap_mld_addr : NULL, -#endif - 1, 0, &use_pt, - &use_pk); + 1, 0, &use_pt, &use_pk); if (!resp) { wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit"); return -1; } wpa_s->sme.sae.state = SAE_COMMITTED; - buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp) -#ifdef CONFIG_MLD_PATCH - + (wpa_s->sme.ext_ml_auth ? WPA_AUTH_FRAME_ML_IE_LEN : 0) -#endif - ); + buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + wpabuf_len(resp) + + (wpa_s->sme.ext_ml_auth ? WPA_AUTH_FRAME_ML_IE_LEN : + 0)); if (!buf) { wpabuf_free(resp); return -1; @@ -1416,16 +1406,12 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, status = WLAN_STATUS_SAE_HASH_TO_ELEMENT; else status = WLAN_STATUS_SUCCESS; -#ifdef CONFIG_MLD_PATCH sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, - bssid, 1, + wpa_s->sme.ext_ml_auth ? + wpa_s->sme.ext_auth_ap_mld_addr : bssid, 1, wpa_s->sme.seq_num, status, wpa_s->sme.ext_ml_auth ? wpa_s->own_addr : NULL); -#else - sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, - bssid, 1, wpa_s->sme.seq_num, status); -#endif wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0); wpabuf_free(resp); wpabuf_free(buf); @@ -1439,6 +1425,7 @@ static void sme_send_external_auth_status(struct wpa_supplicant *wpa_s, { struct external_auth params; + wpa_s->sme.ext_auth_wpa_ssid = NULL; os_memset(¶ms, 0, sizeof(params)); params.status = status; params.ssid = wpa_s->sme.ext_auth_ssid; @@ -1457,13 +1444,18 @@ static int sme_handle_external_auth_start(struct wpa_supplicant *wpa_s, size_t ssid_str_len = data->external_auth.ssid_len; const u8 *ssid_str = data->external_auth.ssid; + wpa_s->sme.ext_auth_wpa_ssid = NULL; /* Get the SSID conf from the ssid string obtained */ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (!wpas_network_disabled(wpa_s, ssid) && ssid_str_len == ssid->ssid_len && os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0 && - wpa_key_mgmt_sae(ssid->key_mgmt)) + wpa_key_mgmt_sae(ssid->key_mgmt)) { + /* Make sure PT is derived */ + wpa_s_setup_sae_pt(wpa_s->conf, ssid, false); + wpa_s->sme.ext_auth_wpa_ssid = ssid; break; + } } if (!ssid || sme_external_auth_send_sae_commit(wpa_s, data->external_auth.bssid, @@ -1486,34 +1478,27 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s, } wpa_s->sme.sae.state = SAE_CONFIRMED; - buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp) -#ifdef CONFIG_MLD_PATCH - + (wpa_s->sme.ext_ml_auth ? WPA_AUTH_FRAME_ML_IE_LEN : 0) -#endif - ); + buf = wpabuf_alloc(4 + SAE_CONFIRM_MAX_LEN + wpabuf_len(resp) + + (wpa_s->sme.ext_ml_auth ? WPA_AUTH_FRAME_ML_IE_LEN : + 0)); if (!buf) { wpa_printf(MSG_DEBUG, "SAE: Auth Confirm buf alloc failure"); wpabuf_free(resp); return; } wpa_s->sme.seq_num++; -#ifdef CONFIG_MLD_PATCH sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, da, 2, wpa_s->sme.seq_num, WLAN_STATUS_SUCCESS, wpa_s->sme.ext_ml_auth ? wpa_s->own_addr : NULL); -#else - sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, - da, 2, wpa_s->sme.seq_num, - WLAN_STATUS_SUCCESS); -#endif + wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0); wpabuf_free(resp); wpabuf_free(buf); } -#ifdef CONFIG_MLD_PATCH + static bool is_sae_key_mgmt_suite(struct wpa_supplicant *wpa_s, u32 suite) { /* suite is supposed to be the selector value in host byte order with @@ -1549,16 +1534,12 @@ static bool is_sae_key_mgmt_suite(struct wpa_supplicant *wpa_s, u32 suite) return true; } -#endif + + void sme_external_auth_trigger(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { -#ifdef CONFIG_MLD_PATCH if (!is_sae_key_mgmt_suite(wpa_s, data->external_auth.key_mgmt_suite)) -#else - if (RSN_SELECTOR_GET(&data->external_auth.key_mgmt_suite) != - RSN_AUTH_KEY_MGMT_SAE) -#endif return; if (data->external_auth.action == EXT_AUTH_START) { @@ -1569,7 +1550,6 @@ void sme_external_auth_trigger(struct wpa_supplicant *wpa_s, os_memcpy(wpa_s->sme.ext_auth_ssid, data->external_auth.ssid, data->external_auth.ssid_len); wpa_s->sme.ext_auth_ssid_len = data->external_auth.ssid_len; -#ifdef CONFIG_MLD_PATCH if (data->external_auth.mld_addr) { wpa_s->sme.ext_ml_auth = true; os_memcpy(wpa_s->sme.ext_auth_ap_mld_addr, @@ -1577,7 +1557,6 @@ void sme_external_auth_trigger(struct wpa_supplicant *wpa_s, } else { wpa_s->sme.ext_ml_auth = false; } -#endif wpa_s->sme.seq_num = 0; wpa_s->sme.sae.state = SAE_NOTHING; wpa_s->sme.sae.send_confirm = 0; @@ -1614,14 +1593,21 @@ static int sme_sae_is_group_enabled(struct wpa_supplicant *wpa_s, int group) static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s, const struct wpabuf *groups) { - size_t i, count; + size_t i, count, len; const u8 *pos; if (!groups) return 0; pos = wpabuf_head(groups); - count = wpabuf_len(groups) / 2; + len = wpabuf_len(groups); + if (len & 1) { + wpa_printf(MSG_DEBUG, + "SAE: Invalid length of the Rejected Groups element payload: %zu", + len); + return 1; + } + count = len / 2; for (i = 0; i < count; i++) { int enabled; u16 group; @@ -1638,7 +1624,7 @@ static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s, return 0; } -#ifdef CONFIG_MLD_PATCH + static int sme_external_ml_auth(struct wpa_supplicant *wpa_s, const u8 *data, size_t len, int ie_offset, u16 status_code) @@ -1672,23 +1658,20 @@ static int sme_external_ml_auth(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "MLD: mld_address=" MACSTR_SEC, MAC2STR_SEC(mld_addr)); - if (os_memcmp(wpa_s->sme.ext_auth_ap_mld_addr, mld_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(wpa_s->sme.ext_auth_ap_mld_addr, mld_addr)) { wpa_printf(MSG_DEBUG, "MLD: Unexpected MLD address (expected " - MACSTR ")", MAC2STR(wpa_s->sme.ext_auth_ap_mld_addr)); + MACSTR ")", + MAC2STR(wpa_s->sme.ext_auth_ap_mld_addr)); return -1; } return 0; } -#endif + static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, u16 status_code, const u8 *data, size_t len, - int external, const u8 *sa -#ifdef CONFIG_MLD_PATCH - , int *ie_offset -#endif - ) + int external, const u8 *sa, int *ie_offset) { int *groups; @@ -1698,7 +1681,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, if (auth_transaction == 1 && status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ && wpa_s->sme.sae.state == SAE_COMMITTED && - (external || wpa_s->current_bss) && wpa_s->current_ssid) { + ((external && wpa_s->sme.ext_auth_wpa_ssid) || + (!external && wpa_s->current_bss && wpa_s->current_ssid))) { int default_groups[] = { 19, 20, 21, 0 }; u16 group; const u8 *token_pos; @@ -1751,25 +1735,30 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, } token_len = elen - 1; } -#ifdef CONFIG_MLD_PATCH + *ie_offset = token_pos + token_len - data; -#endif + wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len); + if (!wpa_s->sme.sae_token) { + wpa_dbg(wpa_s, MSG_ERROR, + "SME: Failed to allocate SAE token"); + return -1; + } + wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token", wpa_s->sme.sae_token); if (!external) { sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 2); } else { -#ifdef CONFIG_MLD_PATCH if (wpa_s->sme.ext_ml_auth && sme_external_ml_auth(wpa_s, data, len, *ie_offset, status_code)) return -1; -#endif + sme_external_auth_send_sae_commit( wpa_s, wpa_s->sme.ext_auth_bssid, - wpa_s->current_ssid); + wpa_s->sme.ext_auth_wpa_ssid); } return 0; } @@ -1777,31 +1766,27 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, if (auth_transaction == 1 && status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED && wpa_s->sme.sae.state == SAE_COMMITTED && - (external || wpa_s->current_bss) && wpa_s->current_ssid) { + ((external && wpa_s->sme.ext_auth_wpa_ssid) || + (!external && wpa_s->current_bss && wpa_s->current_ssid))) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported"); int_array_add_unique(&wpa_s->sme.sae_rejected_groups, wpa_s->sme.sae.group); wpa_s->sme.sae_group_index++; -#ifdef CONFIG_MLD_PATCH if (sme_set_sae_group(wpa_s, external) < 0) -#else - if (sme_set_sae_group(wpa_s) < 0) -#endif return -1; /* no other groups enabled */ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group"); if (!external) { sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 1); } else { -#ifdef CONFIG_MLD_PATCH if (wpa_s->sme.ext_ml_auth && sme_external_ml_auth(wpa_s, data, len, *ie_offset, status_code)) return -1; -#endif + sme_external_auth_send_sae_commit( wpa_s, wpa_s->sme.ext_auth_bssid, - wpa_s->current_ssid); + wpa_s->sme.ext_auth_wpa_ssid); } return 0; } @@ -1832,7 +1817,7 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, " auth_type=%u auth_transaction=%u status_code=%u", MAC2STR(bssid), WLAN_AUTH_SAE, auth_transaction, status_code); - return -1; + return -2; } if (auth_transaction == 1) { @@ -1841,8 +1826,9 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, groups = wpa_s->conf->sae_groups; wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit"); - if ((!external && wpa_s->current_bss == NULL) || - wpa_s->current_ssid == NULL) + if ((external && !wpa_s->sme.ext_auth_wpa_ssid) || + (!external && + (!wpa_s->current_bss || !wpa_s->current_ssid))) return -1; if (wpa_s->sme.sae.state != SAE_COMMITTED) { wpa_printf(MSG_DEBUG, @@ -1872,11 +1858,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL, groups, status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT || - status_code == WLAN_STATUS_SAE_PK -#ifdef CONFIG_MLD_PATCH - , ie_offset -#endif - ); + status_code == WLAN_STATUS_SAE_PK, + ie_offset); if (res == SAE_SILENTLY_DISCARD) { wpa_printf(MSG_DEBUG, "SAE: Drop commit message due to reflection attack"); @@ -1903,11 +1886,11 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 0); } else { -#ifdef CONFIG_MLD_PATCH if (wpa_s->sme.ext_ml_auth && sme_external_ml_auth(wpa_s, data, len, *ie_offset, status_code)) return -1; +#ifdef CONFIG_MLD_PATCH sme_external_auth_send_sae_confirm(wpa_s, wpa_s->sme.ext_auth_bssid); #else sme_external_auth_send_sae_confirm(wpa_s, sa); @@ -1920,20 +1903,17 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm"); if (wpa_s->sme.sae.state != SAE_CONFIRMED) return -1; - if (sae_check_confirm(&wpa_s->sme.sae, data, len -#ifdef CONFIG_MLD_PATCH - , ie_offset -#endif - ) < 0) + if (sae_check_confirm(&wpa_s->sme.sae, data, len, + ie_offset) < 0) return -1; -#ifdef CONFIG_MLD_PATCH if (external && wpa_s->sme.ext_ml_auth && sme_external_ml_auth(wpa_s, data, len, *ie_offset, status_code)) return -1; -#endif + wpa_s->sme.sae.state = SAE_ACCEPTED; sae_clear_temp_data(&wpa_s->sme.sae); + wpa_s_clear_sae_rejected(wpa_s); if (external) { /* Report success to driver */ @@ -1967,7 +1947,7 @@ static int sme_sae_set_pmk(struct wpa_supplicant *wpa_s, const u8 *bssid) } if (wpa_insert_pmkid(wpa_s->sme.assoc_req_ie, &wpa_s->sme.assoc_req_ie_len, - wpa_s->sme.sae.pmkid) < 0) + wpa_s->sme.sae.pmkid, true) < 0) return -1; wpa_hexdump(MSG_DEBUG, "SME: Updated Association Request IEs", @@ -1997,35 +1977,29 @@ void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, if (le_to_host16(header->u.auth.auth_alg) == WLAN_AUTH_SAE) { int res; -#ifdef CONFIG_MLD_PATCH int ie_offset = 0; -#endif + res = sme_sae_auth( wpa_s, le_to_host16(header->u.auth.auth_transaction), le_to_host16(header->u.auth.status_code), header->u.auth.variable, - len - auth_length, 1, header->sa -#ifdef CONFIG_MLD_PATCH - , &ie_offset -#endif - ); + len - auth_length, 1, header->sa, &ie_offset); if (res < 0) { /* Notify failure to the driver */ sme_send_external_auth_status( - wpa_s, WLAN_STATUS_UNSPECIFIED_FAILURE); + wpa_s, + res == -2 ? + le_to_host16(header->u.auth.status_code) : + WLAN_STATUS_UNSPECIFIED_FAILURE); return; } if (res != 1) return; -#ifdef CONFIG_MLD_PATCH if (sme_sae_set_pmk(wpa_s, wpa_s->sme.ext_ml_auth ? wpa_s->sme.ext_auth_ap_mld_addr : wpa_s->sme.ext_auth_bssid) < 0) -#else - if (sme_sae_set_pmk(wpa_s, wpa_s->sme.ext_auth_bssid) < 0) -#endif return; } } @@ -2036,9 +2010,8 @@ void sme_external_auth_mgmt_rx(struct wpa_supplicant *wpa_s, void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { struct wpa_ssid *ssid = wpa_s->current_ssid; -#ifdef CONFIG_MLD_PATCH int ie_offset = 0; -#endif + if (ssid == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Ignore authentication event " "when network is not selected"); @@ -2051,11 +2024,9 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) return; } - if (os_memcmp(wpa_s->pending_bssid, data->auth.peer, ETH_ALEN) != 0 -#ifdef CONFIG_MLD_PATCH - && !(wpa_s->valid_links && os_memcmp(wpa_s->ap_mld_addr, data->auth.peer, ETH_ALEN) == 0) -#endif - ) { + if (!ether_addr_equal(wpa_s->pending_bssid, data->auth.peer) && + !(wpa_s->valid_links && + ether_addr_equal(wpa_s->ap_mld_addr, data->auth.peer))) { wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, "SME: Ignore authentication with " "unexpected peer " MACSTR, MAC2STR(data->auth.peer)); @@ -2082,28 +2053,29 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) if (data->auth.auth_type == WLAN_AUTH_SAE) { const u8 *addr = wpa_s->pending_bssid; int res; + res = sme_sae_auth(wpa_s, data->auth.auth_transaction, data->auth.status_code, data->auth.ies, - data->auth.ies_len, 0, data->auth.peer -#ifdef CONFIG_MLD_PATCH - , &ie_offset -#endif - ); + data->auth.ies_len, 0, data->auth.peer, + &ie_offset); if (res < 0) { -#ifdef CONFIG_MLD_PATCH - wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL); -#else - wpas_connection_failed(wpa_s, wpa_s->pending_bssid); -#endif + wpas_connection_failed(wpa_s, wpa_s->pending_bssid, + NULL); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); + if (wpa_s->sme.sae_rejected_groups && + ssid->disabled_until.sec) { + wpa_printf(MSG_DEBUG, + "SME: Clear SAE state with rejected groups due to continuous failures"); + wpa_s_clear_sae_rejected(wpa_s); + } } if (res != 1) return; -#ifdef CONFIG_MLD_PATCH + if (wpa_s->valid_links) addr = wpa_s->ap_mld_addr; -#endif + if (sme_sae_set_pmk(wpa_s, addr) < 0) return; } @@ -2138,11 +2110,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG || wpa_s->sme.auth_alg == data->auth.auth_type || wpa_s->current_ssid->auth_alg == WPA_AUTH_ALG_LEAP) { -#ifdef CONFIG_MLD_PATCH - wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL); -#else - wpas_connection_failed(wpa_s, wpa_s->pending_bssid); -#endif + wpas_connection_failed(wpa_s, wpa_s->pending_bssid, + NULL); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); return; } @@ -2191,19 +2160,16 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) " reason=%d locally_generated=1", MAC2STR(wpa_s->pending_bssid), WLAN_REASON_DEAUTH_LEAVING); - #ifdef CONFIG_LIBWPA_VENDOR +#ifdef CONFIG_LIBWPA_VENDOR struct WpaDisconnectParam wpaDisconnectParma; os_memcpy(wpaDisconnectParma.bssid, wpa_s->pending_bssid, ETH_ALEN); wpaDisconnectParma.locallyGenerated = 1; wpaDisconnectParma.reasonCode = WLAN_REASON_DEAUTH_LEAVING; wpa_printf(MSG_DEBUG, "%s wpaDisconnectParmabssid[0]=%x", __func__, wpaDisconnectParma.bssid[0]); WpaEventReport(wpa_s->ifname, WPA_EVENT_DISCONNECT, (void *) &wpaDisconnectParma); - #endif -#ifdef CONFIG_MLD_PATCH - wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL); -#else - wpas_connection_failed(wpa_s, wpa_s->pending_bssid); #endif + wpas_connection_failed(wpa_s, wpa_s->pending_bssid, + NULL); wpa_supplicant_mark_disassoc(wpa_s); return; } @@ -2227,19 +2193,16 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) " reason=%d locally_generated=1", MAC2STR(wpa_s->pending_bssid), WLAN_REASON_DEAUTH_LEAVING); - #ifdef CONFIG_LIBWPA_VENDOR +#ifdef CONFIG_LIBWPA_VENDOR struct WpaDisconnectParam wpaDisconnectParma; os_memcpy(wpaDisconnectParma.bssid, wpa_s->pending_bssid, ETH_ALEN); wpaDisconnectParma.locallyGenerated = 1; wpaDisconnectParma.reasonCode = WLAN_REASON_DEAUTH_LEAVING; wpa_printf(MSG_DEBUG, "%s wpaDisconnectParmabssid[0]=%x", __func__, wpaDisconnectParma.bssid[0]); WpaEventReport(wpa_s->ifname, WPA_EVENT_DISCONNECT, (void *) &wpaDisconnectParma); - #endif -#ifdef CONFIG_MLD_PATCH - wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL); -#else - wpas_connection_failed(wpa_s, wpa_s->pending_bssid); #endif + wpas_connection_failed(wpa_s, wpa_s->pending_bssid, + NULL); wpa_supplicant_mark_disassoc(wpa_s); return; } @@ -2253,26 +2216,22 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) " reason=%d locally_generated=1", MAC2STR(wpa_s->pending_bssid), WLAN_REASON_DEAUTH_LEAVING); - #ifdef CONFIG_LIBWPA_VENDOR +#ifdef CONFIG_LIBWPA_VENDOR struct WpaDisconnectParam wpaDisconnectParma; os_memcpy(wpaDisconnectParma.bssid, wpa_s->pending_bssid, ETH_ALEN); wpaDisconnectParma.locallyGenerated = 1; wpaDisconnectParma.reasonCode = WLAN_REASON_DEAUTH_LEAVING; wpa_printf(MSG_DEBUG, "%s wpaDisconnectParmabssid[0]=%x", __func__, wpaDisconnectParma.bssid[0]); WpaEventReport(wpa_s->ifname, WPA_EVENT_DISCONNECT, (void *) &wpaDisconnectParma); - #endif - -#ifdef CONFIG_MLD_PATCH - wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL); -#else - wpas_connection_failed(wpa_s, wpa_s->pending_bssid); #endif + wpas_connection_failed(wpa_s, wpa_s->pending_bssid, + NULL); wpa_supplicant_mark_disassoc(wpa_s); return; } } #endif /* CONFIG_FILS */ -#ifdef CONFIG_MLD_PATCH + /* TODO: Support additional auth_type values as well */ if ((data->auth.auth_type == WLAN_AUTH_OPEN || data->auth.auth_type == WLAN_AUTH_SAE) && @@ -2291,7 +2250,7 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data) wpas_reset_mlo_info(wpa_s); return; } -#endif + sme_associate(wpa_s, ssid->mode, data->auth.peer, data->auth.auth_type); } @@ -2333,6 +2292,9 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, os_memset(¶ms, 0, sizeof(params)); + /* Save auth type, in case we need to retry after comeback timer. */ + wpa_s->sme.assoc_auth_type = auth_type; + #ifdef CONFIG_FILS if (auth_type == WLAN_AUTH_FILS_SK || auth_type == WLAN_AUTH_FILS_SK_PFS) { @@ -2499,6 +2461,7 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, pfs_fail: #endif /* CONFIG_DPP2 */ +#ifndef CONFIG_NO_ROBUST_AV 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) { @@ -2532,15 +2495,20 @@ pfs_fail: wpabuf_free(mscs_ie); } mscs_fail: +#endif /* CONFIG_NO_ROBUST_AV */ if (ssid && ssid->multi_ap_backhaul_sta) { size_t multi_ap_ie_len; + struct multi_ap_params multi_ap = { 0 }; + + multi_ap.capability = MULTI_AP_BACKHAUL_STA; + multi_ap.profile = ssid->multi_ap_profile; multi_ap_ie_len = add_multi_ap_ie( wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len, - MULTI_AP_BACKHAUL_STA); + &multi_ap); if (multi_ap_ie_len == 0) { wpa_printf(MSG_ERROR, "Multi-AP: Failed to build Multi-AP IE"); @@ -2581,6 +2549,7 @@ mscs_fail: #ifdef CONFIG_HE_OVERRIDES wpa_supplicant_apply_he_overrides(wpa_s, ssid, ¶ms); #endif /* CONFIG_HE_OVERRIDES */ + wpa_supplicant_apply_eht_overrides(wpa_s, ssid, ¶ms); #ifdef CONFIG_IEEE80211R if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies && get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len, @@ -2713,16 +2682,63 @@ mscs_fail: else params.uapsd = -1; + if (wpa_s->valid_links) { + unsigned int i; + + wpa_printf(MSG_DEBUG, + "MLD: In association. assoc_link_id=%u, valid_links=0x%x", + wpa_s->mlo_assoc_link_id, wpa_s->valid_links); + + params.mld_params.mld_addr = wpa_s->ap_mld_addr; + params.mld_params.valid_links = wpa_s->valid_links; + params.mld_params.assoc_link_id = wpa_s->mlo_assoc_link_id; + for_each_link(wpa_s->valid_links, i) { + params.mld_params.mld_links[i].bssid = + wpa_s->links[i].bssid; + params.mld_params.mld_links[i].freq = + wpa_s->links[i].freq; + params.mld_params.mld_links[i].disabled = + wpa_s->links[i].disabled; + + wpa_printf(MSG_DEBUG, + "MLD: id=%u, freq=%d, disabled=%u, " MACSTR, + i, wpa_s->links[i].freq, + wpa_s->links[i].disabled, + MAC2STR(wpa_s->links[i].bssid)); + } + } + if (wpa_drv_associate(wpa_s, ¶ms) < 0) { + unsigned int n_failed_links = 0; + int i; + wpa_msg(wpa_s, MSG_INFO, "SME: Association request to the " "driver failed"); -#ifdef CONFIG_MLD_PATCH - wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL); -#else - wpas_connection_failed(wpa_s, wpa_s->pending_bssid); -#endif - wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); - os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); + + /* Prepare list of failed links for error report */ + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + if (!(wpa_s->valid_links & BIT(i)) || + wpa_s->mlo_assoc_link_id == i || + !params.mld_params.mld_links[i].error) + continue; + + wpa_bssid_ignore_add(wpa_s, wpa_s->links[i].bssid); + n_failed_links++; + } + + if (n_failed_links) { + /* Deauth and connect (possibly to the same AP MLD) */ + wpa_drv_deauthenticate(wpa_s, wpa_s->ap_mld_addr, + WLAN_REASON_DEAUTH_LEAVING); + wpas_connect_work_done(wpa_s); + wpa_supplicant_mark_disassoc(wpa_s); + wpas_request_connection(wpa_s); + } else { + wpas_connection_failed(wpa_s, wpa_s->pending_bssid, + NULL); + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); + os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); + } return; } @@ -2762,23 +2778,26 @@ int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, } -static void sme_deauth(struct wpa_supplicant *wpa_s) +static void sme_deauth(struct wpa_supplicant *wpa_s, const u8 **link_bssids) { int bssid_changed; + const u8 *bssid; bssid_changed = !is_zero_ether_addr(wpa_s->bssid); - if (wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid, + if (wpa_s->valid_links) + bssid = wpa_s->ap_mld_addr; + else + bssid = wpa_s->pending_bssid; + + if (wpa_drv_deauthenticate(wpa_s, bssid, WLAN_REASON_DEAUTH_LEAVING) < 0) { wpa_msg(wpa_s, MSG_INFO, "SME: Deauth request to the driver " "failed"); } wpa_s->sme.prev_bssid_set = 0; -#ifdef CONFIG_MLD_PATCH - wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL); -#else - wpas_connection_failed(wpa_s, wpa_s->pending_bssid); -#endif + + wpas_connection_failed(wpa_s, wpa_s->pending_bssid, link_bssids); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); os_memset(wpa_s->bssid, 0, ETH_ALEN); os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); @@ -2787,9 +2806,94 @@ static void sme_deauth(struct wpa_supplicant *wpa_s) } +static void sme_assoc_comeback_timer(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + if (!wpa_s->current_bss || !wpa_s->current_ssid) { + wpa_msg(wpa_s, MSG_DEBUG, + "SME: Comeback timeout expired; SSID/BSSID cleared; ignoring"); + return; + } + + wpa_msg(wpa_s, MSG_DEBUG, + "SME: Comeback timeout expired; retry associating with " + MACSTR "; mode=%d auth_type=%u", + MAC2STR(wpa_s->current_bss->bssid), + wpa_s->current_ssid->mode, + wpa_s->sme.assoc_auth_type); + + /* Authentication state was completed already; just try association + * again. */ + sme_associate(wpa_s, wpa_s->current_ssid->mode, + wpa_s->current_bss->bssid, + wpa_s->sme.assoc_auth_type); +} + + +static bool sme_try_assoc_comeback(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) +{ + struct ieee802_11_elems elems; + u32 timeout_interval; + unsigned long comeback_usec; + u8 type = WLAN_TIMEOUT_ASSOC_COMEBACK; + +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->test_assoc_comeback_type != -1) + type = wpa_s->test_assoc_comeback_type; +#endif /* CONFIG_TESTING_OPTIONS */ + + if (ieee802_11_parse_elems(data->assoc_reject.resp_ies, + data->assoc_reject.resp_ies_len, + &elems, 0) == ParseFailed) { + wpa_msg(wpa_s, MSG_INFO, + "SME: Temporary assoc reject: failed to parse (Re)Association Response frame elements"); + return false; + } + + if (!elems.timeout_int) { + wpa_msg(wpa_s, MSG_INFO, + "SME: Temporary assoc reject: missing timeout interval IE"); + return false; + } + + if (elems.timeout_int[0] != type) { + wpa_msg(wpa_s, MSG_INFO, + "SME: Temporary assoc reject: missing association comeback time"); + return false; + } + + timeout_interval = WPA_GET_LE32(&elems.timeout_int[1]); + if (timeout_interval > 60000) { + /* This is unprotected information and there is no point in + * getting stuck waiting for very long duration based on it */ + wpa_msg(wpa_s, MSG_DEBUG, + "SME: Ignore overly long association comeback interval: %u TUs", + timeout_interval); + return false; + } + wpa_msg(wpa_s, MSG_DEBUG, "SME: Association comeback interval: %u TUs", + timeout_interval); + + comeback_usec = timeout_interval * 1024; + eloop_register_timeout(comeback_usec / 1000000, comeback_usec % 1000000, + sme_assoc_comeback_timer, wpa_s, NULL); + return true; +} + + void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, - union wpa_event_data *data) + union wpa_event_data *data, + const u8 **link_bssids) { + const u8 *bssid; + + if (wpa_s->valid_links) + bssid = wpa_s->ap_mld_addr; + else + bssid = wpa_s->pending_bssid; + wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, "SME: Association with " MACSTR " failed: " "status code %d", MAC2STR(wpa_s->pending_bssid), data->assoc_reject.status_code); @@ -2798,6 +2902,22 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, data->assoc_reject.status_code); eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL); + eloop_cancel_timeout(sme_assoc_comeback_timer, wpa_s, NULL); + + /* Authentication phase has been completed at this point. Check whether + * the AP rejected association temporarily due to still holding a + * security associationis with us (MFP). If so, we must wait for the + * AP's association comeback timeout period before associating again. */ + if (data->assoc_reject.status_code == + WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) { + wpa_msg(wpa_s, MSG_DEBUG, + "SME: Temporary association reject from BSS " MACSTR, + MAC2STR(bssid)); + if (sme_try_assoc_comeback(wpa_s, data)) { + /* Break out early; comeback error is not a failure. */ + return; + } + } #ifdef CONFIG_SAE if (wpa_s->sme.sae_pmksa_caching && wpa_s->current_ssid && @@ -2810,7 +2930,7 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, struct wpa_bss *bss = wpa_s->current_bss; struct wpa_ssid *ssid = wpa_s->current_ssid; - wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid, + wpa_drv_deauthenticate(wpa_s, bssid, WLAN_REASON_DEAUTH_LEAVING); wpas_connect_work_done(wpa_s); wpa_supplicant_mark_disassoc(wpa_s); @@ -2820,6 +2940,34 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_SAE */ +#ifdef CONFIG_DPP + if (wpa_s->current_ssid && + wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP && + !data->assoc_reject.timed_out && + data->assoc_reject.status_code == WLAN_STATUS_INVALID_PMKID) { + struct rsn_pmksa_cache_entry *pmksa; + + pmksa = pmksa_cache_get_current(wpa_s->wpa); + if (pmksa) { + wpa_dbg(wpa_s, MSG_DEBUG, + "DPP: Drop PMKSA cache entry for the BSS due to invalid PMKID report"); + wpa_sm_pmksa_cache_remove(wpa_s->wpa, pmksa); + } + wpa_sm_aborted_cached(wpa_s->wpa); + if (wpa_s->current_bss) { + struct wpa_bss *bss = wpa_s->current_bss; + struct wpa_ssid *ssid = wpa_s->current_ssid; + + wpa_dbg(wpa_s, MSG_DEBUG, + "DPP: Try network introduction again"); + wpas_connect_work_done(wpa_s); + wpa_supplicant_mark_disassoc(wpa_s); + wpa_supplicant_connect(wpa_s, bss, ssid); + return; + } + } +#endif /* CONFIG_DPP */ + /* * For now, unconditionally terminate the previous authentication. In * theory, this should not be needed, but mac80211 gets quite confused @@ -2827,7 +2975,7 @@ void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, * benefit from using the previous authentication, so this could be * optimized in the future. */ - sme_deauth(wpa_s); + sme_deauth(wpa_s, link_bssids); } @@ -2835,11 +2983,7 @@ void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication timed out"); -#ifdef CONFIG_MLD_PATCH wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL); -#else - wpas_connection_failed(wpa_s, wpa_s->pending_bssid); -#endif wpa_supplicant_mark_disassoc(wpa_s); } @@ -2848,11 +2992,7 @@ void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Association timed out"); -#ifdef CONFIG_MLD_PATCH wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL); -#else - wpas_connection_failed(wpa_s, wpa_s->pending_bssid); -#endif wpa_supplicant_mark_disassoc(wpa_s); } @@ -2881,7 +3021,7 @@ static void sme_auth_timer(void *eloop_ctx, void *timeout_ctx) struct wpa_supplicant *wpa_s = eloop_ctx; if (wpa_s->wpa_state == WPA_AUTHENTICATING) { wpa_msg(wpa_s, MSG_DEBUG, "SME: Authentication timeout"); - sme_deauth(wpa_s); + sme_deauth(wpa_s, NULL); } } @@ -2891,7 +3031,7 @@ static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx) struct wpa_supplicant *wpa_s = eloop_ctx; if (wpa_s->wpa_state == WPA_ASSOCIATING) { wpa_msg(wpa_s, MSG_DEBUG, "SME: Association timeout"); - sme_deauth(wpa_s); + sme_deauth(wpa_s, NULL); } } @@ -2899,35 +3039,15 @@ static void sme_assoc_timer(void *eloop_ctx, void *timeout_ctx) void sme_state_changed(struct wpa_supplicant *wpa_s) { /* Make sure timers are cleaned up appropriately. */ - if (wpa_s->wpa_state != WPA_ASSOCIATING) + if (wpa_s->wpa_state != WPA_ASSOCIATING) { eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL); + eloop_cancel_timeout(sme_assoc_comeback_timer, wpa_s, NULL); + } if (wpa_s->wpa_state != WPA_AUTHENTICATING) eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL); } -void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s, - const u8 *prev_pending_bssid) -{ - /* - * mac80211-workaround to force deauth on failed auth cmd, - * requires us to remain in authenticating state to allow the - * second authentication attempt to be continued properly. - */ - wpa_dbg(wpa_s, MSG_DEBUG, "SME: Allow pending authentication " - "to proceed after disconnection event"); - wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING); - os_memcpy(wpa_s->pending_bssid, prev_pending_bssid, ETH_ALEN); - - /* - * Re-arm authentication timer in case auth fails for whatever reason. - */ - eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL); - eloop_register_timeout(SME_AUTH_TIMEOUT, 0, sme_auth_timer, wpa_s, - NULL); -} - - void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s) { wpa_s->sme.prev_bssid_set = 0; @@ -2955,6 +3075,7 @@ void sme_deinit(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL); eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL); eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL); + eloop_cancel_timeout(sme_assoc_comeback_timer, wpa_s, NULL); } @@ -3162,7 +3283,7 @@ static void sme_obss_scan_timeout(void *eloop_ctx, void *timeout_ctx) params.low_priority = 1; wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan"); - if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) + if (wpa_supplicant_trigger_scan(wpa_s, ¶ms, true, false)) wpa_printf(MSG_DEBUG, "SME OBSS: Failed to trigger scan"); else wpa_s->sme.sched_obss_scan = 1; @@ -3390,7 +3511,7 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa, ssid = wpa_s->current_ssid; if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) return; - if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) + if (!ether_addr_equal(sa, wpa_s->bssid)) return; if (reason_code != WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA && reason_code != WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA) @@ -3499,7 +3620,7 @@ static void sme_process_sa_query_response(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "SME: Received SA Query response from " MACSTR_SEC " (trans_id %02x%02x)", MAC2STR_SEC(sa), data[1], data[2]); - if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) + if (!ether_addr_equal(sa, wpa_s->bssid)) return; for (i = 0; i < wpa_s->sme.sa_query_count; i++) { diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/sme.h b/wpa_supplicant-2.9_standard/wpa_supplicant/sme.h index c797d2e9e796eac5050c96f0ebf60334121ba250..f8fd06b95f5a38d5dc5e1c40fb1d586add1bef07 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/sme.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/sme.h @@ -19,7 +19,8 @@ void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data); int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, const u8 *ies, size_t ies_len); void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, - union wpa_event_data *data); + union wpa_event_data *data, + const u8 **link_bssids); void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s, union wpa_event_data *data); void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s, @@ -32,8 +33,6 @@ void sme_event_ch_switch(struct wpa_supplicant *wpa_s); void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *da, const u8 *sa, const u8 *data, size_t len); void sme_state_changed(struct wpa_supplicant *wpa_s); -void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s, - const u8 *prev_pending_bssid); void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s); void sme_deinit(struct wpa_supplicant *wpa_s); @@ -65,7 +64,8 @@ static inline int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, static inline void sme_event_assoc_reject(struct wpa_supplicant *wpa_s, - union wpa_event_data *data) + union wpa_event_data *data, + const u8 **link_bssids) { } @@ -98,12 +98,6 @@ static inline void sme_state_changed(struct wpa_supplicant *wpa_s) { } -static inline void -sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s, - const u8 *prev_pending_bssid) -{ -} - static inline void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s) { } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant-2.9_standard/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in index da69a8705ce8358c5e75b5219f137e6bc434a964..4eab33526bba0ed95a2576f4616c4038b9143508 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in @@ -1,5 +1,5 @@ [Unit] -Description=WPA supplicant daemon (interface- and nl80211 driver-specific version) +Description=WPA supplicant daemon (for interface %I using nl80211) Requires=sys-subsystem-net-devices-%i.device After=sys-subsystem-net-devices-%i.device Before=network.target diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/wpa_supplicant-2.9_standard/wpa_supplicant/systemd/wpa_supplicant.service.arg.in index 55d2b9c8171293c14457452d7196c87e302b5dd6..b0d610fa8efba075af2699306a7351d46b76d0aa 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/systemd/wpa_supplicant.service.arg.in +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/systemd/wpa_supplicant.service.arg.in @@ -1,5 +1,5 @@ [Unit] -Description=WPA supplicant daemon (interface-specific version) +Description=WPA supplicant daemon (for interface %I) Requires=sys-subsystem-net-devices-%i.device After=sys-subsystem-net-devices-%i.device Before=network.target diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/utils/log2pcap.py b/wpa_supplicant-2.9_standard/wpa_supplicant/utils/log2pcap.py index 141aecbe5178a276caeb99b7360b01138c6b50ac..9a3f08de84614dc738c5d4ca7a37f44add85cc75 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/utils/log2pcap.py +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/utils/log2pcap.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -# Copyright (c) 2012, Intel Corporation +# Copyright (c) 2012-2022, Intel Corporation # # Author: Johannes Berg # @@ -8,6 +8,7 @@ # See README for more details. import sys, struct, re +from binascii import unhexlify def write_pcap_header(pcap_file): pcap_file.write( @@ -32,7 +33,7 @@ if __name__ == "__main__": sys.exit(2) input_file = open(input, 'r') - pcap_file = open(pcap, 'w') + pcap_file = open(pcap, 'wb') frame_re = re.compile(r'(([0-9]+.[0-9]{6}):\s*)?nl80211: MLME event frame - hexdump\(len=[0-9]*\):((\s*[0-9a-fA-F]{2})*)') write_pcap_header(pcap_file) @@ -47,7 +48,7 @@ if __name__ == "__main__": ts = 0 hexdata = m.group(3) hexdata = hexdata.split() - data = ''.join([chr(int(x, 16)) for x in hexdata]) + data = unhexlify("".join(hexdata)) pcap_addpacket(pcap_file, ts, data) input_file.close() diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj b/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj index 89122f80cc794a259c6cb1513f2a180a8b2b5809..e79fc0f4666f8638b8271fb72df1539d9d7f2d62 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj @@ -1,203 +1,203 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj b/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj index a6a7291e9c88c88fb0454d206fab1ebfa95f4f1e..d2de768e7cdcaf76fdd6eb7c4a3a5a8978cbbd67 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj @@ -1,215 +1,215 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj b/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj index 636437e29f6340d82c66075fc12c0c0fd3a2b723..97aa2c5aecb5ecbccf6963f2873631e1fbf9918d 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj @@ -1,236 +1,236 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_supplicant.sln b/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_supplicant.sln index 97b756652dade66f515db99bb7930efc0c17d583..df89e3198d2f6d052a792f6030cd5280e498b349 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_supplicant.sln +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/vs2005/wpa_supplicant.sln @@ -1,52 +1,52 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_supplicant", "wpa_supplicant\wpa_supplicant.vcproj", "{8BCFDA77-AEDC-4168-8897-5B73105BBB87}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_cli", "wpa_cli\wpa_cli.vcproj", "{E3A7B181-22CC-4DA3-8410-6AD69879A9EC}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpasvc", "wpasvc\wpasvc.vcproj", "{E2A4A85F-CA77-406D-8ABF-63EF94545ACC}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_passphrase", "wpa_passphrase\wpa_passphrase.vcproj", "{ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_if_list", "win_if_list\win_if_list.vcproj", "{9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eapol_test", "eapol_test\eapol_test.vcproj", "{0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}" -EndProject -Global - GlobalSection(DPCodeReviewSolutionGUID) = preSolution - DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Debug|Win32.ActiveCfg = Debug|Win32 - {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Debug|Win32.Build.0 = Debug|Win32 - {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Release|Win32.ActiveCfg = Release|Win32 - {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Release|Win32.Build.0 = Release|Win32 - {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Debug|Win32.ActiveCfg = Debug|Win32 - {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Debug|Win32.Build.0 = Debug|Win32 - {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Release|Win32.ActiveCfg = Release|Win32 - {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Release|Win32.Build.0 = Release|Win32 - {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Debug|Win32.ActiveCfg = Debug|Win32 - {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Debug|Win32.Build.0 = Debug|Win32 - {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Release|Win32.ActiveCfg = Release|Win32 - {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Release|Win32.Build.0 = Release|Win32 - {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Debug|Win32.ActiveCfg = Debug|Win32 - {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Debug|Win32.Build.0 = Debug|Win32 - {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Release|Win32.ActiveCfg = Release|Win32 - {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Release|Win32.Build.0 = Release|Win32 - {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Debug|Win32.ActiveCfg = Debug|Win32 - {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Debug|Win32.Build.0 = Debug|Win32 - {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Release|Win32.ActiveCfg = Release|Win32 - {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Release|Win32.Build.0 = Release|Win32 - {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Debug|Win32.ActiveCfg = Debug|Win32 - {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Debug|Win32.Build.0 = Debug|Win32 - {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Release|Win32.ActiveCfg = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_supplicant", "wpa_supplicant\wpa_supplicant.vcproj", "{8BCFDA77-AEDC-4168-8897-5B73105BBB87}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_cli", "wpa_cli\wpa_cli.vcproj", "{E3A7B181-22CC-4DA3-8410-6AD69879A9EC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpasvc", "wpasvc\wpasvc.vcproj", "{E2A4A85F-CA77-406D-8ABF-63EF94545ACC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_passphrase", "wpa_passphrase\wpa_passphrase.vcproj", "{ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_if_list", "win_if_list\win_if_list.vcproj", "{9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eapol_test", "eapol_test\eapol_test.vcproj", "{0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}" +EndProject +Global + GlobalSection(DPCodeReviewSolutionGUID) = preSolution + DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Debug|Win32.ActiveCfg = Debug|Win32 + {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Debug|Win32.Build.0 = Debug|Win32 + {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Release|Win32.ActiveCfg = Release|Win32 + {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Release|Win32.Build.0 = Release|Win32 + {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Debug|Win32.ActiveCfg = Debug|Win32 + {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Debug|Win32.Build.0 = Debug|Win32 + {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Release|Win32.ActiveCfg = Release|Win32 + {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Release|Win32.Build.0 = Release|Win32 + {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Debug|Win32.ActiveCfg = Debug|Win32 + {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Debug|Win32.Build.0 = Debug|Win32 + {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Release|Win32.ActiveCfg = Release|Win32 + {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Release|Win32.Build.0 = Release|Win32 + {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Debug|Win32.ActiveCfg = Debug|Win32 + {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Debug|Win32.Build.0 = Debug|Win32 + {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Release|Win32.ActiveCfg = Release|Win32 + {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Release|Win32.Build.0 = Release|Win32 + {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Debug|Win32.ActiveCfg = Debug|Win32 + {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Debug|Win32.Build.0 = Debug|Win32 + {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Release|Win32.ActiveCfg = Release|Win32 + {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Release|Win32.Build.0 = Release|Win32 + {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Debug|Win32.ActiveCfg = Debug|Win32 + {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Debug|Win32.Build.0 = Debug|Win32 + {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Release|Win32.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/win_example.reg b/wpa_supplicant-2.9_standard/wpa_supplicant/win_example.reg index 6e42037e143c4bfd84cf9500cc22384b812e7e51..875d4ef280465415e7e8c230a499f40c78f1edd7 100755 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/win_example.reg +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/win_example.reg @@ -1,42 +1,42 @@ -REGEDIT4 - -[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant] -"debug_level"=dword:00000000 -"debug_show_keys"=dword:00000001 -"debug_timestamp"=dword:00000000 -"debug_use_file"=dword:00000000 - -[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs] - -[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test] -"ap_scan"=dword:00000002 -"update_config"=dword:00000001 -"uuid"="12345678-9abc-def0-1234-56789abcdef0" -"device_name"="Wireless Client" -"manufacturer"="Company" -"model_name"="cmodel" -"serial_number"="12345" -"device_type"="1-0050F204-1" -"os_version"="01020300" - -[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\blobs] -"testblob"=hex:01,02,03,04,05 - -[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks] - -[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000] -"ssid"="\"example network\"" -"key_mgmt"="WPA-PSK" -"psk"="\"secret password\"" -"pairwise"="CCMP" -"group"="CCMP" -"proto"="WPA" - -[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\interfaces] - -[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\interfaces\0000] -"adapter"="{A7627643-C310-49E5-BD89-7E77709C04AB}" -"config"="test" -"ctrl_interface"="" -"skip_on_error"=dword:00000000 - +REGEDIT4 + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant] +"debug_level"=dword:00000000 +"debug_show_keys"=dword:00000001 +"debug_timestamp"=dword:00000000 +"debug_use_file"=dword:00000000 + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs] + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test] +"ap_scan"=dword:00000002 +"update_config"=dword:00000001 +"uuid"="12345678-9abc-def0-1234-56789abcdef0" +"device_name"="Wireless Client" +"manufacturer"="Company" +"model_name"="cmodel" +"serial_number"="12345" +"device_type"="1-0050F204-1" +"os_version"="01020300" + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\blobs] +"testblob"=hex:01,02,03,04,05 + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks] + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000] +"ssid"="\"example network\"" +"key_mgmt"="WPA-PSK" +"psk"="\"secret password\"" +"pairwise"="CCMP" +"group"="CCMP" +"proto"="WPA" + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\interfaces] + +[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\interfaces\0000] +"adapter"="{A7627643-C310-49E5-BD89-7E77709C04AB}" +"config"="test" +"ctrl_interface"="" +"skip_on_error"=dword:00000000 + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wmm_ac.c b/wpa_supplicant-2.9_standard/wpa_supplicant/wmm_ac.c index 598931b3f462daa6845152ce0c224ae10b219a5e..abcfcbe2bd0c2cd8afa146ad5cd600fcf1aaef64 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wmm_ac.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wmm_ac.c @@ -678,7 +678,7 @@ static void wmm_ac_handle_addts_resp(struct wpa_supplicant *wpa_s, const u8 *sa, } /* make sure the params are the same */ - if (os_memcmp(req->address, sa, ETH_ALEN) != 0 || + if (!ether_addr_equal(req->address, sa) || tsid != wmm_ac_get_tsid(&req->tspec) || up != wmm_ac_get_user_priority(&req->tspec) || dir != wmm_ac_get_direction(&req->tspec)) { @@ -755,13 +755,13 @@ void wmm_ac_rx_action(struct wpa_supplicant *wpa_s, const u8 *da, } /* WMM AC action frame */ - if (os_memcmp(da, wpa_s->own_addr, ETH_ALEN) != 0) { + if (!ether_addr_equal(da, wpa_s->own_addr)) { wpa_printf(MSG_DEBUG, "WMM AC: frame destination addr="MACSTR_SEC " is other than ours, ignoring frame", MAC2STR_SEC(da)); return; } - if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { + if (!ether_addr_equal(sa, wpa_s->bssid)) { wpa_printf(MSG_DEBUG, "WMM AC: ignore frame with sa " MACSTR_SEC " different other than our bssid", MAC2STR_SEC(da)); return; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wnm_sta.c b/wpa_supplicant-2.9_standard/wpa_supplicant/wnm_sta.c index 87413a10c90d95756e4334435f97e1f55bab05c8..8c688a1cb5d1b1785ca974947a45b009ec52b401 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wnm_sta.c @@ -418,7 +418,7 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, } -void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) +void wnm_btm_reset(struct wpa_supplicant *wpa_s) { int i; @@ -431,8 +431,17 @@ void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) os_free(wpa_s->wnm_neighbor_report_elements); wpa_s->wnm_neighbor_report_elements = NULL; - wpabuf_free(wpa_s->coloc_intf_elems); - wpa_s->coloc_intf_elems = NULL; + wpa_s->wnm_cand_valid_until.sec = 0; + wpa_s->wnm_cand_valid_until.usec = 0; + + wpa_s->wnm_mode = 0; + wpa_s->wnm_dialog_token = 0; + wpa_s->wnm_reply = 0; + +#ifdef CONFIG_MBO + wpa_s->wnm_mbo_trans_reason_present = 0; + wpa_s->wnm_mbo_transition_reason = 0; +#endif /* CONFIG_MBO */ } @@ -524,6 +533,11 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, rep->mul_bssid->subelem_len = elen - 1; os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); break; + default: + wpa_printf(MSG_DEBUG, + "WNM: Unsupported neighbor report subelement id %u", + id); + break; } } @@ -609,22 +623,6 @@ static void wnm_clear_acceptable(struct wpa_supplicant *wpa_s) wpa_s->wnm_neighbor_report_elements[i].acceptable = 0; } - -static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s) -{ - unsigned int i; - struct neighbor_report *nei; - - for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { - nei = &wpa_s->wnm_neighbor_report_elements[i]; - if (nei->acceptable) - return wpa_bss_get_bssid(wpa_s, nei->bssid); - } - - return NULL; -} - - #ifdef CONFIG_MBO static struct wpa_bss * get_mbo_transition_candidate(struct wpa_supplicant *wpa_s, @@ -697,9 +695,8 @@ get_mbo_transition_candidate(struct wpa_supplicant *wpa_s, if (reason) { for (i = 0; i < info->num; i++) { if (first_candidate_bssid && - os_memcmp(first_candidate_bssid, - info->candidates[i].bssid, ETH_ALEN) == 0) - { + ether_addr_equal(first_candidate_bssid, + info->candidates[i].bssid)) { *reason = info->candidates[i].reject_reason; break; } @@ -719,6 +716,29 @@ end: #endif /* CONFIG_MBO */ +static struct wpa_bss * find_better_target(struct wpa_bss *a, + struct wpa_bss *b) +{ + if (!a) + return b; + if (!b) + return a; + + if (a->est_throughput > b->est_throughput) { + wpa_printf(MSG_DEBUG, "WNM: A is better: " MACSTR + " est-tput: %d B: " MACSTR " est-tput: %d", + MAC2STR(a->bssid), a->est_throughput, + MAC2STR(b->bssid), b->est_throughput); + return a; + } + + wpa_printf(MSG_DEBUG, "WNM: B is better, A: " MACSTR + " est-tput: %d B: " MACSTR " est-tput: %d", + MAC2STR(a->bssid), a->est_throughput, + MAC2STR(b->bssid), b->est_throughput); + return b; +} + static struct wpa_bss * compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, enum mbo_transition_reject_reason *reason) @@ -726,6 +746,8 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, u8 i; struct wpa_bss *bss = wpa_s->current_bss; struct wpa_bss *target; + struct wpa_bss *best_target = NULL; + struct wpa_bss *bss_in_list = NULL; if (!bss) return NULL; @@ -768,22 +790,11 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, } } - if (bss->ssid_len != target->ssid_len || - os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { - /* - * TODO: Could consider allowing transition to another - * ESS if PMF was enabled for the association. - */ - wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR_SEC - " (pref %d) in different ESS", - MAC2STR_SEC(nei->bssid), - nei->preference_present ? nei->preference : - -1); - continue; - } - - if (wpa_s->current_ssid && - !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid, + /* + * TODO: Could consider allowing transition to another ESS if + * PMF was enabled for the association. + */ + if (!wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid, 1, 0)) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR_SEC " (pref %d) does not match the current network profile", @@ -793,14 +804,6 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, continue; } - if (wpa_is_bss_tmp_disallowed(wpa_s, target)) { - wpa_printf(MSG_DEBUG, - "MBO: Candidate BSS " MACSTR_SEC - " retry delay is not over yet", - MAC2STR_SEC(nei->bssid)); - continue; - } - if (target->level < bss->level && target->level < -80) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR_SEC " (pref %d) does not have sufficient signal level (%d)", @@ -812,25 +815,44 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, } nei->acceptable = 1; + + best_target = find_better_target(target, best_target); + if (target == bss) + bss_in_list = bss; } #ifdef CONFIG_MBO if (wpa_s->wnm_mbo_trans_reason_present) target = get_mbo_transition_candidate(wpa_s, reason); else - target = get_first_acceptable(wpa_s); + target = best_target; #else /* CONFIG_MBO */ - target = get_first_acceptable(wpa_s); + target = best_target; #endif /* CONFIG_MBO */ - if (target) { - wpa_printf(MSG_DEBUG, - "WNM: Found an acceptable preferred transition candidate BSS " - MACSTR_SEC " (RSSI %d)", - MAC2STR_SEC(target->bssid), target->level); + if (!target) + return NULL; + + wpa_printf(MSG_DEBUG, + "WNM: Found an acceptable preferred transition candidate BSS " + MACSTR_SEC " (RSSI %d, tput: %d bss-tput: %d)", + MAC2STR_SEC(target->bssid), target->level, + target->est_throughput, bss->est_throughput); + + if (!bss_in_list) + return target; + + if ((!target->est_throughput && !bss_in_list->est_throughput) || + (target->est_throughput > bss_in_list->est_throughput && + target->est_throughput - bss_in_list->est_throughput > + bss_in_list->est_throughput >> 4)) { + /* It is more than 100/16 percent better, so switch. */ + return target; } - return target; + wpa_printf(MSG_DEBUG, + "WNM: Stay with our current BSS, not enough change in estimated throughput to switch"); + return bss_in_list; } @@ -921,7 +943,8 @@ static int wnm_nei_rep_add_bss(struct wpa_supplicant *wpa_s, { const u8 *ie; u8 op_class, chan; - int sec_chan = 0, vht = 0; + int sec_chan = 0; + enum oper_chan_width vht = CONF_OPER_CHWIDTH_USE_HT; enum phy_type phy_type; u32 info; struct ieee80211_ht_operation *ht_oper = NULL; @@ -1012,8 +1035,8 @@ static void wnm_add_cand_list(struct wpa_supplicant *wpa_s, struct wpabuf **buf) #define BTM_RESP_MIN_SIZE 5 + ETH_ALEN -static void wnm_send_bss_transition_mgmt_resp( - struct wpa_supplicant *wpa_s, u8 dialog_token, +static int wnm_send_bss_transition_mgmt_resp( + struct wpa_supplicant *wpa_s, enum bss_trans_mgmt_status_code status, enum mbo_transition_reject_reason reason, u8 delay, const u8 *target_bssid) @@ -1021,21 +1044,24 @@ static void wnm_send_bss_transition_mgmt_resp( struct wpabuf *buf; int res; + wpa_s->wnm_reply = 0; + wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response to " MACSTR_SEC " dialog_token=%u status=%u reason=%u delay=%d", - MAC2STR_SEC(wpa_s->bssid), dialog_token, status, reason, delay); + MAC2STR_SEC(wpa_s->bssid), wpa_s->wnm_dialog_token, status, + reason, delay); if (!wpa_s->current_bss) { wpa_printf(MSG_DEBUG, "WNM: Current BSS not known - drop response"); - return; + return -1; } buf = wpabuf_alloc(BTM_RESP_MIN_SIZE); if (!buf) { wpa_printf(MSG_DEBUG, "WNM: Failed to allocate memory for BTM response"); - return; + return -1; } wpa_s->bss_tm_status = status; @@ -1043,7 +1069,7 @@ static void wnm_send_bss_transition_mgmt_resp( wpabuf_put_u8(buf, WLAN_ACTION_WNM); wpabuf_put_u8(buf, WNM_BSS_TRANS_MGMT_RESP); - wpabuf_put_u8(buf, dialog_token); + wpabuf_put_u8(buf, wpa_s->wnm_dialog_token); wpabuf_put_u8(buf, status); wpabuf_put_u8(buf, delay); if (target_bssid) { @@ -1057,7 +1083,7 @@ static void wnm_send_bss_transition_mgmt_resp( wpabuf_put_data(buf, "\0\0\0\0\0\0", ETH_ALEN); } - if (status == WNM_BSS_TM_ACCEPT) + if (status == WNM_BSS_TM_ACCEPT && target_bssid) wnm_add_cand_list(wpa_s, &buf); #ifdef CONFIG_MBO @@ -1073,7 +1099,7 @@ static void wnm_send_bss_transition_mgmt_resp( wpabuf_free(buf); wpa_printf(MSG_DEBUG, "WNM: Failed to allocate memory for MBO IE"); - return; + return -1; } wpabuf_put_data(buf, mbo, ret); @@ -1090,6 +1116,8 @@ static void wnm_send_bss_transition_mgmt_resp( } wpabuf_free(buf); + + return res; } @@ -1111,19 +1139,24 @@ static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s, /* Send the BSS Management Response - Accept */ if (wpa_s->wnm_reply) { - wpa_s->wnm_reply = 0; + wpa_s->wnm_target_bss = bss; wpa_printf(MSG_DEBUG, "WNM: Sending successful BSS Transition Management Response"); - wnm_send_bss_transition_mgmt_resp( - wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT, - MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, - bss->bssid); + + /* This function will be called again from the TX handler to + * start the actual reassociation after this response has been + * delivered to the current AP. */ + if (wnm_send_bss_transition_mgmt_resp( + wpa_s, WNM_BSS_TM_ACCEPT, + MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, + bss->bssid) >= 0) + return; } if (bss == wpa_s->current_bss) { wpa_printf(MSG_DEBUG, "WNM: Already associated with the preferred candidate"); - wnm_deallocate_memory(wpa_s); + wnm_btm_reset(wpa_s); return; } @@ -1139,11 +1172,10 @@ static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s, */ if (!already_connecting && radio_work_pending(wpa_s, "sme-connect")) wpa_s->bss_trans_mgmt_in_progress = true; - wnm_deallocate_memory(wpa_s); } -int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) +int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check) { struct wpa_bss *bss; struct wpa_ssid *ssid = wpa_s->current_ssid; @@ -1151,27 +1183,51 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) enum mbo_transition_reject_reason reason = MBO_TRANSITION_REJECT_REASON_UNSPECIFIED; - if (!wpa_s->wnm_neighbor_report_elements) + if (!wpa_s->wnm_dialog_token) return 0; wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Process scan results for BSS Transition Management"); - if (os_reltime_before(&wpa_s->wnm_cand_valid_until, + if (!pre_scan_check && + os_reltime_initialized(&wpa_s->wnm_cand_valid_until) && + os_reltime_before(&wpa_s->wnm_cand_valid_until, &wpa_s->scan_trigger_time)) { wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); - wnm_deallocate_memory(wpa_s); - return 0; - } - - if (!wpa_s->current_bss || - os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid, - ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it"); - return 0; + goto send_bss_resp_fail; } /* Compare the Neighbor Report and scan results */ bss = compare_scan_neighbor_results(wpa_s, 0, &reason); + + /* + * If this is a pre-scan check, returning 0 will trigger a scan and + * another call. In that case, reject "bad" candidates in the hope of + * finding a better candidate after scanning. + * + * Use a simple heuristic to check whether the selection is reasonable + * or a scan is a good idea. For that, we need to have found a + * candidate BSS (which might be the current one), it is up-to-date, + * and we don't want to immediately roam back again. + */ + if (pre_scan_check) { + struct os_reltime age; + + if (!bss) + return 0; + + os_reltime_age(&bss->last_update, &age); + if (age.sec >= 10) + return 0; + +#ifndef CONFIG_NO_ROAMING + if (wpa_s->current_bss && bss != wpa_s->current_bss && + wpa_supplicant_need_to_roam_within_ess(wpa_s, + wpa_s->current_bss, + bss)) + return 0; +#endif /* CONFIG_NO_ROAMING */ + } + if (!bss) { wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; @@ -1183,18 +1239,13 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) return 1; send_bss_resp_fail: - if (!reply_on_fail) - return 0; - /* Send reject response for all the failures */ - if (wpa_s->wnm_reply) { - wpa_s->wnm_reply = 0; - wnm_send_bss_transition_mgmt_resp(wpa_s, - wpa_s->wnm_dialog_token, - status, reason, 0, NULL); - } - wnm_deallocate_memory(wpa_s); + if (wpa_s->wnm_reply) + wnm_send_bss_transition_mgmt_resp(wpa_s, status, reason, + 0, NULL); + + wnm_btm_reset(wpa_s); return 0; } @@ -1205,6 +1256,11 @@ static int cand_pref_compar(const void *a, const void *b) const struct neighbor_report *aa = a; const struct neighbor_report *bb = b; + if (aa->disassoc_imminent && !bb->disassoc_imminent) + return 1; + if (bb->disassoc_imminent && !aa->disassoc_imminent) + return -1; + if (!aa->preference_present && !bb->preference_present) return 0; if (!aa->preference_present) @@ -1296,6 +1352,10 @@ static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) struct neighbor_report *nei; nei = &wpa_s->wnm_neighbor_report_elements[i]; + + if (nei->preference_present && nei->preference == 0) + continue; + if (nei->freq <= 0) { wpa_printf(MSG_DEBUG, "WNM: Unknown neighbor operating frequency for " @@ -1320,79 +1380,6 @@ static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) } -static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) -{ - struct wpa_scan_results *scan_res; - struct wpa_bss *bss; - struct wpa_ssid *ssid = wpa_s->current_ssid; - u8 i, found = 0; - size_t j; - - wpa_dbg(wpa_s, MSG_DEBUG, - "WNM: Fetch current scan results from the driver for checking transition candidates"); - scan_res = wpa_drv_get_scan_results2(wpa_s); - if (!scan_res) { - wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results"); - return 0; - } - - if (scan_res->fetch_time.sec == 0) - os_get_reltime(&scan_res->fetch_time); - - filter_scan_res(wpa_s, scan_res); - - for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { - struct neighbor_report *nei; - - nei = &wpa_s->wnm_neighbor_report_elements[i]; - if (nei->preference_present && nei->preference == 0) - continue; - - for (j = 0; j < scan_res->num; j++) { - struct wpa_scan_res *res; - const u8 *ssid_ie; - - res = scan_res->res[j]; - if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 || - res->age > WNM_SCAN_RESULT_AGE * 1000) - continue; - bss = wpa_s->current_bss; - ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID); - if (bss && ssid_ie && ssid_ie[1] && - (bss->ssid_len != ssid_ie[1] || - os_memcmp(bss->ssid, ssid_ie + 2, - bss->ssid_len) != 0)) - continue; /* Skip entries for other ESSs */ - - /* Potential candidate found */ - found = 1; - scan_snr(res); - scan_est_throughput(wpa_s, res); - wpa_bss_update_scan_res(wpa_s, res, - &scan_res->fetch_time); - } - } - - wpa_scan_results_free(scan_res); - if (!found) { - wpa_dbg(wpa_s, MSG_DEBUG, - "WNM: No transition candidate matches existing scan results"); - return 0; - } - - bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE, NULL); - if (!bss) { - wpa_dbg(wpa_s, MSG_DEBUG, - "WNM: Comparison of scan results against transition candidates did not find matches"); - return 0; - } - - /* Associate to the network */ - wnm_bss_tm_connect(wpa_s, bss, ssid, 0); - return 1; -} - - static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, const u8 *pos, const u8 *end, int reply) @@ -1402,6 +1389,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MBO const u8 *vendor; #endif /* CONFIG_MBO */ + bool disassoc_imminent; if (wpa_s->disable_mbo_oce || wpa_s->conf->disable_btm) return; @@ -1409,19 +1397,17 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, if (end - pos < 5) return; -#ifdef CONFIG_MBO - wpa_s->wnm_mbo_trans_reason_present = 0; - wpa_s->wnm_mbo_transition_reason = 0; -#endif /* CONFIG_MBO */ - if (wpa_s->current_bss) beacon_int = wpa_s->current_bss->beacon_int; else beacon_int = 100; /* best guess */ + wnm_btm_reset(wpa_s); + wpa_s->wnm_dialog_token = pos[0]; wpa_s->wnm_mode = pos[1]; wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); + wpa_s->wnm_link_removal = false; valid_int = pos[4]; wpa_s->wnm_reply = reply; @@ -1437,8 +1423,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", wpa_s->reject_btm_req_reason); wnm_send_bss_transition_mgmt_resp( - wpa_s, wpa_s->wnm_dialog_token, - wpa_s->reject_btm_req_reason, + wpa_s, wpa_s->reject_btm_req_reason, MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); return; } @@ -1457,27 +1442,71 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { char url[256]; + u8 url_len; - if (end - pos < 1 || 1 + pos[0] > end - pos) { + if (end - pos < 1) { wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " "Management Request (URL)"); return; } - os_memcpy(url, pos + 1, pos[0]); - url[pos[0]] = '\0'; - pos += 1 + pos[0]; + url_len = *pos++; + if (url_len > end - pos) { + wpa_printf(MSG_DEBUG, + "WNM: Invalid BSS Transition Management Request (URL truncated)"); + return; + } + os_memcpy(url, pos, url_len); + url[url_len] = '\0'; + pos += url_len; wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", wpa_sm_pmf_enabled(wpa_s->wpa), wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); } - if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { + disassoc_imminent = wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT; + + /* + * Based on IEEE P802.11be/D5.0, when a station is a non-AP MLD with + * more than one affiliated link, the Link Removal Imminent field is + * set to 1, and the BSS Termination Included field is set to 1, only + * one of the links is removed and the other links remain associated. + * Ignore the Disassociation Imminent field in such a case. + * + * TODO: We should check if the AP has more than one link. + * TODO: We should pass the RX link and use that + */ + if (disassoc_imminent && wpa_s->valid_links && + (wpa_s->wnm_mode & WNM_BSS_TM_REQ_LINK_REMOVAL_IMMINENT) && + (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED)) { + /* If we still have a link, then just accept the request */ + if (wpa_s->valid_links & (wpa_s->valid_links - 1)) { + wpa_printf(MSG_INFO, + "WNM: BTM request for a single MLO link - ignore disassociation imminent since other links remain associated"); + disassoc_imminent = false; + + wnm_send_bss_transition_mgmt_resp( + wpa_s, WNM_BSS_TM_ACCEPT, 0, 0, NULL); + + return; + } + + /* The last link is being removed (which must be the assoc link) + */ + wpa_s->wnm_link_removal = true; + os_memcpy(wpa_s->wnm_dissoc_addr, + wpa_s->links[wpa_s->mlo_assoc_link_id].bssid, + ETH_ALEN); + } else { + os_memcpy(wpa_s->wnm_dissoc_addr, wpa_s->valid_links ? + wpa_s->ap_mld_addr : wpa_s->bssid, ETH_ALEN); + } + + if (disassoc_imminent) { wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); - if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { - /* TODO: mark current BSS less preferred for - * selection */ + if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning && + (!wpa_s->current_ssid || !wpa_s->current_ssid->bssid_set)) { wpa_printf(MSG_DEBUG, "Trying to find another BSS"); wpa_supplicant_req_scan(wpa_s, 0, 0); } @@ -1493,7 +1522,6 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, unsigned int valid_ms; wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); - wnm_deallocate_memory(wpa_s); wpa_s->wnm_neighbor_report_elements = os_calloc( WNM_MAX_NEIGHBOR_REPORT, sizeof(struct neighbor_report)); @@ -1517,6 +1545,11 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, rep = &wpa_s->wnm_neighbor_report_elements[ wpa_s->wnm_num_neighbor_report]; wnm_parse_neighbor_report(wpa_s, pos, len, rep); + if ((wpa_s->wnm_mode & + WNM_BSS_TM_REQ_DISASSOC_IMMINENT) && + ether_addr_equal(rep->bssid, wpa_s->bssid)) + rep->disassoc_imminent = 1; + wpa_s->wnm_num_neighbor_report++; #ifdef CONFIG_MBO if (wpa_s->wnm_mbo_trans_reason_present && @@ -1536,8 +1569,17 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "WNM: Candidate list included bit is set, but no candidates found"); wnm_send_bss_transition_mgmt_resp( - wpa_s, wpa_s->wnm_dialog_token, - WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, + wpa_s, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, + MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, + NULL); + return; + } + + if (wpa_s->current_ssid && wpa_s->current_ssid->bssid_set) { + wpa_printf(MSG_DEBUG, + "WNM: Configuration prevents roaming (BSSID set)"); + wnm_send_bss_transition_mgmt_resp( + wpa_s, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); return; @@ -1554,35 +1596,21 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_s->wnm_cand_valid_until.sec += wpa_s->wnm_cand_valid_until.usec / 1000000; wpa_s->wnm_cand_valid_until.usec %= 1000000; - os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); /* - * Fetch the latest scan results from the kernel and check for - * candidates based on those results first. This can help in - * finding more up-to-date information should the driver has - * done some internal scanning operations after the last scan - * result update in wpa_supplicant. - */ - if (wnm_fetch_scan_results(wpa_s) > 0) + * Try fetching the latest scan results from the kernel. + * This can help in finding more up-to-date information should + * the driver have done some internal scanning operations after + * the last scan result update in wpa_supplicant. + * + * It is not a new scan, this does not update the last_scan + * timestamp nor will it expire old BSSs. + */ + wpa_supplicant_update_scan_results(wpa_s, NULL); + if (wnm_scan_process(wpa_s, true) > 0) return; - - /* - * Try to use previously received scan results, if they are - * recent enough to use for a connection. - */ - if (wpa_s->last_scan_res_used > 0) { - struct os_reltime now; - - os_get_reltime(&now); - if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { - wpa_printf(MSG_DEBUG, - "WNM: Try to use recent scan results"); - if (wnm_scan_process(wpa_s, 0) > 0) - return; - wpa_printf(MSG_DEBUG, - "WNM: No match in previous scan results - try a new scan"); - } - } + wpa_printf(MSG_DEBUG, + "WNM: No valid match in previous scan results - try a new scan"); wnm_set_scan_freqs(wpa_s); if (wpa_s->wnm_num_neighbor_report == 1) { @@ -1596,19 +1624,54 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_supplicant_req_scan(wpa_s, 0, 0); } else if (reply) { enum bss_trans_mgmt_status_code status; - if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) + + if ((wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) || + wpa_s->wnm_link_removal) status = WNM_BSS_TM_ACCEPT; else { wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); status = WNM_BSS_TM_REJECT_UNSPECIFIED; } wnm_send_bss_transition_mgmt_resp( - wpa_s, wpa_s->wnm_dialog_token, status, + wpa_s, status, MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL); } } +int wnm_btm_resp_tx_status(struct wpa_supplicant *wpa_s, const u8 *data, + size_t data_len) +{ + const struct ieee80211_mgmt *frame = + (const struct ieee80211_mgmt *) data; + + if (data_len < + IEEE80211_HDRLEN + sizeof(frame->u.action.u.bss_tm_resp) || + frame->u.action.category != WLAN_ACTION_WNM || + frame->u.action.u.bss_tm_resp.action != WNM_BSS_TRANS_MGMT_RESP || + frame->u.action.u.bss_tm_resp.status_code != WNM_BSS_TM_ACCEPT) + return -1; + + /* + * If disassoc imminent bit was set in the request, the response may + * indicate accept even if no candidate was found, so bail out here. + */ + if (!wpa_s->wnm_target_bss) { + wpa_printf(MSG_DEBUG, "WNM: Target BSS is not set"); + return 0; + } + + if (!wpa_s->current_ssid) + return 0; + + wnm_bss_tm_connect(wpa_s, wpa_s->wnm_target_bss, wpa_s->current_ssid, + 0); + + wpa_s->wnm_target_bss = NULL; + return 0; +} + + #define BTM_QUERY_MIN_SIZE 4 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, @@ -1823,7 +1886,9 @@ static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, pos, end - pos); if (wpa_s->wpa_state != WPA_COMPLETED || - os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { + (!ether_addr_equal(sa, wpa_s->bssid) && + (!wpa_s->valid_links || + !ether_addr_equal(sa, wpa_s->ap_mld_addr)))) { wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " "from our AP - ignore it"); return; @@ -1870,7 +1935,9 @@ static void ieee802_11_rx_wnm_coloc_intf_req(struct wpa_supplicant *wpa_s, return; /* only nonzero values are used for request */ if (wpa_s->wpa_state != WPA_COMPLETED || - os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { + (!ether_addr_equal(sa, wpa_s->bssid) && + (!wpa_s->valid_links || + !ether_addr_equal(sa, wpa_s->ap_mld_addr)))) { wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Collocated Interference Request frame not from current AP - ignore it"); return; @@ -1900,7 +1967,9 @@ void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR_SEC, act, MAC2STR_SEC(mgmt->sa)); if (wpa_s->wpa_state < WPA_ASSOCIATED || - os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { + (!ether_addr_equal(mgmt->sa, wpa_s->bssid) && + (!wpa_s->valid_links || + !ether_addr_equal(mgmt->sa, wpa_s->ap_mld_addr)))) { wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " "frame"); return; @@ -1961,14 +2030,14 @@ int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token, void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s, struct wpabuf *elems) { - wpabuf_free(wpa_s->coloc_intf_elems); if (elems && wpabuf_len(elems) == 0) { wpabuf_free(elems); elems = NULL; } - wpa_s->coloc_intf_elems = elems; - if (wpa_s->conf->coloc_intf_reporting && wpa_s->coloc_intf_elems && + /* NOTE: The elements are not stored as they are only send out once */ + + if (wpa_s->conf->coloc_intf_reporting && elems && wpa_s->coloc_intf_dialog_token && (wpa_s->coloc_intf_auto_report == 1 || wpa_s->coloc_intf_auto_report == 3)) { @@ -1977,15 +2046,38 @@ void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s, */ wnm_send_coloc_intf_report(wpa_s, wpa_s->coloc_intf_dialog_token, - wpa_s->coloc_intf_elems); + elems); } + + wpabuf_free(elems); } void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s) { -#ifdef CONFIG_WNM wpa_s->coloc_intf_dialog_token = 0; wpa_s->coloc_intf_auto_report = 0; -#endif /* CONFIG_WNM */ +} + + +bool wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +{ + if (!(wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT)) + return false; + + /* + * In case disassociation imminent is set, do no try to use a BSS to + * which we are connected. + */ + if (wpa_s->wnm_link_removal || + !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) || + is_zero_ether_addr(bss->mld_addr)) { + if (ether_addr_equal(bss->bssid, wpa_s->wnm_dissoc_addr)) + return true; + } else { + if (ether_addr_equal(bss->mld_addr, wpa_s->wnm_dissoc_addr)) + return true; + } + + return false; } diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wnm_sta.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wnm_sta.h index 29625f8ca943e62ad955087585573ab5470c3dbd..235a838fab7756a21c7f69621023b3ddb31c7134 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wnm_sta.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wnm_sta.h @@ -37,6 +37,7 @@ struct neighbor_report { u32 distance; /* valid if bearing_present=1 */ u64 bss_term_tsf; /* valid if bss_term_present=1 */ u16 bss_term_dur; /* valid if bss_term_present=1 */ + unsigned int disassoc_imminent:1; unsigned int preference_present:1; unsigned int tsf_present:1; unsigned int country_present:1; @@ -64,18 +65,28 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, const char *btm_candidates, int cand_list); -void wnm_deallocate_memory(struct wpa_supplicant *wpa_s); int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token, const struct wpabuf *elems); void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s, struct wpabuf *elems); +int wnm_btm_resp_tx_status(struct wpa_supplicant *wpa_s, const u8 *data, + size_t data_len); #ifdef CONFIG_WNM -int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail); +int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check); void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s); +bool wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); + +void wnm_btm_reset(struct wpa_supplicant *wpa_s); + +static inline bool wnm_active_bss_trans_mgmt(struct wpa_supplicant *wpa_s) +{ + return !!wpa_s->wnm_dialog_token; +} + #else /* CONFIG_WNM */ static inline int wnm_scan_process(struct wpa_supplicant *wpa_s, @@ -88,6 +99,21 @@ static inline void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s) { } +static inline bool +wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) +{ + return false; +} + +static inline void wnm_btm_reset(struct wpa_supplicant *wpa_s) +{ +} + +static inline bool wnm_active_bss_trans_mgmt(struct wpa_supplicant *wpa_s) +{ + return false; +} + #endif /* CONFIG_WNM */ #endif /* WNM_STA_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_cli.c b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_cli.c index 6da82dd7833573b25f9c7c10288d89080497d1f1..fbe219b1563c1214981cf9e5f94420e53f224fb6 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_cli.c @@ -32,7 +32,7 @@ #define MAX_TEMP_BUFFER_LEN 4096 static const char *const wpa_cli_version = "wpa_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2022, Jouni Malinen and contributors"; +"Copyright (c) 2004-2024, Jouni Malinen and contributors"; #define VENDOR_ELEM_FRAME_ID \ " 0: Probe Req (P2P), 1: Probe Resp (P2P) , 2: Probe Resp (GO), " \ @@ -424,7 +424,7 @@ static int wpa_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[]) return 0; } -#ifdef CONFIG_MLD_PATCH_EXT + static int wpa_cli_cmd_mlo_status(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "MLO_STATUS"); @@ -435,7 +435,7 @@ static int wpa_cli_cmd_mlo_signal_poll(struct wpa_ctrl *ctrl, int argc, char *ar { return wpa_ctrl_command(ctrl, "MLO_SIGNAL_POLL"); } -#endif + static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -515,7 +515,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos) "autoscan", "wps_nfc_dev_pw_id", "wps_nfc_dh_pubkey", "wps_nfc_dh_privkey", "wps_nfc_dev_pw", "ext_password_backend", "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf", - "sae_groups", "dtim_period", "beacon_int", + "sae_check_mfp", "sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements", "ignore_old_scan_res", "freq_list", "scan_cur_freq", "scan_res_valid_for_connect", "sched_scan_interval", @@ -563,6 +563,13 @@ static int wpa_cli_cmd_driver_flags(struct wpa_ctrl *ctrl, int argc, } +static int wpa_cli_cmd_driver_flags2(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DRIVER_FLAGS2"); +} + + static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_cli_cmd(ctrl, "GET", 1, argc, argv); @@ -614,6 +621,7 @@ static char ** wpa_cli_complete_get(const char *str, int pos) "go_venue_group", "go_venue_type", "wps_nfc_dev_pw_id", "ext_password_backend", "p2p_go_max_inactivity", "auto_interworking", "okc", "pmf", + "sae_check_mfp", "dtim_period", "beacon_int", "ignore_old_scan_res", "scan_cur_freq", "scan_res_valid_for_connect", "sched_scan_interval", @@ -1609,7 +1617,6 @@ static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc, wpa_printf(MSG_INFO, "wpa_cli_cmd_set_network cmd: %s", os_strstr(tempBuf, "bssid") ? get_anonymized_result_setnetwork_for_bssid(tempBuf) : get_anonymized_result_setnetwork(tempBuf)); } - return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv); } @@ -1637,15 +1644,15 @@ static const char *network_fields[] = { "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", + "vht_center_freq2", "ht", "edmg", "he", #ifdef IEEE8021X_EAPOL "eap", "identity", "anonymous_identity", "password", "ca_cert", "ca_path", "client_cert", "private_key", "private_key_passwd", - "dh_file", "subject_match", "altsubject_match", + "subject_match", "altsubject_match", "check_cert_subject", "domain_suffix_match", "domain_match", "ca_cert2", "ca_path2", "client_cert2", "private_key2", "private_key2_passwd", - "dh_file2", "subject_match2", "altsubject_match2", + "subject_match2", "altsubject_match2", "check_cert_subject2", "domain_suffix_match2", "domain_match2", "phase1", "phase2", "pcsc", "pin", "engine_id", "key_id", "cert_id", "ca_cert_id", @@ -1690,12 +1697,14 @@ static const char *network_fields[] = { #ifdef CONFIG_HE_OVERRIDES "disable_he", #endif /* CONFIG_HE_OVERRIDES */ + "disable_eht", "ap_max_inactivity", "dtim_period", "beacon_int", #ifdef CONFIG_MACSEC "macsec_policy", "macsec_integ_only", "macsec_replay_protect", "macsec_replay_window", + "macsec_offload", "macsec_port", "mka_priority", #endif /* CONFIG_MACSEC */ @@ -1902,6 +1911,7 @@ static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc, return wpa_ctrl_command(ctrl, "SCAN_RESULTS"); } + #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(CONFIG_HILINK_OKC_STA) static int wpa_cli_cmd_enable_hilink(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -2275,6 +2285,20 @@ static int wpa_cli_cmd_update_beacon(struct wpa_ctrl *ctrl, int argc, return wpa_ctrl_command(ctrl, "UPDATE_BEACON"); } + +static int wpa_cli_cmd_accept_macacl(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "ACCEPT_ACL", 1, argc, argv); +} + + +static int wpa_cli_cmd_deny_macacl(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DENY_ACL", 1, argc, argv); +} + #endif /* CONFIG_AP */ @@ -2291,10 +2315,19 @@ static int wpa_cli_cmd_resume(struct wpa_ctrl *ctrl, int argc, char *argv[]) #ifdef CONFIG_TESTING_OPTIONS + static int wpa_cli_cmd_drop_sa(struct wpa_ctrl *ctrl, int argc, char *argv[]) { return wpa_ctrl_command(ctrl, "DROP_SA"); } + + +static int wpa_cli_cmd_ml_probe_req(struct wpa_ctrl *ctrl, + int argc, char *argv[]) +{ + return wpa_cli_cmd(ctrl, "ML_PROBE_REQ", 2, argc, argv); +} + #endif /* CONFIG_TESTING_OPTIONS */ @@ -3031,6 +3064,8 @@ static int wpa_cli_cmd_tdls_link_status(struct wpa_ctrl *ctrl, int argc, } +#ifndef CONFIG_NO_WMM_AC + static int wpa_cli_cmd_wmm_ac_addts(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -3051,6 +3086,8 @@ static int wpa_cli_cmd_wmm_ac_status(struct wpa_ctrl *ctrl, int argc, return wpa_ctrl_command(ctrl, "WMM_AC_STATUS"); } +#endif /* CONFIG_NO_WMM_AC */ + static int wpa_cli_cmd_tdls_chan_switch(struct wpa_ctrl *ctrl, int argc, char *argv[]) @@ -3123,6 +3160,31 @@ static int wpa_cli_cmd_wnm_bss_query(struct wpa_ctrl *ctrl, int argc, char *argv #endif /* CONFIG_WNM */ +#ifdef CONFIG_WNM_AP + +static int wpa_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DISASSOC_IMMINENT", 2, argc, argv); +} + + +static int wpa_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "ESS_DISASSOC", 3, argc, argv); +} + + +static int wpa_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "BSS_TM_REQ", 1, argc, argv); +} + +#endif /* CONFIG_WNM_AP */ + + static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[]) { if (argc == 0) @@ -3331,7 +3393,7 @@ static int wpa_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc, 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); + return wpa_cli_cmd(ctrl, "DPP_CONTROLLER_START", 0, argc, argv); } @@ -3356,6 +3418,15 @@ static int wpa_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc, } #endif /* CONFIG_DPP2 */ + + +#ifdef CONFIG_DPP3 +static int wpa_cli_cmd_dpp_push_button(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_cli_cmd(ctrl, "DPP_PUSH_BUTTON", 0, argc, argv); +} +#endif /* CONFIG_DPP3 */ #endif /* CONFIG_DPP */ @@ -3436,19 +3507,18 @@ static int wpa_cli_cmd_all_bss(struct wpa_ctrl *ctrl, int argc, char *argv[]) #ifdef CONFIG_PASN -static int wpa_cli_cmd_pasn_auth_start(struct wpa_ctrl *ctrl, int argc, - char *argv[]) +static int wpa_cli_cmd_pasn_start(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - return wpa_cli_cmd(ctrl, "PASN_AUTH_START", 4, argc, argv); + return wpa_cli_cmd(ctrl, "PASN_START", 4, argc, argv); } -static int wpa_cli_cmd_pasn_auth_stop(struct wpa_ctrl *ctrl, int argc, - char *argv[]) +static int wpa_cli_cmd_pasn_stop(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - return wpa_cli_cmd(ctrl, "PASN_AUTH_STOP", 0, argc, argv); + return wpa_cli_cmd(ctrl, "PASN_STOP", 0, argc, argv); } + static int wpa_cli_cmd_ptksa_cache_list(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -3549,6 +3619,9 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "driver_flags", wpa_cli_cmd_driver_flags, NULL, cli_cmd_flag_none, "= list driver flags" }, + { "driver_flags2", wpa_cli_cmd_driver_flags2, NULL, + cli_cmd_flag_none, + "= list driver flags2" }, { "logon", wpa_cli_cmd_logon, NULL, cli_cmd_flag_none, "= IEEE 802.1X EAPOL state machine logon" }, @@ -3855,6 +3928,10 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "update_beacon", wpa_cli_cmd_update_beacon, NULL, cli_cmd_flag_none, "= update Beacon frame contents"}, + { "accept_acl", wpa_cli_cmd_accept_macacl, NULL, cli_cmd_flag_none, + "=Add/Delete/Show/Clear allow MAC ACL" }, + { "deny_acl", wpa_cli_cmd_deny_macacl, NULL, cli_cmd_flag_none, + "=Add/Delete/Show/Clear deny MAC ACL" }, #endif /* CONFIG_AP */ { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none, "= notification of suspend/hibernate" }, @@ -3863,6 +3940,8 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { #ifdef CONFIG_TESTING_OPTIONS { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none, "= drop SA without deauth/disassoc (test command)" }, + { "ml_probe_req", wpa_cli_cmd_ml_probe_req, NULL, cli_cmd_flag_none, + "= send Multi-Link Probe request [link_id=id] (test command)" }, #endif /* CONFIG_TESTING_OPTIONS */ { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss, cli_cmd_flag_none, @@ -4058,6 +4137,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "tdls_link_status", wpa_cli_cmd_tdls_link_status, NULL, cli_cmd_flag_none, " = TDLS link status with " }, +#ifndef CONFIG_NO_WMM_AC { "wmm_ac_addts", wpa_cli_cmd_wmm_ac_addts, NULL, cli_cmd_flag_none, " [nominal_msdu_size=#] " @@ -4069,6 +4149,7 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { { "wmm_ac_status", wpa_cli_cmd_wmm_ac_status, NULL, cli_cmd_flag_none, "= show status for Wireless Multi-Media Admission-Control" }, +#endif /* CONFIG_NO_WMM_AC */ { "tdls_chan_switch", wpa_cli_cmd_tdls_chan_switch, NULL, cli_cmd_flag_none, " [sec_channel_offset=] [center_freq1=] " @@ -4101,6 +4182,14 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { " [neighbor=,,,,[,]" " = Send BSS Transition Management Query" }, #endif /* CONFIG_WNM */ +#ifdef CONFIG_WNM_AP + { "disassoc_imminent", wpa_cli_cmd_disassoc_imminent, NULL, cli_cmd_flag_none, + "= send Disassociation Imminent notification" }, + { "ess_disassoc", wpa_cli_cmd_ess_disassoc, NULL, cli_cmd_flag_none, + "= send ESS Dissassociation Imminent notification" }, + { "bss_tm_req", wpa_cli_cmd_bss_tm_req, NULL, cli_cmd_flag_none, + "= send BSS Transition Management Request" }, +#endif /* CONFIG_WNM_AP */ { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive, " = Sent unprocessed command" }, { "flush", wpa_cli_cmd_flush, NULL, cli_cmd_flag_none, @@ -4208,14 +4297,19 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { cli_cmd_flag_none, "= stop DPP chirp" }, #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + { "dpp_push_button", wpa_cli_cmd_dpp_push_button, NULL, + cli_cmd_flag_none, + "= press DPP push button" }, +#endif /* CONFIG_DPP3 */ #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, + { "pasn_start", wpa_cli_cmd_pasn_start, NULL, cli_cmd_flag_none, "bssid= akmp= cipher= group= nid= = Start PASN authentication" }, - { "pasn_auth_stop", wpa_cli_cmd_pasn_auth_stop, NULL, + { "pasn_stop", wpa_cli_cmd_pasn_stop, NULL, cli_cmd_flag_none, "= Stop PASN authentication" }, { "ptksa_cache_list", wpa_cli_cmd_ptksa_cache_list, NULL, @@ -4240,14 +4334,12 @@ static const struct wpa_cli_cmd wpa_cli_commands[] = { #ifdef CONFIG_VENDOR_EXT WPA_VENDOR_EXT_CMD_LIST, #endif -#ifdef CONFIG_MLD_PATCH_EXT { "mlo_status", wpa_cli_cmd_mlo_status, NULL, cli_cmd_flag_none, "= get MLO status" }, { "mlo_signal_poll", wpa_cli_cmd_mlo_signal_poll, NULL, cli_cmd_flag_none, "= get mlo signal parameters" }, -#endif { NULL, NULL, NULL, cli_cmd_flag_none, NULL } }; @@ -4544,6 +4636,8 @@ static void wpa_cli_action_process(const char *msg) } } else if (str_starts(pos, WPA_EVENT_CHANNEL_SWITCH_STARTED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); + } else if (str_starts(pos, WPA_EVENT_CHANNEL_SWITCH)) { + wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_starts(pos, AP_EVENT_ENABLED)) { wpa_cli_exec(action_file, ctrl_ifname, pos); } else if (str_starts(pos, AP_EVENT_DISABLED)) { @@ -5293,7 +5387,7 @@ int main(int argc, char *argv[]) eloop_register_signal_terminate(wpa_cli_terminate, NULL); - if (ctrl_ifname == NULL) + if (!ctrl_ifname && !global) ctrl_ifname = wpa_cli_get_default_ifname(); if (reconnect && action_file && ctrl_ifname) { diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/.gitignore b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/.gitignore index da818cb665579fc26c263382a1f33ccce9b7d507..8e3854afad4b9b6a0a7774cdc7932f8e103a67ae 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/.gitignore +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/.gitignore @@ -1,4 +1,4 @@ -.moc -.obj -.ui -qrc_icons.cpp +.moc +.obj +.ui +qrc_icons.cpp diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/addinterface.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/addinterface.cpp index 7d92f63d1b1d8c1cd223cea77b55673cf7682860..a80d1de9923d59de3acc3ae75a1c2860326ea501 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/addinterface.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/addinterface.cpp @@ -1,239 +1,239 @@ -/* - * wpa_gui - AddInterface class - * Copyright (c) 2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include -#include "common/wpa_ctrl.h" - -#include - -#include "wpagui.h" -#include "addinterface.h" - -#ifdef CONFIG_NATIVE_WINDOWS -#include - -#ifndef WPA_KEY_ROOT -#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE -#endif -#ifndef WPA_KEY_PREFIX -#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant") -#endif -#endif /* CONFIG_NATIVE_WINDOWS */ - - -AddInterface::AddInterface(WpaGui *_wpagui, QWidget *parent) - : QDialog(parent), wpagui(_wpagui) -{ - setWindowTitle(tr("Select network interface to add")); - resize(400, 200); - vboxLayout = new QVBoxLayout(this); - - interfaceWidget = new QTreeWidget(this); - interfaceWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); - interfaceWidget->setUniformRowHeights(true); - interfaceWidget->setSortingEnabled(true); - interfaceWidget->setColumnCount(3); - interfaceWidget->headerItem()->setText(0, tr("driver")); - interfaceWidget->headerItem()->setText(1, tr("interface")); - interfaceWidget->headerItem()->setText(2, tr("description")); - interfaceWidget->setItemsExpandable(false); - interfaceWidget->setRootIsDecorated(false); - vboxLayout->addWidget(interfaceWidget); - - connect(interfaceWidget, - SIGNAL(itemActivated(QTreeWidgetItem *, int)), this, - SLOT(interfaceSelected(QTreeWidgetItem *))); - - addInterfaces(); -} - - -void AddInterface::addInterfaces() -{ -#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE - struct wpa_ctrl *ctrl; - int ret; - char buf[2048]; - size_t len; - - ctrl = wpa_ctrl_open(NULL); - if (ctrl == NULL) - return; - - len = sizeof(buf) - 1; - ret = wpa_ctrl_request(ctrl, "INTERFACE_LIST", 14, buf, &len, NULL); - if (ret < 0) { - wpa_ctrl_close(ctrl); - return; - } - buf[len] = '\0'; - - wpa_ctrl_close(ctrl); - - QString ifaces(buf); - QStringList lines = ifaces.split(QRegExp("\\n")); - for (QStringList::Iterator it = lines.begin(); - it != lines.end(); it++) { - QStringList arg = (*it).split(QChar('\t')); - if (arg.size() < 3) - continue; - QTreeWidgetItem *item = new QTreeWidgetItem(interfaceWidget); - if (!item) - break; - - item->setText(0, arg[0]); - item->setText(1, arg[1]); - item->setText(2, arg[2]); - } - - interfaceWidget->resizeColumnToContents(0); - interfaceWidget->resizeColumnToContents(1); - interfaceWidget->resizeColumnToContents(2); -#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ -} - - -#ifdef CONFIG_NATIVE_WINDOWS -bool AddInterface::addRegistryInterface(const QString &ifname) -{ - HKEY hk, ihk; - LONG ret; - int id, tmp; - TCHAR name[10]; - DWORD val, i; - - ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX TEXT("\\interfaces"), - 0, KEY_ENUMERATE_SUB_KEYS | KEY_CREATE_SUB_KEY, - &hk); - if (ret != ERROR_SUCCESS) - return false; - - id = -1; - - for (i = 0; ; i++) { - TCHAR name[255]; - DWORD namelen; - - namelen = 255; - ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL, - NULL); - - if (ret == ERROR_NO_MORE_ITEMS) - break; - - if (ret != ERROR_SUCCESS) - break; - - if (namelen >= 255) - namelen = 255 - 1; - name[namelen] = '\0'; - -#ifdef UNICODE - QString s((QChar *) name, namelen); -#else /* UNICODE */ - QString s(name); -#endif /* UNICODE */ - tmp = s.toInt(); - if (tmp > id) - id = tmp; - } - - id += 1; - -#ifdef UNICODE - wsprintf(name, L"%04d", id); -#else /* UNICODE */ - os_snprintf(name, sizeof(name), "%04d", id); -#endif /* UNICODE */ - ret = RegCreateKeyEx(hk, name, 0, NULL, 0, KEY_WRITE, NULL, &ihk, - NULL); - RegCloseKey(hk); - if (ret != ERROR_SUCCESS) - return false; - -#ifdef UNICODE - RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ, - (LPBYTE) ifname.unicode(), - (ifname.length() + 1) * sizeof(TCHAR)); - -#else /* UNICODE */ - RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ, - (LPBYTE) ifname.toLocal8Bit(), ifname.length() + 1); -#endif /* UNICODE */ - RegSetValueEx(ihk, TEXT("config"), 0, REG_SZ, - (LPBYTE) TEXT("default"), 8 * sizeof(TCHAR)); - RegSetValueEx(ihk, TEXT("ctrl_interface"), 0, REG_SZ, - (LPBYTE) TEXT(""), 1 * sizeof(TCHAR)); - val = 1; - RegSetValueEx(ihk, TEXT("skip_on_error"), 0, REG_DWORD, (LPBYTE) &val, - sizeof(val)); - - RegCloseKey(ihk); - return true; -} -#endif /* CONFIG_NATIVE_WINDOWS */ - - -void AddInterface::interfaceSelected(QTreeWidgetItem *sel) -{ - if (!sel) - return; - -#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE - struct wpa_ctrl *ctrl; - int ret; - char buf[20], cmd[256]; - size_t len; - - /* - * INTERFACE_ADD TABTABTABTAB - * TAB - */ - snprintf(cmd, sizeof(cmd), - "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s", - sel->text(1).toLocal8Bit().constData(), - "default", - sel->text(0).toLocal8Bit().constData(), - "yes", "", ""); - cmd[sizeof(cmd) - 1] = '\0'; - - ctrl = wpa_ctrl_open(NULL); - if (ctrl == NULL) - return; - - len = sizeof(buf) - 1; - ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL); - wpa_ctrl_close(ctrl); - - if (ret < 0) { - QMessageBox::warning(this, "wpa_gui", - tr("Add interface command could not be " - "completed.")); - return; - } - - buf[len] = '\0'; - if (buf[0] != 'O' || buf[1] != 'K') { - QMessageBox::warning(this, "wpa_gui", - tr("Failed to add the interface.")); - return; - } - -#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ - -#ifdef CONFIG_NATIVE_WINDOWS - if (!addRegistryInterface(sel->text(1))) { - QMessageBox::information(this, "wpa_gui", - tr("Failed to add the interface into " - "registry.")); - } -#endif /* CONFIG_NATIVE_WINDOWS */ - - wpagui->selectAdapter(sel->text(1)); - close(); -} +/* + * wpa_gui - AddInterface class + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include "common/wpa_ctrl.h" + +#include + +#include "wpagui.h" +#include "addinterface.h" + +#ifdef CONFIG_NATIVE_WINDOWS +#include + +#ifndef WPA_KEY_ROOT +#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE +#endif +#ifndef WPA_KEY_PREFIX +#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant") +#endif +#endif /* CONFIG_NATIVE_WINDOWS */ + + +AddInterface::AddInterface(WpaGui *_wpagui, QWidget *parent) + : QDialog(parent), wpagui(_wpagui) +{ + setWindowTitle(tr("Select network interface to add")); + resize(400, 200); + vboxLayout = new QVBoxLayout(this); + + interfaceWidget = new QTreeWidget(this); + interfaceWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); + interfaceWidget->setUniformRowHeights(true); + interfaceWidget->setSortingEnabled(true); + interfaceWidget->setColumnCount(3); + interfaceWidget->headerItem()->setText(0, tr("driver")); + interfaceWidget->headerItem()->setText(1, tr("interface")); + interfaceWidget->headerItem()->setText(2, tr("description")); + interfaceWidget->setItemsExpandable(false); + interfaceWidget->setRootIsDecorated(false); + vboxLayout->addWidget(interfaceWidget); + + connect(interfaceWidget, + SIGNAL(itemActivated(QTreeWidgetItem *, int)), this, + SLOT(interfaceSelected(QTreeWidgetItem *))); + + addInterfaces(); +} + + +void AddInterface::addInterfaces() +{ +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + struct wpa_ctrl *ctrl; + int ret; + char buf[2048]; + size_t len; + + ctrl = wpa_ctrl_open(NULL); + if (ctrl == NULL) + return; + + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, "INTERFACE_LIST", 14, buf, &len, NULL); + if (ret < 0) { + wpa_ctrl_close(ctrl); + return; + } + buf[len] = '\0'; + + wpa_ctrl_close(ctrl); + + QString ifaces(buf); + QStringList lines = ifaces.split(QRegExp("\\n")); + for (QStringList::Iterator it = lines.begin(); + it != lines.end(); it++) { + QStringList arg = (*it).split(QChar('\t')); + if (arg.size() < 3) + continue; + QTreeWidgetItem *item = new QTreeWidgetItem(interfaceWidget); + if (!item) + break; + + item->setText(0, arg[0]); + item->setText(1, arg[1]); + item->setText(2, arg[2]); + } + + interfaceWidget->resizeColumnToContents(0); + interfaceWidget->resizeColumnToContents(1); + interfaceWidget->resizeColumnToContents(2); +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ +} + + +#ifdef CONFIG_NATIVE_WINDOWS +bool AddInterface::addRegistryInterface(const QString &ifname) +{ + HKEY hk, ihk; + LONG ret; + int id, tmp; + TCHAR name[10]; + DWORD val, i; + + ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX TEXT("\\interfaces"), + 0, KEY_ENUMERATE_SUB_KEYS | KEY_CREATE_SUB_KEY, + &hk); + if (ret != ERROR_SUCCESS) + return false; + + id = -1; + + for (i = 0; ; i++) { + TCHAR name[255]; + DWORD namelen; + + namelen = 255; + ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL, + NULL); + + if (ret == ERROR_NO_MORE_ITEMS) + break; + + if (ret != ERROR_SUCCESS) + break; + + if (namelen >= 255) + namelen = 255 - 1; + name[namelen] = '\0'; + +#ifdef UNICODE + QString s((QChar *) name, namelen); +#else /* UNICODE */ + QString s(name); +#endif /* UNICODE */ + tmp = s.toInt(); + if (tmp > id) + id = tmp; + } + + id += 1; + +#ifdef UNICODE + wsprintf(name, L"%04d", id); +#else /* UNICODE */ + os_snprintf(name, sizeof(name), "%04d", id); +#endif /* UNICODE */ + ret = RegCreateKeyEx(hk, name, 0, NULL, 0, KEY_WRITE, NULL, &ihk, + NULL); + RegCloseKey(hk); + if (ret != ERROR_SUCCESS) + return false; + +#ifdef UNICODE + RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ, + (LPBYTE) ifname.unicode(), + (ifname.length() + 1) * sizeof(TCHAR)); + +#else /* UNICODE */ + RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ, + (LPBYTE) ifname.toLocal8Bit(), ifname.length() + 1); +#endif /* UNICODE */ + RegSetValueEx(ihk, TEXT("config"), 0, REG_SZ, + (LPBYTE) TEXT("default"), 8 * sizeof(TCHAR)); + RegSetValueEx(ihk, TEXT("ctrl_interface"), 0, REG_SZ, + (LPBYTE) TEXT(""), 1 * sizeof(TCHAR)); + val = 1; + RegSetValueEx(ihk, TEXT("skip_on_error"), 0, REG_DWORD, (LPBYTE) &val, + sizeof(val)); + + RegCloseKey(ihk); + return true; +} +#endif /* CONFIG_NATIVE_WINDOWS */ + + +void AddInterface::interfaceSelected(QTreeWidgetItem *sel) +{ + if (!sel) + return; + +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + struct wpa_ctrl *ctrl; + int ret; + char buf[20], cmd[256]; + size_t len; + + /* + * INTERFACE_ADD TABTABTABTAB + * TAB + */ + snprintf(cmd, sizeof(cmd), + "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s", + sel->text(1).toLocal8Bit().constData(), + "default", + sel->text(0).toLocal8Bit().constData(), + "yes", "", ""); + cmd[sizeof(cmd) - 1] = '\0'; + + ctrl = wpa_ctrl_open(NULL); + if (ctrl == NULL) + return; + + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL); + wpa_ctrl_close(ctrl); + + if (ret < 0) { + QMessageBox::warning(this, "wpa_gui", + tr("Add interface command could not be " + "completed.")); + return; + } + + buf[len] = '\0'; + if (buf[0] != 'O' || buf[1] != 'K') { + QMessageBox::warning(this, "wpa_gui", + tr("Failed to add the interface.")); + return; + } + +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + +#ifdef CONFIG_NATIVE_WINDOWS + if (!addRegistryInterface(sel->text(1))) { + QMessageBox::information(this, "wpa_gui", + tr("Failed to add the interface into " + "registry.")); + } +#endif /* CONFIG_NATIVE_WINDOWS */ + + wpagui->selectAdapter(sel->text(1)); + close(); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/addinterface.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/addinterface.h index 332fc7100f572f9b9e9ddf094dc813521e609273..844fec3809e622802c232bfbd62c6e804444f98d 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/addinterface.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/addinterface.h @@ -1,39 +1,39 @@ -/* - * wpa_gui - AddInterface class - * Copyright (c) 2008, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef ADDINTERFACE_H -#define ADDINTERFACE_H - -#include - -#include -#include -#include - -class WpaGui; - -class AddInterface : public QDialog -{ - Q_OBJECT - -public: - AddInterface(WpaGui *_wpagui, QWidget *parent = 0); - -public slots: - virtual void interfaceSelected(QTreeWidgetItem *sel); - -private: - void addInterfaces(); - bool addRegistryInterface(const QString &ifname); - - QVBoxLayout *vboxLayout; - QTreeWidget *interfaceWidget; - WpaGui *wpagui; -}; - -#endif /* ADDINTERFACE_H */ +/* + * wpa_gui - AddInterface class + * Copyright (c) 2008, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef ADDINTERFACE_H +#define ADDINTERFACE_H + +#include + +#include +#include +#include + +class WpaGui; + +class AddInterface : public QDialog +{ + Q_OBJECT + +public: + AddInterface(WpaGui *_wpagui, QWidget *parent = 0); + +public slots: + virtual void interfaceSelected(QTreeWidgetItem *sel); + +private: + void addInterfaces(); + bool addRegistryInterface(const QString &ifname); + + QVBoxLayout *vboxLayout; + QTreeWidget *interfaceWidget; + WpaGui *wpagui; +}; + +#endif /* ADDINTERFACE_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp index 09145cd9d5874cd86c237167100c80a6f01af7d8..13b43f51c2d7f2ed17ae60b6ccd500926543dc6c 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp @@ -1,124 +1,124 @@ -/* - * wpa_gui - EventHistory class - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include -#include - -#include "eventhistory.h" - - -int EventListModel::rowCount(const QModelIndex &) const -{ - return msgList.count(); -} - - -int EventListModel::columnCount(const QModelIndex &) const -{ - return 2; -} - - -QVariant EventListModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (role == Qt::DisplayRole) - if (index.column() == 0) { - if (index.row() >= timeList.size()) - return QVariant(); - return timeList.at(index.row()); - } else { - if (index.row() >= msgList.size()) - return QVariant(); - return msgList.at(index.row()); - } - else - return QVariant(); -} - - -QVariant EventListModel::headerData(int section, Qt::Orientation orientation, - int role) const -{ - if (role != Qt::DisplayRole) - return QVariant(); - - if (orientation == Qt::Horizontal) { - switch (section) { - case 0: - return QString(tr("Timestamp")); - case 1: - return QString(tr("Message")); - default: - return QVariant(); - } - } else - return QString("%1").arg(section); -} - - -void EventListModel::addEvent(QString time, QString msg) -{ - beginInsertRows(QModelIndex(), msgList.size(), msgList.size() + 1); - timeList << time; - msgList << msg; - endInsertRows(); -} - - -EventHistory::EventHistory(QWidget *parent, const char *, bool, Qt::WindowFlags) - : QDialog(parent) -{ - setupUi(this); - - connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); - - eventListView->setItemsExpandable(false); - eventListView->setRootIsDecorated(false); - elm = new EventListModel(parent); - eventListView->setModel(elm); -} - - -EventHistory::~EventHistory() -{ - destroy(); - delete elm; -} - - -void EventHistory::languageChange() -{ - retranslateUi(this); -} - - -void EventHistory::addEvents(WpaMsgList msgs) -{ - WpaMsgList::iterator it; - for (it = msgs.begin(); it != msgs.end(); it++) - addEvent(*it); -} - - -void EventHistory::addEvent(WpaMsg msg) -{ - bool scroll = true; - - if (eventListView->verticalScrollBar()->value() < - eventListView->verticalScrollBar()->maximum()) - scroll = false; - - elm->addEvent(msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"), - msg.getMsg()); - - if (scroll) - eventListView->scrollToBottom(); -} +/* + * wpa_gui - EventHistory class + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include + +#include "eventhistory.h" + + +int EventListModel::rowCount(const QModelIndex &) const +{ + return msgList.count(); +} + + +int EventListModel::columnCount(const QModelIndex &) const +{ + return 2; +} + + +QVariant EventListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == Qt::DisplayRole) + if (index.column() == 0) { + if (index.row() >= timeList.size()) + return QVariant(); + return timeList.at(index.row()); + } else { + if (index.row() >= msgList.size()) + return QVariant(); + return msgList.at(index.row()); + } + else + return QVariant(); +} + + +QVariant EventListModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) { + switch (section) { + case 0: + return QString(tr("Timestamp")); + case 1: + return QString(tr("Message")); + default: + return QVariant(); + } + } else + return QString("%1").arg(section); +} + + +void EventListModel::addEvent(QString time, QString msg) +{ + beginInsertRows(QModelIndex(), msgList.size(), msgList.size() + 1); + timeList << time; + msgList << msg; + endInsertRows(); +} + + +EventHistory::EventHistory(QWidget *parent, const char *, bool, Qt::WindowFlags) + : QDialog(parent) +{ + setupUi(this); + + connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); + + eventListView->setItemsExpandable(false); + eventListView->setRootIsDecorated(false); + elm = new EventListModel(parent); + eventListView->setModel(elm); +} + + +EventHistory::~EventHistory() +{ + destroy(); + delete elm; +} + + +void EventHistory::languageChange() +{ + retranslateUi(this); +} + + +void EventHistory::addEvents(WpaMsgList msgs) +{ + WpaMsgList::iterator it; + for (it = msgs.begin(); it != msgs.end(); it++) + addEvent(*it); +} + + +void EventHistory::addEvent(WpaMsg msg) +{ + bool scroll = true; + + if (eventListView->verticalScrollBar()->value() < + eventListView->verticalScrollBar()->maximum()) + scroll = false; + + elm->addEvent(msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"), + msg.getMsg()); + + if (scroll) + eventListView->scrollToBottom(); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.h index afd7b63469a203de7c5d4ee893c46dba965c209a..fad508d7b2747eec526156b349c5308ff503c8fb 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.h @@ -1,57 +1,57 @@ -/* - * wpa_gui - EventHistory class - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef EVENTHISTORY_H -#define EVENTHISTORY_H - -#include -#include "ui_eventhistory.h" - - -class EventListModel : public QAbstractTableModel -{ - Q_OBJECT - -public: - EventListModel(QObject *parent = 0) - : QAbstractTableModel(parent) {} - - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - void addEvent(QString time, QString msg); - -private: - QStringList timeList; - QStringList msgList; -}; - - -class EventHistory : public QDialog, public Ui::EventHistory -{ - Q_OBJECT - -public: - EventHistory(QWidget *parent = 0, const char *name = 0, - bool modal = false, Qt::WindowFlags fl = 0); - ~EventHistory(); - -public slots: - virtual void addEvents(WpaMsgList msgs); - virtual void addEvent(WpaMsg msg); - -protected slots: - virtual void languageChange(); - -private: - EventListModel *elm; -}; - -#endif /* EVENTHISTORY_H */ +/* + * wpa_gui - EventHistory class + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef EVENTHISTORY_H +#define EVENTHISTORY_H + +#include +#include "ui_eventhistory.h" + + +class EventListModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + EventListModel(QObject *parent = 0) + : QAbstractTableModel(parent) {} + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + void addEvent(QString time, QString msg); + +private: + QStringList timeList; + QStringList msgList; +}; + + +class EventHistory : public QDialog, public Ui::EventHistory +{ + Q_OBJECT + +public: + EventHistory(QWidget *parent = 0, const char *name = 0, + bool modal = false, Qt::WindowFlags fl = 0); + ~EventHistory(); + +public slots: + virtual void addEvents(WpaMsgList msgs); + virtual void addEvent(WpaMsg msg); + +protected slots: + virtual void languageChange(); + +private: + EventListModel *elm; +}; + +#endif /* EVENTHISTORY_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.ui b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.ui index afe9149cfa0fd963bc034e06a42508ad11623460..fbe76efd954af417cb5f87264a3647b565393ff1 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.ui +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/eventhistory.ui @@ -1,61 +1,61 @@ - - EventHistory - - - - 0 - 0 - 533 - 285 - - - - Event history - - - - - - - 0 - 0 - - - - Qt::ScrollBarAlwaysOn - - - QAbstractItemView::NoSelection - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Close - - - - - - - - - wpamsg.h - - - - + + EventHistory + + + + 0 + 0 + 533 + 285 + + + + Event history + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + QAbstractItemView::NoSelection + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Close + + + + + + + + + wpamsg.h + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons.qrc b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons.qrc index dd72c7ef100815cc525be25854ee885ec35baf17..4875dfd07937b48771b808ca67bd43f57c877ef6 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons.qrc +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons.qrc @@ -1,9 +1,9 @@ - - - icons/wpa_gui.svg - icons/ap.svg - icons/laptop.svg - icons/group.svg - icons/invitation.svg - - + + + icons/wpa_gui.svg + icons/ap.svg + icons/laptop.svg + icons/group.svg + icons/invitation.svg + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/.gitignore b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/.gitignore index 8d772cc93884655b9736a449e1176459e33672da..6b0bae7e3226d0b412b14845162dd4e4bcf64b73 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/.gitignore +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/.gitignore @@ -1,2 +1,2 @@ -hicolor -pixmaps +hicolor +pixmaps diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/Makefile b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/Makefile index 88efc3c5b258f8c0c2482fb23bc136400a5fa797..52f368277fdd72b2dcadbe2f84f7c9ca6043cd0b 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/Makefile +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/Makefile @@ -1,37 +1,37 @@ -#!/usr/bin/make -f - -NAMES := wpa_gui ap laptop group invitation -SIZES := 16x16 22x22 32x32 48x48 64x64 128x128 -ICONS := $(addsuffix .png, $(foreach name, $(NAMES), $(foreach size, $(SIZES), $(size)/$(name)))) -ICONS += $(addsuffix .xpm, $(NAMES)) - -ifeq (1, $(shell which inkscape; echo $$?)) -$(error "No inkscape in PATH, it is required for exporting icons.") -else -ifeq (0, $(shell inkscape --without-gui 2>&1 > /dev/null; echo $$?)) -# Inkscape < 1.0 -INKSCAPE_GUI_FLAG := --without-gui -INKSCAPE_OUTPUT_FLAG := --export-png -else -# Inkscape >= 1.0 -INKSCAPE_GUI_FLAG := -INKSCAPE_OUTPUT_FLAG := --export-filename -endif -endif - -all: $(ICONS) - -%.png: - mkdir -p hicolor/$(word 1, $(subst /, ,$(@)))/apps/ - inkscape $(subst .png,.svg, $(word 2, $(subst /, , $(@)))) $(INKSCAPE_GUI_FLAG) \ - --export-width=$(word 1, $(subst x, , $(@))) \ - --export-height=$(word 2, $(subst x, , $(subst /, , $(@)))) \ - $(INKSCAPE_OUTPUT_FLAG)=hicolor/$(word 1, $(subst /, ,$(@)))/apps/$(word 2, $(subst /, , $@)) - -%.xpm: - mkdir -p pixmaps/ - convert hicolor/16x16/apps/$(@:.xpm=.png) pixmaps/$(@:.xpm=-16.xpm) - convert hicolor/32x32/apps/$(@:.xpm=.png) pixmaps/$@ - -clean: - $(RM) -r pixmaps hicolor +#!/usr/bin/make -f + +NAMES := wpa_gui ap laptop group invitation +SIZES := 16x16 22x22 32x32 48x48 64x64 128x128 +ICONS := $(addsuffix .png, $(foreach name, $(NAMES), $(foreach size, $(SIZES), $(size)/$(name)))) +ICONS += $(addsuffix .xpm, $(NAMES)) + +ifeq (1, $(shell which inkscape; echo $$?)) +$(error "No inkscape in PATH, it is required for exporting icons.") +else +ifeq (0, $(shell inkscape --without-gui 2>&1 > /dev/null; echo $$?)) +# Inkscape < 1.0 +INKSCAPE_GUI_FLAG := --without-gui +INKSCAPE_OUTPUT_FLAG := --export-png +else +# Inkscape >= 1.0 +INKSCAPE_GUI_FLAG := +INKSCAPE_OUTPUT_FLAG := --export-filename +endif +endif + +all: $(ICONS) + +%.png: + mkdir -p hicolor/$(word 1, $(subst /, ,$(@)))/apps/ + inkscape $(subst .png,.svg, $(word 2, $(subst /, , $(@)))) $(INKSCAPE_GUI_FLAG) \ + --export-width=$(word 1, $(subst x, , $(@))) \ + --export-height=$(word 2, $(subst x, , $(subst /, , $(@)))) \ + $(INKSCAPE_OUTPUT_FLAG)=hicolor/$(word 1, $(subst /, ,$(@)))/apps/$(word 2, $(subst /, , $@)) + +%.xpm: + mkdir -p pixmaps/ + convert hicolor/16x16/apps/$(@:.xpm=.png) pixmaps/$(@:.xpm=-16.xpm) + convert hicolor/32x32/apps/$(@:.xpm=.png) pixmaps/$@ + +clean: + $(RM) -r pixmaps hicolor diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/README b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/README index 39532389766e2d6e1911f3661f92983bd53e640f..09c0e7f4069e51b95e96507053a238fdc3deb681 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/README +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/README @@ -1,74 +1,74 @@ -wpa_gui icon files - -To convert the svg icons to other formats, make sure inkscape and imagemagick -are installed and use `make' to create various sized png and xpm icons. - - -wpa_gui.svg ------------ - -Copyright (c) 2008 Bernard Gray - -The wpa_gui icon is licensed under the GPL version 2. Alternatively, the icon -may be distributed under the terms of BSD license. - - -ap.svg ------- - -mystica_Wireless_Router.svg - -http://openclipart.org/media/files/mystica/8390 -Wireless Router -by: mystica -last change: April 20, 2008 10:32 pm (File added) -date: April 20, 2008 10:31 pm -license: PD - - -laptop.svg ----------- - -metalmarious_Laptop.svg - -http://openclipart.org/media/files/metalmarious/4056 -Laptop -by: metalmarious -last change: May 18, 2008 07:04 pm (File added) -date: August 27, 2007 04:44 am -license: PD - - -group.svg ---------- - -http://www.openclipart.org/detail/25428 -http://www.openclipart.org/people/Anonymous/Anonymous_Network.svg -Uploader: - Anonymous -Drawn by: - Andrew Fitzsimon / Anonymous -Created: - 2009-04-29 04:07:37 -Description: - A network icon by Andrew Fitzsimon. Etiquette Icon set. - From 0.18 OCAL database. - -Public Domain - - - -invitation.svg --------------- - -http://www.openclipart.org/detail/974 -http://www.openclipart.org/people/jean_victor_balin/jean_victor_balin_unknown_green.svg -Uploader: - jean_victor_balin -Drawn by: - jean_victor_balin -Created: - 2006-10-27 02:12:13 -Description: - -Public Domain +wpa_gui icon files + +To convert the svg icons to other formats, make sure inkscape and imagemagick +are installed and use `make' to create various sized png and xpm icons. + + +wpa_gui.svg +----------- + +Copyright (c) 2008 Bernard Gray + +The wpa_gui icon is licensed under the GPL version 2. Alternatively, the icon +may be distributed under the terms of BSD license. + + +ap.svg +------ + +mystica_Wireless_Router.svg + +http://openclipart.org/media/files/mystica/8390 +Wireless Router +by: mystica +last change: April 20, 2008 10:32 pm (File added) +date: April 20, 2008 10:31 pm +license: PD + + +laptop.svg +---------- + +metalmarious_Laptop.svg + +http://openclipart.org/media/files/metalmarious/4056 +Laptop +by: metalmarious +last change: May 18, 2008 07:04 pm (File added) +date: August 27, 2007 04:44 am +license: PD + + +group.svg +--------- + +http://www.openclipart.org/detail/25428 +http://www.openclipart.org/people/Anonymous/Anonymous_Network.svg +Uploader: + Anonymous +Drawn by: + Andrew Fitzsimon / Anonymous +Created: + 2009-04-29 04:07:37 +Description: + A network icon by Andrew Fitzsimon. Etiquette Icon set. + From 0.18 OCAL database. + +Public Domain + + + +invitation.svg +-------------- + +http://www.openclipart.org/detail/974 +http://www.openclipart.org/people/jean_victor_balin/jean_victor_balin_unknown_green.svg +Uploader: + jean_victor_balin +Drawn by: + jean_victor_balin +Created: + 2006-10-27 02:12:13 +Description: + +Public Domain diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/ap.svg b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/ap.svg index 51cc8ce646ad6bbf9063afb324d568365d3afe01..e3765d19acc22223174a4b4c0836afa31ee2f9b0 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/ap.svg +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/ap.svg @@ -1,832 +1,832 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/group.svg b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/group.svg index 4ea959b5779fd017f6a55b18c913b4e7733e4c72..f08279253c67dd16ac261d1a80fb544885bf0711 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/group.svg +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/group.svg @@ -1,616 +1,616 @@ - - - - - - - Etiquette Icons - - - - hash - - filesystem - computer - icons - - - - - Andy Fitzsimon - - - - - Andy Fitzsimon - - - - - Andy Fitzsimon - - - - image/svg+xml - - - en - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + Etiquette Icons + + + + hash + + filesystem + computer + icons + + + + + Andy Fitzsimon + + + + + Andy Fitzsimon + + + + + Andy Fitzsimon + + + + image/svg+xml + + + en + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg index 1a02d1327eec253884d699c9cbf9337e061342f9..613984ea39479a82e593c9e2adfe2bb81e7ecb4e 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/invitation.svg @@ -1,374 +1,374 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Green Unknown - 2005-11-01 - - - Jean-Victor Balin - - - jean.victor.balin@gmail.com - - - - icon - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Green Unknown + 2005-11-01 + + + Jean-Victor Balin + + + jean.victor.balin@gmail.com + + + + icon + + + + + + + + + + + + + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg index 06235f02d5a38a97ab58d4f57d510d19f726df89..3eb6eab1ab32805fccb8be94f60c25a72d67c53f 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/laptop.svg @@ -1,1568 +1,1568 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg index b3abf0a288d8936a46c1a8a4486e5ca202a54f5c..47149d6c1afdfcb41055c11bb8c2ca6b526b1f69 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg @@ -1,256 +1,256 @@ - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons_png.qrc b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons_png.qrc index 9a30b7f560bab93fe5c9ca7d9ae215c92b228ba7..16bd2265d90fc76f2bc8ccd2d5074c03abb51ad0 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons_png.qrc +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/icons_png.qrc @@ -1,9 +1,9 @@ - - - icons/hicolor/16x16/apps/wpa_gui.png - icons/hicolor/32x32/apps/ap.png - icons/hicolor/32x32/apps/laptop.png - icons/hicolor/32x32/apps/group.png - icons/hicolor/32x32/apps/invitation.png - - + + + icons/hicolor/16x16/apps/wpa_gui.png + icons/hicolor/32x32/apps/ap.png + icons/hicolor/32x32/apps/laptop.png + icons/hicolor/32x32/apps/group.png + icons/hicolor/32x32/apps/invitation.png + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/lang/.gitignore b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/lang/.gitignore index 8df47d550c7d4179fffb1e411b4a4066d32d11f1..e7b008137d99b18fd0adaaaaf55b5a07ec8769a1 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/lang/.gitignore +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/lang/.gitignore @@ -1 +1 @@ -*.qm +*.qm diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts index d7a9c89fa18a115e718ea1eb63a8d3b5d73b9e54..e6aeff8e99d714813ed765bfb0a74ae803aff676 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/lang/wpa_gui_de.ts @@ -1,1262 +1,1262 @@ - - - - - AddInterface - - - Select network interface to add - Wähle die Netzwerkschnittstelle zum hinzufügen aus - - - - driver - Treiber - - - - interface - Schnittstelle - - - - description - Beschreibung - - - - Add interface command could not be completed. - Das Schnittstellen hinzufügen Kommando konnte nicht abgeschlossen werden. - - - - Failed to add the interface. - Fehler beim hinzufügen der Schnittstelle. - - - - Failed to add the interface into registry. - Fehler beim hinzufügen der Schnittstelle in die Registry. - - - - ErrorMsg - - - wpa_gui error - wpa_gui Fehler - - - - EventHistory - - - Event history - Ereignis Historie - - - - Close - Schließen - - - - EventListModel - - - Timestamp - Zeit - - - - Message - Meldung - - - - NetworkConfig - - - NetworkConfig - - - - - Cancel - Abbrechen - - - - SSID - SSID - - - - Network name (Service Set IDentifier) - Netzwerkname (Service Set IDentifier) - - - - Authentication - Authentifizierung - - - - Plaintext (open / no authentication) - Plaintext (offen / keine Authentifizierung) - - - - Static WEP (no authentication) - Static WEP (keine Authentifizierung) - - - - Static WEP (Shared Key authentication) - - - - - IEEE 802.1X - - - - - WPA-Personal (PSK) - - - - - WPA-Enterprise (EAP) - - - - - WPA2-Personal (PSK) - - - - - WPA2-Enterprise (EAP) - - - - - Encryption - Verschlüsselung - - - - None - Keine - - - - WEP - - - - - TKIP - - - - - CCMP - - - - - PSK - - - - - WPA/WPA2 pre-shared key or passphrase - WPA/WPA2 Pre-Shared Key oder Passphrase - - - - EAP method - EAP Verfahren - - - - Identity - Identität - - - - Username/Identity for EAP methods - Nutzername/Identitär für die EAP Verfahren - - - - Password - Passwort - - - - Password for EAP methods - Passwort für die EAP Verfahren - - - - CA certificate - CA Zertifikat - - - - WEP keys - WEP Schlüssel - - - - key 0 - Schlüssel 0 - - - - key 1 - Schlüssel 1 - - - - key 3 - Schlüssel 3 - - - - key 2 - Schlüssel 2 - - - - Optional Settings - Optionale Einstellungen - - - - Network Identification String - Netzwerk Indentifikations Zeichenfolge - - - - Network Priority - Netzwerk Priorität - - - - IDString - - - - - Priority - Priorität - - - - Inner auth - Geheime Auth - - - - Add - Hinzufügen - - - - Remove - Entfernen - - - - WPS - - - - - WPA Pre-Shared Key Error - WPA Pre Shared Key Fehler - - - - WPA-PSK requires a passphrase of 8 to 63 characters -or 64 hex digit PSK - WPA PSK benötigt ein Passphrase mit 8 bis 63 Zeichen -oder 64 hexadezimal stelligen PSK - - - - Network ID Error - Netzwerk ID Fehler - - - - Network ID String contains non-word characters. -It must be a simple string, without spaces, containing -only characters in this range: [A-Za-z0-9_-] - - Netzwerk ID Zeichnfolge beinhaltet ungültige Zeichen. -Es muss eine einfache Zeichnfolge aus [A-Za-z0-9_] ohne -Leerzeichen sein - - - - - Failed to add network to wpa_supplicant -configuration. - Hinzufügen des Netzwerks in die wpa_supplicant -Konfiguration fehlgeschlagen. - - - - Failed to enable network in wpa_supplicant -configuration. - Aktivieren des Netzwerks in der wpa_supplicant -Konfiguration fehlgeschlagen. - - - - This will permanently remove the network -from the configuration. Do you really want -to remove this network? - Dies wird das Netzwerk permanent aus -der Konfiguration entfernen. Möchtest du -das Netzwerk wirklich entfernen? - - - - Yes - Ja - - - - No - Nein - - - - Failed to remove network from wpa_supplicant -configuration. - Entfernen des Netzwerks aus der wpa_supplicant -Konfiguration fehlgeschlagen. - - - - Peers - - - Peers - - - - - Associated station - Verbundene Stationen - - - - AP - - - - - WPS AP - - - - - WPS PIN needed - WPS PIN wird benötigt - - - - ER: WPS AP - - - - - ER: WPS AP (Unconfigured) - ER: WPS AP (nicht konfiguriert) - - - - ER: WPS Enrollee - - - - - WPS Enrollee - - - - - Enter WPS PIN - WPS PIN Eingabe - - - - Connect (PBC) - Verbinden (PBC) - - - - Enroll (PBC) - Anmelden (PBC) - - - - Learn Configuration - Konfiguration lernen - - - - Properties - Eigenschaften - - - - Refresh - Aktualisieren - - - - PIN: - - - - - PIN for - Pin für - - - - Failed to set the WPS PIN. - Setzten des WPS PIN fehlgeschlagen. - - - - Peer Properties - Peer Eigenschaften - - - - Name: - - - - - Address: - - - - - UUID: - - - - - Primary Device Type: - Primärer Geräte Typ: - - - - SSID: - - - - - Configuration Methods: - Konfigurationsverfahren: - - - - [USBA] - - - - - [Ethernet] - - - - - [Label] - - - - - [Display] - - - - - [Ext. NFC Token] - - - - - [Int. NFC Token] - - - - - [NFC Interface] - - - - - [Push Button] - - - - - [Keypad] - - - - - Device Password ID: - Geräte Passwort ID: - - - - (Default PIN) - - - - - (User-specified PIN) - - - - - (Machine-specified PIN) - - - - - (Rekey) - - - - - (Push Button) - - - - - (Registrar-specified) - - - - - Failed to start WPS PBC. - Starten von WPS PBC fehlgeschlagen. - - - - AP PIN: - - - - - AP PIN for - AP PIN für - - - - Failed to start learning AP configuration. - Fehler beim erkennen der AP Konfiguration. - - - - ScanResults - - - Scan results - Scan Ergebnisse - - - - SSID - - - - - BSSID - - - - - frequency - Frequenz - - - - signal - Signal - - - - flags - Flags - - - - Scan - Scannen - - - - Close - Schließen - - - - UserDataRequest - - - Authentication credentials required - Authentifzierungs Beglaubigung nötig - - - - &OK - - - - - &Cancel - - - - - Password: - Passwort: - - - - New password: - Neues Passwort: - - - - Identity: - Identität: - - - - Private key passphrase: - Privater Key Passphrase: - - - - WpaGui - - - wpa_gui - - - - - Adapter: - - - - - Network: - Netzwerk: - - - - Current Status - Aktueller Status - - - - - Status: - - - - - Last message: - Letzte Meldung: - - - - Authentication: - Authentifizierung: - - - - Encryption: - Verschlüsselung: - - - - SSID: - - - - - BSSID: - - - - - IP address: - IP Adresse: - - - - Connect - Verbinden - - - - Disconnect - Trennen - - - - - Scan - Scannen - - - - Manage Networks - Netzwerke verwalten - - - - Enabled - Aktiviert - - - - Edit - Bearbeiten - - - - Remove - Entfernen - - - - Disabled - Deaktiviert - - - - Add - Hinzufügen - - - - WPS - - - - - PBC - push button - PBC - Taste - - - - Generate PIN - PIN erzeugen - - - - PIN: - - - - - Use AP PIN - AP PIN verwenden - - - - AP PIN: - - - - - &File - &Datei - - - - &Network - &Netzwerk - - - - &Help - &Hilfe - - - - Event &History - Ereignis &Historie - - - - &Save Configuration - Konfiguration &Speichern - - - - Ctrl+S - - - - - E&xit - &Beenden - - - - Ctrl+Q - - - - - &Add - &Hinzufügen - - - - &Edit - &Bearbeiten - - - - &Remove - &Entfernen - - - - E&nable All - Alle &aktivieren - - - - &Disable All - Alle &deaktivieren - - - - Re&move All - Alle &entfernen - - - - &Contents... - &Inhalt... - - - - &Index... - - - - - &About - &Über - - - - &Wi-Fi Protected Setup - - - - - &Peers - - - - - Stop Service - Dienst stoppen - - - - Start Service - Dienst starten - - - - Add Interface - Schnittstelle hinzufügen - - - - connecting to wpa_supplicant - Verbindungsaufbau zu wpa_supplicant - - - - wpa_supplicant service is not running. -Do you want to start it? - wpa_supplicant ist nicht gestartet. -Möchtest du ihn starten? - - - - Disconnected - Getrennt - - - - Inactive - Inaktiv - - - - Scanning - Scannen - - - - Authenticating - Authentifizieren - - - - Associating - Assoziieren - - - - Associated - Assoziiert - - - - 4-Way Handshake - 4-Wege Handshake - - - - Group Handshake - Gruppen Handshake - - - - Completed - Abgeschlossen - - - - Unknown - Unbekannt - - - - Could not get status from wpa_supplicant - Status konnte nicht von wpa_supplicant abgerufen werden - - - - No network interfaces in use. -Would you like to add one? - Es ist keine Netzwerkschnittstelle in verwendung. -Möchtest du eine hinzufügen? - - - - - - - Select any network - Wähle beliebiges Netzwerk - - - - Disconnected from network. - Getrennt vom Netzwerk. - - - - Connection to network established. - Verbindung zum Netzwerk wurde aufgebaut. - - - - - WPS AP in active PBC mode found - WPS AP im aktiven PBC Modus gefunden - - - - Press the PBC button on the screen to start registration - Drücke den PBC Knopf auf dem Bildschirm um die Registrierung zu starten - - - - WPS AP with recently selected registrar - WPS AP mit kürzlich ausgewähltem Registrator - - - - WPS AP detected - WPS AP erkannt - - - - PBC mode overlap detected - PBC Modus Overlap erkannt - - - - More than one AP is currently in active WPS PBC mode. Wait couple of minutes and try again - Mehr als ein AP ist momentan im aktiven WPS PBC Modus. Versuch es in ein paar Minuten nochmal - - - - Network configuration received - Netzwerk Konfiguration empfangen - - - - Registration started - Registrierung gestartet - - - - Registrar does not yet know PIN - Registrator kennt den PIN noch nicht - - - - Registration failed - Registrierung fehlgeschlagen - - - - Registration succeeded - Registrierung erfolgreich - - - - - No Networks - Keine Netzwerke - - - - There are no networks to edit. - - Keine Netzwerke zum bearbeiten. - - - - - - Select A Network - Wähle ein Netzwerk - - - - Select a network from the list to edit it. - - Wähle ein Netzwerk aus der Liste zum bearbeiten. - - - - - There are no networks to remove. - - Es sind keine Netzwerke zum entfernen vorhanden. - - - - - Select a network from the list to remove it. - - Wähle ein Netzwerk aus der Liste zum entfernen. - - - - - Failed to save configuration - Speichern der Konfiguration fehlgeschlagen - - - - The configuration could not be saved. - -The update_config=1 configuration option -must be used for configuration saving to -be permitted. - - Die Konfiguration konnte nicht gespeichert werden. - -Die Einstellung update_config=1 muss gesetzt sein, -damit Konfigurationen gespeichert werden können. - - - - - Saved configuration - Konfiguration gespeichert - - - - The current configuration was saved. - - Die aktuelle Konfiguration wurde gespeichert. - - - - - - wpa_supplicant user interface - - wpa_supplicant Benutzerschnittstelle - - - - &Disconnect - &Trennen - - - - Re&connect - &Wiederverbinden - - - - &Event History - &Ereignis Historie - - - - Scan &Results - Scan E&rgebnisse - - - - S&tatus - - - - - &Show Window - &Fenster anzeigen - - - - &Hide Window - &Fenster ausblenden - - - - &Quit - &Beenden - - - - will keep running in the system tray. - wird weiterhin in der System Ablage laufen. - - - - systray - System Ablage - - - - The program will keep running in the system tray. - Das Programm wird weiterhin in der System Ablage laufen. - - - - Press the push button on the AP to start the PBC mode. - Drücke die Taste am AP um den PBC Modus zu starten. - - - - If you have not yet done so, press the push button on the AP to start the PBC mode. - Wenn Sie es noch nicht getan haben, so drücken Sie die Taste am AP um den PBC Modus zu starten. - - - - - Waiting for Registrar - Warte auf Registrator - - - - Enter the generated PIN into the Registrar (either the internal one in the AP or an external one). - Geben Sie den generierten PIN in der Registrierungsstelle ein (entweder der interne oder der externe im AP). - - - - WPS AP selected from scan results - WPS AP ausgewählt aus Scan Ergebnissen - - - - If you want to use an AP device PIN, e.g., from a label in the device, enter the eight digit AP PIN and click Use AP PIN button. - Wenn Sie einen AP Geräte PIN verwenden möchten, z.B.: von einem Aufkleber am Gerät, geben Sie denn acht stelligen AP PIN ein und klicken Sie auf den AP PIN Knopf. - - - - Waiting for AP/Enrollee - Warte auf AP/Bewerber - - - - Connected to the network - Verbunden zum Netzwerk - - - - Stopped - Gestoppt - - - - - OpenSCManager failed - OpenSCManager fehlgeschlagen - - - - - OpenService failed - OpenService fehlgeschlagen - - - - Failed to start wpa_supplicant service - Starten des wpa_supplicant Dienstes fehlgeschlagen - - - - Failed to stop wpa_supplicant service - Stoppen des wpa_supplicant Dienstes fehlgeschlagen - - - OpenSCManager failed: %d - - OpenSCManager fehlgeschlagen: %d - - - - OpenService failed: %d - - - OpenService fehlgeschlagen: %d - - - - - + + + + + AddInterface + + + Select network interface to add + Wähle die Netzwerkschnittstelle zum hinzufügen aus + + + + driver + Treiber + + + + interface + Schnittstelle + + + + description + Beschreibung + + + + Add interface command could not be completed. + Das Schnittstellen hinzufügen Kommando konnte nicht abgeschlossen werden. + + + + Failed to add the interface. + Fehler beim hinzufügen der Schnittstelle. + + + + Failed to add the interface into registry. + Fehler beim hinzufügen der Schnittstelle in die Registry. + + + + ErrorMsg + + + wpa_gui error + wpa_gui Fehler + + + + EventHistory + + + Event history + Ereignis Historie + + + + Close + Schließen + + + + EventListModel + + + Timestamp + Zeit + + + + Message + Meldung + + + + NetworkConfig + + + NetworkConfig + + + + + Cancel + Abbrechen + + + + SSID + SSID + + + + Network name (Service Set IDentifier) + Netzwerkname (Service Set IDentifier) + + + + Authentication + Authentifizierung + + + + Plaintext (open / no authentication) + Plaintext (offen / keine Authentifizierung) + + + + Static WEP (no authentication) + Static WEP (keine Authentifizierung) + + + + Static WEP (Shared Key authentication) + + + + + IEEE 802.1X + + + + + WPA-Personal (PSK) + + + + + WPA-Enterprise (EAP) + + + + + WPA2-Personal (PSK) + + + + + WPA2-Enterprise (EAP) + + + + + Encryption + Verschlüsselung + + + + None + Keine + + + + WEP + + + + + TKIP + + + + + CCMP + + + + + PSK + + + + + WPA/WPA2 pre-shared key or passphrase + WPA/WPA2 Pre-Shared Key oder Passphrase + + + + EAP method + EAP Verfahren + + + + Identity + Identität + + + + Username/Identity for EAP methods + Nutzername/Identitär für die EAP Verfahren + + + + Password + Passwort + + + + Password for EAP methods + Passwort für die EAP Verfahren + + + + CA certificate + CA Zertifikat + + + + WEP keys + WEP Schlüssel + + + + key 0 + Schlüssel 0 + + + + key 1 + Schlüssel 1 + + + + key 3 + Schlüssel 3 + + + + key 2 + Schlüssel 2 + + + + Optional Settings + Optionale Einstellungen + + + + Network Identification String + Netzwerk Indentifikations Zeichenfolge + + + + Network Priority + Netzwerk Priorität + + + + IDString + + + + + Priority + Priorität + + + + Inner auth + Geheime Auth + + + + Add + Hinzufügen + + + + Remove + Entfernen + + + + WPS + + + + + WPA Pre-Shared Key Error + WPA Pre Shared Key Fehler + + + + WPA-PSK requires a passphrase of 8 to 63 characters +or 64 hex digit PSK + WPA PSK benötigt ein Passphrase mit 8 bis 63 Zeichen +oder 64 hexadezimal stelligen PSK + + + + Network ID Error + Netzwerk ID Fehler + + + + Network ID String contains non-word characters. +It must be a simple string, without spaces, containing +only characters in this range: [A-Za-z0-9_-] + + Netzwerk ID Zeichnfolge beinhaltet ungültige Zeichen. +Es muss eine einfache Zeichnfolge aus [A-Za-z0-9_] ohne +Leerzeichen sein + + + + + Failed to add network to wpa_supplicant +configuration. + Hinzufügen des Netzwerks in die wpa_supplicant +Konfiguration fehlgeschlagen. + + + + Failed to enable network in wpa_supplicant +configuration. + Aktivieren des Netzwerks in der wpa_supplicant +Konfiguration fehlgeschlagen. + + + + This will permanently remove the network +from the configuration. Do you really want +to remove this network? + Dies wird das Netzwerk permanent aus +der Konfiguration entfernen. Möchtest du +das Netzwerk wirklich entfernen? + + + + Yes + Ja + + + + No + Nein + + + + Failed to remove network from wpa_supplicant +configuration. + Entfernen des Netzwerks aus der wpa_supplicant +Konfiguration fehlgeschlagen. + + + + Peers + + + Peers + + + + + Associated station + Verbundene Stationen + + + + AP + + + + + WPS AP + + + + + WPS PIN needed + WPS PIN wird benötigt + + + + ER: WPS AP + + + + + ER: WPS AP (Unconfigured) + ER: WPS AP (nicht konfiguriert) + + + + ER: WPS Enrollee + + + + + WPS Enrollee + + + + + Enter WPS PIN + WPS PIN Eingabe + + + + Connect (PBC) + Verbinden (PBC) + + + + Enroll (PBC) + Anmelden (PBC) + + + + Learn Configuration + Konfiguration lernen + + + + Properties + Eigenschaften + + + + Refresh + Aktualisieren + + + + PIN: + + + + + PIN for + Pin für + + + + Failed to set the WPS PIN. + Setzten des WPS PIN fehlgeschlagen. + + + + Peer Properties + Peer Eigenschaften + + + + Name: + + + + + Address: + + + + + UUID: + + + + + Primary Device Type: + Primärer Geräte Typ: + + + + SSID: + + + + + Configuration Methods: + Konfigurationsverfahren: + + + + [USBA] + + + + + [Ethernet] + + + + + [Label] + + + + + [Display] + + + + + [Ext. NFC Token] + + + + + [Int. NFC Token] + + + + + [NFC Interface] + + + + + [Push Button] + + + + + [Keypad] + + + + + Device Password ID: + Geräte Passwort ID: + + + + (Default PIN) + + + + + (User-specified PIN) + + + + + (Machine-specified PIN) + + + + + (Rekey) + + + + + (Push Button) + + + + + (Registrar-specified) + + + + + Failed to start WPS PBC. + Starten von WPS PBC fehlgeschlagen. + + + + AP PIN: + + + + + AP PIN for + AP PIN für + + + + Failed to start learning AP configuration. + Fehler beim erkennen der AP Konfiguration. + + + + ScanResults + + + Scan results + Scan Ergebnisse + + + + SSID + + + + + BSSID + + + + + frequency + Frequenz + + + + signal + Signal + + + + flags + Flags + + + + Scan + Scannen + + + + Close + Schließen + + + + UserDataRequest + + + Authentication credentials required + Authentifzierungs Beglaubigung nötig + + + + &OK + + + + + &Cancel + + + + + Password: + Passwort: + + + + New password: + Neues Passwort: + + + + Identity: + Identität: + + + + Private key passphrase: + Privater Key Passphrase: + + + + WpaGui + + + wpa_gui + + + + + Adapter: + + + + + Network: + Netzwerk: + + + + Current Status + Aktueller Status + + + + + Status: + + + + + Last message: + Letzte Meldung: + + + + Authentication: + Authentifizierung: + + + + Encryption: + Verschlüsselung: + + + + SSID: + + + + + BSSID: + + + + + IP address: + IP Adresse: + + + + Connect + Verbinden + + + + Disconnect + Trennen + + + + + Scan + Scannen + + + + Manage Networks + Netzwerke verwalten + + + + Enabled + Aktiviert + + + + Edit + Bearbeiten + + + + Remove + Entfernen + + + + Disabled + Deaktiviert + + + + Add + Hinzufügen + + + + WPS + + + + + PBC - push button + PBC - Taste + + + + Generate PIN + PIN erzeugen + + + + PIN: + + + + + Use AP PIN + AP PIN verwenden + + + + AP PIN: + + + + + &File + &Datei + + + + &Network + &Netzwerk + + + + &Help + &Hilfe + + + + Event &History + Ereignis &Historie + + + + &Save Configuration + Konfiguration &Speichern + + + + Ctrl+S + + + + + E&xit + &Beenden + + + + Ctrl+Q + + + + + &Add + &Hinzufügen + + + + &Edit + &Bearbeiten + + + + &Remove + &Entfernen + + + + E&nable All + Alle &aktivieren + + + + &Disable All + Alle &deaktivieren + + + + Re&move All + Alle &entfernen + + + + &Contents... + &Inhalt... + + + + &Index... + + + + + &About + &Über + + + + &Wi-Fi Protected Setup + + + + + &Peers + + + + + Stop Service + Dienst stoppen + + + + Start Service + Dienst starten + + + + Add Interface + Schnittstelle hinzufügen + + + + connecting to wpa_supplicant + Verbindungsaufbau zu wpa_supplicant + + + + wpa_supplicant service is not running. +Do you want to start it? + wpa_supplicant ist nicht gestartet. +Möchtest du ihn starten? + + + + Disconnected + Getrennt + + + + Inactive + Inaktiv + + + + Scanning + Scannen + + + + Authenticating + Authentifizieren + + + + Associating + Assoziieren + + + + Associated + Assoziiert + + + + 4-Way Handshake + 4-Wege Handshake + + + + Group Handshake + Gruppen Handshake + + + + Completed + Abgeschlossen + + + + Unknown + Unbekannt + + + + Could not get status from wpa_supplicant + Status konnte nicht von wpa_supplicant abgerufen werden + + + + No network interfaces in use. +Would you like to add one? + Es ist keine Netzwerkschnittstelle in verwendung. +Möchtest du eine hinzufügen? + + + + + + + Select any network + Wähle beliebiges Netzwerk + + + + Disconnected from network. + Getrennt vom Netzwerk. + + + + Connection to network established. + Verbindung zum Netzwerk wurde aufgebaut. + + + + + WPS AP in active PBC mode found + WPS AP im aktiven PBC Modus gefunden + + + + Press the PBC button on the screen to start registration + Drücke den PBC Knopf auf dem Bildschirm um die Registrierung zu starten + + + + WPS AP with recently selected registrar + WPS AP mit kürzlich ausgewähltem Registrator + + + + WPS AP detected + WPS AP erkannt + + + + PBC mode overlap detected + PBC Modus Overlap erkannt + + + + More than one AP is currently in active WPS PBC mode. Wait couple of minutes and try again + Mehr als ein AP ist momentan im aktiven WPS PBC Modus. Versuch es in ein paar Minuten nochmal + + + + Network configuration received + Netzwerk Konfiguration empfangen + + + + Registration started + Registrierung gestartet + + + + Registrar does not yet know PIN + Registrator kennt den PIN noch nicht + + + + Registration failed + Registrierung fehlgeschlagen + + + + Registration succeeded + Registrierung erfolgreich + + + + + No Networks + Keine Netzwerke + + + + There are no networks to edit. + + Keine Netzwerke zum bearbeiten. + + + + + + Select A Network + Wähle ein Netzwerk + + + + Select a network from the list to edit it. + + Wähle ein Netzwerk aus der Liste zum bearbeiten. + + + + + There are no networks to remove. + + Es sind keine Netzwerke zum entfernen vorhanden. + + + + + Select a network from the list to remove it. + + Wähle ein Netzwerk aus der Liste zum entfernen. + + + + + Failed to save configuration + Speichern der Konfiguration fehlgeschlagen + + + + The configuration could not be saved. + +The update_config=1 configuration option +must be used for configuration saving to +be permitted. + + Die Konfiguration konnte nicht gespeichert werden. + +Die Einstellung update_config=1 muss gesetzt sein, +damit Konfigurationen gespeichert werden können. + + + + + Saved configuration + Konfiguration gespeichert + + + + The current configuration was saved. + + Die aktuelle Konfiguration wurde gespeichert. + + + + + - wpa_supplicant user interface + - wpa_supplicant Benutzerschnittstelle + + + + &Disconnect + &Trennen + + + + Re&connect + &Wiederverbinden + + + + &Event History + &Ereignis Historie + + + + Scan &Results + Scan E&rgebnisse + + + + S&tatus + + + + + &Show Window + &Fenster anzeigen + + + + &Hide Window + &Fenster ausblenden + + + + &Quit + &Beenden + + + + will keep running in the system tray. + wird weiterhin in der System Ablage laufen. + + + + systray + System Ablage + + + + The program will keep running in the system tray. + Das Programm wird weiterhin in der System Ablage laufen. + + + + Press the push button on the AP to start the PBC mode. + Drücke die Taste am AP um den PBC Modus zu starten. + + + + If you have not yet done so, press the push button on the AP to start the PBC mode. + Wenn Sie es noch nicht getan haben, so drücken Sie die Taste am AP um den PBC Modus zu starten. + + + + + Waiting for Registrar + Warte auf Registrator + + + + Enter the generated PIN into the Registrar (either the internal one in the AP or an external one). + Geben Sie den generierten PIN in der Registrierungsstelle ein (entweder der interne oder der externe im AP). + + + + WPS AP selected from scan results + WPS AP ausgewählt aus Scan Ergebnissen + + + + If you want to use an AP device PIN, e.g., from a label in the device, enter the eight digit AP PIN and click Use AP PIN button. + Wenn Sie einen AP Geräte PIN verwenden möchten, z.B.: von einem Aufkleber am Gerät, geben Sie denn acht stelligen AP PIN ein und klicken Sie auf den AP PIN Knopf. + + + + Waiting for AP/Enrollee + Warte auf AP/Bewerber + + + + Connected to the network + Verbunden zum Netzwerk + + + + Stopped + Gestoppt + + + + + OpenSCManager failed + OpenSCManager fehlgeschlagen + + + + + OpenService failed + OpenService fehlgeschlagen + + + + Failed to start wpa_supplicant service + Starten des wpa_supplicant Dienstes fehlgeschlagen + + + + Failed to stop wpa_supplicant service + Stoppen des wpa_supplicant Dienstes fehlgeschlagen + + + OpenSCManager failed: %d + + OpenSCManager fehlgeschlagen: %d + + + + OpenService failed: %d + + + OpenService fehlgeschlagen: %d + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/main.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/main.cpp index bbd45c6e1d28dc9e4848875694b3bf3b63ee5398..7264c911a4218e0031f51205545b5ae5a57db62f 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/main.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/main.cpp @@ -1,67 +1,67 @@ -/* - * wpa_gui - Application startup - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifdef CONFIG_NATIVE_WINDOWS -#include -#endif /* CONFIG_NATIVE_WINDOWS */ -#include -#include -#include -#include "wpagui.h" - -WpaGuiApp::WpaGuiApp(int &argc, char **argv) : - QApplication(argc, argv), - argc(argc), - argv(argv) -{ - w = NULL; -} - -#if !defined(QT_NO_SESSIONMANAGER) && QT_VERSION < 0x050000 -void WpaGuiApp::saveState(QSessionManager &manager) -{ - QApplication::saveState(manager); - w->saveState(); -} -#endif - - -int main(int argc, char *argv[]) -{ - WpaGuiApp app(argc, argv); - QTranslator translator; - QString locale; - QString resourceDir; - int ret; - - locale = QLocale::system().name(); - resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); - if (!translator.load("wpa_gui_" + locale, resourceDir)) - translator.load("wpa_gui_" + locale, "lang"); - app.installTranslator(&translator); - - WpaGui w(&app); - -#ifdef CONFIG_NATIVE_WINDOWS - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { - /* printf("Could not find a usable WinSock.dll\n"); */ - return -1; - } -#endif /* CONFIG_NATIVE_WINDOWS */ - - app.w = &w; - - ret = app.exec(); - -#ifdef CONFIG_NATIVE_WINDOWS - WSACleanup(); -#endif /* CONFIG_NATIVE_WINDOWS */ - - return ret; -} +/* + * wpa_gui - Application startup + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifdef CONFIG_NATIVE_WINDOWS +#include +#endif /* CONFIG_NATIVE_WINDOWS */ +#include +#include +#include +#include "wpagui.h" + +WpaGuiApp::WpaGuiApp(int &argc, char **argv) : + QApplication(argc, argv), + argc(argc), + argv(argv) +{ + w = NULL; +} + +#if !defined(QT_NO_SESSIONMANAGER) && QT_VERSION < 0x050000 +void WpaGuiApp::saveState(QSessionManager &manager) +{ + QApplication::saveState(manager); + w->saveState(); +} +#endif + + +int main(int argc, char *argv[]) +{ + WpaGuiApp app(argc, argv); + QTranslator translator; + QString locale; + QString resourceDir; + int ret; + + locale = QLocale::system().name(); + resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + if (!translator.load("wpa_gui_" + locale, resourceDir)) + translator.load("wpa_gui_" + locale, "lang"); + app.installTranslator(&translator); + + WpaGui w(&app); + +#ifdef CONFIG_NATIVE_WINDOWS + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { + /* printf("Could not find a usable WinSock.dll\n"); */ + return -1; + } +#endif /* CONFIG_NATIVE_WINDOWS */ + + app.w = &w; + + ret = app.exec(); + +#ifdef CONFIG_NATIVE_WINDOWS + WSACleanup(); +#endif /* CONFIG_NATIVE_WINDOWS */ + + return ret; +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp index 2727318bcd5c01355deb1a662eb4583e7a510c5e..95b306fb557dc39cd52b64442c2db28c2902f236 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp @@ -1,853 +1,853 @@ -/* - * wpa_gui - NetworkConfig class - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include -#include - -#include "networkconfig.h" -#include "wpagui.h" - -enum { - AUTH_NONE_OPEN, - AUTH_NONE_WEP, - AUTH_NONE_WEP_SHARED, - AUTH_IEEE8021X, - AUTH_WPA_PSK, - AUTH_WPA_EAP, - AUTH_WPA2_PSK, - AUTH_WPA2_EAP -}; - -#define WPA_GUI_KEY_DATA "[key is configured]" - - -NetworkConfig::NetworkConfig(QWidget *parent, const char *, bool, - Qt::WindowFlags) - : QDialog(parent) -{ - setupUi(this); - - encrSelect->setEnabled(false); - connect(authSelect, SIGNAL(activated(int)), this, - SLOT(authChanged(int))); - connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); - connect(addButton, SIGNAL(clicked()), this, SLOT(addNetwork())); - connect(encrSelect, SIGNAL(activated(const QString &)), this, - SLOT(encrChanged(const QString &))); - connect(removeButton, SIGNAL(clicked()), this, SLOT(removeNetwork())); - connect(eapSelect, SIGNAL(activated(int)), this, - SLOT(eapChanged(int))); - connect(useWpsButton, SIGNAL(clicked()), this, SLOT(useWps())); - - wpagui = NULL; - new_network = false; -} - - -NetworkConfig::~NetworkConfig() -{ -} - - -void NetworkConfig::languageChange() -{ - retranslateUi(this); -} - - -void NetworkConfig::paramsFromScanResults(QTreeWidgetItem *sel) -{ - new_network = true; - - /* SSID BSSID frequency signal flags */ - setWindowTitle(sel->text(0)); - ssidEdit->setText(sel->text(0)); - - QString flags = sel->text(4); - int auth, encr = 0; - if (flags.indexOf("[WPA2-EAP") >= 0) - auth = AUTH_WPA2_EAP; - else if (flags.indexOf("[WPA-EAP") >= 0) - auth = AUTH_WPA_EAP; - else if (flags.indexOf("[WPA2-PSK") >= 0) - auth = AUTH_WPA2_PSK; - else if (flags.indexOf("[WPA-PSK") >= 0) - auth = AUTH_WPA_PSK; - else - auth = AUTH_NONE_OPEN; - - if (flags.indexOf("-CCMP") >= 0) - encr = 1; - else if (flags.indexOf("-TKIP") >= 0) - encr = 0; - else if (flags.indexOf("WEP") >= 0) { - encr = 1; - if (auth == AUTH_NONE_OPEN) - auth = AUTH_NONE_WEP; - } else - encr = 0; - - authSelect->setCurrentIndex(auth); - authChanged(auth); - encrSelect->setCurrentIndex(encr); - - wepEnabled(auth == AUTH_NONE_WEP); - - getEapCapa(); - - if (flags.indexOf("[WPS") >= 0) - useWpsButton->setEnabled(true); - bssid = sel->text(1); -} - - -void NetworkConfig::authChanged(int sel) -{ - encrSelect->setEnabled(sel != AUTH_NONE_OPEN && sel != AUTH_NONE_WEP && - sel != AUTH_NONE_WEP_SHARED); - pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK); - bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP || - sel == AUTH_WPA2_EAP; - eapSelect->setEnabled(eap); - identityEdit->setEnabled(eap); - passwordEdit->setEnabled(eap); - cacertEdit->setEnabled(eap); - phase2Select->setEnabled(eap); - if (eap) - eapChanged(eapSelect->currentIndex()); - - while (encrSelect->count()) - encrSelect->removeItem(0); - - if (sel == AUTH_NONE_OPEN || sel == AUTH_NONE_WEP || - sel == AUTH_NONE_WEP_SHARED || sel == AUTH_IEEE8021X) { - encrSelect->addItem("None"); - encrSelect->addItem("WEP"); - encrSelect->setCurrentIndex(sel == AUTH_NONE_OPEN ? 0 : 1); - } else { - encrSelect->addItem("TKIP"); - encrSelect->addItem("CCMP"); - encrSelect->setCurrentIndex((sel == AUTH_WPA2_PSK || - sel == AUTH_WPA2_EAP) ? 1 : 0); - } - - wepEnabled(sel == AUTH_NONE_WEP || sel == AUTH_NONE_WEP_SHARED); -} - - -void NetworkConfig::eapChanged(int sel) -{ - QString prev_val = phase2Select->currentText(); - while (phase2Select->count()) - phase2Select->removeItem(0); - - QStringList inner; - inner << "PEAP" << "TTLS" << "FAST"; - if (!inner.contains(eapSelect->itemText(sel))) - return; - - phase2Select->addItem("[ any ]"); - - /* Add special cases based on outer method */ - if (eapSelect->currentText().compare("TTLS") == 0) { - phase2Select->addItem("PAP"); - phase2Select->addItem("CHAP"); - phase2Select->addItem("MSCHAP"); - phase2Select->addItem("MSCHAPv2"); - } else if (eapSelect->currentText().compare("FAST") == 0) - phase2Select->addItem("GTC(auth) + MSCHAPv2(prov)"); - - /* Add all enabled EAP methods that can be used in the tunnel */ - int i; - QStringList allowed; - allowed << "MSCHAPV2" << "MD5" << "GTC" << "TLS" << "OTP" << "SIM" - << "AKA"; - for (i = 0; i < eapSelect->count(); i++) { - if (allowed.contains(eapSelect->itemText(i))) { - phase2Select->addItem("EAP-" + eapSelect->itemText(i)); - } - } - - for (i = 0; i < phase2Select->count(); i++) { - if (phase2Select->itemText(i).compare(prev_val) == 0) { - phase2Select->setCurrentIndex(i); - break; - } - } -} - - -void NetworkConfig::addNetwork() -{ - char reply[10], cmd[256]; - size_t reply_len; - int id; - int psklen = pskEdit->text().length(); - int auth = authSelect->currentIndex(); - - if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) { - if (psklen < 8 || psklen > 64) { - QMessageBox::warning( - this, - tr("WPA Pre-Shared Key Error"), - tr("WPA-PSK requires a passphrase of 8 to 63 " - "characters\n" - "or 64 hex digit PSK")); - pskEdit->setFocus(); - return; - } - } - - if (idstrEdit->isEnabled() && !idstrEdit->text().isEmpty()) { - QRegExp rx("^(\\w|-)+$"); - if (rx.indexIn(idstrEdit->text()) < 0) { - QMessageBox::warning( - this, tr("Network ID Error"), - tr("Network ID String contains non-word " - "characters.\n" - "It must be a simple string, " - "without spaces, containing\n" - "only characters in this range: " - "[A-Za-z0-9_-]\n")); - idstrEdit->setFocus(); - return; - } - } - - if (wpagui == NULL) - return; - - memset(reply, 0, sizeof(reply)); - reply_len = sizeof(reply) - 1; - - if (new_network) { - wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len); - if (reply[0] == 'F') { - QMessageBox::warning(this, "wpa_gui", - tr("Failed to add " - "network to wpa_supplicant\n" - "configuration.")); - return; - } - id = atoi(reply); - } else - id = edit_network_id; - - setNetworkParam(id, "ssid", ssidEdit->text().toLocal8Bit().constData(), - true); - - const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL; - switch (auth) { - case AUTH_NONE_OPEN: - case AUTH_NONE_WEP: - case AUTH_NONE_WEP_SHARED: - key_mgmt = "NONE"; - break; - case AUTH_IEEE8021X: - key_mgmt = "IEEE8021X"; - break; - case AUTH_WPA_PSK: - key_mgmt = "WPA-PSK"; - proto = "WPA"; - break; - case AUTH_WPA_EAP: - key_mgmt = "WPA-EAP"; - proto = "WPA"; - break; - case AUTH_WPA2_PSK: - key_mgmt = "WPA-PSK"; - proto = "WPA2"; - break; - case AUTH_WPA2_EAP: - key_mgmt = "WPA-EAP"; - proto = "WPA2"; - break; - } - - if (auth == AUTH_NONE_WEP_SHARED) - setNetworkParam(id, "auth_alg", "SHARED", false); - else - setNetworkParam(id, "auth_alg", "OPEN", false); - - if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP || - auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) { - int encr = encrSelect->currentIndex(); - if (encr == 0) - pairwise = "TKIP"; - else - pairwise = "CCMP"; - } - - if (proto) - setNetworkParam(id, "proto", proto, false); - if (key_mgmt) - setNetworkParam(id, "key_mgmt", key_mgmt, false); - if (pairwise) { - setNetworkParam(id, "pairwise", pairwise, false); - setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false); - } - if (pskEdit->isEnabled() && - strcmp(pskEdit->text().toLocal8Bit().constData(), - WPA_GUI_KEY_DATA) != 0) - setNetworkParam(id, "psk", - pskEdit->text().toLocal8Bit().constData(), - psklen != 64); - if (eapSelect->isEnabled()) { - const char *eap = - eapSelect->currentText().toLocal8Bit().constData(); - setNetworkParam(id, "eap", eap, false); - if (strcmp(eap, "SIM") == 0 || strcmp(eap, "AKA") == 0) - setNetworkParam(id, "pcsc", "", true); - else - setNetworkParam(id, "pcsc", "NULL", false); - } - if (phase2Select->isEnabled()) { - QString eap = eapSelect->currentText(); - QString inner = phase2Select->currentText(); - char phase2[32]; - phase2[0] = '\0'; - if (eap.compare("PEAP") == 0) { - if (inner.startsWith("EAP-")) - snprintf(phase2, sizeof(phase2), "auth=%s", - inner.right(inner.size() - 4). - toLocal8Bit().constData()); - } else if (eap.compare("TTLS") == 0) { - if (inner.startsWith("EAP-")) - snprintf(phase2, sizeof(phase2), "autheap=%s", - inner.right(inner.size() - 4). - toLocal8Bit().constData()); - else - snprintf(phase2, sizeof(phase2), "auth=%s", - inner.toLocal8Bit().constData()); - } else if (eap.compare("FAST") == 0) { - const char *provisioning = NULL; - if (inner.startsWith("EAP-")) { - snprintf(phase2, sizeof(phase2), "auth=%s", - inner.right(inner.size() - 4). - toLocal8Bit().constData()); - provisioning = "fast_provisioning=2"; - } else if (inner.compare("GTC(auth) + MSCHAPv2(prov)") - == 0) { - snprintf(phase2, sizeof(phase2), - "auth=GTC auth=MSCHAPV2"); - provisioning = "fast_provisioning=1"; - } else - provisioning = "fast_provisioning=3"; - if (provisioning) { - char blob[32]; - setNetworkParam(id, "phase1", provisioning, - true); - snprintf(blob, sizeof(blob), - "blob://fast-pac-%d", id); - setNetworkParam(id, "pac_file", blob, true); - } - } - if (phase2[0]) - setNetworkParam(id, "phase2", phase2, true); - else - setNetworkParam(id, "phase2", "NULL", false); - } else - setNetworkParam(id, "phase2", "NULL", false); - if (identityEdit->isEnabled() && identityEdit->text().length() > 0) - setNetworkParam(id, "identity", - identityEdit->text().toLocal8Bit().constData(), - true); - else - setNetworkParam(id, "identity", "NULL", false); - if (passwordEdit->isEnabled() && passwordEdit->text().length() > 0 && - strcmp(passwordEdit->text().toLocal8Bit().constData(), - WPA_GUI_KEY_DATA) != 0) - setNetworkParam(id, "password", - passwordEdit->text().toLocal8Bit().constData(), - true); - else if (passwordEdit->text().length() == 0) - setNetworkParam(id, "password", "NULL", false); - if (cacertEdit->isEnabled() && cacertEdit->text().length() > 0) - setNetworkParam(id, "ca_cert", - cacertEdit->text().toLocal8Bit().constData(), - true); - else - setNetworkParam(id, "ca_cert", "NULL", false); - writeWepKey(id, wep0Edit, 0); - writeWepKey(id, wep1Edit, 1); - writeWepKey(id, wep2Edit, 2); - writeWepKey(id, wep3Edit, 3); - - if (wep0Radio->isEnabled() && wep0Radio->isChecked()) - setNetworkParam(id, "wep_tx_keyidx", "0", false); - else if (wep1Radio->isEnabled() && wep1Radio->isChecked()) - setNetworkParam(id, "wep_tx_keyidx", "1", false); - else if (wep2Radio->isEnabled() && wep2Radio->isChecked()) - setNetworkParam(id, "wep_tx_keyidx", "2", false); - else if (wep3Radio->isEnabled() && wep3Radio->isChecked()) - setNetworkParam(id, "wep_tx_keyidx", "3", false); - - if (idstrEdit->isEnabled() && idstrEdit->text().length() > 0) - setNetworkParam(id, "id_str", - idstrEdit->text().toLocal8Bit().constData(), - true); - else - setNetworkParam(id, "id_str", "NULL", false); - - if (prioritySpinBox->isEnabled()) { - QString prio; - prio = prio.setNum(prioritySpinBox->value()); - setNetworkParam(id, "priority", prio.toLocal8Bit().constData(), - false); - } - - snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id); - reply_len = sizeof(reply); - wpagui->ctrlRequest(cmd, reply, &reply_len); - if (strncmp(reply, "OK", 2) != 0) { - QMessageBox::warning(this, "wpa_gui", - tr("Failed to enable " - "network in wpa_supplicant\n" - "configuration.")); - /* Network was added, so continue anyway */ - } - wpagui->triggerUpdate(); - wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); - - close(); -} - - -void NetworkConfig::setWpaGui(WpaGui *_wpagui) -{ - wpagui = _wpagui; -} - - -int NetworkConfig::setNetworkParam(int id, const char *field, - const char *value, bool quote) -{ - char reply[10], cmd[256]; - size_t reply_len; - snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s", - id, field, quote ? "\"" : "", value, quote ? "\"" : ""); - reply_len = sizeof(reply); - wpagui->ctrlRequest(cmd, reply, &reply_len); - return strncmp(reply, "OK", 2) == 0 ? 0 : -1; -} - - -void NetworkConfig::encrChanged(const QString &) -{ -} - - -void NetworkConfig::wepEnabled(bool enabled) -{ - wep0Edit->setEnabled(enabled); - wep1Edit->setEnabled(enabled); - wep2Edit->setEnabled(enabled); - wep3Edit->setEnabled(enabled); - wep0Radio->setEnabled(enabled); - wep1Radio->setEnabled(enabled); - wep2Radio->setEnabled(enabled); - wep3Radio->setEnabled(enabled); -} - - -void NetworkConfig::writeWepKey(int network_id, QLineEdit *edit, int id) -{ - char buf[10]; - bool hex; - const char *txt, *pos; - size_t len; - - if (!edit->isEnabled() || edit->text().isEmpty()) - return; - - /* - * Assume hex key if only hex characters are present and length matches - * with 40, 104, or 128-bit key - */ - txt = edit->text().toLocal8Bit().constData(); - if (strcmp(txt, WPA_GUI_KEY_DATA) == 0) - return; - len = strlen(txt); - if (len == 0) - return; - pos = txt; - hex = true; - while (*pos) { - if (!((*pos >= '0' && *pos <= '9') || - (*pos >= 'a' && *pos <= 'f') || - (*pos >= 'A' && *pos <= 'F'))) { - hex = false; - break; - } - pos++; - } - if (hex && len != 10 && len != 26 && len != 32) - hex = false; - snprintf(buf, sizeof(buf), "wep_key%d", id); - setNetworkParam(network_id, buf, txt, !hex); -} - - -static int key_value_isset(const char *reply, size_t reply_len) -{ - return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0); -} - - -void NetworkConfig::paramsFromConfig(int network_id) -{ - int i, res; - - edit_network_id = network_id; - getEapCapa(); - - char reply[1024], cmd[256], *pos; - size_t reply_len; - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && - reply_len >= 2 && reply[0] == '"') { - reply[reply_len] = '\0'; - pos = strchr(reply + 1, '"'); - if (pos) - *pos = '\0'; - ssidEdit->setText(reply + 1); - } - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id); - reply_len = sizeof(reply) - 1; - int wpa = 0; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { - reply[reply_len] = '\0'; - if (strstr(reply, "RSN") || strstr(reply, "WPA2")) - wpa = 2; - else if (strstr(reply, "WPA")) - wpa = 1; - } - - int auth = AUTH_NONE_OPEN, encr = 0; - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { - reply[reply_len] = '\0'; - if (strstr(reply, "WPA-EAP")) - auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP; - else if (strstr(reply, "WPA-PSK")) - auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK; - else if (strstr(reply, "IEEE8021X")) { - auth = AUTH_IEEE8021X; - encr = 1; - } - } - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { - reply[reply_len] = '\0'; - if (strstr(reply, "CCMP") && auth != AUTH_NONE_OPEN && - auth != AUTH_NONE_WEP && auth != AUTH_NONE_WEP_SHARED) - encr = 1; - else if (strstr(reply, "TKIP")) - encr = 0; - else if (strstr(reply, "WEP")) - encr = 1; - else - encr = 0; - } - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id); - reply_len = sizeof(reply) - 1; - res = wpagui->ctrlRequest(cmd, reply, &reply_len); - if (res >= 0 && reply_len >= 2 && reply[0] == '"') { - reply[reply_len] = '\0'; - pos = strchr(reply + 1, '"'); - if (pos) - *pos = '\0'; - pskEdit->setText(reply + 1); - } else if (res >= 0 && key_value_isset(reply, reply_len)) { - pskEdit->setText(WPA_GUI_KEY_DATA); - } - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && - reply_len >= 2 && reply[0] == '"') { - reply[reply_len] = '\0'; - pos = strchr(reply + 1, '"'); - if (pos) - *pos = '\0'; - identityEdit->setText(reply + 1); - } - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id); - reply_len = sizeof(reply) - 1; - res = wpagui->ctrlRequest(cmd, reply, &reply_len); - if (res >= 0 && reply_len >= 2 && reply[0] == '"') { - reply[reply_len] = '\0'; - pos = strchr(reply + 1, '"'); - if (pos) - *pos = '\0'; - passwordEdit->setText(reply + 1); - } else if (res >= 0 && key_value_isset(reply, reply_len)) { - passwordEdit->setText(WPA_GUI_KEY_DATA); - } - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && - reply_len >= 2 && reply[0] == '"') { - reply[reply_len] = '\0'; - pos = strchr(reply + 1, '"'); - if (pos) - *pos = '\0'; - cacertEdit->setText(reply + 1); - } - - enum { NO_INNER, PEAP_INNER, TTLS_INNER, FAST_INNER } eap = NO_INNER; - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && - reply_len >= 1) { - reply[reply_len] = '\0'; - for (i = 0; i < eapSelect->count(); i++) { - if (eapSelect->itemText(i).compare(reply) == 0) { - eapSelect->setCurrentIndex(i); - if (strcmp(reply, "PEAP") == 0) - eap = PEAP_INNER; - else if (strcmp(reply, "TTLS") == 0) - eap = TTLS_INNER; - else if (strcmp(reply, "FAST") == 0) - eap = FAST_INNER; - break; - } - } - } - - if (eap != NO_INNER) { - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d phase2", - network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && - reply_len >= 1) { - reply[reply_len] = '\0'; - eapChanged(eapSelect->currentIndex()); - } else - eap = NO_INNER; - } - - char *val; - val = reply + 1; - while (*(val + 1)) - val++; - if (*val == '"') - *val = '\0'; - - switch (eap) { - case PEAP_INNER: - if (strncmp(reply, "\"auth=", 6)) - break; - val = reply + 2; - memcpy(val, "EAP-", 4); - break; - case TTLS_INNER: - if (strncmp(reply, "\"autheap=", 9) == 0) { - val = reply + 5; - memcpy(val, "EAP-", 4); - } else if (strncmp(reply, "\"auth=", 6) == 0) - val = reply + 6; - break; - case FAST_INNER: - if (strncmp(reply, "\"auth=", 6)) - break; - if (strcmp(reply + 6, "GTC auth=MSCHAPV2") == 0) { - val = (char *) "GTC(auth) + MSCHAPv2(prov)"; - break; - } - val = reply + 2; - memcpy(val, "EAP-", 4); - break; - case NO_INNER: - break; - } - - for (i = 0; i < phase2Select->count(); i++) { - if (phase2Select->itemText(i).compare(val) == 0) { - phase2Select->setCurrentIndex(i); - break; - } - } - - for (i = 0; i < 4; i++) { - QLineEdit *wepEdit; - switch (i) { - default: - case 0: - wepEdit = wep0Edit; - break; - case 1: - wepEdit = wep1Edit; - break; - case 2: - wepEdit = wep2Edit; - break; - case 3: - wepEdit = wep3Edit; - break; - } - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", - network_id, i); - reply_len = sizeof(reply) - 1; - res = wpagui->ctrlRequest(cmd, reply, &reply_len); - if (res >= 0 && reply_len >= 2 && reply[0] == '"') { - reply[reply_len] = '\0'; - pos = strchr(reply + 1, '"'); - if (pos) - *pos = '\0'; - if (auth == AUTH_NONE_OPEN || auth == AUTH_IEEE8021X) { - if (auth == AUTH_NONE_OPEN) - auth = AUTH_NONE_WEP; - encr = 1; - } - - wepEdit->setText(reply + 1); - } else if (res >= 0 && key_value_isset(reply, reply_len)) { - if (auth == AUTH_NONE_OPEN || auth == AUTH_IEEE8021X) { - if (auth == AUTH_NONE_OPEN) - auth = AUTH_NONE_WEP; - encr = 1; - } - wepEdit->setText(WPA_GUI_KEY_DATA); - } - } - - if (auth == AUTH_NONE_WEP) { - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d auth_alg", - network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { - reply[reply_len] = '\0'; - if (strcmp(reply, "SHARED") == 0) - auth = AUTH_NONE_WEP_SHARED; - } - } - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) - { - reply[reply_len] = '\0'; - switch (atoi(reply)) { - case 0: - wep0Radio->setChecked(true); - break; - case 1: - wep1Radio->setChecked(true); - break; - case 2: - wep2Radio->setChecked(true); - break; - case 3: - wep3Radio->setChecked(true); - break; - } - } - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && - reply_len >= 2 && reply[0] == '"') { - reply[reply_len] = '\0'; - pos = strchr(reply + 1, '"'); - if (pos) - *pos = '\0'; - idstrEdit->setText(reply + 1); - } - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d priority", network_id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) - { - reply[reply_len] = '\0'; - prioritySpinBox->setValue(atoi(reply)); - } - - authSelect->setCurrentIndex(auth); - authChanged(auth); - encrSelect->setCurrentIndex(encr); - wepEnabled(auth == AUTH_NONE_WEP || auth == AUTH_NONE_WEP_SHARED); - - removeButton->setEnabled(true); - addButton->setText("Save"); -} - - -void NetworkConfig::removeNetwork() -{ - char reply[10], cmd[256]; - size_t reply_len; - - if (QMessageBox::information( - this, "wpa_gui", - tr("This will permanently remove the network\n" - "from the configuration. Do you really want\n" - "to remove this network?"), - tr("Yes"), tr("No")) != 0) - return; - - snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id); - reply_len = sizeof(reply); - wpagui->ctrlRequest(cmd, reply, &reply_len); - if (strncmp(reply, "OK", 2) != 0) { - QMessageBox::warning(this, "wpa_gui", - tr("Failed to remove network from " - "wpa_supplicant\n" - "configuration.")); - } else { - wpagui->triggerUpdate(); - wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); - } - - close(); -} - - -void NetworkConfig::newNetwork() -{ - new_network = true; - getEapCapa(); -} - - -void NetworkConfig::getEapCapa() -{ - char reply[256]; - size_t reply_len; - - if (wpagui == NULL) - return; - - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0) - return; - reply[reply_len] = '\0'; - - QString res(reply); - QStringList types = res.split(QChar(' ')); - eapSelect->insertItems(-1, types); -} - - -void NetworkConfig::useWps() -{ - if (wpagui == NULL) - return; - wpagui->setBssFromScan(bssid); - wpagui->wpsDialog(); - close(); -} +/* + * wpa_gui - NetworkConfig class + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include + +#include "networkconfig.h" +#include "wpagui.h" + +enum { + AUTH_NONE_OPEN, + AUTH_NONE_WEP, + AUTH_NONE_WEP_SHARED, + AUTH_IEEE8021X, + AUTH_WPA_PSK, + AUTH_WPA_EAP, + AUTH_WPA2_PSK, + AUTH_WPA2_EAP +}; + +#define WPA_GUI_KEY_DATA "[key is configured]" + + +NetworkConfig::NetworkConfig(QWidget *parent, const char *, bool, + Qt::WindowFlags) + : QDialog(parent) +{ + setupUi(this); + + encrSelect->setEnabled(false); + connect(authSelect, SIGNAL(activated(int)), this, + SLOT(authChanged(int))); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); + connect(addButton, SIGNAL(clicked()), this, SLOT(addNetwork())); + connect(encrSelect, SIGNAL(activated(const QString &)), this, + SLOT(encrChanged(const QString &))); + connect(removeButton, SIGNAL(clicked()), this, SLOT(removeNetwork())); + connect(eapSelect, SIGNAL(activated(int)), this, + SLOT(eapChanged(int))); + connect(useWpsButton, SIGNAL(clicked()), this, SLOT(useWps())); + + wpagui = NULL; + new_network = false; +} + + +NetworkConfig::~NetworkConfig() +{ +} + + +void NetworkConfig::languageChange() +{ + retranslateUi(this); +} + + +void NetworkConfig::paramsFromScanResults(QTreeWidgetItem *sel) +{ + new_network = true; + + /* SSID BSSID frequency signal flags */ + setWindowTitle(sel->text(0)); + ssidEdit->setText(sel->text(0)); + + QString flags = sel->text(4); + int auth, encr = 0; + if (flags.indexOf("[WPA2-EAP") >= 0) + auth = AUTH_WPA2_EAP; + else if (flags.indexOf("[WPA-EAP") >= 0) + auth = AUTH_WPA_EAP; + else if (flags.indexOf("[WPA2-PSK") >= 0) + auth = AUTH_WPA2_PSK; + else if (flags.indexOf("[WPA-PSK") >= 0) + auth = AUTH_WPA_PSK; + else + auth = AUTH_NONE_OPEN; + + if (flags.indexOf("-CCMP") >= 0) + encr = 1; + else if (flags.indexOf("-TKIP") >= 0) + encr = 0; + else if (flags.indexOf("WEP") >= 0) { + encr = 1; + if (auth == AUTH_NONE_OPEN) + auth = AUTH_NONE_WEP; + } else + encr = 0; + + authSelect->setCurrentIndex(auth); + authChanged(auth); + encrSelect->setCurrentIndex(encr); + + wepEnabled(auth == AUTH_NONE_WEP); + + getEapCapa(); + + if (flags.indexOf("[WPS") >= 0) + useWpsButton->setEnabled(true); + bssid = sel->text(1); +} + + +void NetworkConfig::authChanged(int sel) +{ + encrSelect->setEnabled(sel != AUTH_NONE_OPEN && sel != AUTH_NONE_WEP && + sel != AUTH_NONE_WEP_SHARED); + pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK); + bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP || + sel == AUTH_WPA2_EAP; + eapSelect->setEnabled(eap); + identityEdit->setEnabled(eap); + passwordEdit->setEnabled(eap); + cacertEdit->setEnabled(eap); + phase2Select->setEnabled(eap); + if (eap) + eapChanged(eapSelect->currentIndex()); + + while (encrSelect->count()) + encrSelect->removeItem(0); + + if (sel == AUTH_NONE_OPEN || sel == AUTH_NONE_WEP || + sel == AUTH_NONE_WEP_SHARED || sel == AUTH_IEEE8021X) { + encrSelect->addItem("None"); + encrSelect->addItem("WEP"); + encrSelect->setCurrentIndex(sel == AUTH_NONE_OPEN ? 0 : 1); + } else { + encrSelect->addItem("TKIP"); + encrSelect->addItem("CCMP"); + encrSelect->setCurrentIndex((sel == AUTH_WPA2_PSK || + sel == AUTH_WPA2_EAP) ? 1 : 0); + } + + wepEnabled(sel == AUTH_NONE_WEP || sel == AUTH_NONE_WEP_SHARED); +} + + +void NetworkConfig::eapChanged(int sel) +{ + QString prev_val = phase2Select->currentText(); + while (phase2Select->count()) + phase2Select->removeItem(0); + + QStringList inner; + inner << "PEAP" << "TTLS" << "FAST"; + if (!inner.contains(eapSelect->itemText(sel))) + return; + + phase2Select->addItem("[ any ]"); + + /* Add special cases based on outer method */ + if (eapSelect->currentText().compare("TTLS") == 0) { + phase2Select->addItem("PAP"); + phase2Select->addItem("CHAP"); + phase2Select->addItem("MSCHAP"); + phase2Select->addItem("MSCHAPv2"); + } else if (eapSelect->currentText().compare("FAST") == 0) + phase2Select->addItem("GTC(auth) + MSCHAPv2(prov)"); + + /* Add all enabled EAP methods that can be used in the tunnel */ + int i; + QStringList allowed; + allowed << "MSCHAPV2" << "MD5" << "GTC" << "TLS" << "OTP" << "SIM" + << "AKA"; + for (i = 0; i < eapSelect->count(); i++) { + if (allowed.contains(eapSelect->itemText(i))) { + phase2Select->addItem("EAP-" + eapSelect->itemText(i)); + } + } + + for (i = 0; i < phase2Select->count(); i++) { + if (phase2Select->itemText(i).compare(prev_val) == 0) { + phase2Select->setCurrentIndex(i); + break; + } + } +} + + +void NetworkConfig::addNetwork() +{ + char reply[10], cmd[256]; + size_t reply_len; + int id; + int psklen = pskEdit->text().length(); + int auth = authSelect->currentIndex(); + + if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) { + if (psklen < 8 || psklen > 64) { + QMessageBox::warning( + this, + tr("WPA Pre-Shared Key Error"), + tr("WPA-PSK requires a passphrase of 8 to 63 " + "characters\n" + "or 64 hex digit PSK")); + pskEdit->setFocus(); + return; + } + } + + if (idstrEdit->isEnabled() && !idstrEdit->text().isEmpty()) { + QRegExp rx("^(\\w|-)+$"); + if (rx.indexIn(idstrEdit->text()) < 0) { + QMessageBox::warning( + this, tr("Network ID Error"), + tr("Network ID String contains non-word " + "characters.\n" + "It must be a simple string, " + "without spaces, containing\n" + "only characters in this range: " + "[A-Za-z0-9_-]\n")); + idstrEdit->setFocus(); + return; + } + } + + if (wpagui == NULL) + return; + + memset(reply, 0, sizeof(reply)); + reply_len = sizeof(reply) - 1; + + if (new_network) { + wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len); + if (reply[0] == 'F') { + QMessageBox::warning(this, "wpa_gui", + tr("Failed to add " + "network to wpa_supplicant\n" + "configuration.")); + return; + } + id = atoi(reply); + } else + id = edit_network_id; + + setNetworkParam(id, "ssid", ssidEdit->text().toLocal8Bit().constData(), + true); + + const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL; + switch (auth) { + case AUTH_NONE_OPEN: + case AUTH_NONE_WEP: + case AUTH_NONE_WEP_SHARED: + key_mgmt = "NONE"; + break; + case AUTH_IEEE8021X: + key_mgmt = "IEEE8021X"; + break; + case AUTH_WPA_PSK: + key_mgmt = "WPA-PSK"; + proto = "WPA"; + break; + case AUTH_WPA_EAP: + key_mgmt = "WPA-EAP"; + proto = "WPA"; + break; + case AUTH_WPA2_PSK: + key_mgmt = "WPA-PSK"; + proto = "WPA2"; + break; + case AUTH_WPA2_EAP: + key_mgmt = "WPA-EAP"; + proto = "WPA2"; + break; + } + + if (auth == AUTH_NONE_WEP_SHARED) + setNetworkParam(id, "auth_alg", "SHARED", false); + else + setNetworkParam(id, "auth_alg", "OPEN", false); + + if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP || + auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) { + int encr = encrSelect->currentIndex(); + if (encr == 0) + pairwise = "TKIP"; + else + pairwise = "CCMP"; + } + + if (proto) + setNetworkParam(id, "proto", proto, false); + if (key_mgmt) + setNetworkParam(id, "key_mgmt", key_mgmt, false); + if (pairwise) { + setNetworkParam(id, "pairwise", pairwise, false); + setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false); + } + if (pskEdit->isEnabled() && + strcmp(pskEdit->text().toLocal8Bit().constData(), + WPA_GUI_KEY_DATA) != 0) + setNetworkParam(id, "psk", + pskEdit->text().toLocal8Bit().constData(), + psklen != 64); + if (eapSelect->isEnabled()) { + const char *eap = + eapSelect->currentText().toLocal8Bit().constData(); + setNetworkParam(id, "eap", eap, false); + if (strcmp(eap, "SIM") == 0 || strcmp(eap, "AKA") == 0) + setNetworkParam(id, "pcsc", "", true); + else + setNetworkParam(id, "pcsc", "NULL", false); + } + if (phase2Select->isEnabled()) { + QString eap = eapSelect->currentText(); + QString inner = phase2Select->currentText(); + char phase2[32]; + phase2[0] = '\0'; + if (eap.compare("PEAP") == 0) { + if (inner.startsWith("EAP-")) + snprintf(phase2, sizeof(phase2), "auth=%s", + inner.right(inner.size() - 4). + toLocal8Bit().constData()); + } else if (eap.compare("TTLS") == 0) { + if (inner.startsWith("EAP-")) + snprintf(phase2, sizeof(phase2), "autheap=%s", + inner.right(inner.size() - 4). + toLocal8Bit().constData()); + else + snprintf(phase2, sizeof(phase2), "auth=%s", + inner.toLocal8Bit().constData()); + } else if (eap.compare("FAST") == 0) { + const char *provisioning = NULL; + if (inner.startsWith("EAP-")) { + snprintf(phase2, sizeof(phase2), "auth=%s", + inner.right(inner.size() - 4). + toLocal8Bit().constData()); + provisioning = "fast_provisioning=2"; + } else if (inner.compare("GTC(auth) + MSCHAPv2(prov)") + == 0) { + snprintf(phase2, sizeof(phase2), + "auth=GTC auth=MSCHAPV2"); + provisioning = "fast_provisioning=1"; + } else + provisioning = "fast_provisioning=3"; + if (provisioning) { + char blob[32]; + setNetworkParam(id, "phase1", provisioning, + true); + snprintf(blob, sizeof(blob), + "blob://fast-pac-%d", id); + setNetworkParam(id, "pac_file", blob, true); + } + } + if (phase2[0]) + setNetworkParam(id, "phase2", phase2, true); + else + setNetworkParam(id, "phase2", "NULL", false); + } else + setNetworkParam(id, "phase2", "NULL", false); + if (identityEdit->isEnabled() && identityEdit->text().length() > 0) + setNetworkParam(id, "identity", + identityEdit->text().toLocal8Bit().constData(), + true); + else + setNetworkParam(id, "identity", "NULL", false); + if (passwordEdit->isEnabled() && passwordEdit->text().length() > 0 && + strcmp(passwordEdit->text().toLocal8Bit().constData(), + WPA_GUI_KEY_DATA) != 0) + setNetworkParam(id, "password", + passwordEdit->text().toLocal8Bit().constData(), + true); + else if (passwordEdit->text().length() == 0) + setNetworkParam(id, "password", "NULL", false); + if (cacertEdit->isEnabled() && cacertEdit->text().length() > 0) + setNetworkParam(id, "ca_cert", + cacertEdit->text().toLocal8Bit().constData(), + true); + else + setNetworkParam(id, "ca_cert", "NULL", false); + writeWepKey(id, wep0Edit, 0); + writeWepKey(id, wep1Edit, 1); + writeWepKey(id, wep2Edit, 2); + writeWepKey(id, wep3Edit, 3); + + if (wep0Radio->isEnabled() && wep0Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "0", false); + else if (wep1Radio->isEnabled() && wep1Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "1", false); + else if (wep2Radio->isEnabled() && wep2Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "2", false); + else if (wep3Radio->isEnabled() && wep3Radio->isChecked()) + setNetworkParam(id, "wep_tx_keyidx", "3", false); + + if (idstrEdit->isEnabled() && idstrEdit->text().length() > 0) + setNetworkParam(id, "id_str", + idstrEdit->text().toLocal8Bit().constData(), + true); + else + setNetworkParam(id, "id_str", "NULL", false); + + if (prioritySpinBox->isEnabled()) { + QString prio; + prio = prio.setNum(prioritySpinBox->value()); + setNetworkParam(id, "priority", prio.toLocal8Bit().constData(), + false); + } + + snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id); + reply_len = sizeof(reply); + wpagui->ctrlRequest(cmd, reply, &reply_len); + if (strncmp(reply, "OK", 2) != 0) { + QMessageBox::warning(this, "wpa_gui", + tr("Failed to enable " + "network in wpa_supplicant\n" + "configuration.")); + /* Network was added, so continue anyway */ + } + wpagui->triggerUpdate(); + wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); + + close(); +} + + +void NetworkConfig::setWpaGui(WpaGui *_wpagui) +{ + wpagui = _wpagui; +} + + +int NetworkConfig::setNetworkParam(int id, const char *field, + const char *value, bool quote) +{ + char reply[10], cmd[256]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s", + id, field, quote ? "\"" : "", value, quote ? "\"" : ""); + reply_len = sizeof(reply); + wpagui->ctrlRequest(cmd, reply, &reply_len); + return strncmp(reply, "OK", 2) == 0 ? 0 : -1; +} + + +void NetworkConfig::encrChanged(const QString &) +{ +} + + +void NetworkConfig::wepEnabled(bool enabled) +{ + wep0Edit->setEnabled(enabled); + wep1Edit->setEnabled(enabled); + wep2Edit->setEnabled(enabled); + wep3Edit->setEnabled(enabled); + wep0Radio->setEnabled(enabled); + wep1Radio->setEnabled(enabled); + wep2Radio->setEnabled(enabled); + wep3Radio->setEnabled(enabled); +} + + +void NetworkConfig::writeWepKey(int network_id, QLineEdit *edit, int id) +{ + char buf[10]; + bool hex; + const char *txt, *pos; + size_t len; + + if (!edit->isEnabled() || edit->text().isEmpty()) + return; + + /* + * Assume hex key if only hex characters are present and length matches + * with 40, 104, or 128-bit key + */ + txt = edit->text().toLocal8Bit().constData(); + if (strcmp(txt, WPA_GUI_KEY_DATA) == 0) + return; + len = strlen(txt); + if (len == 0) + return; + pos = txt; + hex = true; + while (*pos) { + if (!((*pos >= '0' && *pos <= '9') || + (*pos >= 'a' && *pos <= 'f') || + (*pos >= 'A' && *pos <= 'F'))) { + hex = false; + break; + } + pos++; + } + if (hex && len != 10 && len != 26 && len != 32) + hex = false; + snprintf(buf, sizeof(buf), "wep_key%d", id); + setNetworkParam(network_id, buf, txt, !hex); +} + + +static int key_value_isset(const char *reply, size_t reply_len) +{ + return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0); +} + + +void NetworkConfig::paramsFromConfig(int network_id) +{ + int i, res; + + edit_network_id = network_id; + getEapCapa(); + + char reply[1024], cmd[256], *pos; + size_t reply_len; + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + ssidEdit->setText(reply + 1); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id); + reply_len = sizeof(reply) - 1; + int wpa = 0; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { + reply[reply_len] = '\0'; + if (strstr(reply, "RSN") || strstr(reply, "WPA2")) + wpa = 2; + else if (strstr(reply, "WPA")) + wpa = 1; + } + + int auth = AUTH_NONE_OPEN, encr = 0; + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { + reply[reply_len] = '\0'; + if (strstr(reply, "WPA-EAP")) + auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP; + else if (strstr(reply, "WPA-PSK")) + auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK; + else if (strstr(reply, "IEEE8021X")) { + auth = AUTH_IEEE8021X; + encr = 1; + } + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { + reply[reply_len] = '\0'; + if (strstr(reply, "CCMP") && auth != AUTH_NONE_OPEN && + auth != AUTH_NONE_WEP && auth != AUTH_NONE_WEP_SHARED) + encr = 1; + else if (strstr(reply, "TKIP")) + encr = 0; + else if (strstr(reply, "WEP")) + encr = 1; + else + encr = 0; + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id); + reply_len = sizeof(reply) - 1; + res = wpagui->ctrlRequest(cmd, reply, &reply_len); + if (res >= 0 && reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + pskEdit->setText(reply + 1); + } else if (res >= 0 && key_value_isset(reply, reply_len)) { + pskEdit->setText(WPA_GUI_KEY_DATA); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + identityEdit->setText(reply + 1); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id); + reply_len = sizeof(reply) - 1; + res = wpagui->ctrlRequest(cmd, reply, &reply_len); + if (res >= 0 && reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + passwordEdit->setText(reply + 1); + } else if (res >= 0 && key_value_isset(reply, reply_len)) { + passwordEdit->setText(WPA_GUI_KEY_DATA); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + cacertEdit->setText(reply + 1); + } + + enum { NO_INNER, PEAP_INNER, TTLS_INNER, FAST_INNER } eap = NO_INNER; + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 1) { + reply[reply_len] = '\0'; + for (i = 0; i < eapSelect->count(); i++) { + if (eapSelect->itemText(i).compare(reply) == 0) { + eapSelect->setCurrentIndex(i); + if (strcmp(reply, "PEAP") == 0) + eap = PEAP_INNER; + else if (strcmp(reply, "TTLS") == 0) + eap = TTLS_INNER; + else if (strcmp(reply, "FAST") == 0) + eap = FAST_INNER; + break; + } + } + } + + if (eap != NO_INNER) { + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d phase2", + network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 1) { + reply[reply_len] = '\0'; + eapChanged(eapSelect->currentIndex()); + } else + eap = NO_INNER; + } + + char *val; + val = reply + 1; + while (*(val + 1)) + val++; + if (*val == '"') + *val = '\0'; + + switch (eap) { + case PEAP_INNER: + if (strncmp(reply, "\"auth=", 6)) + break; + val = reply + 2; + memcpy(val, "EAP-", 4); + break; + case TTLS_INNER: + if (strncmp(reply, "\"autheap=", 9) == 0) { + val = reply + 5; + memcpy(val, "EAP-", 4); + } else if (strncmp(reply, "\"auth=", 6) == 0) + val = reply + 6; + break; + case FAST_INNER: + if (strncmp(reply, "\"auth=", 6)) + break; + if (strcmp(reply + 6, "GTC auth=MSCHAPV2") == 0) { + val = (char *) "GTC(auth) + MSCHAPv2(prov)"; + break; + } + val = reply + 2; + memcpy(val, "EAP-", 4); + break; + case NO_INNER: + break; + } + + for (i = 0; i < phase2Select->count(); i++) { + if (phase2Select->itemText(i).compare(val) == 0) { + phase2Select->setCurrentIndex(i); + break; + } + } + + for (i = 0; i < 4; i++) { + QLineEdit *wepEdit; + switch (i) { + default: + case 0: + wepEdit = wep0Edit; + break; + case 1: + wepEdit = wep1Edit; + break; + case 2: + wepEdit = wep2Edit; + break; + case 3: + wepEdit = wep3Edit; + break; + } + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", + network_id, i); + reply_len = sizeof(reply) - 1; + res = wpagui->ctrlRequest(cmd, reply, &reply_len); + if (res >= 0 && reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + if (auth == AUTH_NONE_OPEN || auth == AUTH_IEEE8021X) { + if (auth == AUTH_NONE_OPEN) + auth = AUTH_NONE_WEP; + encr = 1; + } + + wepEdit->setText(reply + 1); + } else if (res >= 0 && key_value_isset(reply, reply_len)) { + if (auth == AUTH_NONE_OPEN || auth == AUTH_IEEE8021X) { + if (auth == AUTH_NONE_OPEN) + auth = AUTH_NONE_WEP; + encr = 1; + } + wepEdit->setText(WPA_GUI_KEY_DATA); + } + } + + if (auth == AUTH_NONE_WEP) { + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d auth_alg", + network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { + reply[reply_len] = '\0'; + if (strcmp(reply, "SHARED") == 0) + auth = AUTH_NONE_WEP_SHARED; + } + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) + { + reply[reply_len] = '\0'; + switch (atoi(reply)) { + case 0: + wep0Radio->setChecked(true); + break; + case 1: + wep1Radio->setChecked(true); + break; + case 2: + wep2Radio->setChecked(true); + break; + case 3: + wep3Radio->setChecked(true); + break; + } + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && + reply_len >= 2 && reply[0] == '"') { + reply[reply_len] = '\0'; + pos = strchr(reply + 1, '"'); + if (pos) + *pos = '\0'; + idstrEdit->setText(reply + 1); + } + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d priority", network_id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) + { + reply[reply_len] = '\0'; + prioritySpinBox->setValue(atoi(reply)); + } + + authSelect->setCurrentIndex(auth); + authChanged(auth); + encrSelect->setCurrentIndex(encr); + wepEnabled(auth == AUTH_NONE_WEP || auth == AUTH_NONE_WEP_SHARED); + + removeButton->setEnabled(true); + addButton->setText("Save"); +} + + +void NetworkConfig::removeNetwork() +{ + char reply[10], cmd[256]; + size_t reply_len; + + if (QMessageBox::information( + this, "wpa_gui", + tr("This will permanently remove the network\n" + "from the configuration. Do you really want\n" + "to remove this network?"), + tr("Yes"), tr("No")) != 0) + return; + + snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id); + reply_len = sizeof(reply); + wpagui->ctrlRequest(cmd, reply, &reply_len); + if (strncmp(reply, "OK", 2) != 0) { + QMessageBox::warning(this, "wpa_gui", + tr("Failed to remove network from " + "wpa_supplicant\n" + "configuration.")); + } else { + wpagui->triggerUpdate(); + wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); + } + + close(); +} + + +void NetworkConfig::newNetwork() +{ + new_network = true; + getEapCapa(); +} + + +void NetworkConfig::getEapCapa() +{ + char reply[256]; + size_t reply_len; + + if (wpagui == NULL) + return; + + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0) + return; + reply[reply_len] = '\0'; + + QString res(reply); + QStringList types = res.split(QChar(' ')); + eapSelect->insertItems(-1, types); +} + + +void NetworkConfig::useWps() +{ + if (wpagui == NULL) + return; + wpagui->setBssFromScan(bssid); + wpagui->wpsDialog(); + close(); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.h index fd09dec54318fd8f1f8f6e0542790e543aee92d5..cf5bda22d382ba1a673f9a0ee0ba934af44c5785 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.h @@ -1,55 +1,55 @@ -/* - * wpa_gui - NetworkConfig class - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef NETWORKCONFIG_H -#define NETWORKCONFIG_H - -#include -#include "ui_networkconfig.h" - -class WpaGui; - -class NetworkConfig : public QDialog, public Ui::NetworkConfig -{ - Q_OBJECT - -public: - NetworkConfig(QWidget *parent = 0, const char *name = 0, - bool modal = false, Qt::WindowFlags fl = 0); - ~NetworkConfig(); - - virtual void paramsFromScanResults(QTreeWidgetItem *sel); - virtual void setWpaGui(WpaGui *_wpagui); - virtual int setNetworkParam(int id, const char *field, - const char *value, bool quote); - virtual void paramsFromConfig(int network_id); - virtual void newNetwork(); - -public slots: - virtual void authChanged(int sel); - virtual void addNetwork(); - virtual void encrChanged(const QString &sel); - virtual void writeWepKey(int network_id, QLineEdit *edit, int id); - virtual void removeNetwork(); - virtual void eapChanged(int sel); - virtual void useWps(); - -protected slots: - virtual void languageChange(); - -private: - WpaGui *wpagui; - int edit_network_id; - bool new_network; - QString bssid; - - virtual void wepEnabled(bool enabled); - virtual void getEapCapa(); -}; - -#endif /* NETWORKCONFIG_H */ +/* + * wpa_gui - NetworkConfig class + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef NETWORKCONFIG_H +#define NETWORKCONFIG_H + +#include +#include "ui_networkconfig.h" + +class WpaGui; + +class NetworkConfig : public QDialog, public Ui::NetworkConfig +{ + Q_OBJECT + +public: + NetworkConfig(QWidget *parent = 0, const char *name = 0, + bool modal = false, Qt::WindowFlags fl = 0); + ~NetworkConfig(); + + virtual void paramsFromScanResults(QTreeWidgetItem *sel); + virtual void setWpaGui(WpaGui *_wpagui); + virtual int setNetworkParam(int id, const char *field, + const char *value, bool quote); + virtual void paramsFromConfig(int network_id); + virtual void newNetwork(); + +public slots: + virtual void authChanged(int sel); + virtual void addNetwork(); + virtual void encrChanged(const QString &sel); + virtual void writeWepKey(int network_id, QLineEdit *edit, int id); + virtual void removeNetwork(); + virtual void eapChanged(int sel); + virtual void useWps(); + +protected slots: + virtual void languageChange(); + +private: + WpaGui *wpagui; + int edit_network_id; + bool new_network; + QString bssid; + + virtual void wepEnabled(bool enabled); + virtual void getEapCapa(); +}; + +#endif /* NETWORKCONFIG_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.ui b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.ui index 217a8ff587046d77ba8802ea51b5a225b822400e..5ad9151f43786a51f2caebf7dce42dc70e0f3421 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.ui +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/networkconfig.ui @@ -1,435 +1,435 @@ - - NetworkConfig - - - - 0 - 0 - 410 - 534 - - - - NetworkConfig - - - - - - Cancel - - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - - - - SSID - - - - - - - Network name (Service Set IDentifier) - - - - - - - - - - Authentication - - - - - - - - Plaintext (open / no authentication) - - - - - Static WEP (no authentication) - - - - - Static WEP (Shared Key authentication) - - - - - IEEE 802.1X - - - - - WPA-Personal (PSK) - - - - - WPA-Enterprise (EAP) - - - - - WPA2-Personal (PSK) - - - - - WPA2-Enterprise (EAP) - - - - - - - - Encryption - - - - - - - - None - - - - - WEP - - - - - TKIP - - - - - CCMP - - - - - - - - PSK - - - - - - - false - - - WPA/WPA2 pre-shared key or passphrase - - - - - - QLineEdit::Password - - - - - - - EAP method - - - - - - - false - - - - - - - Identity - - - - - - - false - - - Username/Identity for EAP methods - - - - - - - Password - - - - - - - false - - - Password for EAP methods - - - QLineEdit::Password - - - - - - - CA certificate - - - - - - - false - - - - - - - true - - - WEP keys - - - - - - false - - - key 0 - - - - - - - false - - - key 1 - - - - - - - false - - - key 3 - - - - - - - false - - - key 2 - - - - - - - false - - - - - - - false - - - - - - - false - - - - - - - false - - - - - - - - - - true - - - Optional Settings - - - - - - Network Identification String - - - - - - - Network Priority - - - 10000 - - - 10 - - - - - - - IDString - - - - - - - Priority - - - - - - - Inner auth - - - - - - - false - - - - - - - - - - - - - Add - - - - - - - false - - - Remove - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - false - - - WPS - - - - - - - - - ssidEdit - authSelect - encrSelect - pskEdit - eapSelect - identityEdit - passwordEdit - cacertEdit - wep0Radio - wep0Edit - wep1Radio - wep1Edit - wep2Radio - wep2Edit - wep3Radio - wep3Edit - idstrEdit - prioritySpinBox - phase2Select - addButton - removeButton - cancelButton - - - qtreewidget.h - - - - + + NetworkConfig + + + + 0 + 0 + 410 + 534 + + + + NetworkConfig + + + + + + Cancel + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + SSID + + + + + + + Network name (Service Set IDentifier) + + + + + + + + + + Authentication + + + + + + + + Plaintext (open / no authentication) + + + + + Static WEP (no authentication) + + + + + Static WEP (Shared Key authentication) + + + + + IEEE 802.1X + + + + + WPA-Personal (PSK) + + + + + WPA-Enterprise (EAP) + + + + + WPA2-Personal (PSK) + + + + + WPA2-Enterprise (EAP) + + + + + + + + Encryption + + + + + + + + None + + + + + WEP + + + + + TKIP + + + + + CCMP + + + + + + + + PSK + + + + + + + false + + + WPA/WPA2 pre-shared key or passphrase + + + + + + QLineEdit::Password + + + + + + + EAP method + + + + + + + false + + + + + + + Identity + + + + + + + false + + + Username/Identity for EAP methods + + + + + + + Password + + + + + + + false + + + Password for EAP methods + + + QLineEdit::Password + + + + + + + CA certificate + + + + + + + false + + + + + + + true + + + WEP keys + + + + + + false + + + key 0 + + + + + + + false + + + key 1 + + + + + + + false + + + key 3 + + + + + + + false + + + key 2 + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + false + + + + + + + + + + true + + + Optional Settings + + + + + + Network Identification String + + + + + + + Network Priority + + + 10000 + + + 10 + + + + + + + IDString + + + + + + + Priority + + + + + + + Inner auth + + + + + + + false + + + + + + + + + + + + + Add + + + + + + + false + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + false + + + WPS + + + + + + + + + ssidEdit + authSelect + encrSelect + pskEdit + eapSelect + identityEdit + passwordEdit + cacertEdit + wep0Radio + wep0Edit + wep1Radio + wep1Edit + wep2Radio + wep2Edit + wep3Radio + wep3Edit + idstrEdit + prioritySpinBox + phase2Select + addButton + removeButton + cancelButton + + + qtreewidget.h + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.cpp index 0a0b3ffcb51b6dd10c68578d60f25e370ba9d81c..833eb9f3fb4b1f8cbead4614bfcdc30ae079ea67 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.cpp @@ -1,1885 +1,1885 @@ -/* - * wpa_gui - Peers class - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include -#include -#include - -#include "common/wpa_ctrl.h" -#include "wpagui.h" -#include "stringquery.h" -#include "peers.h" - - -enum { - peer_role_address = Qt::UserRole + 1, - peer_role_type, - peer_role_uuid, - peer_role_details, - peer_role_ifname, - peer_role_pri_dev_type, - peer_role_ssid, - peer_role_config_methods, - peer_role_dev_passwd_id, - peer_role_bss_id, - peer_role_selected_method, - peer_role_selected_pin, - peer_role_requested_method, - peer_role_network_id -}; - -enum selected_method { - SEL_METHOD_NONE, - SEL_METHOD_PIN_PEER_DISPLAY, - SEL_METHOD_PIN_LOCAL_DISPLAY -}; - -/* - * TODO: - * - add current AP info (e.g., from WPS) in station mode - */ - -enum peer_type { - PEER_TYPE_ASSOCIATED_STATION, - PEER_TYPE_AP, - PEER_TYPE_AP_WPS, - PEER_TYPE_WPS_PIN_NEEDED, - PEER_TYPE_P2P, - PEER_TYPE_P2P_CLIENT, - PEER_TYPE_P2P_GROUP, - PEER_TYPE_P2P_PERSISTENT_GROUP_GO, - PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT, - PEER_TYPE_P2P_INVITATION, - PEER_TYPE_WPS_ER_AP, - PEER_TYPE_WPS_ER_AP_UNCONFIGURED, - PEER_TYPE_WPS_ER_ENROLLEE, - PEER_TYPE_WPS_ENROLLEE -}; - - -Peers::Peers(QWidget *parent, const char *, bool, Qt::WindowFlags) - : QDialog(parent) -{ - setupUi(this); - - if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) - { - default_icon = new QIcon(":/icons/wpa_gui.svg"); - ap_icon = new QIcon(":/icons/ap.svg"); - laptop_icon = new QIcon(":/icons/laptop.svg"); - group_icon = new QIcon(":/icons/group.svg"); - invitation_icon = new QIcon(":/icons/invitation.svg"); - } else { - default_icon = new QIcon(":/icons/wpa_gui.png"); - ap_icon = new QIcon(":/icons/ap.png"); - laptop_icon = new QIcon(":/icons/laptop.png"); - group_icon = new QIcon(":/icons/group.png"); - invitation_icon = new QIcon(":/icons/invitation.png"); - } - - peers->setModel(&model); - peers->setResizeMode(QListView::Adjust); - peers->setDragEnabled(false); - peers->setSelectionMode(QAbstractItemView::NoSelection); - - peers->setContextMenuPolicy(Qt::CustomContextMenu); - connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)), - this, SLOT(context_menu(const QPoint &))); - - wpagui = NULL; - hide_ap = false; -} - - -void Peers::setWpaGui(WpaGui *_wpagui) -{ - wpagui = _wpagui; - update_peers(); -} - - -Peers::~Peers() -{ - delete default_icon; - delete ap_icon; - delete laptop_icon; - delete group_icon; - delete invitation_icon; -} - - -void Peers::languageChange() -{ - retranslateUi(this); -} - - -QString Peers::ItemType(int type) -{ - QString title; - switch (type) { - case PEER_TYPE_ASSOCIATED_STATION: - title = tr("Associated station"); - break; - case PEER_TYPE_AP: - title = tr("AP"); - break; - case PEER_TYPE_AP_WPS: - title = tr("WPS AP"); - break; - case PEER_TYPE_WPS_PIN_NEEDED: - title = tr("WPS PIN needed"); - break; - case PEER_TYPE_P2P: - title = tr("P2P Device"); - break; - case PEER_TYPE_P2P_CLIENT: - title = tr("P2P Device (group client)"); - break; - case PEER_TYPE_P2P_GROUP: - title = tr("P2P Group"); - break; - case PEER_TYPE_P2P_PERSISTENT_GROUP_GO: - title = tr("P2P Persistent Group (GO)"); - break; - case PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT: - title = tr("P2P Persistent Group (client)"); - break; - case PEER_TYPE_P2P_INVITATION: - title = tr("P2P Invitation"); - break; - case PEER_TYPE_WPS_ER_AP: - title = tr("ER: WPS AP"); - break; - case PEER_TYPE_WPS_ER_AP_UNCONFIGURED: - title = tr("ER: WPS AP (Unconfigured)"); - break; - case PEER_TYPE_WPS_ER_ENROLLEE: - title = tr("ER: WPS Enrollee"); - break; - case PEER_TYPE_WPS_ENROLLEE: - title = tr("WPS Enrollee"); - break; - } - return title; -} - - -void Peers::context_menu(const QPoint &pos) -{ - QMenu *menu = new QMenu; - if (menu == NULL) - return; - - QModelIndex idx = peers->indexAt(pos); - if (idx.isValid()) { - ctx_item = model.itemFromIndex(idx); - int type = ctx_item->data(peer_role_type).toInt(); - menu->addAction(Peers::ItemType(type))->setEnabled(false); - menu->addSeparator(); - - int config_methods = -1; - QVariant var = ctx_item->data(peer_role_config_methods); - if (var.isValid()) - config_methods = var.toInt(); - - enum selected_method method = SEL_METHOD_NONE; - var = ctx_item->data(peer_role_selected_method); - if (var.isValid()) - method = (enum selected_method) var.toInt(); - - if ((type == PEER_TYPE_ASSOCIATED_STATION || - type == PEER_TYPE_AP_WPS || - type == PEER_TYPE_WPS_PIN_NEEDED || - type == PEER_TYPE_WPS_ER_ENROLLEE || - type == PEER_TYPE_WPS_ENROLLEE) && - (config_methods == -1 || (config_methods & 0x010c))) { - menu->addAction(tr("Enter WPS PIN"), this, - SLOT(enter_pin())); - } - - if (type == PEER_TYPE_P2P || type == PEER_TYPE_P2P_CLIENT) { - menu->addAction(tr("P2P Connect"), this, - SLOT(ctx_p2p_connect())); - if (method == SEL_METHOD_NONE && - config_methods > -1 && - config_methods & 0x0080 /* PBC */ && - config_methods != 0x0080) - menu->addAction(tr("P2P Connect (PBC)"), this, - SLOT(connect_pbc())); - if (method == SEL_METHOD_NONE) { - menu->addAction(tr("P2P Request PIN"), this, - SLOT(ctx_p2p_req_pin())); - menu->addAction(tr("P2P Show PIN"), this, - SLOT(ctx_p2p_show_pin())); - } - - if (config_methods > -1 && (config_methods & 0x0100)) { - /* Peer has Keypad */ - menu->addAction(tr("P2P Display PIN"), this, - SLOT(ctx_p2p_display_pin())); - } - - if (config_methods > -1 && (config_methods & 0x000c)) { - /* Peer has Label or Display */ - menu->addAction(tr("P2P Enter PIN"), this, - SLOT(ctx_p2p_enter_pin())); - } - } - - if (type == PEER_TYPE_P2P_GROUP) { - menu->addAction(tr("Show passphrase"), this, - SLOT(ctx_p2p_show_passphrase())); - menu->addAction(tr("Remove P2P Group"), this, - SLOT(ctx_p2p_remove_group())); - } - - if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || - type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT || - type == PEER_TYPE_P2P_INVITATION) { - menu->addAction(tr("Start group"), this, - SLOT(ctx_p2p_start_persistent())); - } - - if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || - type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) { - menu->addAction(tr("Invite"), this, - SLOT(ctx_p2p_invite())); - } - - if (type == PEER_TYPE_P2P_INVITATION) { - menu->addAction(tr("Ignore"), this, - SLOT(ctx_p2p_delete())); - } - - if (type == PEER_TYPE_AP_WPS) { - menu->addAction(tr("Connect (PBC)"), this, - SLOT(connect_pbc())); - } - - if ((type == PEER_TYPE_ASSOCIATED_STATION || - type == PEER_TYPE_WPS_ER_ENROLLEE || - type == PEER_TYPE_WPS_ENROLLEE) && - config_methods >= 0 && (config_methods & 0x0080)) { - menu->addAction(tr("Enroll (PBC)"), this, - SLOT(connect_pbc())); - } - - if (type == PEER_TYPE_WPS_ER_AP) { - menu->addAction(tr("Learn Configuration"), this, - SLOT(learn_ap_config())); - } - - menu->addAction(tr("Properties"), this, SLOT(properties())); - } else { - ctx_item = NULL; - menu->addAction(QString(tr("Refresh")), this, - SLOT(ctx_refresh())); - menu->addAction(tr("Start P2P discovery"), this, - SLOT(ctx_p2p_start())); - menu->addAction(tr("Stop P2P discovery"), this, - SLOT(ctx_p2p_stop())); - menu->addAction(tr("P2P listen only"), this, - SLOT(ctx_p2p_listen())); - menu->addAction(tr("Start P2P group"), this, - SLOT(ctx_p2p_start_group())); - if (hide_ap) - menu->addAction(tr("Show AP entries"), this, - SLOT(ctx_show_ap())); - else - menu->addAction(tr("Hide AP entries"), this, - SLOT(ctx_hide_ap())); - } - - menu->exec(peers->mapToGlobal(pos)); -} - - -void Peers::enter_pin() -{ - if (ctx_item == NULL) - return; - - int peer_type = ctx_item->data(peer_role_type).toInt(); - QString uuid; - QString addr; - addr = ctx_item->data(peer_role_address).toString(); - if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) - uuid = ctx_item->data(peer_role_uuid).toString(); - - StringQuery input(tr("PIN:")); - input.setWindowTitle(tr("PIN for ") + ctx_item->text()); - if (input.exec() != QDialog::Accepted) - return; - - char cmd[100]; - char reply[100]; - size_t reply_len; - - if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { - snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s", - uuid.toLocal8Bit().constData(), - input.get_string().toLocal8Bit().constData(), - addr.toLocal8Bit().constData()); - } else { - snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", - addr.toLocal8Bit().constData(), - input.get_string().toLocal8Bit().constData()); - } - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText(tr("Failed to set the WPS PIN.")); - msg.exec(); - } -} - - -void Peers::ctx_refresh() -{ - update_peers(); -} - - -void Peers::ctx_p2p_start() -{ - char reply[20]; - size_t reply_len; - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest("P2P_FIND", reply, &reply_len) < 0 || - memcmp(reply, "FAIL", 4) == 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText("Failed to start P2P discovery."); - msg.exec(); - } -} - - -void Peers::ctx_p2p_stop() -{ - char reply[20]; - size_t reply_len; - reply_len = sizeof(reply) - 1; - wpagui->ctrlRequest("P2P_STOP_FIND", reply, &reply_len); -} - - -void Peers::ctx_p2p_listen() -{ - char reply[20]; - size_t reply_len; - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest("P2P_LISTEN 3600", reply, &reply_len) < 0 || - memcmp(reply, "FAIL", 4) == 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText("Failed to start P2P listen."); - msg.exec(); - } -} - - -void Peers::ctx_p2p_start_group() -{ - char reply[20]; - size_t reply_len; - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest("P2P_GROUP_ADD", reply, &reply_len) < 0 || - memcmp(reply, "FAIL", 4) == 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText("Failed to start P2P group."); - msg.exec(); - } -} - - -void Peers::add_station(QString info) -{ - QStringList lines = info.split(QRegExp("\\n")); - QString name; - - for (QStringList::Iterator it = lines.begin(); - it != lines.end(); it++) { - int pos = (*it).indexOf('=') + 1; - if (pos < 1) - continue; - - if ((*it).startsWith("wpsDeviceName=")) - name = (*it).mid(pos); - else if ((*it).startsWith("p2p_device_name=")) - name = (*it).mid(pos); - } - - if (name.isEmpty()) - name = lines[0]; - - QStandardItem *item = new QStandardItem(*laptop_icon, name); - if (item) { - /* Remove WPS enrollee entry if one is still pending */ - if (model.rowCount() > 0) { - QModelIndexList lst = model.match(model.index(0, 0), - peer_role_address, - lines[0]); - for (int i = 0; i < lst.size(); i++) { - QStandardItem *item; - item = model.itemFromIndex(lst[i]); - if (item == NULL) - continue; - int type = item->data(peer_role_type).toInt(); - if (type == PEER_TYPE_WPS_ENROLLEE) { - model.removeRow(lst[i].row()); - break; - } - } - } - - item->setData(lines[0], peer_role_address); - item->setData(PEER_TYPE_ASSOCIATED_STATION, - peer_role_type); - item->setData(info, peer_role_details); - item->setToolTip(ItemType(PEER_TYPE_ASSOCIATED_STATION)); - model.appendRow(item); - } -} - - -void Peers::add_stations() -{ - char reply[2048]; - size_t reply_len; - char cmd[30]; - int res; - - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0) - return; - - do { - reply[reply_len] = '\0'; - QString info(reply); - char *txt = reply; - while (*txt != '\0' && *txt != '\n') - txt++; - *txt++ = '\0'; - if (strncmp(reply, "FAIL", 4) == 0 || - strncmp(reply, "UNKNOWN", 7) == 0) - break; - - add_station(info); - - reply_len = sizeof(reply) - 1; - res = snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply); - if (res < 0 || (size_t) res >= sizeof(cmd)) - break; - res = wpagui->ctrlRequest(cmd, reply, &reply_len); - } while (res >= 0); -} - - -void Peers::add_single_station(const char *addr) -{ - char reply[2048]; - size_t reply_len; - char cmd[30]; - - reply_len = sizeof(reply) - 1; - snprintf(cmd, sizeof(cmd), "STA %s", addr); - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) - return; - - reply[reply_len] = '\0'; - QString info(reply); - char *txt = reply; - while (*txt != '\0' && *txt != '\n') - txt++; - *txt++ = '\0'; - if (strncmp(reply, "FAIL", 4) == 0 || - strncmp(reply, "UNKNOWN", 7) == 0) - return; - - add_station(info); -} - - -void Peers::add_p2p_group_client(QStandardItem * /*parent*/, QString params) -{ - /* - * dev=02:b5:64:63:30:63 iface=02:b5:64:63:30:63 dev_capab=0x0 - * dev_type=1-0050f204-1 dev_name='Wireless Client' - * config_methods=0x8c - */ - - QStringList items = - params.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)")); - QString addr = ""; - QString name = ""; - int config_methods = 0; - QString dev_type; - - for (int i = 0; i < items.size(); i++) { - QString str = items.at(i); - int pos = str.indexOf('=') + 1; - if (str.startsWith("dev_name='")) - name = str.section('\'', 1, -2); - else if (str.startsWith("config_methods=")) - config_methods = - str.section('=', 1).toInt(0, 0); - else if (str.startsWith("dev=")) - addr = str.mid(pos); - else if (str.startsWith("dev_type=") && dev_type.isEmpty()) - dev_type = str.mid(pos); - } - - QStandardItem *item = find_addr(addr); - if (item) - return; - - item = new QStandardItem(*default_icon, name); - if (item) { - /* TODO: indicate somehow the relationship to the group owner - * (parent) */ - item->setData(addr, peer_role_address); - item->setData(config_methods, peer_role_config_methods); - item->setData(PEER_TYPE_P2P_CLIENT, peer_role_type); - if (!dev_type.isEmpty()) - item->setData(dev_type, peer_role_pri_dev_type); - item->setData(items.join(QString("\n")), peer_role_details); - item->setToolTip(ItemType(PEER_TYPE_P2P_CLIENT)); - model.appendRow(item); - } -} - - -void Peers::remove_bss(int id) -{ - if (model.rowCount() == 0) - return; - - QModelIndexList lst = model.match(model.index(0, 0), peer_role_bss_id, - id); - if (lst.size() == 0) - return; - model.removeRow(lst[0].row()); -} - - -bool Peers::add_bss(const char *cmd) -{ - char reply[2048]; - size_t reply_len; - - if (hide_ap) - return false; - - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) - return false; - reply[reply_len] = '\0'; - - QString bss(reply); - if (bss.isEmpty() || bss.startsWith("FAIL")) - return false; - - QString ssid, bssid, flags, wps_name, pri_dev_type; - int id = -1; - - QStringList lines = bss.split(QRegExp("\\n")); - for (QStringList::Iterator it = lines.begin(); - it != lines.end(); it++) { - int pos = (*it).indexOf('=') + 1; - if (pos < 1) - continue; - - if ((*it).startsWith("bssid=")) - bssid = (*it).mid(pos); - else if ((*it).startsWith("id=")) - id = (*it).mid(pos).toInt(); - else if ((*it).startsWith("flags=")) - flags = (*it).mid(pos); - else if ((*it).startsWith("ssid=")) - ssid = (*it).mid(pos); - else if ((*it).startsWith("wps_device_name=")) - wps_name = (*it).mid(pos); - else if ((*it).startsWith("wps_primary_device_type=")) - pri_dev_type = (*it).mid(pos); - } - - QString name = wps_name; - if (name.isEmpty()) - name = ssid + "\n" + bssid; - - QStandardItem *item = new QStandardItem(*ap_icon, name); - if (item) { - item->setData(bssid, peer_role_address); - if (id >= 0) - item->setData(id, peer_role_bss_id); - int type; - if (flags.contains("[WPS")) - type = PEER_TYPE_AP_WPS; - else - type = PEER_TYPE_AP; - item->setData(type, peer_role_type); - - for (int i = 0; i < lines.size(); i++) { - if (lines[i].length() > 60) { - lines[i].remove(60, lines[i].length()); - lines[i] += ".."; - } - } - item->setToolTip(ItemType(type)); - item->setData(lines.join("\n"), peer_role_details); - if (!pri_dev_type.isEmpty()) - item->setData(pri_dev_type, - peer_role_pri_dev_type); - if (!ssid.isEmpty()) - item->setData(ssid, peer_role_ssid); - model.appendRow(item); - - lines = bss.split(QRegExp("\\n")); - for (QStringList::Iterator it = lines.begin(); - it != lines.end(); it++) { - if ((*it).startsWith("p2p_group_client:")) - add_p2p_group_client(item, - (*it).mid(18)); - } - } - - return true; -} - - -void Peers::add_scan_results() -{ - int index; - char cmd[20]; - - index = 0; - while (wpagui) { - snprintf(cmd, sizeof(cmd), "BSS %d", index++); - if (index > 1000) - break; - - if (!add_bss(cmd)) - break; - } -} - - -void Peers::add_persistent(int id, const char *ssid, const char *bssid) -{ - char cmd[100]; - char reply[100]; - size_t reply_len; - int mode; - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d mode", id); - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) - return; - reply[reply_len] = '\0'; - mode = atoi(reply); - - QString name = ssid; - name = '[' + name + ']'; - - QStandardItem *item = new QStandardItem(*group_icon, name); - if (!item) - return; - - int type; - if (mode == 3) - type = PEER_TYPE_P2P_PERSISTENT_GROUP_GO; - else - type = PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT; - item->setData(type, peer_role_type); - item->setToolTip(ItemType(type)); - item->setData(ssid, peer_role_ssid); - if (bssid && strcmp(bssid, "any") == 0) - bssid = NULL; - if (bssid) - item->setData(bssid, peer_role_address); - item->setData(id, peer_role_network_id); - item->setBackground(Qt::BDiagPattern); - - model.appendRow(item); -} - - -void Peers::add_persistent_groups() -{ - char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; - size_t len; - - len = sizeof(buf) - 1; - if (wpagui->ctrlRequest("LIST_NETWORKS", buf, &len) < 0) - return; - - buf[len] = '\0'; - start = strchr(buf, '\n'); - if (start == NULL) - return; - start++; - - while (*start) { - bool last = false; - end = strchr(start, '\n'); - if (end == NULL) { - last = true; - end = start; - while (end[0] && end[1]) - end++; - } - *end = '\0'; - - id = start; - ssid = strchr(id, '\t'); - if (ssid == NULL) - break; - *ssid++ = '\0'; - bssid = strchr(ssid, '\t'); - if (bssid == NULL) - break; - *bssid++ = '\0'; - flags = strchr(bssid, '\t'); - if (flags == NULL) - break; - *flags++ = '\0'; - - if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) - add_persistent(atoi(id), ssid, bssid); - - if (last) - break; - start = end + 1; - } -} - - -void Peers::update_peers() -{ - model.clear(); - if (wpagui == NULL) - return; - - char reply[20]; - size_t replylen = sizeof(reply) - 1; - wpagui->ctrlRequest("WPS_ER_START", reply, &replylen); - - add_stations(); - add_scan_results(); - add_persistent_groups(); -} - - -QStandardItem * Peers::find_addr(QString addr) -{ - if (model.rowCount() == 0) - return NULL; - - QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, - addr); - if (lst.size() == 0) - return NULL; - return model.itemFromIndex(lst[0]); -} - - -QStandardItem * Peers::find_addr_type(QString addr, int type) -{ - if (model.rowCount() == 0) - return NULL; - - QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, - addr); - for (int i = 0; i < lst.size(); i++) { - QStandardItem *item = model.itemFromIndex(lst[i]); - if (item->data(peer_role_type).toInt() == type) - return item; - } - return NULL; -} - - -QStandardItem * Peers::find_uuid(QString uuid) -{ - if (model.rowCount() == 0) - return NULL; - - QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid, - uuid); - if (lst.size() == 0) - return NULL; - return model.itemFromIndex(lst[0]); -} - - -void Peers::event_notify(WpaMsg msg) -{ - QString text = msg.getMsg(); - - if (text.startsWith(WPS_EVENT_PIN_NEEDED)) { - /* - * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7 - * 02:2a:c4:18:5b:f3 - * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1] - */ - QStringList items = text.split(' '); - QString uuid = items[1]; - QString addr = items[2]; - QString name = ""; - - QStandardItem *item = find_addr(addr); - if (item) - return; - - int pos = text.indexOf('['); - if (pos >= 0) { - int pos2 = text.lastIndexOf(']'); - if (pos2 >= pos) { - items = text.mid(pos + 1, pos2 - pos - 1). - split('|'); - name = items[0]; - items.append(addr); - } - } - - item = new QStandardItem(*laptop_icon, name); - if (item) { - item->setData(addr, peer_role_address); - item->setData(PEER_TYPE_WPS_PIN_NEEDED, - peer_role_type); - item->setToolTip(ItemType(PEER_TYPE_WPS_PIN_NEEDED)); - item->setData(items.join("\n"), peer_role_details); - item->setData(items[5], peer_role_pri_dev_type); - model.appendRow(item); - } - return; - } - - if (text.startsWith(AP_STA_CONNECTED)) { - /* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */ - QStringList items = text.split(' '); - QString addr = items[1]; - QStandardItem *item = find_addr(addr); - if (item == NULL || item->data(peer_role_type).toInt() != - PEER_TYPE_ASSOCIATED_STATION) - add_single_station(addr.toLocal8Bit().constData()); - return; - } - - if (text.startsWith(AP_STA_DISCONNECTED)) { - /* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */ - QStringList items = text.split(' '); - QString addr = items[1]; - - if (model.rowCount() == 0) - return; - - QModelIndexList lst = model.match(model.index(0, 0), - peer_role_address, addr, -1); - for (int i = 0; i < lst.size(); i++) { - QStandardItem *item = model.itemFromIndex(lst[i]); - if (item && item->data(peer_role_type).toInt() == - PEER_TYPE_ASSOCIATED_STATION) { - model.removeRow(lst[i].row()); - break; - } - } - return; - } - - if (text.startsWith(P2P_EVENT_DEVICE_FOUND)) { - /* - * P2P-DEVICE-FOUND 02:b5:64:63:30:63 - * p2p_dev_addr=02:b5:64:63:30:63 pri_dev_type=1-0050f204-1 - * name='Wireless Client' config_methods=0x84 dev_capab=0x21 - * group_capab=0x0 - */ - QStringList items = - text.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)")); - QString addr = items[1]; - QString name = ""; - QString pri_dev_type; - int config_methods = 0; - for (int i = 0; i < items.size(); i++) { - QString str = items.at(i); - if (str.startsWith("name='")) - name = str.section('\'', 1, -2); - else if (str.startsWith("config_methods=")) - config_methods = - str.section('=', 1).toInt(0, 0); - else if (str.startsWith("pri_dev_type=")) - pri_dev_type = str.section('=', 1); - } - - QStandardItem *item = find_addr(addr); - if (item) { - int type = item->data(peer_role_type).toInt(); - if (type == PEER_TYPE_P2P) - return; - } - - item = new QStandardItem(*default_icon, name); - if (item) { - item->setData(addr, peer_role_address); - item->setData(config_methods, - peer_role_config_methods); - item->setData(PEER_TYPE_P2P, peer_role_type); - if (!pri_dev_type.isEmpty()) - item->setData(pri_dev_type, - peer_role_pri_dev_type); - item->setData(items.join(QString("\n")), - peer_role_details); - item->setToolTip(ItemType(PEER_TYPE_P2P)); - model.appendRow(item); - } - - item = find_addr_type(addr, - PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT); - if (item) - item->setBackground(Qt::NoBrush); - } - - if (text.startsWith(P2P_EVENT_GROUP_STARTED)) { - /* P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F" - * passphrase="YOyTkxID" go_dev_addr=02:40:61:c2:f3:b7 - * [PERSISTENT] */ - QStringList items = text.split(' '); - if (items.size() < 4) - return; - - int pos = text.indexOf(" ssid=\""); - if (pos < 0) - return; - QString ssid = text.mid(pos + 7); - pos = ssid.indexOf(" passphrase=\""); - if (pos < 0) - pos = ssid.indexOf(" psk="); - if (pos >= 0) - ssid.truncate(pos); - pos = ssid.lastIndexOf('"'); - if (pos >= 0) - ssid.truncate(pos); - - QStandardItem *item = new QStandardItem(*group_icon, ssid); - if (item) { - item->setData(PEER_TYPE_P2P_GROUP, peer_role_type); - item->setData(items[1], peer_role_ifname); - QString details; - if (items[2] == "GO") { - details = tr("P2P GO for interface ") + - items[1]; - } else { - details = tr("P2P client for interface ") + - items[1]; - } - if (text.contains(" [PERSISTENT]")) - details += "\nPersistent group"; - item->setData(details, peer_role_details); - item->setToolTip(ItemType(PEER_TYPE_P2P_GROUP)); - model.appendRow(item); - } - } - - if (text.startsWith(P2P_EVENT_GROUP_REMOVED)) { - /* P2P-GROUP-REMOVED wlan0-p2p-0 GO */ - QStringList items = text.split(' '); - if (items.size() < 2) - return; - - if (model.rowCount() == 0) - return; - - QModelIndexList lst = model.match(model.index(0, 0), - peer_role_ifname, items[1]); - for (int i = 0; i < lst.size(); i++) - model.removeRow(lst[i].row()); - return; - } - - if (text.startsWith(P2P_EVENT_PROV_DISC_SHOW_PIN)) { - /* P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670 */ - QStringList items = text.split(' '); - if (items.size() < 3) - return; - QString addr = items[1]; - QString pin = items[2]; - - QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P); - if (item == NULL) - return; - item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY, - peer_role_selected_method); - item->setData(pin, peer_role_selected_pin); - QVariant var = item->data(peer_role_requested_method); - if (var.isValid() && - var.toInt() == SEL_METHOD_PIN_LOCAL_DISPLAY) { - ctx_item = item; - ctx_p2p_display_pin_pd(); - } - return; - } - - if (text.startsWith(P2P_EVENT_PROV_DISC_ENTER_PIN)) { - /* P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 */ - QStringList items = text.split(' '); - if (items.size() < 2) - return; - QString addr = items[1]; - - QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P); - if (item == NULL) - return; - item->setData(SEL_METHOD_PIN_PEER_DISPLAY, - peer_role_selected_method); - QVariant var = item->data(peer_role_requested_method); - if (var.isValid() && - var.toInt() == SEL_METHOD_PIN_PEER_DISPLAY) { - ctx_item = item; - ctx_p2p_connect(); - } - return; - } - - if (text.startsWith(P2P_EVENT_INVITATION_RECEIVED)) { - /* P2P-INVITATION-RECEIVED sa=02:f0:bc:44:87:62 persistent=4 */ - QStringList items = text.split(' '); - if (items.size() < 3) - return; - if (!items[1].startsWith("sa=") || - !items[2].startsWith("persistent=")) - return; - QString addr = items[1].mid(3); - int id = items[2].mid(11).toInt(); - - char cmd[100]; - char reply[100]; - size_t reply_len; - - snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", id); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) - return; - reply[reply_len] = '\0'; - QString name; - char *pos = strrchr(reply, '"'); - if (pos && reply[0] == '"') { - *pos = '\0'; - name = reply + 1; - } else - name = reply; - - QStandardItem *item; - item = find_addr_type(addr, PEER_TYPE_P2P_INVITATION); - if (item) - model.removeRow(item->row()); - - item = new QStandardItem(*invitation_icon, name); - if (!item) - return; - item->setData(PEER_TYPE_P2P_INVITATION, peer_role_type); - item->setToolTip(ItemType(PEER_TYPE_P2P_INVITATION)); - item->setData(addr, peer_role_address); - item->setData(id, peer_role_network_id); - - model.appendRow(item); - - enable_persistent(id); - - return; - } - - if (text.startsWith(P2P_EVENT_INVITATION_RESULT)) { - /* P2P-INVITATION-RESULT status=1 */ - /* TODO */ - return; - } - - if (text.startsWith(WPS_EVENT_ER_AP_ADD)) { - /* - * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 - * 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 - * |Very friendly name|Company|Long description of the model| - * WAP|http://w1.fi/|http://w1.fi/hostapd/ - */ - QStringList items = text.split(' '); - if (items.size() < 5) - return; - QString uuid = items[1]; - QString addr = items[2]; - QString pri_dev_type = items[3].mid(13); - int wps_state = items[4].mid(10).toInt(); - - int pos = text.indexOf('|'); - if (pos < 0) - return; - items = text.mid(pos + 1).split('|'); - if (items.size() < 1) - return; - - QStandardItem *item = find_uuid(uuid); - if (item) - return; - - item = new QStandardItem(*ap_icon, items[0]); - if (item) { - item->setData(uuid, peer_role_uuid); - item->setData(addr, peer_role_address); - int type = wps_state == 2 ? PEER_TYPE_WPS_ER_AP: - PEER_TYPE_WPS_ER_AP_UNCONFIGURED; - item->setData(type, peer_role_type); - item->setToolTip(ItemType(type)); - item->setData(pri_dev_type, peer_role_pri_dev_type); - item->setData(items.join(QString("\n")), - peer_role_details); - model.appendRow(item); - } - - return; - } - - if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) { - /* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */ - QStringList items = text.split(' '); - if (items.size() < 2) - return; - if (model.rowCount() == 0) - return; - - QModelIndexList lst = model.match(model.index(0, 0), - peer_role_uuid, items[1]); - for (int i = 0; i < lst.size(); i++) { - QStandardItem *item = model.itemFromIndex(lst[i]); - if (item && - (item->data(peer_role_type).toInt() == - PEER_TYPE_WPS_ER_AP || - item->data(peer_role_type).toInt() == - PEER_TYPE_WPS_ER_AP_UNCONFIGURED)) - model.removeRow(lst[i].row()); - } - return; - } - - if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) { - /* - * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 - * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 - * pri_dev_type=1-0050F204-1 - * |Wireless Client|Company|cmodel|123|12345| - */ - QStringList items = text.split(' '); - if (items.size() < 3) - return; - QString uuid = items[1]; - QString addr = items[2]; - QString pri_dev_type = items[6].mid(13); - int config_methods = -1; - int dev_passwd_id = -1; - - for (int i = 3; i < items.size(); i++) { - int pos = items[i].indexOf('=') + 1; - if (pos < 1) - continue; - QString val = items[i].mid(pos); - if (items[i].startsWith("config_methods=")) { - config_methods = val.toInt(0, 0); - } else if (items[i].startsWith("dev_passwd_id=")) { - dev_passwd_id = val.toInt(); - } - } - - int pos = text.indexOf('|'); - if (pos < 0) - return; - items = text.mid(pos + 1).split('|'); - if (items.size() < 1) - return; - QString name = items[0]; - if (name.length() == 0) - name = addr; - - remove_enrollee_uuid(uuid); - - QStandardItem *item; - item = new QStandardItem(*laptop_icon, name); - if (item) { - item->setData(uuid, peer_role_uuid); - item->setData(addr, peer_role_address); - item->setData(PEER_TYPE_WPS_ER_ENROLLEE, - peer_role_type); - item->setToolTip(ItemType(PEER_TYPE_WPS_ER_ENROLLEE)); - item->setData(items.join(QString("\n")), - peer_role_details); - item->setData(pri_dev_type, peer_role_pri_dev_type); - if (config_methods >= 0) - item->setData(config_methods, - peer_role_config_methods); - if (dev_passwd_id >= 0) - item->setData(dev_passwd_id, - peer_role_dev_passwd_id); - model.appendRow(item); - } - - return; - } - - if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) { - /* - * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 - * 02:66:a0:ee:17:27 - */ - QStringList items = text.split(' '); - if (items.size() < 2) - return; - remove_enrollee_uuid(items[1]); - return; - } - - if (text.startsWith(WPS_EVENT_ENROLLEE_SEEN)) { - /* TODO: need to time out this somehow or remove on successful - * WPS run, etc. */ - /* - * WPS-ENROLLEE-SEEN 02:00:00:00:01:00 - * 572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1 - * [Wireless Client] - * (MAC addr, UUID-E, pri dev type, config methods, - * dev passwd id, request type, [dev name]) - */ - QStringList items = text.split(' '); - if (items.size() < 7) - return; - QString addr = items[1]; - QString uuid = items[2]; - QString pri_dev_type = items[3]; - int config_methods = items[4].toInt(0, 0); - int dev_passwd_id = items[5].toInt(); - QString name; - - QStandardItem *item = find_addr(addr); - if (item) { - int type = item->data(peer_role_type).toInt(); - if (type == PEER_TYPE_ASSOCIATED_STATION) - return; /* already associated */ - } - - int pos = text.indexOf('['); - if (pos >= 0) { - int pos2 = text.lastIndexOf(']'); - if (pos2 >= pos) { - QStringList items2 = - text.mid(pos + 1, pos2 - pos - 1). - split('|'); - name = items2[0]; - } - } - if (name.isEmpty()) - name = addr; - - item = find_uuid(uuid); - if (item) { - QVariant var = item->data(peer_role_config_methods); - QVariant var2 = item->data(peer_role_dev_passwd_id); - if ((var.isValid() && config_methods != var.toInt()) || - (var2.isValid() && dev_passwd_id != var2.toInt())) - remove_enrollee_uuid(uuid); - else - return; - } - - item = new QStandardItem(*laptop_icon, name); - if (item) { - item->setData(uuid, peer_role_uuid); - item->setData(addr, peer_role_address); - item->setData(PEER_TYPE_WPS_ENROLLEE, - peer_role_type); - item->setToolTip(ItemType(PEER_TYPE_WPS_ENROLLEE)); - item->setData(items.join(QString("\n")), - peer_role_details); - item->setData(pri_dev_type, peer_role_pri_dev_type); - item->setData(config_methods, - peer_role_config_methods); - item->setData(dev_passwd_id, peer_role_dev_passwd_id); - model.appendRow(item); - } - - return; - } - - if (text.startsWith(WPA_EVENT_BSS_ADDED)) { - /* CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55 */ - QStringList items = text.split(' '); - if (items.size() < 2) - return; - char cmd[20]; - snprintf(cmd, sizeof(cmd), "BSS ID-%d", items[1].toInt()); - add_bss(cmd); - return; - } - - if (text.startsWith(WPA_EVENT_BSS_REMOVED)) { - /* CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55 */ - QStringList items = text.split(' '); - if (items.size() < 2) - return; - remove_bss(items[1].toInt()); - return; - } -} - - -void Peers::ctx_p2p_connect() -{ - if (ctx_item == NULL) - return; - QString addr = ctx_item->data(peer_role_address).toString(); - QString arg; - int config_methods = - ctx_item->data(peer_role_config_methods).toInt(); - enum selected_method method = SEL_METHOD_NONE; - QVariant var = ctx_item->data(peer_role_selected_method); - if (var.isValid()) - method = (enum selected_method) var.toInt(); - if (method == SEL_METHOD_PIN_LOCAL_DISPLAY) { - arg = ctx_item->data(peer_role_selected_pin).toString(); - char cmd[100]; - char reply[100]; - size_t reply_len; - snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display", - addr.toLocal8Bit().constData(), - arg.toLocal8Bit().constData()); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText("Failed to initiate P2P connect."); - msg.exec(); - return; - } - QMessageBox::information(this, - tr("PIN for ") + ctx_item->text(), - tr("Enter the following PIN on the\n" - "peer device: ") + arg); - } else if (method == SEL_METHOD_PIN_PEER_DISPLAY) { - StringQuery input(tr("PIN from peer display:")); - input.setWindowTitle(tr("PIN for ") + ctx_item->text()); - if (input.exec() != QDialog::Accepted) - return; - arg = input.get_string(); - } else if (config_methods == 0x0080 /* PBC */) { - arg = "pbc"; - } else { - StringQuery input(tr("PIN:")); - input.setWindowTitle(tr("PIN for ") + ctx_item->text()); - if (input.exec() != QDialog::Accepted) - return; - arg = input.get_string(); - } - - char cmd[100]; - char reply[100]; - size_t reply_len; - snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s", - addr.toLocal8Bit().constData(), - arg.toLocal8Bit().constData()); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText("Failed to initiate P2P connect."); - msg.exec(); - } -} - - -void Peers::ctx_p2p_req_pin() -{ - if (ctx_item == NULL) - return; - QString addr = ctx_item->data(peer_role_address).toString(); - ctx_item->setData(SEL_METHOD_PIN_PEER_DISPLAY, - peer_role_requested_method); - - char cmd[100]; - char reply[100]; - size_t reply_len; - snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s display", - addr.toLocal8Bit().constData()); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText(tr("Failed to request PIN from peer.")); - msg.exec(); - } -} - - -void Peers::ctx_p2p_show_pin() -{ - if (ctx_item == NULL) - return; - QString addr = ctx_item->data(peer_role_address).toString(); - ctx_item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY, - peer_role_requested_method); - - char cmd[100]; - char reply[100]; - size_t reply_len; - snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s keypad", - addr.toLocal8Bit().constData()); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText(tr("Failed to request peer to enter PIN.")); - msg.exec(); - } -} - - -void Peers::ctx_p2p_display_pin() -{ - if (ctx_item == NULL) - return; - QString addr = ctx_item->data(peer_role_address).toString(); - - char cmd[100]; - char reply[100]; - size_t reply_len; - snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pin", - addr.toLocal8Bit().constData()); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText("Failed to initiate P2P connect."); - msg.exec(); - return; - } - reply[reply_len] = '\0'; - QMessageBox::information(this, - tr("PIN for ") + ctx_item->text(), - tr("Enter the following PIN on the\n" - "peer device: ") + reply); -} - - -void Peers::ctx_p2p_display_pin_pd() -{ - if (ctx_item == NULL) - return; - QString addr = ctx_item->data(peer_role_address).toString(); - QString arg = ctx_item->data(peer_role_selected_pin).toString(); - - char cmd[100]; - char reply[100]; - size_t reply_len; - snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display", - addr.toLocal8Bit().constData(), - arg.toLocal8Bit().constData()); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText("Failed to initiate P2P connect."); - msg.exec(); - return; - } - reply[reply_len] = '\0'; - QMessageBox::information(this, - tr("PIN for ") + ctx_item->text(), - tr("Enter the following PIN on the\n" - "peer device: ") + arg); -} - - -void Peers::ctx_p2p_enter_pin() -{ - if (ctx_item == NULL) - return; - QString addr = ctx_item->data(peer_role_address).toString(); - QString arg; - - StringQuery input(tr("PIN from peer:")); - input.setWindowTitle(tr("PIN for ") + ctx_item->text()); - if (input.exec() != QDialog::Accepted) - return; - arg = input.get_string(); - - char cmd[100]; - char reply[100]; - size_t reply_len; - snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s keypad", - addr.toLocal8Bit().constData(), - arg.toLocal8Bit().constData()); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText("Failed to initiate P2P connect."); - msg.exec(); - } -} - - -void Peers::ctx_p2p_remove_group() -{ - if (ctx_item == NULL) - return; - char cmd[100]; - char reply[100]; - size_t reply_len; - snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s", - ctx_item->data(peer_role_ifname).toString().toLocal8Bit(). - constData()); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText("Failed to remove P2P Group."); - msg.exec(); - } -} - - -void Peers::closeEvent(QCloseEvent *) -{ - if (wpagui) { - char reply[20]; - size_t replylen = sizeof(reply) - 1; - wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen); - } -} - - -void Peers::done(int r) -{ - QDialog::done(r); - close(); -} - - -void Peers::remove_enrollee_uuid(QString uuid) -{ - if (model.rowCount() == 0) - return; - - QModelIndexList lst = model.match(model.index(0, 0), - peer_role_uuid, uuid); - for (int i = 0; i < lst.size(); i++) { - QStandardItem *item = model.itemFromIndex(lst[i]); - if (item == NULL) - continue; - int type = item->data(peer_role_type).toInt(); - if (type == PEER_TYPE_WPS_ER_ENROLLEE || - type == PEER_TYPE_WPS_ENROLLEE) - model.removeRow(lst[i].row()); - } -} - - -void Peers::properties() -{ - if (ctx_item == NULL) - return; - - QMessageBox msg(this); - msg.setStandardButtons(QMessageBox::Ok); - msg.setDefaultButton(QMessageBox::Ok); - msg.setEscapeButton(QMessageBox::Ok); - msg.setWindowTitle(tr("Peer Properties")); - - int type = ctx_item->data(peer_role_type).toInt(); - QString title = Peers::ItemType(type); - - msg.setText(title + QString("\n") + tr("Name: ") + ctx_item->text()); - - QVariant var; - QString info; - - var = ctx_item->data(peer_role_address); - if (var.isValid()) - info += tr("Address: ") + var.toString() + QString("\n"); - - var = ctx_item->data(peer_role_uuid); - if (var.isValid()) - info += tr("UUID: ") + var.toString() + QString("\n"); - - var = ctx_item->data(peer_role_pri_dev_type); - if (var.isValid()) - info += tr("Primary Device Type: ") + var.toString() + - QString("\n"); - - var = ctx_item->data(peer_role_ssid); - if (var.isValid()) - info += tr("SSID: ") + var.toString() + QString("\n"); - - var = ctx_item->data(peer_role_config_methods); - if (var.isValid()) { - int methods = var.toInt(); - info += tr("Configuration Methods: "); - if (methods & 0x0001) - info += tr("[USBA]"); - if (methods & 0x0002) - info += tr("[Ethernet]"); - if (methods & 0x0004) - info += tr("[Label]"); - if (methods & 0x0008) - info += tr("[Display]"); - if (methods & 0x0010) - info += tr("[Ext. NFC Token]"); - if (methods & 0x0020) - info += tr("[Int. NFC Token]"); - if (methods & 0x0040) - info += tr("[NFC Interface]"); - if (methods & 0x0080) - info += tr("[Push Button]"); - if (methods & 0x0100) - info += tr("[Keypad]"); - info += "\n"; - } - - var = ctx_item->data(peer_role_selected_method); - if (var.isValid()) { - enum selected_method method = - (enum selected_method) var.toInt(); - switch (method) { - case SEL_METHOD_NONE: - break; - case SEL_METHOD_PIN_PEER_DISPLAY: - info += tr("Selected Method: PIN on peer display\n"); - break; - case SEL_METHOD_PIN_LOCAL_DISPLAY: - info += tr("Selected Method: PIN on local display\n"); - break; - } - } - - var = ctx_item->data(peer_role_selected_pin); - if (var.isValid()) { - info += tr("PIN to enter on peer: ") + var.toString() + "\n"; - } - - var = ctx_item->data(peer_role_dev_passwd_id); - if (var.isValid()) { - info += tr("Device Password ID: ") + var.toString(); - switch (var.toInt()) { - case 0: - info += tr(" (Default PIN)"); - break; - case 1: - info += tr(" (User-specified PIN)"); - break; - case 2: - info += tr(" (Machine-specified PIN)"); - break; - case 3: - info += tr(" (Rekey)"); - break; - case 4: - info += tr(" (Push Button)"); - break; - case 5: - info += tr(" (Registrar-specified)"); - break; - } - info += "\n"; - } - - msg.setInformativeText(info); - - var = ctx_item->data(peer_role_details); - if (var.isValid()) - msg.setDetailedText(var.toString()); - - msg.exec(); -} - - -void Peers::connect_pbc() -{ - if (ctx_item == NULL) - return; - - char cmd[100]; - char reply[100]; - size_t reply_len; - - int peer_type = ctx_item->data(peer_role_type).toInt(); - if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { - snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s", - ctx_item->data(peer_role_uuid).toString().toLocal8Bit(). - constData()); - } else if (peer_type == PEER_TYPE_P2P || - peer_type == PEER_TYPE_P2P_CLIENT) { - snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pbc", - ctx_item->data(peer_role_address).toString(). - toLocal8Bit().constData()); - } else { - snprintf(cmd, sizeof(cmd), "WPS_PBC"); - } - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText(tr("Failed to start WPS PBC.")); - msg.exec(); - } -} - - -void Peers::learn_ap_config() -{ - if (ctx_item == NULL) - return; - - QString uuid = ctx_item->data(peer_role_uuid).toString(); - - StringQuery input(tr("AP PIN:")); - input.setWindowTitle(tr("AP PIN for ") + ctx_item->text()); - if (input.exec() != QDialog::Accepted) - return; - - char cmd[100]; - char reply[100]; - size_t reply_len; - - snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s", - uuid.toLocal8Bit().constData(), - input.get_string().toLocal8Bit().constData()); - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText(tr("Failed to start learning AP configuration.")); - msg.exec(); - } -} - - -void Peers::ctx_hide_ap() -{ - hide_ap = true; - - if (model.rowCount() == 0) - return; - - do { - QModelIndexList lst; - lst = model.match(model.index(0, 0), - peer_role_type, PEER_TYPE_AP); - if (lst.size() == 0) { - lst = model.match(model.index(0, 0), - peer_role_type, PEER_TYPE_AP_WPS); - if (lst.size() == 0) - break; - } - - model.removeRow(lst[0].row()); - } while (1); -} - - -void Peers::ctx_show_ap() -{ - hide_ap = false; - add_scan_results(); -} - - -void Peers::ctx_p2p_show_passphrase() -{ - char reply[64]; - size_t reply_len; - - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest("P2P_GET_PASSPHRASE", reply, &reply_len) < 0 || - memcmp(reply, "FAIL", 4) == 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText("Failed to get P2P group passphrase."); - msg.exec(); - } else { - reply[reply_len] = '\0'; - QMessageBox::information(this, tr("Passphrase"), - tr("P2P group passphrase:\n") + - reply); - } -} - - -void Peers::ctx_p2p_start_persistent() -{ - if (ctx_item == NULL) - return; - - char cmd[100]; - char reply[100]; - size_t reply_len; - - snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD persistent=%d", - ctx_item->data(peer_role_network_id).toInt()); - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 || - memcmp(reply, "FAIL", 4) == 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText(tr("Failed to start persistent P2P Group.")); - msg.exec(); - } else if (ctx_item->data(peer_role_type).toInt() == - PEER_TYPE_P2P_INVITATION) - model.removeRow(ctx_item->row()); -} - - -void Peers::ctx_p2p_invite() -{ - if (ctx_item == NULL) - return; - - char cmd[100]; - char reply[100]; - size_t reply_len; - - snprintf(cmd, sizeof(cmd), "P2P_INVITE persistent=%d", - ctx_item->data(peer_role_network_id).toInt()); - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 || - memcmp(reply, "FAIL", 4) == 0) { - QMessageBox msg; - msg.setIcon(QMessageBox::Warning); - msg.setText(tr("Failed to invite peer to start persistent " - "P2P Group.")); - msg.exec(); - } -} - - -void Peers::ctx_p2p_delete() -{ - if (ctx_item == NULL) - return; - model.removeRow(ctx_item->row()); -} - - -void Peers::enable_persistent(int id) -{ - if (model.rowCount() == 0) - return; - - QModelIndexList lst = model.match(model.index(0, 0), - peer_role_network_id, id); - for (int i = 0; i < lst.size(); i++) { - QStandardItem *item = model.itemFromIndex(lst[i]); - int type = item->data(peer_role_type).toInt(); - if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || - type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) - item->setBackground(Qt::NoBrush); - } -} +/* + * wpa_gui - Peers class + * Copyright (c) 2009-2010, Atheros Communications + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include +#include + +#include "common/wpa_ctrl.h" +#include "wpagui.h" +#include "stringquery.h" +#include "peers.h" + + +enum { + peer_role_address = Qt::UserRole + 1, + peer_role_type, + peer_role_uuid, + peer_role_details, + peer_role_ifname, + peer_role_pri_dev_type, + peer_role_ssid, + peer_role_config_methods, + peer_role_dev_passwd_id, + peer_role_bss_id, + peer_role_selected_method, + peer_role_selected_pin, + peer_role_requested_method, + peer_role_network_id +}; + +enum selected_method { + SEL_METHOD_NONE, + SEL_METHOD_PIN_PEER_DISPLAY, + SEL_METHOD_PIN_LOCAL_DISPLAY +}; + +/* + * TODO: + * - add current AP info (e.g., from WPS) in station mode + */ + +enum peer_type { + PEER_TYPE_ASSOCIATED_STATION, + PEER_TYPE_AP, + PEER_TYPE_AP_WPS, + PEER_TYPE_WPS_PIN_NEEDED, + PEER_TYPE_P2P, + PEER_TYPE_P2P_CLIENT, + PEER_TYPE_P2P_GROUP, + PEER_TYPE_P2P_PERSISTENT_GROUP_GO, + PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT, + PEER_TYPE_P2P_INVITATION, + PEER_TYPE_WPS_ER_AP, + PEER_TYPE_WPS_ER_AP_UNCONFIGURED, + PEER_TYPE_WPS_ER_ENROLLEE, + PEER_TYPE_WPS_ENROLLEE +}; + + +Peers::Peers(QWidget *parent, const char *, bool, Qt::WindowFlags) + : QDialog(parent) +{ + setupUi(this); + + if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) + { + default_icon = new QIcon(":/icons/wpa_gui.svg"); + ap_icon = new QIcon(":/icons/ap.svg"); + laptop_icon = new QIcon(":/icons/laptop.svg"); + group_icon = new QIcon(":/icons/group.svg"); + invitation_icon = new QIcon(":/icons/invitation.svg"); + } else { + default_icon = new QIcon(":/icons/wpa_gui.png"); + ap_icon = new QIcon(":/icons/ap.png"); + laptop_icon = new QIcon(":/icons/laptop.png"); + group_icon = new QIcon(":/icons/group.png"); + invitation_icon = new QIcon(":/icons/invitation.png"); + } + + peers->setModel(&model); + peers->setResizeMode(QListView::Adjust); + peers->setDragEnabled(false); + peers->setSelectionMode(QAbstractItemView::NoSelection); + + peers->setContextMenuPolicy(Qt::CustomContextMenu); + connect(peers, SIGNAL(customContextMenuRequested(const QPoint &)), + this, SLOT(context_menu(const QPoint &))); + + wpagui = NULL; + hide_ap = false; +} + + +void Peers::setWpaGui(WpaGui *_wpagui) +{ + wpagui = _wpagui; + update_peers(); +} + + +Peers::~Peers() +{ + delete default_icon; + delete ap_icon; + delete laptop_icon; + delete group_icon; + delete invitation_icon; +} + + +void Peers::languageChange() +{ + retranslateUi(this); +} + + +QString Peers::ItemType(int type) +{ + QString title; + switch (type) { + case PEER_TYPE_ASSOCIATED_STATION: + title = tr("Associated station"); + break; + case PEER_TYPE_AP: + title = tr("AP"); + break; + case PEER_TYPE_AP_WPS: + title = tr("WPS AP"); + break; + case PEER_TYPE_WPS_PIN_NEEDED: + title = tr("WPS PIN needed"); + break; + case PEER_TYPE_P2P: + title = tr("P2P Device"); + break; + case PEER_TYPE_P2P_CLIENT: + title = tr("P2P Device (group client)"); + break; + case PEER_TYPE_P2P_GROUP: + title = tr("P2P Group"); + break; + case PEER_TYPE_P2P_PERSISTENT_GROUP_GO: + title = tr("P2P Persistent Group (GO)"); + break; + case PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT: + title = tr("P2P Persistent Group (client)"); + break; + case PEER_TYPE_P2P_INVITATION: + title = tr("P2P Invitation"); + break; + case PEER_TYPE_WPS_ER_AP: + title = tr("ER: WPS AP"); + break; + case PEER_TYPE_WPS_ER_AP_UNCONFIGURED: + title = tr("ER: WPS AP (Unconfigured)"); + break; + case PEER_TYPE_WPS_ER_ENROLLEE: + title = tr("ER: WPS Enrollee"); + break; + case PEER_TYPE_WPS_ENROLLEE: + title = tr("WPS Enrollee"); + break; + } + return title; +} + + +void Peers::context_menu(const QPoint &pos) +{ + QMenu *menu = new QMenu; + if (menu == NULL) + return; + + QModelIndex idx = peers->indexAt(pos); + if (idx.isValid()) { + ctx_item = model.itemFromIndex(idx); + int type = ctx_item->data(peer_role_type).toInt(); + menu->addAction(Peers::ItemType(type))->setEnabled(false); + menu->addSeparator(); + + int config_methods = -1; + QVariant var = ctx_item->data(peer_role_config_methods); + if (var.isValid()) + config_methods = var.toInt(); + + enum selected_method method = SEL_METHOD_NONE; + var = ctx_item->data(peer_role_selected_method); + if (var.isValid()) + method = (enum selected_method) var.toInt(); + + if ((type == PEER_TYPE_ASSOCIATED_STATION || + type == PEER_TYPE_AP_WPS || + type == PEER_TYPE_WPS_PIN_NEEDED || + type == PEER_TYPE_WPS_ER_ENROLLEE || + type == PEER_TYPE_WPS_ENROLLEE) && + (config_methods == -1 || (config_methods & 0x010c))) { + menu->addAction(tr("Enter WPS PIN"), this, + SLOT(enter_pin())); + } + + if (type == PEER_TYPE_P2P || type == PEER_TYPE_P2P_CLIENT) { + menu->addAction(tr("P2P Connect"), this, + SLOT(ctx_p2p_connect())); + if (method == SEL_METHOD_NONE && + config_methods > -1 && + config_methods & 0x0080 /* PBC */ && + config_methods != 0x0080) + menu->addAction(tr("P2P Connect (PBC)"), this, + SLOT(connect_pbc())); + if (method == SEL_METHOD_NONE) { + menu->addAction(tr("P2P Request PIN"), this, + SLOT(ctx_p2p_req_pin())); + menu->addAction(tr("P2P Show PIN"), this, + SLOT(ctx_p2p_show_pin())); + } + + if (config_methods > -1 && (config_methods & 0x0100)) { + /* Peer has Keypad */ + menu->addAction(tr("P2P Display PIN"), this, + SLOT(ctx_p2p_display_pin())); + } + + if (config_methods > -1 && (config_methods & 0x000c)) { + /* Peer has Label or Display */ + menu->addAction(tr("P2P Enter PIN"), this, + SLOT(ctx_p2p_enter_pin())); + } + } + + if (type == PEER_TYPE_P2P_GROUP) { + menu->addAction(tr("Show passphrase"), this, + SLOT(ctx_p2p_show_passphrase())); + menu->addAction(tr("Remove P2P Group"), this, + SLOT(ctx_p2p_remove_group())); + } + + if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || + type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT || + type == PEER_TYPE_P2P_INVITATION) { + menu->addAction(tr("Start group"), this, + SLOT(ctx_p2p_start_persistent())); + } + + if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || + type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) { + menu->addAction(tr("Invite"), this, + SLOT(ctx_p2p_invite())); + } + + if (type == PEER_TYPE_P2P_INVITATION) { + menu->addAction(tr("Ignore"), this, + SLOT(ctx_p2p_delete())); + } + + if (type == PEER_TYPE_AP_WPS) { + menu->addAction(tr("Connect (PBC)"), this, + SLOT(connect_pbc())); + } + + if ((type == PEER_TYPE_ASSOCIATED_STATION || + type == PEER_TYPE_WPS_ER_ENROLLEE || + type == PEER_TYPE_WPS_ENROLLEE) && + config_methods >= 0 && (config_methods & 0x0080)) { + menu->addAction(tr("Enroll (PBC)"), this, + SLOT(connect_pbc())); + } + + if (type == PEER_TYPE_WPS_ER_AP) { + menu->addAction(tr("Learn Configuration"), this, + SLOT(learn_ap_config())); + } + + menu->addAction(tr("Properties"), this, SLOT(properties())); + } else { + ctx_item = NULL; + menu->addAction(QString(tr("Refresh")), this, + SLOT(ctx_refresh())); + menu->addAction(tr("Start P2P discovery"), this, + SLOT(ctx_p2p_start())); + menu->addAction(tr("Stop P2P discovery"), this, + SLOT(ctx_p2p_stop())); + menu->addAction(tr("P2P listen only"), this, + SLOT(ctx_p2p_listen())); + menu->addAction(tr("Start P2P group"), this, + SLOT(ctx_p2p_start_group())); + if (hide_ap) + menu->addAction(tr("Show AP entries"), this, + SLOT(ctx_show_ap())); + else + menu->addAction(tr("Hide AP entries"), this, + SLOT(ctx_hide_ap())); + } + + menu->exec(peers->mapToGlobal(pos)); +} + + +void Peers::enter_pin() +{ + if (ctx_item == NULL) + return; + + int peer_type = ctx_item->data(peer_role_type).toInt(); + QString uuid; + QString addr; + addr = ctx_item->data(peer_role_address).toString(); + if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) + uuid = ctx_item->data(peer_role_uuid).toString(); + + StringQuery input(tr("PIN:")); + input.setWindowTitle(tr("PIN for ") + ctx_item->text()); + if (input.exec() != QDialog::Accepted) + return; + + char cmd[100]; + char reply[100]; + size_t reply_len; + + if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { + snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s", + uuid.toLocal8Bit().constData(), + input.get_string().toLocal8Bit().constData(), + addr.toLocal8Bit().constData()); + } else { + snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", + addr.toLocal8Bit().constData(), + input.get_string().toLocal8Bit().constData()); + } + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText(tr("Failed to set the WPS PIN.")); + msg.exec(); + } +} + + +void Peers::ctx_refresh() +{ + update_peers(); +} + + +void Peers::ctx_p2p_start() +{ + char reply[20]; + size_t reply_len; + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest("P2P_FIND", reply, &reply_len) < 0 || + memcmp(reply, "FAIL", 4) == 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText("Failed to start P2P discovery."); + msg.exec(); + } +} + + +void Peers::ctx_p2p_stop() +{ + char reply[20]; + size_t reply_len; + reply_len = sizeof(reply) - 1; + wpagui->ctrlRequest("P2P_STOP_FIND", reply, &reply_len); +} + + +void Peers::ctx_p2p_listen() +{ + char reply[20]; + size_t reply_len; + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest("P2P_LISTEN 3600", reply, &reply_len) < 0 || + memcmp(reply, "FAIL", 4) == 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText("Failed to start P2P listen."); + msg.exec(); + } +} + + +void Peers::ctx_p2p_start_group() +{ + char reply[20]; + size_t reply_len; + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest("P2P_GROUP_ADD", reply, &reply_len) < 0 || + memcmp(reply, "FAIL", 4) == 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText("Failed to start P2P group."); + msg.exec(); + } +} + + +void Peers::add_station(QString info) +{ + QStringList lines = info.split(QRegExp("\\n")); + QString name; + + for (QStringList::Iterator it = lines.begin(); + it != lines.end(); it++) { + int pos = (*it).indexOf('=') + 1; + if (pos < 1) + continue; + + if ((*it).startsWith("wpsDeviceName=")) + name = (*it).mid(pos); + else if ((*it).startsWith("p2p_device_name=")) + name = (*it).mid(pos); + } + + if (name.isEmpty()) + name = lines[0]; + + QStandardItem *item = new QStandardItem(*laptop_icon, name); + if (item) { + /* Remove WPS enrollee entry if one is still pending */ + if (model.rowCount() > 0) { + QModelIndexList lst = model.match(model.index(0, 0), + peer_role_address, + lines[0]); + for (int i = 0; i < lst.size(); i++) { + QStandardItem *item; + item = model.itemFromIndex(lst[i]); + if (item == NULL) + continue; + int type = item->data(peer_role_type).toInt(); + if (type == PEER_TYPE_WPS_ENROLLEE) { + model.removeRow(lst[i].row()); + break; + } + } + } + + item->setData(lines[0], peer_role_address); + item->setData(PEER_TYPE_ASSOCIATED_STATION, + peer_role_type); + item->setData(info, peer_role_details); + item->setToolTip(ItemType(PEER_TYPE_ASSOCIATED_STATION)); + model.appendRow(item); + } +} + + +void Peers::add_stations() +{ + char reply[2048]; + size_t reply_len; + char cmd[30]; + int res; + + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest("STA-FIRST", reply, &reply_len) < 0) + return; + + do { + reply[reply_len] = '\0'; + QString info(reply); + char *txt = reply; + while (*txt != '\0' && *txt != '\n') + txt++; + *txt++ = '\0'; + if (strncmp(reply, "FAIL", 4) == 0 || + strncmp(reply, "UNKNOWN", 7) == 0) + break; + + add_station(info); + + reply_len = sizeof(reply) - 1; + res = snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply); + if (res < 0 || (size_t) res >= sizeof(cmd)) + break; + res = wpagui->ctrlRequest(cmd, reply, &reply_len); + } while (res >= 0); +} + + +void Peers::add_single_station(const char *addr) +{ + char reply[2048]; + size_t reply_len; + char cmd[30]; + + reply_len = sizeof(reply) - 1; + snprintf(cmd, sizeof(cmd), "STA %s", addr); + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) + return; + + reply[reply_len] = '\0'; + QString info(reply); + char *txt = reply; + while (*txt != '\0' && *txt != '\n') + txt++; + *txt++ = '\0'; + if (strncmp(reply, "FAIL", 4) == 0 || + strncmp(reply, "UNKNOWN", 7) == 0) + return; + + add_station(info); +} + + +void Peers::add_p2p_group_client(QStandardItem * /*parent*/, QString params) +{ + /* + * dev=02:b5:64:63:30:63 iface=02:b5:64:63:30:63 dev_capab=0x0 + * dev_type=1-0050f204-1 dev_name='Wireless Client' + * config_methods=0x8c + */ + + QStringList items = + params.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)")); + QString addr = ""; + QString name = ""; + int config_methods = 0; + QString dev_type; + + for (int i = 0; i < items.size(); i++) { + QString str = items.at(i); + int pos = str.indexOf('=') + 1; + if (str.startsWith("dev_name='")) + name = str.section('\'', 1, -2); + else if (str.startsWith("config_methods=")) + config_methods = + str.section('=', 1).toInt(0, 0); + else if (str.startsWith("dev=")) + addr = str.mid(pos); + else if (str.startsWith("dev_type=") && dev_type.isEmpty()) + dev_type = str.mid(pos); + } + + QStandardItem *item = find_addr(addr); + if (item) + return; + + item = new QStandardItem(*default_icon, name); + if (item) { + /* TODO: indicate somehow the relationship to the group owner + * (parent) */ + item->setData(addr, peer_role_address); + item->setData(config_methods, peer_role_config_methods); + item->setData(PEER_TYPE_P2P_CLIENT, peer_role_type); + if (!dev_type.isEmpty()) + item->setData(dev_type, peer_role_pri_dev_type); + item->setData(items.join(QString("\n")), peer_role_details); + item->setToolTip(ItemType(PEER_TYPE_P2P_CLIENT)); + model.appendRow(item); + } +} + + +void Peers::remove_bss(int id) +{ + if (model.rowCount() == 0) + return; + + QModelIndexList lst = model.match(model.index(0, 0), peer_role_bss_id, + id); + if (lst.size() == 0) + return; + model.removeRow(lst[0].row()); +} + + +bool Peers::add_bss(const char *cmd) +{ + char reply[2048]; + size_t reply_len; + + if (hide_ap) + return false; + + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) + return false; + reply[reply_len] = '\0'; + + QString bss(reply); + if (bss.isEmpty() || bss.startsWith("FAIL")) + return false; + + QString ssid, bssid, flags, wps_name, pri_dev_type; + int id = -1; + + QStringList lines = bss.split(QRegExp("\\n")); + for (QStringList::Iterator it = lines.begin(); + it != lines.end(); it++) { + int pos = (*it).indexOf('=') + 1; + if (pos < 1) + continue; + + if ((*it).startsWith("bssid=")) + bssid = (*it).mid(pos); + else if ((*it).startsWith("id=")) + id = (*it).mid(pos).toInt(); + else if ((*it).startsWith("flags=")) + flags = (*it).mid(pos); + else if ((*it).startsWith("ssid=")) + ssid = (*it).mid(pos); + else if ((*it).startsWith("wps_device_name=")) + wps_name = (*it).mid(pos); + else if ((*it).startsWith("wps_primary_device_type=")) + pri_dev_type = (*it).mid(pos); + } + + QString name = wps_name; + if (name.isEmpty()) + name = ssid + "\n" + bssid; + + QStandardItem *item = new QStandardItem(*ap_icon, name); + if (item) { + item->setData(bssid, peer_role_address); + if (id >= 0) + item->setData(id, peer_role_bss_id); + int type; + if (flags.contains("[WPS")) + type = PEER_TYPE_AP_WPS; + else + type = PEER_TYPE_AP; + item->setData(type, peer_role_type); + + for (int i = 0; i < lines.size(); i++) { + if (lines[i].length() > 60) { + lines[i].remove(60, lines[i].length()); + lines[i] += ".."; + } + } + item->setToolTip(ItemType(type)); + item->setData(lines.join("\n"), peer_role_details); + if (!pri_dev_type.isEmpty()) + item->setData(pri_dev_type, + peer_role_pri_dev_type); + if (!ssid.isEmpty()) + item->setData(ssid, peer_role_ssid); + model.appendRow(item); + + lines = bss.split(QRegExp("\\n")); + for (QStringList::Iterator it = lines.begin(); + it != lines.end(); it++) { + if ((*it).startsWith("p2p_group_client:")) + add_p2p_group_client(item, + (*it).mid(18)); + } + } + + return true; +} + + +void Peers::add_scan_results() +{ + int index; + char cmd[20]; + + index = 0; + while (wpagui) { + snprintf(cmd, sizeof(cmd), "BSS %d", index++); + if (index > 1000) + break; + + if (!add_bss(cmd)) + break; + } +} + + +void Peers::add_persistent(int id, const char *ssid, const char *bssid) +{ + char cmd[100]; + char reply[100]; + size_t reply_len; + int mode; + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d mode", id); + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) + return; + reply[reply_len] = '\0'; + mode = atoi(reply); + + QString name = ssid; + name = '[' + name + ']'; + + QStandardItem *item = new QStandardItem(*group_icon, name); + if (!item) + return; + + int type; + if (mode == 3) + type = PEER_TYPE_P2P_PERSISTENT_GROUP_GO; + else + type = PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT; + item->setData(type, peer_role_type); + item->setToolTip(ItemType(type)); + item->setData(ssid, peer_role_ssid); + if (bssid && strcmp(bssid, "any") == 0) + bssid = NULL; + if (bssid) + item->setData(bssid, peer_role_address); + item->setData(id, peer_role_network_id); + item->setBackground(Qt::BDiagPattern); + + model.appendRow(item); +} + + +void Peers::add_persistent_groups() +{ + char buf[2048], *start, *end, *id, *ssid, *bssid, *flags; + size_t len; + + len = sizeof(buf) - 1; + if (wpagui->ctrlRequest("LIST_NETWORKS", buf, &len) < 0) + return; + + buf[len] = '\0'; + start = strchr(buf, '\n'); + if (start == NULL) + return; + start++; + + while (*start) { + bool last = false; + end = strchr(start, '\n'); + if (end == NULL) { + last = true; + end = start; + while (end[0] && end[1]) + end++; + } + *end = '\0'; + + id = start; + ssid = strchr(id, '\t'); + if (ssid == NULL) + break; + *ssid++ = '\0'; + bssid = strchr(ssid, '\t'); + if (bssid == NULL) + break; + *bssid++ = '\0'; + flags = strchr(bssid, '\t'); + if (flags == NULL) + break; + *flags++ = '\0'; + + if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) + add_persistent(atoi(id), ssid, bssid); + + if (last) + break; + start = end + 1; + } +} + + +void Peers::update_peers() +{ + model.clear(); + if (wpagui == NULL) + return; + + char reply[20]; + size_t replylen = sizeof(reply) - 1; + wpagui->ctrlRequest("WPS_ER_START", reply, &replylen); + + add_stations(); + add_scan_results(); + add_persistent_groups(); +} + + +QStandardItem * Peers::find_addr(QString addr) +{ + if (model.rowCount() == 0) + return NULL; + + QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, + addr); + if (lst.size() == 0) + return NULL; + return model.itemFromIndex(lst[0]); +} + + +QStandardItem * Peers::find_addr_type(QString addr, int type) +{ + if (model.rowCount() == 0) + return NULL; + + QModelIndexList lst = model.match(model.index(0, 0), peer_role_address, + addr); + for (int i = 0; i < lst.size(); i++) { + QStandardItem *item = model.itemFromIndex(lst[i]); + if (item->data(peer_role_type).toInt() == type) + return item; + } + return NULL; +} + + +QStandardItem * Peers::find_uuid(QString uuid) +{ + if (model.rowCount() == 0) + return NULL; + + QModelIndexList lst = model.match(model.index(0, 0), peer_role_uuid, + uuid); + if (lst.size() == 0) + return NULL; + return model.itemFromIndex(lst[0]); +} + + +void Peers::event_notify(WpaMsg msg) +{ + QString text = msg.getMsg(); + + if (text.startsWith(WPS_EVENT_PIN_NEEDED)) { + /* + * WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7 + * 02:2a:c4:18:5b:f3 + * [Wireless Client|Company|cmodel|123|12345|1-0050F204-1] + */ + QStringList items = text.split(' '); + QString uuid = items[1]; + QString addr = items[2]; + QString name = ""; + + QStandardItem *item = find_addr(addr); + if (item) + return; + + int pos = text.indexOf('['); + if (pos >= 0) { + int pos2 = text.lastIndexOf(']'); + if (pos2 >= pos) { + items = text.mid(pos + 1, pos2 - pos - 1). + split('|'); + name = items[0]; + items.append(addr); + } + } + + item = new QStandardItem(*laptop_icon, name); + if (item) { + item->setData(addr, peer_role_address); + item->setData(PEER_TYPE_WPS_PIN_NEEDED, + peer_role_type); + item->setToolTip(ItemType(PEER_TYPE_WPS_PIN_NEEDED)); + item->setData(items.join("\n"), peer_role_details); + item->setData(items[5], peer_role_pri_dev_type); + model.appendRow(item); + } + return; + } + + if (text.startsWith(AP_STA_CONNECTED)) { + /* AP-STA-CONNECTED 02:2a:c4:18:5b:f3 */ + QStringList items = text.split(' '); + QString addr = items[1]; + QStandardItem *item = find_addr(addr); + if (item == NULL || item->data(peer_role_type).toInt() != + PEER_TYPE_ASSOCIATED_STATION) + add_single_station(addr.toLocal8Bit().constData()); + return; + } + + if (text.startsWith(AP_STA_DISCONNECTED)) { + /* AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3 */ + QStringList items = text.split(' '); + QString addr = items[1]; + + if (model.rowCount() == 0) + return; + + QModelIndexList lst = model.match(model.index(0, 0), + peer_role_address, addr, -1); + for (int i = 0; i < lst.size(); i++) { + QStandardItem *item = model.itemFromIndex(lst[i]); + if (item && item->data(peer_role_type).toInt() == + PEER_TYPE_ASSOCIATED_STATION) { + model.removeRow(lst[i].row()); + break; + } + } + return; + } + + if (text.startsWith(P2P_EVENT_DEVICE_FOUND)) { + /* + * P2P-DEVICE-FOUND 02:b5:64:63:30:63 + * p2p_dev_addr=02:b5:64:63:30:63 pri_dev_type=1-0050f204-1 + * name='Wireless Client' config_methods=0x84 dev_capab=0x21 + * group_capab=0x0 + */ + QStringList items = + text.split(QRegExp(" (?=[^']*('[^']*'[^']*)*$)")); + QString addr = items[1]; + QString name = ""; + QString pri_dev_type; + int config_methods = 0; + for (int i = 0; i < items.size(); i++) { + QString str = items.at(i); + if (str.startsWith("name='")) + name = str.section('\'', 1, -2); + else if (str.startsWith("config_methods=")) + config_methods = + str.section('=', 1).toInt(0, 0); + else if (str.startsWith("pri_dev_type=")) + pri_dev_type = str.section('=', 1); + } + + QStandardItem *item = find_addr(addr); + if (item) { + int type = item->data(peer_role_type).toInt(); + if (type == PEER_TYPE_P2P) + return; + } + + item = new QStandardItem(*default_icon, name); + if (item) { + item->setData(addr, peer_role_address); + item->setData(config_methods, + peer_role_config_methods); + item->setData(PEER_TYPE_P2P, peer_role_type); + if (!pri_dev_type.isEmpty()) + item->setData(pri_dev_type, + peer_role_pri_dev_type); + item->setData(items.join(QString("\n")), + peer_role_details); + item->setToolTip(ItemType(PEER_TYPE_P2P)); + model.appendRow(item); + } + + item = find_addr_type(addr, + PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT); + if (item) + item->setBackground(Qt::NoBrush); + } + + if (text.startsWith(P2P_EVENT_GROUP_STARTED)) { + /* P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F" + * passphrase="YOyTkxID" go_dev_addr=02:40:61:c2:f3:b7 + * [PERSISTENT] */ + QStringList items = text.split(' '); + if (items.size() < 4) + return; + + int pos = text.indexOf(" ssid=\""); + if (pos < 0) + return; + QString ssid = text.mid(pos + 7); + pos = ssid.indexOf(" passphrase=\""); + if (pos < 0) + pos = ssid.indexOf(" psk="); + if (pos >= 0) + ssid.truncate(pos); + pos = ssid.lastIndexOf('"'); + if (pos >= 0) + ssid.truncate(pos); + + QStandardItem *item = new QStandardItem(*group_icon, ssid); + if (item) { + item->setData(PEER_TYPE_P2P_GROUP, peer_role_type); + item->setData(items[1], peer_role_ifname); + QString details; + if (items[2] == "GO") { + details = tr("P2P GO for interface ") + + items[1]; + } else { + details = tr("P2P client for interface ") + + items[1]; + } + if (text.contains(" [PERSISTENT]")) + details += "\nPersistent group"; + item->setData(details, peer_role_details); + item->setToolTip(ItemType(PEER_TYPE_P2P_GROUP)); + model.appendRow(item); + } + } + + if (text.startsWith(P2P_EVENT_GROUP_REMOVED)) { + /* P2P-GROUP-REMOVED wlan0-p2p-0 GO */ + QStringList items = text.split(' '); + if (items.size() < 2) + return; + + if (model.rowCount() == 0) + return; + + QModelIndexList lst = model.match(model.index(0, 0), + peer_role_ifname, items[1]); + for (int i = 0; i < lst.size(); i++) + model.removeRow(lst[i].row()); + return; + } + + if (text.startsWith(P2P_EVENT_PROV_DISC_SHOW_PIN)) { + /* P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670 */ + QStringList items = text.split(' '); + if (items.size() < 3) + return; + QString addr = items[1]; + QString pin = items[2]; + + QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P); + if (item == NULL) + return; + item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY, + peer_role_selected_method); + item->setData(pin, peer_role_selected_pin); + QVariant var = item->data(peer_role_requested_method); + if (var.isValid() && + var.toInt() == SEL_METHOD_PIN_LOCAL_DISPLAY) { + ctx_item = item; + ctx_p2p_display_pin_pd(); + } + return; + } + + if (text.startsWith(P2P_EVENT_PROV_DISC_ENTER_PIN)) { + /* P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 */ + QStringList items = text.split(' '); + if (items.size() < 2) + return; + QString addr = items[1]; + + QStandardItem *item = find_addr_type(addr, PEER_TYPE_P2P); + if (item == NULL) + return; + item->setData(SEL_METHOD_PIN_PEER_DISPLAY, + peer_role_selected_method); + QVariant var = item->data(peer_role_requested_method); + if (var.isValid() && + var.toInt() == SEL_METHOD_PIN_PEER_DISPLAY) { + ctx_item = item; + ctx_p2p_connect(); + } + return; + } + + if (text.startsWith(P2P_EVENT_INVITATION_RECEIVED)) { + /* P2P-INVITATION-RECEIVED sa=02:f0:bc:44:87:62 persistent=4 */ + QStringList items = text.split(' '); + if (items.size() < 3) + return; + if (!items[1].startsWith("sa=") || + !items[2].startsWith("persistent=")) + return; + QString addr = items[1].mid(3); + int id = items[2].mid(11).toInt(); + + char cmd[100]; + char reply[100]; + size_t reply_len; + + snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", id); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) + return; + reply[reply_len] = '\0'; + QString name; + char *pos = strrchr(reply, '"'); + if (pos && reply[0] == '"') { + *pos = '\0'; + name = reply + 1; + } else + name = reply; + + QStandardItem *item; + item = find_addr_type(addr, PEER_TYPE_P2P_INVITATION); + if (item) + model.removeRow(item->row()); + + item = new QStandardItem(*invitation_icon, name); + if (!item) + return; + item->setData(PEER_TYPE_P2P_INVITATION, peer_role_type); + item->setToolTip(ItemType(PEER_TYPE_P2P_INVITATION)); + item->setData(addr, peer_role_address); + item->setData(id, peer_role_network_id); + + model.appendRow(item); + + enable_persistent(id); + + return; + } + + if (text.startsWith(P2P_EVENT_INVITATION_RESULT)) { + /* P2P-INVITATION-RESULT status=1 */ + /* TODO */ + return; + } + + if (text.startsWith(WPS_EVENT_ER_AP_ADD)) { + /* + * WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 + * 02:11:22:33:44:55 pri_dev_type=6-0050F204-1 wps_state=1 + * |Very friendly name|Company|Long description of the model| + * WAP|http://w1.fi/|http://w1.fi/hostapd/ + */ + QStringList items = text.split(' '); + if (items.size() < 5) + return; + QString uuid = items[1]; + QString addr = items[2]; + QString pri_dev_type = items[3].mid(13); + int wps_state = items[4].mid(10).toInt(); + + int pos = text.indexOf('|'); + if (pos < 0) + return; + items = text.mid(pos + 1).split('|'); + if (items.size() < 1) + return; + + QStandardItem *item = find_uuid(uuid); + if (item) + return; + + item = new QStandardItem(*ap_icon, items[0]); + if (item) { + item->setData(uuid, peer_role_uuid); + item->setData(addr, peer_role_address); + int type = wps_state == 2 ? PEER_TYPE_WPS_ER_AP: + PEER_TYPE_WPS_ER_AP_UNCONFIGURED; + item->setData(type, peer_role_type); + item->setToolTip(ItemType(type)); + item->setData(pri_dev_type, peer_role_pri_dev_type); + item->setData(items.join(QString("\n")), + peer_role_details); + model.appendRow(item); + } + + return; + } + + if (text.startsWith(WPS_EVENT_ER_AP_REMOVE)) { + /* WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002 */ + QStringList items = text.split(' '); + if (items.size() < 2) + return; + if (model.rowCount() == 0) + return; + + QModelIndexList lst = model.match(model.index(0, 0), + peer_role_uuid, items[1]); + for (int i = 0; i < lst.size(); i++) { + QStandardItem *item = model.itemFromIndex(lst[i]); + if (item && + (item->data(peer_role_type).toInt() == + PEER_TYPE_WPS_ER_AP || + item->data(peer_role_type).toInt() == + PEER_TYPE_WPS_ER_AP_UNCONFIGURED)) + model.removeRow(lst[i].row()); + } + return; + } + + if (text.startsWith(WPS_EVENT_ER_ENROLLEE_ADD)) { + /* + * WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333 + * 02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0 + * pri_dev_type=1-0050F204-1 + * |Wireless Client|Company|cmodel|123|12345| + */ + QStringList items = text.split(' '); + if (items.size() < 3) + return; + QString uuid = items[1]; + QString addr = items[2]; + QString pri_dev_type = items[6].mid(13); + int config_methods = -1; + int dev_passwd_id = -1; + + for (int i = 3; i < items.size(); i++) { + int pos = items[i].indexOf('=') + 1; + if (pos < 1) + continue; + QString val = items[i].mid(pos); + if (items[i].startsWith("config_methods=")) { + config_methods = val.toInt(0, 0); + } else if (items[i].startsWith("dev_passwd_id=")) { + dev_passwd_id = val.toInt(); + } + } + + int pos = text.indexOf('|'); + if (pos < 0) + return; + items = text.mid(pos + 1).split('|'); + if (items.size() < 1) + return; + QString name = items[0]; + if (name.length() == 0) + name = addr; + + remove_enrollee_uuid(uuid); + + QStandardItem *item; + item = new QStandardItem(*laptop_icon, name); + if (item) { + item->setData(uuid, peer_role_uuid); + item->setData(addr, peer_role_address); + item->setData(PEER_TYPE_WPS_ER_ENROLLEE, + peer_role_type); + item->setToolTip(ItemType(PEER_TYPE_WPS_ER_ENROLLEE)); + item->setData(items.join(QString("\n")), + peer_role_details); + item->setData(pri_dev_type, peer_role_pri_dev_type); + if (config_methods >= 0) + item->setData(config_methods, + peer_role_config_methods); + if (dev_passwd_id >= 0) + item->setData(dev_passwd_id, + peer_role_dev_passwd_id); + model.appendRow(item); + } + + return; + } + + if (text.startsWith(WPS_EVENT_ER_ENROLLEE_REMOVE)) { + /* + * WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333 + * 02:66:a0:ee:17:27 + */ + QStringList items = text.split(' '); + if (items.size() < 2) + return; + remove_enrollee_uuid(items[1]); + return; + } + + if (text.startsWith(WPS_EVENT_ENROLLEE_SEEN)) { + /* TODO: need to time out this somehow or remove on successful + * WPS run, etc. */ + /* + * WPS-ENROLLEE-SEEN 02:00:00:00:01:00 + * 572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1 + * [Wireless Client] + * (MAC addr, UUID-E, pri dev type, config methods, + * dev passwd id, request type, [dev name]) + */ + QStringList items = text.split(' '); + if (items.size() < 7) + return; + QString addr = items[1]; + QString uuid = items[2]; + QString pri_dev_type = items[3]; + int config_methods = items[4].toInt(0, 0); + int dev_passwd_id = items[5].toInt(); + QString name; + + QStandardItem *item = find_addr(addr); + if (item) { + int type = item->data(peer_role_type).toInt(); + if (type == PEER_TYPE_ASSOCIATED_STATION) + return; /* already associated */ + } + + int pos = text.indexOf('['); + if (pos >= 0) { + int pos2 = text.lastIndexOf(']'); + if (pos2 >= pos) { + QStringList items2 = + text.mid(pos + 1, pos2 - pos - 1). + split('|'); + name = items2[0]; + } + } + if (name.isEmpty()) + name = addr; + + item = find_uuid(uuid); + if (item) { + QVariant var = item->data(peer_role_config_methods); + QVariant var2 = item->data(peer_role_dev_passwd_id); + if ((var.isValid() && config_methods != var.toInt()) || + (var2.isValid() && dev_passwd_id != var2.toInt())) + remove_enrollee_uuid(uuid); + else + return; + } + + item = new QStandardItem(*laptop_icon, name); + if (item) { + item->setData(uuid, peer_role_uuid); + item->setData(addr, peer_role_address); + item->setData(PEER_TYPE_WPS_ENROLLEE, + peer_role_type); + item->setToolTip(ItemType(PEER_TYPE_WPS_ENROLLEE)); + item->setData(items.join(QString("\n")), + peer_role_details); + item->setData(pri_dev_type, peer_role_pri_dev_type); + item->setData(config_methods, + peer_role_config_methods); + item->setData(dev_passwd_id, peer_role_dev_passwd_id); + model.appendRow(item); + } + + return; + } + + if (text.startsWith(WPA_EVENT_BSS_ADDED)) { + /* CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55 */ + QStringList items = text.split(' '); + if (items.size() < 2) + return; + char cmd[20]; + snprintf(cmd, sizeof(cmd), "BSS ID-%d", items[1].toInt()); + add_bss(cmd); + return; + } + + if (text.startsWith(WPA_EVENT_BSS_REMOVED)) { + /* CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55 */ + QStringList items = text.split(' '); + if (items.size() < 2) + return; + remove_bss(items[1].toInt()); + return; + } +} + + +void Peers::ctx_p2p_connect() +{ + if (ctx_item == NULL) + return; + QString addr = ctx_item->data(peer_role_address).toString(); + QString arg; + int config_methods = + ctx_item->data(peer_role_config_methods).toInt(); + enum selected_method method = SEL_METHOD_NONE; + QVariant var = ctx_item->data(peer_role_selected_method); + if (var.isValid()) + method = (enum selected_method) var.toInt(); + if (method == SEL_METHOD_PIN_LOCAL_DISPLAY) { + arg = ctx_item->data(peer_role_selected_pin).toString(); + char cmd[100]; + char reply[100]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display", + addr.toLocal8Bit().constData(), + arg.toLocal8Bit().constData()); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText("Failed to initiate P2P connect."); + msg.exec(); + return; + } + QMessageBox::information(this, + tr("PIN for ") + ctx_item->text(), + tr("Enter the following PIN on the\n" + "peer device: ") + arg); + } else if (method == SEL_METHOD_PIN_PEER_DISPLAY) { + StringQuery input(tr("PIN from peer display:")); + input.setWindowTitle(tr("PIN for ") + ctx_item->text()); + if (input.exec() != QDialog::Accepted) + return; + arg = input.get_string(); + } else if (config_methods == 0x0080 /* PBC */) { + arg = "pbc"; + } else { + StringQuery input(tr("PIN:")); + input.setWindowTitle(tr("PIN for ") + ctx_item->text()); + if (input.exec() != QDialog::Accepted) + return; + arg = input.get_string(); + } + + char cmd[100]; + char reply[100]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s", + addr.toLocal8Bit().constData(), + arg.toLocal8Bit().constData()); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText("Failed to initiate P2P connect."); + msg.exec(); + } +} + + +void Peers::ctx_p2p_req_pin() +{ + if (ctx_item == NULL) + return; + QString addr = ctx_item->data(peer_role_address).toString(); + ctx_item->setData(SEL_METHOD_PIN_PEER_DISPLAY, + peer_role_requested_method); + + char cmd[100]; + char reply[100]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s display", + addr.toLocal8Bit().constData()); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText(tr("Failed to request PIN from peer.")); + msg.exec(); + } +} + + +void Peers::ctx_p2p_show_pin() +{ + if (ctx_item == NULL) + return; + QString addr = ctx_item->data(peer_role_address).toString(); + ctx_item->setData(SEL_METHOD_PIN_LOCAL_DISPLAY, + peer_role_requested_method); + + char cmd[100]; + char reply[100]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s keypad", + addr.toLocal8Bit().constData()); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText(tr("Failed to request peer to enter PIN.")); + msg.exec(); + } +} + + +void Peers::ctx_p2p_display_pin() +{ + if (ctx_item == NULL) + return; + QString addr = ctx_item->data(peer_role_address).toString(); + + char cmd[100]; + char reply[100]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pin", + addr.toLocal8Bit().constData()); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText("Failed to initiate P2P connect."); + msg.exec(); + return; + } + reply[reply_len] = '\0'; + QMessageBox::information(this, + tr("PIN for ") + ctx_item->text(), + tr("Enter the following PIN on the\n" + "peer device: ") + reply); +} + + +void Peers::ctx_p2p_display_pin_pd() +{ + if (ctx_item == NULL) + return; + QString addr = ctx_item->data(peer_role_address).toString(); + QString arg = ctx_item->data(peer_role_selected_pin).toString(); + + char cmd[100]; + char reply[100]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s display", + addr.toLocal8Bit().constData(), + arg.toLocal8Bit().constData()); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText("Failed to initiate P2P connect."); + msg.exec(); + return; + } + reply[reply_len] = '\0'; + QMessageBox::information(this, + tr("PIN for ") + ctx_item->text(), + tr("Enter the following PIN on the\n" + "peer device: ") + arg); +} + + +void Peers::ctx_p2p_enter_pin() +{ + if (ctx_item == NULL) + return; + QString addr = ctx_item->data(peer_role_address).toString(); + QString arg; + + StringQuery input(tr("PIN from peer:")); + input.setWindowTitle(tr("PIN for ") + ctx_item->text()); + if (input.exec() != QDialog::Accepted) + return; + arg = input.get_string(); + + char cmd[100]; + char reply[100]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s keypad", + addr.toLocal8Bit().constData(), + arg.toLocal8Bit().constData()); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText("Failed to initiate P2P connect."); + msg.exec(); + } +} + + +void Peers::ctx_p2p_remove_group() +{ + if (ctx_item == NULL) + return; + char cmd[100]; + char reply[100]; + size_t reply_len; + snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s", + ctx_item->data(peer_role_ifname).toString().toLocal8Bit(). + constData()); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText("Failed to remove P2P Group."); + msg.exec(); + } +} + + +void Peers::closeEvent(QCloseEvent *) +{ + if (wpagui) { + char reply[20]; + size_t replylen = sizeof(reply) - 1; + wpagui->ctrlRequest("WPS_ER_STOP", reply, &replylen); + } +} + + +void Peers::done(int r) +{ + QDialog::done(r); + close(); +} + + +void Peers::remove_enrollee_uuid(QString uuid) +{ + if (model.rowCount() == 0) + return; + + QModelIndexList lst = model.match(model.index(0, 0), + peer_role_uuid, uuid); + for (int i = 0; i < lst.size(); i++) { + QStandardItem *item = model.itemFromIndex(lst[i]); + if (item == NULL) + continue; + int type = item->data(peer_role_type).toInt(); + if (type == PEER_TYPE_WPS_ER_ENROLLEE || + type == PEER_TYPE_WPS_ENROLLEE) + model.removeRow(lst[i].row()); + } +} + + +void Peers::properties() +{ + if (ctx_item == NULL) + return; + + QMessageBox msg(this); + msg.setStandardButtons(QMessageBox::Ok); + msg.setDefaultButton(QMessageBox::Ok); + msg.setEscapeButton(QMessageBox::Ok); + msg.setWindowTitle(tr("Peer Properties")); + + int type = ctx_item->data(peer_role_type).toInt(); + QString title = Peers::ItemType(type); + + msg.setText(title + QString("\n") + tr("Name: ") + ctx_item->text()); + + QVariant var; + QString info; + + var = ctx_item->data(peer_role_address); + if (var.isValid()) + info += tr("Address: ") + var.toString() + QString("\n"); + + var = ctx_item->data(peer_role_uuid); + if (var.isValid()) + info += tr("UUID: ") + var.toString() + QString("\n"); + + var = ctx_item->data(peer_role_pri_dev_type); + if (var.isValid()) + info += tr("Primary Device Type: ") + var.toString() + + QString("\n"); + + var = ctx_item->data(peer_role_ssid); + if (var.isValid()) + info += tr("SSID: ") + var.toString() + QString("\n"); + + var = ctx_item->data(peer_role_config_methods); + if (var.isValid()) { + int methods = var.toInt(); + info += tr("Configuration Methods: "); + if (methods & 0x0001) + info += tr("[USBA]"); + if (methods & 0x0002) + info += tr("[Ethernet]"); + if (methods & 0x0004) + info += tr("[Label]"); + if (methods & 0x0008) + info += tr("[Display]"); + if (methods & 0x0010) + info += tr("[Ext. NFC Token]"); + if (methods & 0x0020) + info += tr("[Int. NFC Token]"); + if (methods & 0x0040) + info += tr("[NFC Interface]"); + if (methods & 0x0080) + info += tr("[Push Button]"); + if (methods & 0x0100) + info += tr("[Keypad]"); + info += "\n"; + } + + var = ctx_item->data(peer_role_selected_method); + if (var.isValid()) { + enum selected_method method = + (enum selected_method) var.toInt(); + switch (method) { + case SEL_METHOD_NONE: + break; + case SEL_METHOD_PIN_PEER_DISPLAY: + info += tr("Selected Method: PIN on peer display\n"); + break; + case SEL_METHOD_PIN_LOCAL_DISPLAY: + info += tr("Selected Method: PIN on local display\n"); + break; + } + } + + var = ctx_item->data(peer_role_selected_pin); + if (var.isValid()) { + info += tr("PIN to enter on peer: ") + var.toString() + "\n"; + } + + var = ctx_item->data(peer_role_dev_passwd_id); + if (var.isValid()) { + info += tr("Device Password ID: ") + var.toString(); + switch (var.toInt()) { + case 0: + info += tr(" (Default PIN)"); + break; + case 1: + info += tr(" (User-specified PIN)"); + break; + case 2: + info += tr(" (Machine-specified PIN)"); + break; + case 3: + info += tr(" (Rekey)"); + break; + case 4: + info += tr(" (Push Button)"); + break; + case 5: + info += tr(" (Registrar-specified)"); + break; + } + info += "\n"; + } + + msg.setInformativeText(info); + + var = ctx_item->data(peer_role_details); + if (var.isValid()) + msg.setDetailedText(var.toString()); + + msg.exec(); +} + + +void Peers::connect_pbc() +{ + if (ctx_item == NULL) + return; + + char cmd[100]; + char reply[100]; + size_t reply_len; + + int peer_type = ctx_item->data(peer_role_type).toInt(); + if (peer_type == PEER_TYPE_WPS_ER_ENROLLEE) { + snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s", + ctx_item->data(peer_role_uuid).toString().toLocal8Bit(). + constData()); + } else if (peer_type == PEER_TYPE_P2P || + peer_type == PEER_TYPE_P2P_CLIENT) { + snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s pbc", + ctx_item->data(peer_role_address).toString(). + toLocal8Bit().constData()); + } else { + snprintf(cmd, sizeof(cmd), "WPS_PBC"); + } + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText(tr("Failed to start WPS PBC.")); + msg.exec(); + } +} + + +void Peers::learn_ap_config() +{ + if (ctx_item == NULL) + return; + + QString uuid = ctx_item->data(peer_role_uuid).toString(); + + StringQuery input(tr("AP PIN:")); + input.setWindowTitle(tr("AP PIN for ") + ctx_item->text()); + if (input.exec() != QDialog::Accepted) + return; + + char cmd[100]; + char reply[100]; + size_t reply_len; + + snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s", + uuid.toLocal8Bit().constData(), + input.get_string().toLocal8Bit().constData()); + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText(tr("Failed to start learning AP configuration.")); + msg.exec(); + } +} + + +void Peers::ctx_hide_ap() +{ + hide_ap = true; + + if (model.rowCount() == 0) + return; + + do { + QModelIndexList lst; + lst = model.match(model.index(0, 0), + peer_role_type, PEER_TYPE_AP); + if (lst.size() == 0) { + lst = model.match(model.index(0, 0), + peer_role_type, PEER_TYPE_AP_WPS); + if (lst.size() == 0) + break; + } + + model.removeRow(lst[0].row()); + } while (1); +} + + +void Peers::ctx_show_ap() +{ + hide_ap = false; + add_scan_results(); +} + + +void Peers::ctx_p2p_show_passphrase() +{ + char reply[64]; + size_t reply_len; + + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest("P2P_GET_PASSPHRASE", reply, &reply_len) < 0 || + memcmp(reply, "FAIL", 4) == 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText("Failed to get P2P group passphrase."); + msg.exec(); + } else { + reply[reply_len] = '\0'; + QMessageBox::information(this, tr("Passphrase"), + tr("P2P group passphrase:\n") + + reply); + } +} + + +void Peers::ctx_p2p_start_persistent() +{ + if (ctx_item == NULL) + return; + + char cmd[100]; + char reply[100]; + size_t reply_len; + + snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD persistent=%d", + ctx_item->data(peer_role_network_id).toInt()); + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 || + memcmp(reply, "FAIL", 4) == 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText(tr("Failed to start persistent P2P Group.")); + msg.exec(); + } else if (ctx_item->data(peer_role_type).toInt() == + PEER_TYPE_P2P_INVITATION) + model.removeRow(ctx_item->row()); +} + + +void Peers::ctx_p2p_invite() +{ + if (ctx_item == NULL) + return; + + char cmd[100]; + char reply[100]; + size_t reply_len; + + snprintf(cmd, sizeof(cmd), "P2P_INVITE persistent=%d", + ctx_item->data(peer_role_network_id).toInt()); + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0 || + memcmp(reply, "FAIL", 4) == 0) { + QMessageBox msg; + msg.setIcon(QMessageBox::Warning); + msg.setText(tr("Failed to invite peer to start persistent " + "P2P Group.")); + msg.exec(); + } +} + + +void Peers::ctx_p2p_delete() +{ + if (ctx_item == NULL) + return; + model.removeRow(ctx_item->row()); +} + + +void Peers::enable_persistent(int id) +{ + if (model.rowCount() == 0) + return; + + QModelIndexList lst = model.match(model.index(0, 0), + peer_role_network_id, id); + for (int i = 0; i < lst.size(); i++) { + QStandardItem *item = model.itemFromIndex(lst[i]); + int type = item->data(peer_role_type).toInt(); + if (type == PEER_TYPE_P2P_PERSISTENT_GROUP_GO || + type == PEER_TYPE_P2P_PERSISTENT_GROUP_CLIENT) + item->setBackground(Qt::NoBrush); + } +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.h index bb7373749c2fc7cd3959b734adfeb17c57b20282..5d6f6f86c271100cbee61fbf35c8aebfe67e5c69 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.h @@ -1,90 +1,90 @@ -/* - * wpa_gui - Peers class - * Copyright (c) 2009-2010, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef PEERS_H -#define PEERS_H - -#include -#include -#include "wpamsg.h" -#include "ui_peers.h" - -class WpaGui; - -class Peers : public QDialog, public Ui::Peers -{ - Q_OBJECT - -public: - Peers(QWidget *parent = 0, const char *name = 0, - bool modal = false, Qt::WindowFlags fl = 0); - ~Peers(); - void setWpaGui(WpaGui *_wpagui); - void event_notify(WpaMsg msg); - -public slots: - virtual void context_menu(const QPoint &pos); - virtual void enter_pin(); - virtual void connect_pbc(); - virtual void learn_ap_config(); - virtual void ctx_refresh(); - virtual void ctx_p2p_start(); - virtual void ctx_p2p_stop(); - virtual void ctx_p2p_listen(); - virtual void ctx_p2p_start_group(); - virtual void ctx_p2p_remove_group(); - virtual void ctx_p2p_connect(); - virtual void ctx_p2p_req_pin(); - virtual void ctx_p2p_show_pin(); - virtual void ctx_p2p_display_pin(); - virtual void ctx_p2p_display_pin_pd(); - virtual void ctx_p2p_enter_pin(); - virtual void properties(); - virtual void ctx_hide_ap(); - virtual void ctx_show_ap(); - virtual void ctx_p2p_show_passphrase(); - virtual void ctx_p2p_start_persistent(); - virtual void ctx_p2p_invite(); - virtual void ctx_p2p_delete(); - -protected slots: - virtual void languageChange(); - virtual void closeEvent(QCloseEvent *event); - -private: - void add_station(QString info); - void add_stations(); - void add_single_station(const char *addr); - bool add_bss(const char *cmd); - void remove_bss(int id); - void add_scan_results(); - void add_persistent(int id, const char *ssid, const char *bssid); - void add_persistent_groups(); - void update_peers(); - QStandardItem * find_addr(QString addr); - QStandardItem * find_addr_type(QString addr, int type); - void add_p2p_group_client(QStandardItem *parent, QString params); - QStandardItem * find_uuid(QString uuid); - void done(int r); - void remove_enrollee_uuid(QString uuid); - QString ItemType(int type); - void enable_persistent(int id); - - WpaGui *wpagui; - QStandardItemModel model; - QIcon *default_icon; - QIcon *ap_icon; - QIcon *laptop_icon; - QIcon *group_icon; - QIcon *invitation_icon; - QStandardItem *ctx_item; - - bool hide_ap; -}; - -#endif /* PEERS_H */ +/* + * wpa_gui - Peers class + * Copyright (c) 2009-2010, Atheros Communications + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef PEERS_H +#define PEERS_H + +#include +#include +#include "wpamsg.h" +#include "ui_peers.h" + +class WpaGui; + +class Peers : public QDialog, public Ui::Peers +{ + Q_OBJECT + +public: + Peers(QWidget *parent = 0, const char *name = 0, + bool modal = false, Qt::WindowFlags fl = 0); + ~Peers(); + void setWpaGui(WpaGui *_wpagui); + void event_notify(WpaMsg msg); + +public slots: + virtual void context_menu(const QPoint &pos); + virtual void enter_pin(); + virtual void connect_pbc(); + virtual void learn_ap_config(); + virtual void ctx_refresh(); + virtual void ctx_p2p_start(); + virtual void ctx_p2p_stop(); + virtual void ctx_p2p_listen(); + virtual void ctx_p2p_start_group(); + virtual void ctx_p2p_remove_group(); + virtual void ctx_p2p_connect(); + virtual void ctx_p2p_req_pin(); + virtual void ctx_p2p_show_pin(); + virtual void ctx_p2p_display_pin(); + virtual void ctx_p2p_display_pin_pd(); + virtual void ctx_p2p_enter_pin(); + virtual void properties(); + virtual void ctx_hide_ap(); + virtual void ctx_show_ap(); + virtual void ctx_p2p_show_passphrase(); + virtual void ctx_p2p_start_persistent(); + virtual void ctx_p2p_invite(); + virtual void ctx_p2p_delete(); + +protected slots: + virtual void languageChange(); + virtual void closeEvent(QCloseEvent *event); + +private: + void add_station(QString info); + void add_stations(); + void add_single_station(const char *addr); + bool add_bss(const char *cmd); + void remove_bss(int id); + void add_scan_results(); + void add_persistent(int id, const char *ssid, const char *bssid); + void add_persistent_groups(); + void update_peers(); + QStandardItem * find_addr(QString addr); + QStandardItem * find_addr_type(QString addr, int type); + void add_p2p_group_client(QStandardItem *parent, QString params); + QStandardItem * find_uuid(QString uuid); + void done(int r); + void remove_enrollee_uuid(QString uuid); + QString ItemType(int type); + void enable_persistent(int id); + + WpaGui *wpagui; + QStandardItemModel model; + QIcon *default_icon; + QIcon *ap_icon; + QIcon *laptop_icon; + QIcon *group_icon; + QIcon *invitation_icon; + QStandardItem *ctx_item; + + bool hide_ap; +}; + +#endif /* PEERS_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.ui b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.ui index 9508c254b70e3eb93c6945892925e687d4678432..1acaa46dd49a5376ef2e1570a3ab54f27f683446 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.ui +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/peers.ui @@ -1,40 +1,40 @@ - - - Peers - - - - 0 - 0 - 400 - 300 - - - - Peers - - - - - - - 0 - 0 - - - - true - - - QAbstractItemView::NoEditTriggers - - - QListView::IconMode - - - - - - - - + + + Peers + + + + 0 + 0 + 400 + 300 + + + + Peers + + + + + + + 0 + 0 + + + + true + + + QAbstractItemView::NoEditTriggers + + + QListView::IconMode + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.cpp index a2e3072fb6e1e339b6e3e39abb15dbf8354d429b..9428327269694a8ad641cbc06f97b2acd4b234d5 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.cpp @@ -1,141 +1,141 @@ -/* - * wpa_gui - ScanResults class - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include - -#include "scanresults.h" -#include "signalbar.h" -#include "wpagui.h" -#include "networkconfig.h" -#include "scanresultsitem.h" - - -ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WindowFlags) - : QDialog(parent) -{ - setupUi(this); - - connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); - connect(scanButton, SIGNAL(clicked()), this, SLOT(scanRequest())); - connect(scanResultsWidget, - SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, - SLOT(bssSelected(QTreeWidgetItem *))); - - wpagui = NULL; - scanResultsWidget->setItemsExpandable(false); - scanResultsWidget->setRootIsDecorated(false); - scanResultsWidget->setItemDelegate(new SignalBar(scanResultsWidget)); -} - - -ScanResults::~ScanResults() -{ -} - - -void ScanResults::languageChange() -{ - retranslateUi(this); -} - - -void ScanResults::setWpaGui(WpaGui *_wpagui) -{ - wpagui = _wpagui; - updateResults(); -} - - -void ScanResults::updateResults() -{ - char reply[2048]; - size_t reply_len; - int index; - char cmd[20]; - - scanResultsWidget->clear(); - - index = 0; - while (wpagui) { - snprintf(cmd, sizeof(cmd), "BSS %d", index++); - if (index > 1000) - break; - - reply_len = sizeof(reply) - 1; - if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) - break; - reply[reply_len] = '\0'; - - QString bss(reply); - if (bss.isEmpty() || bss.startsWith("FAIL")) - break; - - QString ssid, bssid, freq, signal, flags; - - QStringList lines = bss.split(QRegExp("\\n")); - for (QStringList::Iterator it = lines.begin(); - it != lines.end(); it++) { - int pos = (*it).indexOf('=') + 1; - if (pos < 1) - continue; - - if ((*it).startsWith("bssid=")) - bssid = (*it).mid(pos); - else if ((*it).startsWith("freq=")) - freq = (*it).mid(pos); - else if ((*it).startsWith("level=")) - signal = (*it).mid(pos); - else if ((*it).startsWith("flags=")) - flags = (*it).mid(pos); - else if ((*it).startsWith("ssid=")) - ssid = (*it).mid(pos); - } - - ScanResultsItem *item = new ScanResultsItem(scanResultsWidget); - if (item) { - item->setText(0, ssid); - item->setText(1, bssid); - item->setText(2, freq); - item->setText(3, signal); - item->setText(4, flags); - } - - if (bssid.isEmpty()) - break; - } -} - - -void ScanResults::scanRequest() -{ - char reply[10]; - size_t reply_len = sizeof(reply); - - if (wpagui == NULL) - return; - - wpagui->ctrlRequest("SCAN", reply, &reply_len); -} - - -void ScanResults::getResults() -{ - updateResults(); -} - - -void ScanResults::bssSelected(QTreeWidgetItem *sel) -{ - NetworkConfig *nc = new NetworkConfig(); - if (nc == NULL) - return; - nc->setWpaGui(wpagui); - nc->paramsFromScanResults(sel); - nc->show(); - nc->exec(); -} +/* + * wpa_gui - ScanResults class + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include + +#include "scanresults.h" +#include "signalbar.h" +#include "wpagui.h" +#include "networkconfig.h" +#include "scanresultsitem.h" + + +ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WindowFlags) + : QDialog(parent) +{ + setupUi(this); + + connect(closeButton, SIGNAL(clicked()), this, SLOT(close())); + connect(scanButton, SIGNAL(clicked()), this, SLOT(scanRequest())); + connect(scanResultsWidget, + SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, + SLOT(bssSelected(QTreeWidgetItem *))); + + wpagui = NULL; + scanResultsWidget->setItemsExpandable(false); + scanResultsWidget->setRootIsDecorated(false); + scanResultsWidget->setItemDelegate(new SignalBar(scanResultsWidget)); +} + + +ScanResults::~ScanResults() +{ +} + + +void ScanResults::languageChange() +{ + retranslateUi(this); +} + + +void ScanResults::setWpaGui(WpaGui *_wpagui) +{ + wpagui = _wpagui; + updateResults(); +} + + +void ScanResults::updateResults() +{ + char reply[2048]; + size_t reply_len; + int index; + char cmd[20]; + + scanResultsWidget->clear(); + + index = 0; + while (wpagui) { + snprintf(cmd, sizeof(cmd), "BSS %d", index++); + if (index > 1000) + break; + + reply_len = sizeof(reply) - 1; + if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0) + break; + reply[reply_len] = '\0'; + + QString bss(reply); + if (bss.isEmpty() || bss.startsWith("FAIL")) + break; + + QString ssid, bssid, freq, signal, flags; + + QStringList lines = bss.split(QRegExp("\\n")); + for (QStringList::Iterator it = lines.begin(); + it != lines.end(); it++) { + int pos = (*it).indexOf('=') + 1; + if (pos < 1) + continue; + + if ((*it).startsWith("bssid=")) + bssid = (*it).mid(pos); + else if ((*it).startsWith("freq=")) + freq = (*it).mid(pos); + else if ((*it).startsWith("level=")) + signal = (*it).mid(pos); + else if ((*it).startsWith("flags=")) + flags = (*it).mid(pos); + else if ((*it).startsWith("ssid=")) + ssid = (*it).mid(pos); + } + + ScanResultsItem *item = new ScanResultsItem(scanResultsWidget); + if (item) { + item->setText(0, ssid); + item->setText(1, bssid); + item->setText(2, freq); + item->setText(3, signal); + item->setText(4, flags); + } + + if (bssid.isEmpty()) + break; + } +} + + +void ScanResults::scanRequest() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + + if (wpagui == NULL) + return; + + wpagui->ctrlRequest("SCAN", reply, &reply_len); +} + + +void ScanResults::getResults() +{ + updateResults(); +} + + +void ScanResults::bssSelected(QTreeWidgetItem *sel) +{ + NetworkConfig *nc = new NetworkConfig(); + if (nc == NULL) + return; + nc->setWpaGui(wpagui); + nc->paramsFromScanResults(sel); + nc->show(); + nc->exec(); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.h index 2cddd133fe2b7f987f08490b81d5ea2edcd9036d..3939af22fc5a31d86d8c8eb23a930713f95f696e 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.h @@ -1,40 +1,40 @@ -/* - * wpa_gui - ScanResults class - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef SCANRESULTS_H -#define SCANRESULTS_H - -#include -#include "ui_scanresults.h" - -class WpaGui; - -class ScanResults : public QDialog, public Ui::ScanResults -{ - Q_OBJECT - -public: - ScanResults(QWidget *parent = 0, const char *name = 0, - bool modal = false, Qt::WindowFlags fl = 0); - ~ScanResults(); - -public slots: - virtual void setWpaGui(WpaGui *_wpagui); - virtual void updateResults(); - virtual void scanRequest(); - virtual void getResults(); - virtual void bssSelected(QTreeWidgetItem *sel); - -protected slots: - virtual void languageChange(); - -private: - WpaGui *wpagui; -}; - -#endif /* SCANRESULTS_H */ +/* + * wpa_gui - ScanResults class + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef SCANRESULTS_H +#define SCANRESULTS_H + +#include +#include "ui_scanresults.h" + +class WpaGui; + +class ScanResults : public QDialog, public Ui::ScanResults +{ + Q_OBJECT + +public: + ScanResults(QWidget *parent = 0, const char *name = 0, + bool modal = false, Qt::WindowFlags fl = 0); + ~ScanResults(); + +public slots: + virtual void setWpaGui(WpaGui *_wpagui); + virtual void updateResults(); + virtual void scanRequest(); + virtual void getResults(); + virtual void bssSelected(QTreeWidgetItem *sel); + +protected slots: + virtual void languageChange(); + +private: + WpaGui *wpagui; +}; + +#endif /* SCANRESULTS_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.ui b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.ui index 81e405efc3198dbee891843831bbd1a68e40ac17..39d728e910b9bcf24e8489c4a5435608a863fc18 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.ui +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresults.ui @@ -1,94 +1,94 @@ - - ScanResults - - - - 0 - 0 - 452 - 244 - - - - Scan results - - - - - - QAbstractItemView::NoEditTriggers - - - true - - - true - - - 5 - - - - SSID - - - - - BSSID - - - - - frequency - - - - - signal - - - - - flags - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Scan - - - - - - - Close - - - - - - - - - - - - + + ScanResults + + + + 0 + 0 + 452 + 244 + + + + Scan results + + + + + + QAbstractItemView::NoEditTriggers + + + true + + + true + + + 5 + + + + SSID + + + + + BSSID + + + + + frequency + + + + + signal + + + + + flags + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Scan + + + + + + + Close + + + + + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp index 9cd937cd6e24bf053a77d2c5e8d3709aae2cf597..b14c7bc47da0011ba5c97d4e30fca010589513e0 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp @@ -1,18 +1,18 @@ -/* - * wpa_gui - ScanResultsItem class - * Copyright (c) 2015, Adrian Nowicki - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "scanresultsitem.h" - -bool ScanResultsItem::operator< (const QTreeWidgetItem &other) const -{ - int sortCol = treeWidget()->sortColumn(); - if (sortCol == 2 || sortCol == 3) { - return text(sortCol).toInt() < other.text(sortCol).toInt(); - } - return text(sortCol) < other.text(sortCol); -} +/* + * wpa_gui - ScanResultsItem class + * Copyright (c) 2015, Adrian Nowicki + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "scanresultsitem.h" + +bool ScanResultsItem::operator< (const QTreeWidgetItem &other) const +{ + int sortCol = treeWidget()->sortColumn(); + if (sortCol == 2 || sortCol == 3) { + return text(sortCol).toInt() < other.text(sortCol).toInt(); + } + return text(sortCol) < other.text(sortCol); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h index 74887eefb59c6f9192dfbf02fffb0ff0c09f50f6..9cb2c85379ce16086e6aa6ee3176b2a8eeeff784 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h @@ -1,21 +1,21 @@ -/* - * wpa_gui - ScanResultsItem class - * Copyright (c) 2015, Adrian Nowicki - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef SCANRESULTSITEM_H -#define SCANRESULTSITEM_H - -#include - -class ScanResultsItem : public QTreeWidgetItem -{ -public: - ScanResultsItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {} - bool operator< (const QTreeWidgetItem &other) const; -}; - -#endif /* SCANRESULTSITEM_H */ +/* + * wpa_gui - ScanResultsItem class + * Copyright (c) 2015, Adrian Nowicki + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef SCANRESULTSITEM_H +#define SCANRESULTSITEM_H + +#include + +class ScanResultsItem : public QTreeWidgetItem +{ +public: + ScanResultsItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {} + bool operator< (const QTreeWidgetItem &other) const; +}; + +#endif /* SCANRESULTSITEM_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/signalbar.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/signalbar.cpp index 2bba582175e53fe90918d4b035533924873c311d..badbaf9e10303ca977ef6db6fb88395437b9e26b 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/signalbar.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/signalbar.cpp @@ -1,58 +1,58 @@ -/* - * wpa_gui - SignalBar class - * Copyright (c) 2011, Kel Modderman - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include -#include - -#include "signalbar.h" - - -SignalBar::SignalBar(QObject *parent) - : QStyledItemDelegate(parent) -{ -} - - -SignalBar::~SignalBar() -{ -} - - -void SignalBar::paint(QPainter *painter, - const QStyleOptionViewItem &option, - const QModelIndex &index) const -{ - QStyleOptionProgressBar opts; - int signal; - - if (index.column() != 3) { - QStyledItemDelegate::paint(painter, option, index); - return; - } - - if (index.data().toInt() > 0) - signal = 0 - (256 - index.data().toInt()); - else - signal = index.data().toInt(); - - opts.minimum = -95; - opts.maximum = -35; - if (signal < opts.minimum) - opts.progress = opts.minimum; - else if (signal > opts.maximum) - opts.progress = opts.maximum; - else - opts.progress = signal; - - opts.text = QString::number(signal) + " dBm"; - opts.textVisible = true; - opts.rect = option.rect; - - QApplication::style()->drawControl(QStyle::CE_ProgressBar, - &opts, painter); -} +/* + * wpa_gui - SignalBar class + * Copyright (c) 2011, Kel Modderman + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include + +#include "signalbar.h" + + +SignalBar::SignalBar(QObject *parent) + : QStyledItemDelegate(parent) +{ +} + + +SignalBar::~SignalBar() +{ +} + + +void SignalBar::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QStyleOptionProgressBar opts; + int signal; + + if (index.column() != 3) { + QStyledItemDelegate::paint(painter, option, index); + return; + } + + if (index.data().toInt() > 0) + signal = 0 - (256 - index.data().toInt()); + else + signal = index.data().toInt(); + + opts.minimum = -95; + opts.maximum = -35; + if (signal < opts.minimum) + opts.progress = opts.minimum; + else if (signal > opts.maximum) + opts.progress = opts.maximum; + else + opts.progress = signal; + + opts.text = QString::number(signal) + " dBm"; + opts.textVisible = true; + opts.rect = option.rect; + + QApplication::style()->drawControl(QStyle::CE_ProgressBar, + &opts, painter); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/signalbar.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/signalbar.h index 37da5dd2ce94172c20d561e8712741f5c79baa4b..f461b0488942b9457889fc337044ec67dc24d3c4 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/signalbar.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/signalbar.h @@ -1,28 +1,28 @@ -/* - * wpa_gui - SignalBar class - * Copyright (c) 2011, Kel Modderman - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef SIGNALBAR_H -#define SIGNALBAR_H - -#include -#include - -class SignalBar : public QStyledItemDelegate -{ - Q_OBJECT - -public: - SignalBar(QObject *parent = 0); - ~SignalBar(); - - virtual void paint(QPainter *painter, - const QStyleOptionViewItem &option, - const QModelIndex &index) const ; -}; - -#endif /* SIGNALBAR_H */ +/* + * wpa_gui - SignalBar class + * Copyright (c) 2011, Kel Modderman + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef SIGNALBAR_H +#define SIGNALBAR_H + +#include +#include + +class SignalBar : public QStyledItemDelegate +{ + Q_OBJECT + +public: + SignalBar(QObject *parent = 0); + ~SignalBar(); + + virtual void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const ; +}; + +#endif /* SIGNALBAR_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/stringquery.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/stringquery.cpp index 420e0bec4d04ed52b1a2611814ab03100fccd18f..285765690bfcf775f8810ccd795b97d4323460af 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/stringquery.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/stringquery.cpp @@ -1,31 +1,31 @@ -/* - * wpa_gui - StringQuery class - * Copyright (c) 2009, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include -#include - -#include "stringquery.h" - - -StringQuery::StringQuery(QString label) -{ - edit = new QLineEdit; - edit->setFocus(); - QGridLayout *layout = new QGridLayout; - layout->addWidget(new QLabel(label), 0, 0); - layout->addWidget(edit, 0, 1); - setLayout(layout); - - connect(edit, SIGNAL(returnPressed()), this, SLOT(accept())); -} - - -QString StringQuery::get_string() -{ - return edit->text(); -} +/* + * wpa_gui - StringQuery class + * Copyright (c) 2009, Atheros Communications + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include + +#include "stringquery.h" + + +StringQuery::StringQuery(QString label) +{ + edit = new QLineEdit; + edit->setFocus(); + QGridLayout *layout = new QGridLayout; + layout->addWidget(new QLabel(label), 0, 0); + layout->addWidget(edit, 0, 1); + setLayout(layout); + + connect(edit, SIGNAL(returnPressed()), this, SLOT(accept())); +} + + +QString StringQuery::get_string() +{ + return edit->text(); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/stringquery.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/stringquery.h index 9d6bffd3e7b62c783b22d65335fac525a7ea746f..d069fbd084336274f979045378e761c5ae6c3729 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/stringquery.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/stringquery.h @@ -1,28 +1,28 @@ -/* - * wpa_gui - StringQuery class - * Copyright (c) 2009, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef STRINGQUERY_H -#define STRINGQUERY_H - -#include -#include -#include - -class StringQuery : public QDialog -{ - Q_OBJECT - -public: - StringQuery(QString label); - QString get_string(); - -private: - QLineEdit *edit; -}; - -#endif /* STRINGQUERY_H */ +/* + * wpa_gui - StringQuery class + * Copyright (c) 2009, Atheros Communications + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef STRINGQUERY_H +#define STRINGQUERY_H + +#include +#include +#include + +class StringQuery : public QDialog +{ + Q_OBJECT + +public: + StringQuery(QString label); + QString get_string(); + +private: + QLineEdit *edit; +}; + +#endif /* STRINGQUERY_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp index 9d933b012053d4265075a351f383a56076d8311d..96e7978fc6b22e92bc7c61f981ce88ad508a4005 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp @@ -1,94 +1,94 @@ -/* - * wpa_gui - UserDataRequest class - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "userdatarequest.h" -#include "wpagui.h" -#include "common/wpa_ctrl.h" - - -UserDataRequest::UserDataRequest(QWidget *parent, const char *, bool, - Qt::WindowFlags) - : QDialog(parent) -{ - setupUi(this); - - connect(buttonOk, SIGNAL(clicked()), this, SLOT(sendReply())); - connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject())); - connect(queryEdit, SIGNAL(returnPressed()), this, SLOT(sendReply())); -} - - -UserDataRequest::~UserDataRequest() -{ -} - - -void UserDataRequest::languageChange() -{ - retranslateUi(this); -} - - -int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg) -{ - char *tmp, *pos, *pos2; - wpagui = _wpagui; - tmp = strdup(reqMsg); - if (tmp == NULL) - return -1; - pos = strchr(tmp, '-'); - if (pos == NULL) { - free(tmp); - return -1; - } - *pos++ = '\0'; - field = tmp; - pos2 = strchr(pos, ':'); - if (pos2 == NULL) { - free(tmp); - return -1; - } - *pos2++ = '\0'; - - networkid = atoi(pos); - queryInfo->setText(pos2); - if (strcmp(tmp, "PASSWORD") == 0) { - queryField->setText(tr("Password: ")); - queryEdit->setEchoMode(QLineEdit::Password); - } else if (strcmp(tmp, "NEW_PASSWORD") == 0) { - queryField->setText(tr("New password: ")); - queryEdit->setEchoMode(QLineEdit::Password); - } else if (strcmp(tmp, "IDENTITY") == 0) - queryField->setText(tr("Identity: ")); - else if (strcmp(tmp, "PASSPHRASE") == 0) { - queryField->setText(tr("Private key passphrase: ")); - queryEdit->setEchoMode(QLineEdit::Password); - } else - queryField->setText(field + ":"); - free(tmp); - - return 0; -} - - -void UserDataRequest::sendReply() -{ - char reply[10]; - size_t reply_len = sizeof(reply); - - if (wpagui == NULL) { - reject(); - return; - } - - QString cmd = QString(WPA_CTRL_RSP) + field + '-' + - QString::number(networkid) + ':' + - queryEdit->text(); - wpagui->ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); - accept(); -} +/* + * wpa_gui - UserDataRequest class + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "userdatarequest.h" +#include "wpagui.h" +#include "common/wpa_ctrl.h" + + +UserDataRequest::UserDataRequest(QWidget *parent, const char *, bool, + Qt::WindowFlags) + : QDialog(parent) +{ + setupUi(this); + + connect(buttonOk, SIGNAL(clicked()), this, SLOT(sendReply())); + connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject())); + connect(queryEdit, SIGNAL(returnPressed()), this, SLOT(sendReply())); +} + + +UserDataRequest::~UserDataRequest() +{ +} + + +void UserDataRequest::languageChange() +{ + retranslateUi(this); +} + + +int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg) +{ + char *tmp, *pos, *pos2; + wpagui = _wpagui; + tmp = strdup(reqMsg); + if (tmp == NULL) + return -1; + pos = strchr(tmp, '-'); + if (pos == NULL) { + free(tmp); + return -1; + } + *pos++ = '\0'; + field = tmp; + pos2 = strchr(pos, ':'); + if (pos2 == NULL) { + free(tmp); + return -1; + } + *pos2++ = '\0'; + + networkid = atoi(pos); + queryInfo->setText(pos2); + if (strcmp(tmp, "PASSWORD") == 0) { + queryField->setText(tr("Password: ")); + queryEdit->setEchoMode(QLineEdit::Password); + } else if (strcmp(tmp, "NEW_PASSWORD") == 0) { + queryField->setText(tr("New password: ")); + queryEdit->setEchoMode(QLineEdit::Password); + } else if (strcmp(tmp, "IDENTITY") == 0) + queryField->setText(tr("Identity: ")); + else if (strcmp(tmp, "PASSPHRASE") == 0) { + queryField->setText(tr("Private key passphrase: ")); + queryEdit->setEchoMode(QLineEdit::Password); + } else + queryField->setText(field + ":"); + free(tmp); + + return 0; +} + + +void UserDataRequest::sendReply() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + + if (wpagui == NULL) { + reject(); + return; + } + + QString cmd = QString(WPA_CTRL_RSP) + field + '-' + + QString::number(networkid) + ':' + + queryEdit->text(); + wpagui->ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); + accept(); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.h index b6d1ad2f4f1ebce3d0750f8b548d0c0f10813a9b..8ef49c4cfe2bf12dc81d772c6ad995657f697f01 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.h @@ -1,40 +1,40 @@ -/* - * wpa_gui - UserDataRequest class - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef USERDATAREQUEST_H -#define USERDATAREQUEST_H - -#include -#include "ui_userdatarequest.h" - -class WpaGui; - -class UserDataRequest : public QDialog, public Ui::UserDataRequest -{ - Q_OBJECT - -public: - UserDataRequest(QWidget *parent = 0, const char *name = 0, - bool modal = false, Qt::WindowFlags fl = 0); - ~UserDataRequest(); - - int setParams(WpaGui *_wpagui, const char *reqMsg); - -public slots: - virtual void sendReply(); - -protected slots: - virtual void languageChange(); - -private: - WpaGui *wpagui; - int networkid; - QString field; -}; - -#endif /* USERDATAREQUEST_H */ +/* + * wpa_gui - UserDataRequest class + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef USERDATAREQUEST_H +#define USERDATAREQUEST_H + +#include +#include "ui_userdatarequest.h" + +class WpaGui; + +class UserDataRequest : public QDialog, public Ui::UserDataRequest +{ + Q_OBJECT + +public: + UserDataRequest(QWidget *parent = 0, const char *name = 0, + bool modal = false, Qt::WindowFlags fl = 0); + ~UserDataRequest(); + + int setParams(WpaGui *_wpagui, const char *reqMsg); + +public slots: + virtual void sendReply(); + +protected slots: + virtual void languageChange(); + +private: + WpaGui *wpagui; + int networkid; + QString field; +}; + +#endif /* USERDATAREQUEST_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui index 1de2a26da1cd0feee6b9aa72e8a0e2222dbb47d6..ab84547cd21163e137e56ea803f895e4e0a3b2c8 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui @@ -1,109 +1,109 @@ - - - - - UserDataRequest - - - - 0 - 0 - 216 - 103 - - - - Authentication credentials required - - - true - - - - - - - - - - - - - 0 - - - - - - - - - - - - true - - - QLineEdit::Password - - - - - - - - - 0 - - - - - - 20 - 20 - - - - Expanding - - - Horizontal - - - - - - - &OK - - - - - - true - - - true - - - - - - - &Cancel - - - - - - true - - - - - - - - - - + + + + + UserDataRequest + + + + 0 + 0 + 216 + 103 + + + + Authentication credentials required + + + true + + + + + + + + + + + + + 0 + + + + + + + + + + + + true + + + QLineEdit::Password + + + + + + + + + 0 + + + + + + 20 + 20 + + + + Expanding + + + Horizontal + + + + + + + &OK + + + + + + true + + + true + + + + + + + &Cancel + + + + + + true + + + + + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop index ccc7d8741d02b93f62f7c5905d590293a07f26c3..cccb80827ebe88e5971edef0a60d7d6a82b78f18 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop @@ -1,10 +1,10 @@ -[Desktop Entry] -Version=1.0 -Name=wpa_gui -Comment=Graphical user interface for wpa_supplicant -Exec=wpa_gui -Icon=wpa_gui -GenericName=wpa_supplicant user interface -Terminal=false -Type=Application -Categories=Qt;Network; +[Desktop Entry] +Version=1.0 +Name=wpa_gui +Comment=Graphical user interface for wpa_supplicant +Exec=wpa_gui +Icon=wpa_gui +GenericName=wpa_supplicant user interface +Terminal=false +Type=Application +Categories=Qt;Network; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro index 3fa734b577585b59e4eb9e7d2b797f6b550bbe9a..626ae83be33f711ef24c24493f42f1cbe06afbc3 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro @@ -1,73 +1,73 @@ -TEMPLATE = app -LANGUAGE = C++ -TRANSLATIONS = lang/wpa_gui_de.ts -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -CONFIG += qt warn_on release - -DEFINES += CONFIG_CTRL_IFACE - -win32 { - LIBS += -lws2_32 -static - DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE - SOURCES += ../../src/utils/os_win32.c -} else:win32-g++ { - # cross compilation to win32 - LIBS += -lws2_32 -static -mwindows - DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE - SOURCES += ../../src/utils/os_win32.c - RESOURCES += icons_png.qrc -} else:win32-x-g++ { - # cross compilation to win32 - LIBS += -lws2_32 -static -mwindows - DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE - DEFINES += _X86_ - SOURCES += ../../src/utils/os_win32.c - RESOURCES += icons_png.qrc -} else { - DEFINES += CONFIG_CTRL_IFACE_UNIX - SOURCES += ../../src/utils/os_unix.c -} - -INCLUDEPATH += . .. ../../src ../../src/utils - -HEADERS += wpamsg.h \ - wpagui.h \ - eventhistory.h \ - scanresults.h \ - scanresultsitem.h \ - signalbar.h \ - userdatarequest.h \ - networkconfig.h \ - addinterface.h \ - peers.h \ - stringquery.h - -SOURCES += main.cpp \ - wpagui.cpp \ - eventhistory.cpp \ - scanresults.cpp \ - scanresultsitem.cpp \ - signalbar.cpp \ - userdatarequest.cpp \ - networkconfig.cpp \ - addinterface.cpp \ - peers.cpp \ - stringquery.cpp \ - ../../src/common/wpa_ctrl.c - -RESOURCES += icons.qrc - -FORMS = wpagui.ui \ - eventhistory.ui \ - scanresults.ui \ - userdatarequest.ui \ - networkconfig.ui \ - peers.ui - - -unix { - UI_DIR = .ui - MOC_DIR = .moc - OBJECTS_DIR = .obj -} +TEMPLATE = app +LANGUAGE = C++ +TRANSLATIONS = lang/wpa_gui_de.ts +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += qt warn_on release + +DEFINES += CONFIG_CTRL_IFACE + +win32 { + LIBS += -lws2_32 -static + DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE + SOURCES += ../../src/utils/os_win32.c +} else:win32-g++ { + # cross compilation to win32 + LIBS += -lws2_32 -static -mwindows + DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE + SOURCES += ../../src/utils/os_win32.c + RESOURCES += icons_png.qrc +} else:win32-x-g++ { + # cross compilation to win32 + LIBS += -lws2_32 -static -mwindows + DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE + DEFINES += _X86_ + SOURCES += ../../src/utils/os_win32.c + RESOURCES += icons_png.qrc +} else { + DEFINES += CONFIG_CTRL_IFACE_UNIX + SOURCES += ../../src/utils/os_unix.c +} + +INCLUDEPATH += . .. ../../src ../../src/utils + +HEADERS += wpamsg.h \ + wpagui.h \ + eventhistory.h \ + scanresults.h \ + scanresultsitem.h \ + signalbar.h \ + userdatarequest.h \ + networkconfig.h \ + addinterface.h \ + peers.h \ + stringquery.h + +SOURCES += main.cpp \ + wpagui.cpp \ + eventhistory.cpp \ + scanresults.cpp \ + scanresultsitem.cpp \ + signalbar.cpp \ + userdatarequest.cpp \ + networkconfig.cpp \ + addinterface.cpp \ + peers.cpp \ + stringquery.cpp \ + ../../src/common/wpa_ctrl.c + +RESOURCES += icons.qrc + +FORMS = wpagui.ui \ + eventhistory.ui \ + scanresults.ui \ + userdatarequest.ui \ + networkconfig.ui \ + peers.ui + + +unix { + UI_DIR = .ui + MOC_DIR = .moc + OBJECTS_DIR = .obj +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.cpp index 9404ab4249b786c921841e29aaa897c11fe5edb0..82f1b7e0d2b32bd1d6a342487b233709010f392f 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.cpp @@ -1,1913 +1,1913 @@ -/* - * wpa_gui - WpaGui class - * Copyright (c) 2005-2011, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifdef CONFIG_NATIVE_WINDOWS -#include -#endif /* CONFIG_NATIVE_WINDOWS */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wpagui.h" -#include "dirent.h" -#include "common/wpa_ctrl.h" -#include "userdatarequest.h" -#include "networkconfig.h" - - -#ifndef QT_NO_DEBUG -#define debug(M, ...) qDebug("DEBUG %d: " M, __LINE__, ##__VA_ARGS__) -#else -#define debug(M, ...) do {} while (0) -#endif - - -WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, - Qt::WindowFlags) - : QMainWindow(parent), app(_app) -{ - setupUi(this); - this->setWindowFlags(Qt::Dialog); - -#ifdef CONFIG_NATIVE_WINDOWS - fileStopServiceAction = new QAction(this); - fileStopServiceAction->setObjectName("Stop Service"); - fileStopServiceAction->setIconText(tr("Stop Service")); - fileMenu->insertAction(actionWPS, fileStopServiceAction); - - fileStartServiceAction = new QAction(this); - fileStartServiceAction->setObjectName("Start Service"); - fileStartServiceAction->setIconText(tr("Start Service")); - fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction); - - connect(fileStartServiceAction, SIGNAL(triggered()), this, - SLOT(startService())); - connect(fileStopServiceAction, SIGNAL(triggered()), this, - SLOT(stopService())); - - addInterfaceAction = new QAction(this); - addInterfaceAction->setIconText(tr("Add Interface")); - fileMenu->insertAction(fileStartServiceAction, addInterfaceAction); - - connect(addInterfaceAction, SIGNAL(triggered()), this, - SLOT(addInterface())); -#endif /* CONFIG_NATIVE_WINDOWS */ - - (void) statusBar(); - - /* - * Disable WPS tab by default; it will be enabled if wpa_supplicant is - * built with WPS support. - */ - wpsTab->setEnabled(false); - wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false); - - connect(fileEventHistoryAction, SIGNAL(triggered()), this, - SLOT(eventHistory())); - connect(fileSaveConfigAction, SIGNAL(triggered()), this, - SLOT(saveConfig())); - connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog())); - connect(actionPeers, SIGNAL(triggered()), this, SLOT(peersDialog())); - connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit())); - connect(networkAddAction, SIGNAL(triggered()), this, - SLOT(addNetwork())); - connect(networkEditAction, SIGNAL(triggered()), this, - SLOT(editSelectedNetwork())); - connect(networkRemoveAction, SIGNAL(triggered()), this, - SLOT(removeSelectedNetwork())); - connect(networkEnableAllAction, SIGNAL(triggered()), this, - SLOT(enableAllNetworks())); - connect(networkDisableAllAction, SIGNAL(triggered()), this, - SLOT(disableAllNetworks())); - connect(networkRemoveAllAction, SIGNAL(triggered()), this, - SLOT(removeAllNetworks())); - connect(helpIndexAction, SIGNAL(triggered()), this, SLOT(helpIndex())); - connect(helpContentsAction, SIGNAL(triggered()), this, - SLOT(helpContents())); - connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(helpAbout())); - connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect())); - connect(scanButton, SIGNAL(clicked()), this, SLOT(scan())); - connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB())); - connect(adapterSelect, SIGNAL(activated(const QString&)), this, - SLOT(selectAdapter(const QString&))); - connect(networkSelect, SIGNAL(activated(const QString&)), this, - SLOT(selectNetwork(const QString&))); - connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork())); - connect(editNetworkButton, SIGNAL(clicked()), this, - SLOT(editListedNetwork())); - connect(removeNetworkButton, SIGNAL(clicked()), this, - SLOT(removeListedNetwork())); - connect(networkList, SIGNAL(itemSelectionChanged()), this, - SLOT(updateNetworkDisabledStatus())); - connect(enableRadioButton, SIGNAL(toggled(bool)), this, - SLOT(enableListedNetwork(bool))); - connect(disableRadioButton, SIGNAL(toggled(bool)), this, - SLOT(disableListedNetwork(bool))); - connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan())); - connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), - this, SLOT(editListedNetwork())); - connect(wpaguiTab, SIGNAL(currentChanged(int)), this, - SLOT(tabChanged(int))); - connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc())); - connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin())); - connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this, - SLOT(wpsApPinChanged(const QString &))); - connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin())); - - eh = NULL; - scanres = NULL; - peers = NULL; - add_iface = NULL; - udr = NULL; - tray_icon = NULL; - startInTray = false; - quietMode = false; - ctrl_iface = NULL; - ctrl_conn = NULL; - monitor_conn = NULL; - msgNotifier = NULL; - ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); - signalMeterInterval = 0; - - parse_argv(); - -#ifndef QT_NO_SESSIONMANAGER - if (app->isSessionRestored()) { - QSettings settings("wpa_supplicant", "wpa_gui"); - settings.beginGroup("state"); - if (app->sessionId().compare(settings.value("session_id"). - toString()) == 0) - startInTray = settings.value("in_tray").toBool(); - settings.endGroup(); - } -#endif - - if (QSystemTrayIcon::isSystemTrayAvailable()) - createTrayIcon(startInTray); - else - show(); - - connectedToService = false; - textStatus->setText(tr("connecting to wpa_supplicant")); - timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), SLOT(ping())); - timer->setSingleShot(false); - timer->start(1000); - - signalMeterTimer = new QTimer(this); - signalMeterTimer->setInterval(signalMeterInterval); - connect(signalMeterTimer, SIGNAL(timeout()), SLOT(signalMeterUpdate())); - - if (openCtrlConnection(ctrl_iface) < 0) { - debug("Failed to open control connection to " - "wpa_supplicant."); - } - - updateStatus(); - networkMayHaveChanged = true; - updateNetworks(); -} - - -WpaGui::~WpaGui() -{ - delete msgNotifier; - - if (monitor_conn) { - wpa_ctrl_detach(monitor_conn); - wpa_ctrl_close(monitor_conn); - monitor_conn = NULL; - } - if (ctrl_conn) { - wpa_ctrl_close(ctrl_conn); - ctrl_conn = NULL; - } - - if (eh) { - eh->close(); - delete eh; - eh = NULL; - } - - if (scanres) { - scanres->close(); - delete scanres; - scanres = NULL; - } - - if (peers) { - peers->close(); - delete peers; - peers = NULL; - } - - if (add_iface) { - add_iface->close(); - delete add_iface; - add_iface = NULL; - } - - if (udr) { - udr->close(); - delete udr; - udr = NULL; - } - - free(ctrl_iface); - ctrl_iface = NULL; - - free(ctrl_iface_dir); - ctrl_iface_dir = NULL; -} - - -void WpaGui::languageChange() -{ - retranslateUi(this); -} - - -void WpaGui::parse_argv() -{ - int c; - WpaGuiApp *app = qobject_cast(qApp); - for (;;) { - c = getopt(app->argc, app->argv, "i:m:p:tq"); - if (c < 0) - break; - switch (c) { - case 'i': - free(ctrl_iface); - ctrl_iface = strdup(optarg); - break; - case 'm': - signalMeterInterval = atoi(optarg) * 1000; - break; - case 'p': - free(ctrl_iface_dir); - ctrl_iface_dir = strdup(optarg); - break; - case 't': - startInTray = true; - break; - case 'q': - quietMode = true; - break; - } - } -} - - -int WpaGui::openCtrlConnection(const char *ifname) -{ - char *cfile; - int flen; - char buf[2048], *pos, *pos2; - size_t len; - - if (ifname) { - if (ifname != ctrl_iface) { - free(ctrl_iface); - ctrl_iface = strdup(ifname); - } - } else { -#ifdef CONFIG_CTRL_IFACE_UDP - free(ctrl_iface); - ctrl_iface = strdup("udp"); -#endif /* CONFIG_CTRL_IFACE_UDP */ -#ifdef CONFIG_CTRL_IFACE_UNIX - struct dirent *dent; - DIR *dir = opendir(ctrl_iface_dir); - free(ctrl_iface); - ctrl_iface = NULL; - if (dir) { - while ((dent = readdir(dir))) { -#ifdef _DIRENT_HAVE_D_TYPE - /* Skip the file if it is not a socket. - * Also accept DT_UNKNOWN (0) in case - * the C library or underlying file - * system does not support d_type. */ - if (dent->d_type != DT_SOCK && - dent->d_type != DT_UNKNOWN) - continue; -#endif /* _DIRENT_HAVE_D_TYPE */ - - if (strcmp(dent->d_name, ".") == 0 || - strcmp(dent->d_name, "..") == 0) - continue; - debug("Selected interface '%s'", - dent->d_name); - ctrl_iface = strdup(dent->d_name); - break; - } - closedir(dir); - } -#endif /* CONFIG_CTRL_IFACE_UNIX */ -#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE - struct wpa_ctrl *ctrl; - int ret; - - free(ctrl_iface); - ctrl_iface = NULL; - - ctrl = wpa_ctrl_open(NULL); - if (ctrl) { - len = sizeof(buf) - 1; - ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, - &len, NULL); - if (ret >= 0) { - connectedToService = true; - buf[len] = '\0'; - pos = strchr(buf, '\n'); - if (pos) - *pos = '\0'; - ctrl_iface = strdup(buf); - } - wpa_ctrl_close(ctrl); - } -#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ - } - - if (ctrl_iface == NULL) { -#ifdef CONFIG_NATIVE_WINDOWS - static bool first = true; - if (first && !serviceRunning()) { - first = false; - if (QMessageBox::warning( - this, qAppName(), - tr("wpa_supplicant service is not " - "running.\n" - "Do you want to start it?"), - QMessageBox::Yes | QMessageBox::No) == - QMessageBox::Yes) - startService(); - } -#endif /* CONFIG_NATIVE_WINDOWS */ - return -1; - } - -#ifdef CONFIG_CTRL_IFACE_UNIX - flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2; - cfile = (char *) malloc(flen); - if (cfile == NULL) - return -1; - snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface); -#else /* CONFIG_CTRL_IFACE_UNIX */ - flen = strlen(ctrl_iface) + 1; - cfile = (char *) malloc(flen); - if (cfile == NULL) - return -1; - snprintf(cfile, flen, "%s", ctrl_iface); -#endif /* CONFIG_CTRL_IFACE_UNIX */ - - if (ctrl_conn) { - wpa_ctrl_close(ctrl_conn); - ctrl_conn = NULL; - } - - if (monitor_conn) { - delete msgNotifier; - msgNotifier = NULL; - wpa_ctrl_detach(monitor_conn); - wpa_ctrl_close(monitor_conn); - monitor_conn = NULL; - } - - debug("Trying to connect to '%s'", cfile); - ctrl_conn = wpa_ctrl_open(cfile); - if (ctrl_conn == NULL) { - free(cfile); - return -1; - } - monitor_conn = wpa_ctrl_open(cfile); - free(cfile); - if (monitor_conn == NULL) { - wpa_ctrl_close(ctrl_conn); - return -1; - } - if (wpa_ctrl_attach(monitor_conn)) { - debug("Failed to attach to wpa_supplicant"); - wpa_ctrl_close(monitor_conn); - monitor_conn = NULL; - wpa_ctrl_close(ctrl_conn); - ctrl_conn = NULL; - return -1; - } - -#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) - msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn), - QSocketNotifier::Read, this); - connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs())); -#endif - - adapterSelect->clear(); - adapterSelect->addItem(ctrl_iface); - adapterSelect->setCurrentIndex(0); - - len = sizeof(buf) - 1; - if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= - 0) { - buf[len] = '\0'; - pos = buf; - while (*pos) { - pos2 = strchr(pos, '\n'); - if (pos2) - *pos2 = '\0'; - if (strcmp(pos, ctrl_iface) != 0) - adapterSelect->addItem(pos); - if (pos2) - pos = pos2 + 1; - else - break; - } - } - - len = sizeof(buf) - 1; - if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len, - NULL) >= 0) { - buf[len] = '\0'; - - QString res(buf); - QStringList types = res.split(QChar(' ')); - bool wps = types.contains("WSC"); - actionWPS->setEnabled(wps); - wpsTab->setEnabled(wps); - wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps); - } - - return 0; -} - - -int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen) -{ - int ret; - - if (ctrl_conn == NULL) - return -3; - ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL); - if (ret == -2) - debug("'%s' command timed out.", cmd); - else if (ret < 0) - debug("'%s' command failed.", cmd); - - return ret; -} - - -QString WpaGui::wpaStateTranslate(char *state) -{ - if (!strcmp(state, "DISCONNECTED")) - return tr("Disconnected"); - else if (!strcmp(state, "INACTIVE")) - return tr("Inactive"); - else if (!strcmp(state, "SCANNING")) - return tr("Scanning"); - else if (!strcmp(state, "AUTHENTICATING")) - return tr("Authenticating"); - else if (!strcmp(state, "ASSOCIATING")) - return tr("Associating"); - else if (!strcmp(state, "ASSOCIATED")) - return tr("Associated"); - else if (!strcmp(state, "4WAY_HANDSHAKE")) - return tr("4-Way Handshake"); - else if (!strcmp(state, "GROUP_HANDSHAKE")) - return tr("Group Handshake"); - else if (!strcmp(state, "COMPLETED")) - return tr("Completed"); - else - return tr("Unknown"); -} - - -void WpaGui::updateStatus() -{ - char buf[2048], *start, *end, *pos; - size_t len; - - pingsToStatusUpdate = 10; - - len = sizeof(buf) - 1; - if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) { - textStatus->setText(tr("Could not get status from " - "wpa_supplicant")); - textAuthentication->clear(); - textEncryption->clear(); - textSsid->clear(); - textBssid->clear(); - textIpAddress->clear(); - updateTrayToolTip(tr("no status information")); - updateTrayIcon(TrayIconOffline); - signalMeterTimer->stop(); - -#ifdef CONFIG_NATIVE_WINDOWS - static bool first = true; - if (first && connectedToService && - (ctrl_iface == NULL || *ctrl_iface == '\0')) { - first = false; - if (QMessageBox::information( - this, qAppName(), - tr("No network interfaces in use.\n" - "Would you like to add one?"), - QMessageBox::Yes | QMessageBox::No) == - QMessageBox::Yes) - addInterface(); - } -#endif /* CONFIG_NATIVE_WINDOWS */ - return; - } - - buf[len] = '\0'; - - bool auth_updated = false, ssid_updated = false; - bool bssid_updated = false, ipaddr_updated = false; - bool status_updated = false; - char *pairwise_cipher = NULL, *group_cipher = NULL; - char *mode = NULL; - - start = buf; - while (*start) { - bool last = false; - end = strchr(start, '\n'); - if (end == NULL) { - last = true; - end = start; - while (end[0] && end[1]) - end++; - } - *end = '\0'; - - pos = strchr(start, '='); - if (pos) { - *pos++ = '\0'; - if (strcmp(start, "bssid") == 0) { - bssid_updated = true; - textBssid->setText(pos); - } else if (strcmp(start, "ssid") == 0) { - ssid_updated = true; - textSsid->setText(pos); - updateTrayToolTip(pos + tr(" (associated)")); - if (!signalMeterInterval) { - /* if signal meter is not enabled show - * full signal strength */ - updateTrayIcon(TrayIconSignalExcellent); - } - } else if (strcmp(start, "ip_address") == 0) { - ipaddr_updated = true; - textIpAddress->setText(pos); - } else if (strcmp(start, "wpa_state") == 0) { - status_updated = true; - textStatus->setText(wpaStateTranslate(pos)); - } else if (strcmp(start, "key_mgmt") == 0) { - auth_updated = true; - textAuthentication->setText(pos); - /* TODO: could add EAP status to this */ - } else if (strcmp(start, "pairwise_cipher") == 0) { - pairwise_cipher = pos; - } else if (strcmp(start, "group_cipher") == 0) { - group_cipher = pos; - } else if (strcmp(start, "mode") == 0) { - mode = pos; - } - } - - if (last) - break; - start = end + 1; - } - if (status_updated && mode) - textStatus->setText(textStatus->text() + " (" + mode + ")"); - - if (pairwise_cipher || group_cipher) { - QString encr; - if (pairwise_cipher && group_cipher && - strcmp(pairwise_cipher, group_cipher) != 0) { - encr.append(pairwise_cipher); - encr.append(" + "); - encr.append(group_cipher); - } else if (pairwise_cipher) { - encr.append(pairwise_cipher); - } else { - encr.append(group_cipher); - encr.append(" [group key only]"); - } - textEncryption->setText(encr); - } else - textEncryption->clear(); - - if (signalMeterInterval) { - /* - * Handle signal meter service. When network is not associated, - * deactivate timer, otherwise keep it going. Tray icon has to - * be initialized here, because of the initial delay of the - * timer. - */ - if (ssid_updated) { - if (!signalMeterTimer->isActive()) { - updateTrayIcon(TrayIconConnected); - signalMeterTimer->start(); - } - } else { - signalMeterTimer->stop(); - } - } - - if (!status_updated) - textStatus->clear(); - if (!auth_updated) - textAuthentication->clear(); - if (!ssid_updated) { - textSsid->clear(); - updateTrayToolTip(tr("(not-associated)")); - updateTrayIcon(TrayIconOffline); - } - if (!bssid_updated) - textBssid->clear(); - if (!ipaddr_updated) - textIpAddress->clear(); -} - - -void WpaGui::updateNetworks() -{ - char buf[4096], *start, *end, *id, *ssid, *bssid, *flags; - size_t len; - int first_active = -1; - int was_selected = -1; - bool current = false; - - if (!networkMayHaveChanged) - return; - - if (networkList->currentRow() >= 0) - was_selected = networkList->currentRow(); - - networkSelect->clear(); - networkList->clear(); - - if (ctrl_conn == NULL) - return; - - len = sizeof(buf) - 1; - if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0) - return; - - buf[len] = '\0'; - start = strchr(buf, '\n'); - if (start == NULL) - return; - start++; - - while (*start) { - bool last = false; - end = strchr(start, '\n'); - if (end == NULL) { - last = true; - end = start; - while (end[0] && end[1]) - end++; - } - *end = '\0'; - - id = start; - ssid = strchr(id, '\t'); - if (ssid == NULL) - break; - *ssid++ = '\0'; - bssid = strchr(ssid, '\t'); - if (bssid == NULL) - break; - *bssid++ = '\0'; - flags = strchr(bssid, '\t'); - if (flags == NULL) - break; - *flags++ = '\0'; - - if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) { - if (last) - break; - start = end + 1; - continue; - } - - QString network(id); - network.append(": "); - network.append(ssid); - networkSelect->addItem(network); - networkList->addItem(network); - - if (strstr(flags, "[CURRENT]")) { - networkSelect->setCurrentIndex(networkSelect->count() - - 1); - current = true; - } else if (first_active < 0 && - strstr(flags, "[DISABLED]") == NULL) - first_active = networkSelect->count() - 1; - - start = end + 1; - if (*start && strchr(start, '\n')) - continue; - - /* avoid race conditions */ - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - QString cmd("LIST_NETWORKS LAST_ID="); - cmd.append(id); - if (ctrlRequest(cmd.toLocal8Bit().constData(), buf, &len) < 0) - break; - - buf[len] = '\0'; - start = strchr(buf, '\n'); - if (!start) - break; - start++; - } - - if (networkSelect->count() > 1) - networkSelect->addItem(tr("Select any network")); - - if (!current && first_active >= 0) - networkSelect->setCurrentIndex(first_active); - - if (was_selected >= 0 && networkList->count() > 0) { - if (was_selected < networkList->count()) - networkList->setCurrentRow(was_selected); - else - networkList->setCurrentRow(networkList->count() - 1); - } - else - networkList->setCurrentRow(networkSelect->currentIndex()); - - networkMayHaveChanged = false; -} - - -void WpaGui::helpIndex() -{ - debug("helpIndex"); -} - - -void WpaGui::helpContents() -{ - debug("helpContents"); -} - - -void WpaGui::helpAbout() -{ - QMessageBox::about(this, "wpa_gui for wpa_supplicant", - "Copyright (c) 2003-2015,\n" - "Jouni Malinen \n" - "and contributors.\n" - "\n" - "This software may be distributed under\n" - "the terms of the BSD license.\n" - "See README for more details.\n" - "\n" - "This product includes software developed\n" - "by the OpenSSL Project for use in the\n" - "OpenSSL Toolkit (http://www.openssl.org/)\n"); -} - - -void WpaGui::disconnect() -{ - char reply[10]; - size_t reply_len = sizeof(reply); - ctrlRequest("DISCONNECT", reply, &reply_len); - stopWpsRun(false); -} - - -void WpaGui::scan() -{ - if (scanres) { - scanres->close(); - delete scanres; - } - - scanres = new ScanResults(); - if (scanres == NULL) - return; - scanres->setWpaGui(this); - scanres->show(); - scanres->exec(); -} - - -void WpaGui::eventHistory() -{ - if (eh) { - eh->close(); - delete eh; - } - - eh = new EventHistory(); - if (eh == NULL) - return; - eh->addEvents(msgs); - eh->show(); - eh->exec(); -} - - -void WpaGui::ping() -{ - char buf[10]; - size_t len; - -#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE - /* - * QSocketNotifier cannot be used with Windows named pipes, so use a - * timer to check for received messages for now. This could be - * optimized be doing something specific to named pipes or Windows - * events, but it is not clear what would be the best way of doing that - * in Qt. - */ - receiveMsgs(); -#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ - - if (scanres && !scanres->isVisible()) { - delete scanres; - scanres = NULL; - } - - if (eh && !eh->isVisible()) { - delete eh; - eh = NULL; - } - - if (udr && !udr->isVisible()) { - delete udr; - udr = NULL; - } - - len = sizeof(buf) - 1; - if (ctrlRequest("PING", buf, &len) < 0) { - debug("PING failed - trying to reconnect"); - if (openCtrlConnection(ctrl_iface) >= 0) { - debug("Reconnected successfully"); - pingsToStatusUpdate = 0; - } - } - - pingsToStatusUpdate--; - if (pingsToStatusUpdate <= 0) { - updateStatus(); - updateNetworks(); - } - -#ifndef CONFIG_CTRL_IFACE_NAMED_PIPE - /* Use less frequent pings and status updates when the main window is - * hidden (running in taskbar). */ - int interval = isHidden() ? 5000 : 1000; - if (timer->interval() != interval) - timer->setInterval(interval); -#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ -} - - -void WpaGui::signalMeterUpdate() -{ - char reply[128]; - size_t reply_len = sizeof(reply); - char *rssi; - int rssi_value; - - ctrlRequest("SIGNAL_POLL", reply, &reply_len); - - /* In order to eliminate signal strength fluctuations, try - * to obtain averaged RSSI value in the first place. */ - if ((rssi = strstr(reply, "AVG_RSSI=")) != NULL) - rssi_value = atoi(&rssi[sizeof("AVG_RSSI")]); - else if ((rssi = strstr(reply, "RSSI=")) != NULL) - rssi_value = atoi(&rssi[sizeof("RSSI")]); - else { - debug("Failed to get RSSI value"); - updateTrayIcon(TrayIconSignalNone); - return; - } - - debug("RSSI value: %d", rssi_value); - - /* - * NOTE: The code below assumes, that the unit of the value returned - * by the SIGNAL POLL request is dBm. It might not be true for all - * wpa_supplicant drivers. - */ - - /* - * Calibration is based on "various Internet sources". Nonetheless, - * it seems to be compatible with the Windows 8.1 strength meter - - * tested on Intel Centrino Advanced-N 6235. - */ - if (rssi_value >= -60) - updateTrayIcon(TrayIconSignalExcellent); - else if (rssi_value >= -68) - updateTrayIcon(TrayIconSignalGood); - else if (rssi_value >= -76) - updateTrayIcon(TrayIconSignalOk); - else if (rssi_value >= -84) - updateTrayIcon(TrayIconSignalWeak); - else - updateTrayIcon(TrayIconSignalNone); -} - - -static int str_match(const char *a, const char *b) -{ - return strncmp(a, b, strlen(b)) == 0; -} - - -void WpaGui::processMsg(char *msg) -{ - char *pos = msg, *pos2; - int priority = 2; - - if (*pos == '<') { - /* skip priority */ - pos++; - priority = atoi(pos); - pos = strchr(pos, '>'); - if (pos) - pos++; - else - pos = msg; - } - - WpaMsg wm(pos, priority); - if (eh) - eh->addEvent(wm); - if (peers) - peers->event_notify(wm); - msgs.append(wm); - while (msgs.count() > 100) - msgs.pop_front(); - - /* Update last message with truncated version of the event */ - if (strncmp(pos, "CTRL-", 5) == 0) { - pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' '); - if (pos2) - pos2++; - else - pos2 = pos; - } else - pos2 = pos; - QString lastmsg = pos2; - lastmsg.truncate(40); - textLastMessage->setText(lastmsg); - - pingsToStatusUpdate = 0; - networkMayHaveChanged = true; - - if (str_match(pos, WPA_CTRL_REQ)) - processCtrlReq(pos + strlen(WPA_CTRL_REQ)); - else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres) - scanres->updateResults(); - else if (str_match(pos, WPA_EVENT_DISCONNECTED)) - showTrayMessage(QSystemTrayIcon::Information, 3, - tr("Disconnected from network.")); - else if (str_match(pos, WPA_EVENT_CONNECTED)) { - showTrayMessage(QSystemTrayIcon::Information, 3, - tr("Connection to network established.")); - QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus())); - stopWpsRun(true); - } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) { - wpsStatusText->setText(tr("WPS AP in active PBC mode found")); - if (textStatus->text() == "INACTIVE" || - textStatus->text() == "DISCONNECTED") - wpaguiTab->setCurrentWidget(wpsTab); - wpsInstructions->setText(tr("Press the PBC button on the " - "screen to start registration")); - } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) { - wpsStatusText->setText(tr("WPS AP with recently selected " - "registrar")); - if (textStatus->text() == "INACTIVE" || - textStatus->text() == "DISCONNECTED") - wpaguiTab->setCurrentWidget(wpsTab); - } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) { - showTrayMessage(QSystemTrayIcon::Information, 3, - "Wi-Fi Protected Setup (WPS) AP\n" - "indicating this client is authorized."); - wpsStatusText->setText("WPS AP indicating this client is " - "authorized"); - if (textStatus->text() == "INACTIVE" || - textStatus->text() == "DISCONNECTED") - wpaguiTab->setCurrentWidget(wpsTab); - } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) { - wpsStatusText->setText(tr("WPS AP detected")); - } else if (str_match(pos, WPS_EVENT_OVERLAP)) { - wpsStatusText->setText(tr("PBC mode overlap detected")); - wpsInstructions->setText(tr("More than one AP is currently in " - "active WPS PBC mode. Wait couple " - "of minutes and try again")); - wpaguiTab->setCurrentWidget(wpsTab); - } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) { - wpsStatusText->setText(tr("Network configuration received")); - wpaguiTab->setCurrentWidget(wpsTab); - } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) { - if (strstr(pos, "(WSC)")) - wpsStatusText->setText(tr("Registration started")); - } else if (str_match(pos, WPS_EVENT_M2D)) { - wpsStatusText->setText(tr("Registrar does not yet know PIN")); - } else if (str_match(pos, WPS_EVENT_FAIL)) { - wpsStatusText->setText(tr("Registration failed")); - } else if (str_match(pos, WPS_EVENT_SUCCESS)) { - wpsStatusText->setText(tr("Registration succeeded")); - } -} - - -void WpaGui::processCtrlReq(const char *req) -{ - if (udr) { - udr->close(); - delete udr; - } - udr = new UserDataRequest(); - if (udr == NULL) - return; - if (udr->setParams(this, req) < 0) { - delete udr; - udr = NULL; - return; - } - udr->show(); - udr->exec(); -} - - -void WpaGui::receiveMsgs() -{ - char buf[256]; - size_t len; - - while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) { - len = sizeof(buf) - 1; - if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) { - buf[len] = '\0'; - processMsg(buf); - } - } -} - - -void WpaGui::connectB() -{ - char reply[10]; - size_t reply_len = sizeof(reply); - ctrlRequest("REASSOCIATE", reply, &reply_len); -} - - -void WpaGui::selectNetwork( const QString &sel ) -{ - QString cmd(sel); - char reply[10]; - size_t reply_len = sizeof(reply); - - if (cmd.contains(QRegExp("^\\d+:"))) - cmd.truncate(cmd.indexOf(':')); - else - cmd = "any"; - cmd.prepend("SELECT_NETWORK "); - ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); - triggerUpdate(); - stopWpsRun(false); -} - - -void WpaGui::enableNetwork(const QString &sel) -{ - QString cmd(sel); - char reply[10]; - size_t reply_len = sizeof(reply); - - if (cmd.contains(QRegExp("^\\d+:"))) - cmd.truncate(cmd.indexOf(':')); - else if (!cmd.startsWith("all")) { - debug("Invalid editNetwork '%s'", - cmd.toLocal8Bit().constData()); - return; - } - cmd.prepend("ENABLE_NETWORK "); - ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); - triggerUpdate(); -} - - -void WpaGui::disableNetwork(const QString &sel) -{ - QString cmd(sel); - char reply[10]; - size_t reply_len = sizeof(reply); - - if (cmd.contains(QRegExp("^\\d+:"))) - cmd.truncate(cmd.indexOf(':')); - else if (!cmd.startsWith("all")) { - debug("Invalid editNetwork '%s'", - cmd.toLocal8Bit().constData()); - return; - } - cmd.prepend("DISABLE_NETWORK "); - ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); - triggerUpdate(); -} - - -void WpaGui::editNetwork(const QString &sel) -{ - QString cmd(sel); - int id = -1; - - if (cmd.contains(QRegExp("^\\d+:"))) { - cmd.truncate(cmd.indexOf(':')); - id = cmd.toInt(); - } - - NetworkConfig *nc = new NetworkConfig(); - if (nc == NULL) - return; - nc->setWpaGui(this); - - if (id >= 0) - nc->paramsFromConfig(id); - else - nc->newNetwork(); - - nc->show(); - nc->exec(); -} - - -void WpaGui::editSelectedNetwork() -{ - if (networkSelect->count() < 1) { - QMessageBox::information( - this, tr("No Networks"), - tr("There are no networks to edit.\n")); - return; - } - QString sel(networkSelect->currentText()); - editNetwork(sel); -} - - -void WpaGui::editListedNetwork() -{ - if (networkList->currentRow() < 0) { - QMessageBox::information(this, tr("Select A Network"), - tr("Select a network from the list to" - " edit it.\n")); - return; - } - QString sel(networkList->currentItem()->text()); - editNetwork(sel); -} - - -void WpaGui::triggerUpdate() -{ - updateStatus(); - networkMayHaveChanged = true; - updateNetworks(); -} - - -void WpaGui::addNetwork() -{ - NetworkConfig *nc = new NetworkConfig(); - if (nc == NULL) - return; - nc->setWpaGui(this); - nc->newNetwork(); - nc->show(); - nc->exec(); -} - - -void WpaGui::removeNetwork(const QString &sel) -{ - QString cmd(sel); - char reply[10]; - size_t reply_len = sizeof(reply); - - if (cmd.contains(QRegExp("^\\d+:"))) - cmd.truncate(cmd.indexOf(':')); - else if (!cmd.startsWith("all")) { - debug("Invalid editNetwork '%s'", - cmd.toLocal8Bit().constData()); - return; - } - cmd.prepend("REMOVE_NETWORK "); - ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); - triggerUpdate(); -} - - -void WpaGui::removeSelectedNetwork() -{ - if (networkSelect->count() < 1) { - QMessageBox::information(this, tr("No Networks"), - tr("There are no networks to remove." - "\n")); - return; - } - QString sel(networkSelect->currentText()); - removeNetwork(sel); -} - - -void WpaGui::removeListedNetwork() -{ - if (networkList->currentRow() < 0) { - QMessageBox::information(this, tr("Select A Network"), - tr("Select a network from the list " - "to remove it.\n")); - return; - } - QString sel(networkList->currentItem()->text()); - removeNetwork(sel); -} - - -void WpaGui::enableAllNetworks() -{ - QString sel("all"); - enableNetwork(sel); -} - - -void WpaGui::disableAllNetworks() -{ - QString sel("all"); - disableNetwork(sel); -} - - -void WpaGui::removeAllNetworks() -{ - QString sel("all"); - removeNetwork(sel); -} - - -int WpaGui::getNetworkDisabled(const QString &sel) -{ - QString cmd(sel); - char reply[10]; - size_t reply_len = sizeof(reply) - 1; - int pos = cmd.indexOf(':'); - if (pos < 0) { - debug("Invalid getNetworkDisabled '%s'", - cmd.toLocal8Bit().constData()); - return -1; - } - cmd.truncate(pos); - cmd.prepend("GET_NETWORK "); - cmd.append(" disabled"); - - if (ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len) >= 0 - && reply_len >= 1) { - reply[reply_len] = '\0'; - if (!str_match(reply, "FAIL")) - return atoi(reply); - } - - return -1; -} - - -void WpaGui::updateNetworkDisabledStatus() -{ - if (networkList->currentRow() < 0) - return; - - QString sel(networkList->currentItem()->text()); - - switch (getNetworkDisabled(sel)) { - case 0: - if (!enableRadioButton->isChecked()) - enableRadioButton->setChecked(true); - return; - case 1: - if (!disableRadioButton->isChecked()) - disableRadioButton->setChecked(true); - return; - } -} - - -void WpaGui::enableListedNetwork(bool enabled) -{ - if (networkList->currentRow() < 0 || !enabled) - return; - - QString sel(networkList->currentItem()->text()); - - if (getNetworkDisabled(sel) == 1) - enableNetwork(sel); -} - - -void WpaGui::disableListedNetwork(bool disabled) -{ - if (networkList->currentRow() < 0 || !disabled) - return; - - QString sel(networkList->currentItem()->text()); - - if (getNetworkDisabled(sel) == 0) - disableNetwork(sel); -} - - -void WpaGui::saveConfig() -{ - char buf[10]; - size_t len; - - len = sizeof(buf) - 1; - ctrlRequest("SAVE_CONFIG", buf, &len); - - buf[len] = '\0'; - - if (str_match(buf, "FAIL")) - QMessageBox::warning( - this, tr("Failed to save configuration"), - tr("The configuration could not be saved.\n" - "\n" - "The update_config=1 configuration option\n" - "must be used for configuration saving to\n" - "be permitted.\n")); - else - QMessageBox::information( - this, tr("Saved configuration"), - tr("The current configuration was saved." - "\n")); -} - - -void WpaGui::selectAdapter( const QString & sel ) -{ - if (openCtrlConnection(sel.toLocal8Bit().constData()) < 0) - debug("Failed to open control connection to " - "wpa_supplicant."); - updateStatus(); - updateNetworks(); -} - - -void WpaGui::createTrayIcon(bool trayOnly) -{ - QApplication::setQuitOnLastWindowClosed(false); - - tray_icon = new QSystemTrayIcon(this); - updateTrayIcon(TrayIconOffline); - - connect(tray_icon, - SIGNAL(activated(QSystemTrayIcon::ActivationReason)), - this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); - - ackTrayIcon = false; - - tray_menu = new QMenu(this); - - disconnectAction = new QAction(tr("&Disconnect"), this); - reconnectAction = new QAction(tr("Re&connect"), this); - connect(disconnectAction, SIGNAL(triggered()), this, - SLOT(disconnect())); - connect(reconnectAction, SIGNAL(triggered()), this, - SLOT(connectB())); - tray_menu->addAction(disconnectAction); - tray_menu->addAction(reconnectAction); - tray_menu->addSeparator(); - - eventAction = new QAction(tr("&Event History"), this); - scanAction = new QAction(tr("Scan &Results"), this); - statAction = new QAction(tr("S&tatus"), this); - connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory())); - connect(scanAction, SIGNAL(triggered()), this, SLOT(scan())); - connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus())); - tray_menu->addAction(eventAction); - tray_menu->addAction(scanAction); - tray_menu->addAction(statAction); - tray_menu->addSeparator(); - - showAction = new QAction(tr("&Show Window"), this); - hideAction = new QAction(tr("&Hide Window"), this); - quitAction = new QAction(tr("&Quit"), this); - connect(showAction, SIGNAL(triggered()), this, SLOT(show())); - connect(hideAction, SIGNAL(triggered()), this, SLOT(hide())); - connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); - tray_menu->addAction(showAction); - tray_menu->addAction(hideAction); - tray_menu->addSeparator(); - tray_menu->addAction(quitAction); - - tray_icon->setContextMenu(tray_menu); - - tray_icon->show(); - - if (!trayOnly) - show(); - inTray = trayOnly; -} - - -void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec, - const QString & msg) -{ - if (!QSystemTrayIcon::supportsMessages()) - return; - - if (isVisible() || !tray_icon || !tray_icon->isVisible() || quietMode) - return; - - tray_icon->showMessage(qAppName(), msg, type, sec * 1000); -} - - -void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how) - { - switch (how) { - /* use close() here instead of hide() and allow the - * custom closeEvent handler take care of children */ - case QSystemTrayIcon::Trigger: - ackTrayIcon = true; - if (isVisible()) { - close(); - inTray = true; - } else { - show(); - inTray = false; - } - break; - case QSystemTrayIcon::MiddleClick: - showTrayStatus(); - break; - default: - break; - } -} - - -void WpaGui::showTrayStatus() -{ - char buf[2048]; - size_t len; - - len = sizeof(buf) - 1; - if (ctrlRequest("STATUS", buf, &len) < 0) - return; - buf[len] = '\0'; - - QString msg, status(buf); - - QStringList lines = status.split(QRegExp("\\n")); - for (QStringList::Iterator it = lines.begin(); - it != lines.end(); it++) { - int pos = (*it).indexOf('=') + 1; - if (pos < 1) - continue; - - if ((*it).startsWith("bssid=")) - msg.append("BSSID:\t" + (*it).mid(pos) + "\n"); - else if ((*it).startsWith("ssid=")) - msg.append("SSID: \t" + (*it).mid(pos) + "\n"); - else if ((*it).startsWith("pairwise_cipher=")) - msg.append("PAIR: \t" + (*it).mid(pos) + "\n"); - else if ((*it).startsWith("group_cipher=")) - msg.append("GROUP:\t" + (*it).mid(pos) + "\n"); - else if ((*it).startsWith("key_mgmt=")) - msg.append("AUTH: \t" + (*it).mid(pos) + "\n"); - else if ((*it).startsWith("wpa_state=")) - msg.append("STATE:\t" + (*it).mid(pos) + "\n"); - else if ((*it).startsWith("ip_address=")) - msg.append("IP: \t" + (*it).mid(pos) + "\n"); - else if ((*it).startsWith("Supplicant PAE state=")) - msg.append("PAE: \t" + (*it).mid(pos) + "\n"); - else if ((*it).startsWith("EAP state=")) - msg.append("EAP: \t" + (*it).mid(pos) + "\n"); - } - - if (!msg.isEmpty()) - showTrayMessage(QSystemTrayIcon::Information, 10, msg); -} - - -void WpaGui::updateTrayToolTip(const QString &msg) -{ - if (tray_icon) - tray_icon->setToolTip(msg); -} - - -void WpaGui::updateTrayIcon(TrayIconType type) -{ - if (!tray_icon || currentIconType == type) - return; - - QIcon fallback_icon; - QStringList names; - - if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) - fallback_icon = QIcon(":/icons/wpa_gui.svg"); - else - fallback_icon = QIcon(":/icons/wpa_gui.png"); - - switch (type) { - case TrayIconOffline: - names << "network-wireless-offline-symbolic" - << "network-wireless-offline" - << "network-wireless-signal-none-symbolic" - << "network-wireless-signal-none"; - break; - case TrayIconAcquiring: - names << "network-wireless-acquiring-symbolic" - << "network-wireless-acquiring"; - break; - case TrayIconConnected: - names << "network-wireless-connected-symbolic" - << "network-wireless-connected"; - break; - case TrayIconSignalNone: - names << "network-wireless-signal-none-symbolic" - << "network-wireless-signal-none"; - break; - case TrayIconSignalWeak: - names << "network-wireless-signal-weak-symbolic" - << "network-wireless-signal-weak"; - break; - case TrayIconSignalOk: - names << "network-wireless-signal-ok-symbolic" - << "network-wireless-signal-ok"; - break; - case TrayIconSignalGood: - names << "network-wireless-signal-good-symbolic" - << "network-wireless-signal-good"; - break; - case TrayIconSignalExcellent: - names << "network-wireless-signal-excellent-symbolic" - << "network-wireless-signal-excellent"; - break; - } - - currentIconType = type; - tray_icon->setIcon(loadThemedIcon(names, fallback_icon)); -} - - -QIcon WpaGui::loadThemedIcon(const QStringList &names, - const QIcon &fallback) -{ - QIcon icon; - - for (QStringList::ConstIterator it = names.begin(); - it != names.end(); it++) { - icon = QIcon::fromTheme(*it); - if (!icon.isNull()) - return icon; - } - - return fallback; -} - - -void WpaGui::closeEvent(QCloseEvent *event) -{ - if (eh) { - eh->close(); - delete eh; - eh = NULL; - } - - if (scanres) { - scanres->close(); - delete scanres; - scanres = NULL; - } - - if (peers) { - peers->close(); - delete peers; - peers = NULL; - } - - if (udr) { - udr->close(); - delete udr; - udr = NULL; - } - - if (tray_icon && !ackTrayIcon) { - /* give user a visual hint that the tray icon exists */ - if (QSystemTrayIcon::supportsMessages()) { - hide(); - showTrayMessage(QSystemTrayIcon::Information, 3, - qAppName() + - tr(" will keep running in " - "the system tray.")); - } else { - QMessageBox::information(this, qAppName() + - tr(" systray"), - tr("The program will keep " - "running in the system " - "tray.")); - } - ackTrayIcon = true; - } - - event->accept(); -} - - -void WpaGui::wpsDialog() -{ - wpaguiTab->setCurrentWidget(wpsTab); -} - - -void WpaGui::peersDialog() -{ - if (peers) { - peers->close(); - delete peers; - } - - peers = new Peers(); - if (peers == NULL) - return; - peers->setWpaGui(this); - peers->show(); - peers->exec(); -} - - -void WpaGui::tabChanged(int index) -{ - if (index != 2) - return; - - if (wpsRunning) - return; - - wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); - if (bssFromScan.isEmpty()) - wpsApPinButton->setEnabled(false); -} - - -void WpaGui::wpsPbc() -{ - char reply[20]; - size_t reply_len = sizeof(reply); - - if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0) - return; - - wpsPinEdit->setEnabled(false); - if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) { - wpsInstructions->setText(tr("Press the push button on the AP to " - "start the PBC mode.")); - } else { - wpsInstructions->setText(tr("If you have not yet done so, press " - "the push button on the AP to start " - "the PBC mode.")); - } - wpsStatusText->setText(tr("Waiting for Registrar")); - wpsRunning = true; -} - - -void WpaGui::wpsGeneratePin() -{ - char reply[20]; - size_t reply_len = sizeof(reply) - 1; - - if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0) - return; - - reply[reply_len] = '\0'; - - wpsPinEdit->setText(reply); - wpsPinEdit->setEnabled(true); - wpsInstructions->setText(tr("Enter the generated PIN into the Registrar " - "(either the internal one in the AP or an " - "external one).")); - wpsStatusText->setText(tr("Waiting for Registrar")); - wpsRunning = true; -} - - -void WpaGui::setBssFromScan(const QString &bssid) -{ - bssFromScan = bssid; - wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); - wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8); - wpsStatusText->setText(tr("WPS AP selected from scan results")); - wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., " - "from a label in the device, enter the eight " - "digit AP PIN and click Use AP PIN button.")); -} - - -void WpaGui::wpsApPinChanged(const QString &text) -{ - wpsApPinButton->setEnabled(text.length() == 8); -} - - -void WpaGui::wpsApPin() -{ - char reply[20]; - size_t reply_len = sizeof(reply); - - QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text()); - if (ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len) < 0) - return; - - wpsStatusText->setText(tr("Waiting for AP/Enrollee")); - wpsRunning = true; -} - - -void WpaGui::stopWpsRun(bool success) -{ - if (wpsRunning) - wpsStatusText->setText(success ? tr("Connected to the network") : - tr("Stopped")); - else - wpsStatusText->setText(""); - wpsPinEdit->setEnabled(false); - wpsInstructions->setText(""); - wpsRunning = false; - bssFromScan = ""; - wpsApPinEdit->setEnabled(false); - wpsApPinButton->setEnabled(false); -} - - -#ifdef CONFIG_NATIVE_WINDOWS - -#ifndef WPASVC_NAME -#define WPASVC_NAME TEXT("wpasvc") -#endif - -class ErrorMsg : public QMessageBox { -public: - ErrorMsg(QWidget *parent, DWORD last_err = GetLastError()); - void showMsg(QString msg); -private: - DWORD err; -}; - -ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) : - QMessageBox(parent), err(last_err) -{ - setWindowTitle(tr("wpa_gui error")); - setIcon(QMessageBox::Warning); -} - -void ErrorMsg::showMsg(QString msg) -{ - LPTSTR buf; - - setText(msg); - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM, - NULL, err, 0, (LPTSTR) (void *) &buf, - 0, NULL) > 0) { - QString msg = QString::fromWCharArray(buf); - setInformativeText(QString("[%1] %2").arg(err).arg(msg)); - LocalFree(buf); - } else { - setInformativeText(QString("[%1]").arg(err)); - } - - exec(); -} - - -void WpaGui::startService() -{ - SC_HANDLE svc, scm; - - scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (!scm) { - ErrorMsg(this).showMsg(tr("OpenSCManager failed")); - return; - } - - svc = OpenService(scm, WPASVC_NAME, SERVICE_START); - if (!svc) { - ErrorMsg(this).showMsg(tr("OpenService failed")); - CloseServiceHandle(scm); - return; - } - - if (!StartService(svc, 0, NULL)) { - ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant " - "service")); - } - - CloseServiceHandle(svc); - CloseServiceHandle(scm); -} - - -void WpaGui::stopService() -{ - SC_HANDLE svc, scm; - SERVICE_STATUS status; - - scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (!scm) { - ErrorMsg(this).showMsg(tr("OpenSCManager failed")); - return; - } - - svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP); - if (!svc) { - ErrorMsg(this).showMsg(tr("OpenService failed")); - CloseServiceHandle(scm); - return; - } - - if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) { - ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant " - "service")); - } - - CloseServiceHandle(svc); - CloseServiceHandle(scm); -} - - -bool WpaGui::serviceRunning() -{ - SC_HANDLE svc, scm; - SERVICE_STATUS status; - bool running = false; - - scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (!scm) { - debug("OpenSCManager failed: %d", (int) GetLastError()); - return false; - } - - svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS); - if (!svc) { - debug("OpenService failed: %d", (int) GetLastError()); - CloseServiceHandle(scm); - return false; - } - - if (QueryServiceStatus(svc, &status)) { - if (status.dwCurrentState != SERVICE_STOPPED) - running = true; - } - - CloseServiceHandle(svc); - CloseServiceHandle(scm); - - return running; -} - -#endif /* CONFIG_NATIVE_WINDOWS */ - - -void WpaGui::addInterface() -{ - if (add_iface) { - add_iface->close(); - delete add_iface; - } - add_iface = new AddInterface(this, this); - add_iface->show(); - add_iface->exec(); -} - - -#ifndef QT_NO_SESSIONMANAGER -void WpaGui::saveState() -{ - QSettings settings("wpa_supplicant", "wpa_gui"); - settings.beginGroup("state"); - settings.setValue("session_id", app->sessionId()); - settings.setValue("in_tray", inTray); - settings.endGroup(); -} -#endif +/* + * wpa_gui - WpaGui class + * Copyright (c) 2005-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifdef CONFIG_NATIVE_WINDOWS +#include +#endif /* CONFIG_NATIVE_WINDOWS */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wpagui.h" +#include "dirent.h" +#include "common/wpa_ctrl.h" +#include "userdatarequest.h" +#include "networkconfig.h" + + +#ifndef QT_NO_DEBUG +#define debug(M, ...) qDebug("DEBUG %d: " M, __LINE__, ##__VA_ARGS__) +#else +#define debug(M, ...) do {} while (0) +#endif + + +WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, + Qt::WindowFlags) + : QMainWindow(parent), app(_app) +{ + setupUi(this); + this->setWindowFlags(Qt::Dialog); + +#ifdef CONFIG_NATIVE_WINDOWS + fileStopServiceAction = new QAction(this); + fileStopServiceAction->setObjectName("Stop Service"); + fileStopServiceAction->setIconText(tr("Stop Service")); + fileMenu->insertAction(actionWPS, fileStopServiceAction); + + fileStartServiceAction = new QAction(this); + fileStartServiceAction->setObjectName("Start Service"); + fileStartServiceAction->setIconText(tr("Start Service")); + fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction); + + connect(fileStartServiceAction, SIGNAL(triggered()), this, + SLOT(startService())); + connect(fileStopServiceAction, SIGNAL(triggered()), this, + SLOT(stopService())); + + addInterfaceAction = new QAction(this); + addInterfaceAction->setIconText(tr("Add Interface")); + fileMenu->insertAction(fileStartServiceAction, addInterfaceAction); + + connect(addInterfaceAction, SIGNAL(triggered()), this, + SLOT(addInterface())); +#endif /* CONFIG_NATIVE_WINDOWS */ + + (void) statusBar(); + + /* + * Disable WPS tab by default; it will be enabled if wpa_supplicant is + * built with WPS support. + */ + wpsTab->setEnabled(false); + wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false); + + connect(fileEventHistoryAction, SIGNAL(triggered()), this, + SLOT(eventHistory())); + connect(fileSaveConfigAction, SIGNAL(triggered()), this, + SLOT(saveConfig())); + connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog())); + connect(actionPeers, SIGNAL(triggered()), this, SLOT(peersDialog())); + connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + connect(networkAddAction, SIGNAL(triggered()), this, + SLOT(addNetwork())); + connect(networkEditAction, SIGNAL(triggered()), this, + SLOT(editSelectedNetwork())); + connect(networkRemoveAction, SIGNAL(triggered()), this, + SLOT(removeSelectedNetwork())); + connect(networkEnableAllAction, SIGNAL(triggered()), this, + SLOT(enableAllNetworks())); + connect(networkDisableAllAction, SIGNAL(triggered()), this, + SLOT(disableAllNetworks())); + connect(networkRemoveAllAction, SIGNAL(triggered()), this, + SLOT(removeAllNetworks())); + connect(helpIndexAction, SIGNAL(triggered()), this, SLOT(helpIndex())); + connect(helpContentsAction, SIGNAL(triggered()), this, + SLOT(helpContents())); + connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(helpAbout())); + connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect())); + connect(scanButton, SIGNAL(clicked()), this, SLOT(scan())); + connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB())); + connect(adapterSelect, SIGNAL(activated(const QString&)), this, + SLOT(selectAdapter(const QString&))); + connect(networkSelect, SIGNAL(activated(const QString&)), this, + SLOT(selectNetwork(const QString&))); + connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork())); + connect(editNetworkButton, SIGNAL(clicked()), this, + SLOT(editListedNetwork())); + connect(removeNetworkButton, SIGNAL(clicked()), this, + SLOT(removeListedNetwork())); + connect(networkList, SIGNAL(itemSelectionChanged()), this, + SLOT(updateNetworkDisabledStatus())); + connect(enableRadioButton, SIGNAL(toggled(bool)), this, + SLOT(enableListedNetwork(bool))); + connect(disableRadioButton, SIGNAL(toggled(bool)), this, + SLOT(disableListedNetwork(bool))); + connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan())); + connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)), + this, SLOT(editListedNetwork())); + connect(wpaguiTab, SIGNAL(currentChanged(int)), this, + SLOT(tabChanged(int))); + connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc())); + connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin())); + connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this, + SLOT(wpsApPinChanged(const QString &))); + connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin())); + + eh = NULL; + scanres = NULL; + peers = NULL; + add_iface = NULL; + udr = NULL; + tray_icon = NULL; + startInTray = false; + quietMode = false; + ctrl_iface = NULL; + ctrl_conn = NULL; + monitor_conn = NULL; + msgNotifier = NULL; + ctrl_iface_dir = strdup("/var/run/wpa_supplicant"); + signalMeterInterval = 0; + + parse_argv(); + +#ifndef QT_NO_SESSIONMANAGER + if (app->isSessionRestored()) { + QSettings settings("wpa_supplicant", "wpa_gui"); + settings.beginGroup("state"); + if (app->sessionId().compare(settings.value("session_id"). + toString()) == 0) + startInTray = settings.value("in_tray").toBool(); + settings.endGroup(); + } +#endif + + if (QSystemTrayIcon::isSystemTrayAvailable()) + createTrayIcon(startInTray); + else + show(); + + connectedToService = false; + textStatus->setText(tr("connecting to wpa_supplicant")); + timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), SLOT(ping())); + timer->setSingleShot(false); + timer->start(1000); + + signalMeterTimer = new QTimer(this); + signalMeterTimer->setInterval(signalMeterInterval); + connect(signalMeterTimer, SIGNAL(timeout()), SLOT(signalMeterUpdate())); + + if (openCtrlConnection(ctrl_iface) < 0) { + debug("Failed to open control connection to " + "wpa_supplicant."); + } + + updateStatus(); + networkMayHaveChanged = true; + updateNetworks(); +} + + +WpaGui::~WpaGui() +{ + delete msgNotifier; + + if (monitor_conn) { + wpa_ctrl_detach(monitor_conn); + wpa_ctrl_close(monitor_conn); + monitor_conn = NULL; + } + if (ctrl_conn) { + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; + } + + if (eh) { + eh->close(); + delete eh; + eh = NULL; + } + + if (scanres) { + scanres->close(); + delete scanres; + scanres = NULL; + } + + if (peers) { + peers->close(); + delete peers; + peers = NULL; + } + + if (add_iface) { + add_iface->close(); + delete add_iface; + add_iface = NULL; + } + + if (udr) { + udr->close(); + delete udr; + udr = NULL; + } + + free(ctrl_iface); + ctrl_iface = NULL; + + free(ctrl_iface_dir); + ctrl_iface_dir = NULL; +} + + +void WpaGui::languageChange() +{ + retranslateUi(this); +} + + +void WpaGui::parse_argv() +{ + int c; + WpaGuiApp *app = qobject_cast(qApp); + for (;;) { + c = getopt(app->argc, app->argv, "i:m:p:tq"); + if (c < 0) + break; + switch (c) { + case 'i': + free(ctrl_iface); + ctrl_iface = strdup(optarg); + break; + case 'm': + signalMeterInterval = atoi(optarg) * 1000; + break; + case 'p': + free(ctrl_iface_dir); + ctrl_iface_dir = strdup(optarg); + break; + case 't': + startInTray = true; + break; + case 'q': + quietMode = true; + break; + } + } +} + + +int WpaGui::openCtrlConnection(const char *ifname) +{ + char *cfile; + int flen; + char buf[2048], *pos, *pos2; + size_t len; + + if (ifname) { + if (ifname != ctrl_iface) { + free(ctrl_iface); + ctrl_iface = strdup(ifname); + } + } else { +#ifdef CONFIG_CTRL_IFACE_UDP + free(ctrl_iface); + ctrl_iface = strdup("udp"); +#endif /* CONFIG_CTRL_IFACE_UDP */ +#ifdef CONFIG_CTRL_IFACE_UNIX + struct dirent *dent; + DIR *dir = opendir(ctrl_iface_dir); + free(ctrl_iface); + ctrl_iface = NULL; + if (dir) { + while ((dent = readdir(dir))) { +#ifdef _DIRENT_HAVE_D_TYPE + /* Skip the file if it is not a socket. + * Also accept DT_UNKNOWN (0) in case + * the C library or underlying file + * system does not support d_type. */ + if (dent->d_type != DT_SOCK && + dent->d_type != DT_UNKNOWN) + continue; +#endif /* _DIRENT_HAVE_D_TYPE */ + + if (strcmp(dent->d_name, ".") == 0 || + strcmp(dent->d_name, "..") == 0) + continue; + debug("Selected interface '%s'", + dent->d_name); + ctrl_iface = strdup(dent->d_name); + break; + } + closedir(dir); + } +#endif /* CONFIG_CTRL_IFACE_UNIX */ +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + struct wpa_ctrl *ctrl; + int ret; + + free(ctrl_iface); + ctrl_iface = NULL; + + ctrl = wpa_ctrl_open(NULL); + if (ctrl) { + len = sizeof(buf) - 1; + ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, + &len, NULL); + if (ret >= 0) { + connectedToService = true; + buf[len] = '\0'; + pos = strchr(buf, '\n'); + if (pos) + *pos = '\0'; + ctrl_iface = strdup(buf); + } + wpa_ctrl_close(ctrl); + } +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + } + + if (ctrl_iface == NULL) { +#ifdef CONFIG_NATIVE_WINDOWS + static bool first = true; + if (first && !serviceRunning()) { + first = false; + if (QMessageBox::warning( + this, qAppName(), + tr("wpa_supplicant service is not " + "running.\n" + "Do you want to start it?"), + QMessageBox::Yes | QMessageBox::No) == + QMessageBox::Yes) + startService(); + } +#endif /* CONFIG_NATIVE_WINDOWS */ + return -1; + } + +#ifdef CONFIG_CTRL_IFACE_UNIX + flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2; + cfile = (char *) malloc(flen); + if (cfile == NULL) + return -1; + snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface); +#else /* CONFIG_CTRL_IFACE_UNIX */ + flen = strlen(ctrl_iface) + 1; + cfile = (char *) malloc(flen); + if (cfile == NULL) + return -1; + snprintf(cfile, flen, "%s", ctrl_iface); +#endif /* CONFIG_CTRL_IFACE_UNIX */ + + if (ctrl_conn) { + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; + } + + if (monitor_conn) { + delete msgNotifier; + msgNotifier = NULL; + wpa_ctrl_detach(monitor_conn); + wpa_ctrl_close(monitor_conn); + monitor_conn = NULL; + } + + debug("Trying to connect to '%s'", cfile); + ctrl_conn = wpa_ctrl_open(cfile); + if (ctrl_conn == NULL) { + free(cfile); + return -1; + } + monitor_conn = wpa_ctrl_open(cfile); + free(cfile); + if (monitor_conn == NULL) { + wpa_ctrl_close(ctrl_conn); + return -1; + } + if (wpa_ctrl_attach(monitor_conn)) { + debug("Failed to attach to wpa_supplicant"); + wpa_ctrl_close(monitor_conn); + monitor_conn = NULL; + wpa_ctrl_close(ctrl_conn); + ctrl_conn = NULL; + return -1; + } + +#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP) + msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn), + QSocketNotifier::Read, this); + connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs())); +#endif + + adapterSelect->clear(); + adapterSelect->addItem(ctrl_iface); + adapterSelect->setCurrentIndex(0); + + len = sizeof(buf) - 1; + if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= + 0) { + buf[len] = '\0'; + pos = buf; + while (*pos) { + pos2 = strchr(pos, '\n'); + if (pos2) + *pos2 = '\0'; + if (strcmp(pos, ctrl_iface) != 0) + adapterSelect->addItem(pos); + if (pos2) + pos = pos2 + 1; + else + break; + } + } + + len = sizeof(buf) - 1; + if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len, + NULL) >= 0) { + buf[len] = '\0'; + + QString res(buf); + QStringList types = res.split(QChar(' ')); + bool wps = types.contains("WSC"); + actionWPS->setEnabled(wps); + wpsTab->setEnabled(wps); + wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps); + } + + return 0; +} + + +int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen) +{ + int ret; + + if (ctrl_conn == NULL) + return -3; + ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen, NULL); + if (ret == -2) + debug("'%s' command timed out.", cmd); + else if (ret < 0) + debug("'%s' command failed.", cmd); + + return ret; +} + + +QString WpaGui::wpaStateTranslate(char *state) +{ + if (!strcmp(state, "DISCONNECTED")) + return tr("Disconnected"); + else if (!strcmp(state, "INACTIVE")) + return tr("Inactive"); + else if (!strcmp(state, "SCANNING")) + return tr("Scanning"); + else if (!strcmp(state, "AUTHENTICATING")) + return tr("Authenticating"); + else if (!strcmp(state, "ASSOCIATING")) + return tr("Associating"); + else if (!strcmp(state, "ASSOCIATED")) + return tr("Associated"); + else if (!strcmp(state, "4WAY_HANDSHAKE")) + return tr("4-Way Handshake"); + else if (!strcmp(state, "GROUP_HANDSHAKE")) + return tr("Group Handshake"); + else if (!strcmp(state, "COMPLETED")) + return tr("Completed"); + else + return tr("Unknown"); +} + + +void WpaGui::updateStatus() +{ + char buf[2048], *start, *end, *pos; + size_t len; + + pingsToStatusUpdate = 10; + + len = sizeof(buf) - 1; + if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) { + textStatus->setText(tr("Could not get status from " + "wpa_supplicant")); + textAuthentication->clear(); + textEncryption->clear(); + textSsid->clear(); + textBssid->clear(); + textIpAddress->clear(); + updateTrayToolTip(tr("no status information")); + updateTrayIcon(TrayIconOffline); + signalMeterTimer->stop(); + +#ifdef CONFIG_NATIVE_WINDOWS + static bool first = true; + if (first && connectedToService && + (ctrl_iface == NULL || *ctrl_iface == '\0')) { + first = false; + if (QMessageBox::information( + this, qAppName(), + tr("No network interfaces in use.\n" + "Would you like to add one?"), + QMessageBox::Yes | QMessageBox::No) == + QMessageBox::Yes) + addInterface(); + } +#endif /* CONFIG_NATIVE_WINDOWS */ + return; + } + + buf[len] = '\0'; + + bool auth_updated = false, ssid_updated = false; + bool bssid_updated = false, ipaddr_updated = false; + bool status_updated = false; + char *pairwise_cipher = NULL, *group_cipher = NULL; + char *mode = NULL; + + start = buf; + while (*start) { + bool last = false; + end = strchr(start, '\n'); + if (end == NULL) { + last = true; + end = start; + while (end[0] && end[1]) + end++; + } + *end = '\0'; + + pos = strchr(start, '='); + if (pos) { + *pos++ = '\0'; + if (strcmp(start, "bssid") == 0) { + bssid_updated = true; + textBssid->setText(pos); + } else if (strcmp(start, "ssid") == 0) { + ssid_updated = true; + textSsid->setText(pos); + updateTrayToolTip(pos + tr(" (associated)")); + if (!signalMeterInterval) { + /* if signal meter is not enabled show + * full signal strength */ + updateTrayIcon(TrayIconSignalExcellent); + } + } else if (strcmp(start, "ip_address") == 0) { + ipaddr_updated = true; + textIpAddress->setText(pos); + } else if (strcmp(start, "wpa_state") == 0) { + status_updated = true; + textStatus->setText(wpaStateTranslate(pos)); + } else if (strcmp(start, "key_mgmt") == 0) { + auth_updated = true; + textAuthentication->setText(pos); + /* TODO: could add EAP status to this */ + } else if (strcmp(start, "pairwise_cipher") == 0) { + pairwise_cipher = pos; + } else if (strcmp(start, "group_cipher") == 0) { + group_cipher = pos; + } else if (strcmp(start, "mode") == 0) { + mode = pos; + } + } + + if (last) + break; + start = end + 1; + } + if (status_updated && mode) + textStatus->setText(textStatus->text() + " (" + mode + ")"); + + if (pairwise_cipher || group_cipher) { + QString encr; + if (pairwise_cipher && group_cipher && + strcmp(pairwise_cipher, group_cipher) != 0) { + encr.append(pairwise_cipher); + encr.append(" + "); + encr.append(group_cipher); + } else if (pairwise_cipher) { + encr.append(pairwise_cipher); + } else { + encr.append(group_cipher); + encr.append(" [group key only]"); + } + textEncryption->setText(encr); + } else + textEncryption->clear(); + + if (signalMeterInterval) { + /* + * Handle signal meter service. When network is not associated, + * deactivate timer, otherwise keep it going. Tray icon has to + * be initialized here, because of the initial delay of the + * timer. + */ + if (ssid_updated) { + if (!signalMeterTimer->isActive()) { + updateTrayIcon(TrayIconConnected); + signalMeterTimer->start(); + } + } else { + signalMeterTimer->stop(); + } + } + + if (!status_updated) + textStatus->clear(); + if (!auth_updated) + textAuthentication->clear(); + if (!ssid_updated) { + textSsid->clear(); + updateTrayToolTip(tr("(not-associated)")); + updateTrayIcon(TrayIconOffline); + } + if (!bssid_updated) + textBssid->clear(); + if (!ipaddr_updated) + textIpAddress->clear(); +} + + +void WpaGui::updateNetworks() +{ + char buf[4096], *start, *end, *id, *ssid, *bssid, *flags; + size_t len; + int first_active = -1; + int was_selected = -1; + bool current = false; + + if (!networkMayHaveChanged) + return; + + if (networkList->currentRow() >= 0) + was_selected = networkList->currentRow(); + + networkSelect->clear(); + networkList->clear(); + + if (ctrl_conn == NULL) + return; + + len = sizeof(buf) - 1; + if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0) + return; + + buf[len] = '\0'; + start = strchr(buf, '\n'); + if (start == NULL) + return; + start++; + + while (*start) { + bool last = false; + end = strchr(start, '\n'); + if (end == NULL) { + last = true; + end = start; + while (end[0] && end[1]) + end++; + } + *end = '\0'; + + id = start; + ssid = strchr(id, '\t'); + if (ssid == NULL) + break; + *ssid++ = '\0'; + bssid = strchr(ssid, '\t'); + if (bssid == NULL) + break; + *bssid++ = '\0'; + flags = strchr(bssid, '\t'); + if (flags == NULL) + break; + *flags++ = '\0'; + + if (strstr(flags, "[DISABLED][P2P-PERSISTENT]")) { + if (last) + break; + start = end + 1; + continue; + } + + QString network(id); + network.append(": "); + network.append(ssid); + networkSelect->addItem(network); + networkList->addItem(network); + + if (strstr(flags, "[CURRENT]")) { + networkSelect->setCurrentIndex(networkSelect->count() - + 1); + current = true; + } else if (first_active < 0 && + strstr(flags, "[DISABLED]") == NULL) + first_active = networkSelect->count() - 1; + + start = end + 1; + if (*start && strchr(start, '\n')) + continue; + + /* avoid race conditions */ + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + QString cmd("LIST_NETWORKS LAST_ID="); + cmd.append(id); + if (ctrlRequest(cmd.toLocal8Bit().constData(), buf, &len) < 0) + break; + + buf[len] = '\0'; + start = strchr(buf, '\n'); + if (!start) + break; + start++; + } + + if (networkSelect->count() > 1) + networkSelect->addItem(tr("Select any network")); + + if (!current && first_active >= 0) + networkSelect->setCurrentIndex(first_active); + + if (was_selected >= 0 && networkList->count() > 0) { + if (was_selected < networkList->count()) + networkList->setCurrentRow(was_selected); + else + networkList->setCurrentRow(networkList->count() - 1); + } + else + networkList->setCurrentRow(networkSelect->currentIndex()); + + networkMayHaveChanged = false; +} + + +void WpaGui::helpIndex() +{ + debug("helpIndex"); +} + + +void WpaGui::helpContents() +{ + debug("helpContents"); +} + + +void WpaGui::helpAbout() +{ + QMessageBox::about(this, "wpa_gui for wpa_supplicant", + "Copyright (c) 2003-2015,\n" + "Jouni Malinen \n" + "and contributors.\n" + "\n" + "This software may be distributed under\n" + "the terms of the BSD license.\n" + "See README for more details.\n" + "\n" + "This product includes software developed\n" + "by the OpenSSL Project for use in the\n" + "OpenSSL Toolkit (http://www.openssl.org/)\n"); +} + + +void WpaGui::disconnect() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + ctrlRequest("DISCONNECT", reply, &reply_len); + stopWpsRun(false); +} + + +void WpaGui::scan() +{ + if (scanres) { + scanres->close(); + delete scanres; + } + + scanres = new ScanResults(); + if (scanres == NULL) + return; + scanres->setWpaGui(this); + scanres->show(); + scanres->exec(); +} + + +void WpaGui::eventHistory() +{ + if (eh) { + eh->close(); + delete eh; + } + + eh = new EventHistory(); + if (eh == NULL) + return; + eh->addEvents(msgs); + eh->show(); + eh->exec(); +} + + +void WpaGui::ping() +{ + char buf[10]; + size_t len; + +#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE + /* + * QSocketNotifier cannot be used with Windows named pipes, so use a + * timer to check for received messages for now. This could be + * optimized be doing something specific to named pipes or Windows + * events, but it is not clear what would be the best way of doing that + * in Qt. + */ + receiveMsgs(); +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ + + if (scanres && !scanres->isVisible()) { + delete scanres; + scanres = NULL; + } + + if (eh && !eh->isVisible()) { + delete eh; + eh = NULL; + } + + if (udr && !udr->isVisible()) { + delete udr; + udr = NULL; + } + + len = sizeof(buf) - 1; + if (ctrlRequest("PING", buf, &len) < 0) { + debug("PING failed - trying to reconnect"); + if (openCtrlConnection(ctrl_iface) >= 0) { + debug("Reconnected successfully"); + pingsToStatusUpdate = 0; + } + } + + pingsToStatusUpdate--; + if (pingsToStatusUpdate <= 0) { + updateStatus(); + updateNetworks(); + } + +#ifndef CONFIG_CTRL_IFACE_NAMED_PIPE + /* Use less frequent pings and status updates when the main window is + * hidden (running in taskbar). */ + int interval = isHidden() ? 5000 : 1000; + if (timer->interval() != interval) + timer->setInterval(interval); +#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */ +} + + +void WpaGui::signalMeterUpdate() +{ + char reply[128]; + size_t reply_len = sizeof(reply); + char *rssi; + int rssi_value; + + ctrlRequest("SIGNAL_POLL", reply, &reply_len); + + /* In order to eliminate signal strength fluctuations, try + * to obtain averaged RSSI value in the first place. */ + if ((rssi = strstr(reply, "AVG_RSSI=")) != NULL) + rssi_value = atoi(&rssi[sizeof("AVG_RSSI")]); + else if ((rssi = strstr(reply, "RSSI=")) != NULL) + rssi_value = atoi(&rssi[sizeof("RSSI")]); + else { + debug("Failed to get RSSI value"); + updateTrayIcon(TrayIconSignalNone); + return; + } + + debug("RSSI value: %d", rssi_value); + + /* + * NOTE: The code below assumes, that the unit of the value returned + * by the SIGNAL POLL request is dBm. It might not be true for all + * wpa_supplicant drivers. + */ + + /* + * Calibration is based on "various Internet sources". Nonetheless, + * it seems to be compatible with the Windows 8.1 strength meter - + * tested on Intel Centrino Advanced-N 6235. + */ + if (rssi_value >= -60) + updateTrayIcon(TrayIconSignalExcellent); + else if (rssi_value >= -68) + updateTrayIcon(TrayIconSignalGood); + else if (rssi_value >= -76) + updateTrayIcon(TrayIconSignalOk); + else if (rssi_value >= -84) + updateTrayIcon(TrayIconSignalWeak); + else + updateTrayIcon(TrayIconSignalNone); +} + + +static int str_match(const char *a, const char *b) +{ + return strncmp(a, b, strlen(b)) == 0; +} + + +void WpaGui::processMsg(char *msg) +{ + char *pos = msg, *pos2; + int priority = 2; + + if (*pos == '<') { + /* skip priority */ + pos++; + priority = atoi(pos); + pos = strchr(pos, '>'); + if (pos) + pos++; + else + pos = msg; + } + + WpaMsg wm(pos, priority); + if (eh) + eh->addEvent(wm); + if (peers) + peers->event_notify(wm); + msgs.append(wm); + while (msgs.count() > 100) + msgs.pop_front(); + + /* Update last message with truncated version of the event */ + if (strncmp(pos, "CTRL-", 5) == 0) { + pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' '); + if (pos2) + pos2++; + else + pos2 = pos; + } else + pos2 = pos; + QString lastmsg = pos2; + lastmsg.truncate(40); + textLastMessage->setText(lastmsg); + + pingsToStatusUpdate = 0; + networkMayHaveChanged = true; + + if (str_match(pos, WPA_CTRL_REQ)) + processCtrlReq(pos + strlen(WPA_CTRL_REQ)); + else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres) + scanres->updateResults(); + else if (str_match(pos, WPA_EVENT_DISCONNECTED)) + showTrayMessage(QSystemTrayIcon::Information, 3, + tr("Disconnected from network.")); + else if (str_match(pos, WPA_EVENT_CONNECTED)) { + showTrayMessage(QSystemTrayIcon::Information, 3, + tr("Connection to network established.")); + QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus())); + stopWpsRun(true); + } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) { + wpsStatusText->setText(tr("WPS AP in active PBC mode found")); + if (textStatus->text() == "INACTIVE" || + textStatus->text() == "DISCONNECTED") + wpaguiTab->setCurrentWidget(wpsTab); + wpsInstructions->setText(tr("Press the PBC button on the " + "screen to start registration")); + } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) { + wpsStatusText->setText(tr("WPS AP with recently selected " + "registrar")); + if (textStatus->text() == "INACTIVE" || + textStatus->text() == "DISCONNECTED") + wpaguiTab->setCurrentWidget(wpsTab); + } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_AUTH)) { + showTrayMessage(QSystemTrayIcon::Information, 3, + "Wi-Fi Protected Setup (WPS) AP\n" + "indicating this client is authorized."); + wpsStatusText->setText("WPS AP indicating this client is " + "authorized"); + if (textStatus->text() == "INACTIVE" || + textStatus->text() == "DISCONNECTED") + wpaguiTab->setCurrentWidget(wpsTab); + } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) { + wpsStatusText->setText(tr("WPS AP detected")); + } else if (str_match(pos, WPS_EVENT_OVERLAP)) { + wpsStatusText->setText(tr("PBC mode overlap detected")); + wpsInstructions->setText(tr("More than one AP is currently in " + "active WPS PBC mode. Wait couple " + "of minutes and try again")); + wpaguiTab->setCurrentWidget(wpsTab); + } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) { + wpsStatusText->setText(tr("Network configuration received")); + wpaguiTab->setCurrentWidget(wpsTab); + } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) { + if (strstr(pos, "(WSC)")) + wpsStatusText->setText(tr("Registration started")); + } else if (str_match(pos, WPS_EVENT_M2D)) { + wpsStatusText->setText(tr("Registrar does not yet know PIN")); + } else if (str_match(pos, WPS_EVENT_FAIL)) { + wpsStatusText->setText(tr("Registration failed")); + } else if (str_match(pos, WPS_EVENT_SUCCESS)) { + wpsStatusText->setText(tr("Registration succeeded")); + } +} + + +void WpaGui::processCtrlReq(const char *req) +{ + if (udr) { + udr->close(); + delete udr; + } + udr = new UserDataRequest(); + if (udr == NULL) + return; + if (udr->setParams(this, req) < 0) { + delete udr; + udr = NULL; + return; + } + udr->show(); + udr->exec(); +} + + +void WpaGui::receiveMsgs() +{ + char buf[256]; + size_t len; + + while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) { + len = sizeof(buf) - 1; + if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) { + buf[len] = '\0'; + processMsg(buf); + } + } +} + + +void WpaGui::connectB() +{ + char reply[10]; + size_t reply_len = sizeof(reply); + ctrlRequest("REASSOCIATE", reply, &reply_len); +} + + +void WpaGui::selectNetwork( const QString &sel ) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply); + + if (cmd.contains(QRegExp("^\\d+:"))) + cmd.truncate(cmd.indexOf(':')); + else + cmd = "any"; + cmd.prepend("SELECT_NETWORK "); + ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); + triggerUpdate(); + stopWpsRun(false); +} + + +void WpaGui::enableNetwork(const QString &sel) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply); + + if (cmd.contains(QRegExp("^\\d+:"))) + cmd.truncate(cmd.indexOf(':')); + else if (!cmd.startsWith("all")) { + debug("Invalid editNetwork '%s'", + cmd.toLocal8Bit().constData()); + return; + } + cmd.prepend("ENABLE_NETWORK "); + ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); + triggerUpdate(); +} + + +void WpaGui::disableNetwork(const QString &sel) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply); + + if (cmd.contains(QRegExp("^\\d+:"))) + cmd.truncate(cmd.indexOf(':')); + else if (!cmd.startsWith("all")) { + debug("Invalid editNetwork '%s'", + cmd.toLocal8Bit().constData()); + return; + } + cmd.prepend("DISABLE_NETWORK "); + ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); + triggerUpdate(); +} + + +void WpaGui::editNetwork(const QString &sel) +{ + QString cmd(sel); + int id = -1; + + if (cmd.contains(QRegExp("^\\d+:"))) { + cmd.truncate(cmd.indexOf(':')); + id = cmd.toInt(); + } + + NetworkConfig *nc = new NetworkConfig(); + if (nc == NULL) + return; + nc->setWpaGui(this); + + if (id >= 0) + nc->paramsFromConfig(id); + else + nc->newNetwork(); + + nc->show(); + nc->exec(); +} + + +void WpaGui::editSelectedNetwork() +{ + if (networkSelect->count() < 1) { + QMessageBox::information( + this, tr("No Networks"), + tr("There are no networks to edit.\n")); + return; + } + QString sel(networkSelect->currentText()); + editNetwork(sel); +} + + +void WpaGui::editListedNetwork() +{ + if (networkList->currentRow() < 0) { + QMessageBox::information(this, tr("Select A Network"), + tr("Select a network from the list to" + " edit it.\n")); + return; + } + QString sel(networkList->currentItem()->text()); + editNetwork(sel); +} + + +void WpaGui::triggerUpdate() +{ + updateStatus(); + networkMayHaveChanged = true; + updateNetworks(); +} + + +void WpaGui::addNetwork() +{ + NetworkConfig *nc = new NetworkConfig(); + if (nc == NULL) + return; + nc->setWpaGui(this); + nc->newNetwork(); + nc->show(); + nc->exec(); +} + + +void WpaGui::removeNetwork(const QString &sel) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply); + + if (cmd.contains(QRegExp("^\\d+:"))) + cmd.truncate(cmd.indexOf(':')); + else if (!cmd.startsWith("all")) { + debug("Invalid editNetwork '%s'", + cmd.toLocal8Bit().constData()); + return; + } + cmd.prepend("REMOVE_NETWORK "); + ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len); + triggerUpdate(); +} + + +void WpaGui::removeSelectedNetwork() +{ + if (networkSelect->count() < 1) { + QMessageBox::information(this, tr("No Networks"), + tr("There are no networks to remove." + "\n")); + return; + } + QString sel(networkSelect->currentText()); + removeNetwork(sel); +} + + +void WpaGui::removeListedNetwork() +{ + if (networkList->currentRow() < 0) { + QMessageBox::information(this, tr("Select A Network"), + tr("Select a network from the list " + "to remove it.\n")); + return; + } + QString sel(networkList->currentItem()->text()); + removeNetwork(sel); +} + + +void WpaGui::enableAllNetworks() +{ + QString sel("all"); + enableNetwork(sel); +} + + +void WpaGui::disableAllNetworks() +{ + QString sel("all"); + disableNetwork(sel); +} + + +void WpaGui::removeAllNetworks() +{ + QString sel("all"); + removeNetwork(sel); +} + + +int WpaGui::getNetworkDisabled(const QString &sel) +{ + QString cmd(sel); + char reply[10]; + size_t reply_len = sizeof(reply) - 1; + int pos = cmd.indexOf(':'); + if (pos < 0) { + debug("Invalid getNetworkDisabled '%s'", + cmd.toLocal8Bit().constData()); + return -1; + } + cmd.truncate(pos); + cmd.prepend("GET_NETWORK "); + cmd.append(" disabled"); + + if (ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len) >= 0 + && reply_len >= 1) { + reply[reply_len] = '\0'; + if (!str_match(reply, "FAIL")) + return atoi(reply); + } + + return -1; +} + + +void WpaGui::updateNetworkDisabledStatus() +{ + if (networkList->currentRow() < 0) + return; + + QString sel(networkList->currentItem()->text()); + + switch (getNetworkDisabled(sel)) { + case 0: + if (!enableRadioButton->isChecked()) + enableRadioButton->setChecked(true); + return; + case 1: + if (!disableRadioButton->isChecked()) + disableRadioButton->setChecked(true); + return; + } +} + + +void WpaGui::enableListedNetwork(bool enabled) +{ + if (networkList->currentRow() < 0 || !enabled) + return; + + QString sel(networkList->currentItem()->text()); + + if (getNetworkDisabled(sel) == 1) + enableNetwork(sel); +} + + +void WpaGui::disableListedNetwork(bool disabled) +{ + if (networkList->currentRow() < 0 || !disabled) + return; + + QString sel(networkList->currentItem()->text()); + + if (getNetworkDisabled(sel) == 0) + disableNetwork(sel); +} + + +void WpaGui::saveConfig() +{ + char buf[10]; + size_t len; + + len = sizeof(buf) - 1; + ctrlRequest("SAVE_CONFIG", buf, &len); + + buf[len] = '\0'; + + if (str_match(buf, "FAIL")) + QMessageBox::warning( + this, tr("Failed to save configuration"), + tr("The configuration could not be saved.\n" + "\n" + "The update_config=1 configuration option\n" + "must be used for configuration saving to\n" + "be permitted.\n")); + else + QMessageBox::information( + this, tr("Saved configuration"), + tr("The current configuration was saved." + "\n")); +} + + +void WpaGui::selectAdapter( const QString & sel ) +{ + if (openCtrlConnection(sel.toLocal8Bit().constData()) < 0) + debug("Failed to open control connection to " + "wpa_supplicant."); + updateStatus(); + updateNetworks(); +} + + +void WpaGui::createTrayIcon(bool trayOnly) +{ + QApplication::setQuitOnLastWindowClosed(false); + + tray_icon = new QSystemTrayIcon(this); + updateTrayIcon(TrayIconOffline); + + connect(tray_icon, + SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); + + ackTrayIcon = false; + + tray_menu = new QMenu(this); + + disconnectAction = new QAction(tr("&Disconnect"), this); + reconnectAction = new QAction(tr("Re&connect"), this); + connect(disconnectAction, SIGNAL(triggered()), this, + SLOT(disconnect())); + connect(reconnectAction, SIGNAL(triggered()), this, + SLOT(connectB())); + tray_menu->addAction(disconnectAction); + tray_menu->addAction(reconnectAction); + tray_menu->addSeparator(); + + eventAction = new QAction(tr("&Event History"), this); + scanAction = new QAction(tr("Scan &Results"), this); + statAction = new QAction(tr("S&tatus"), this); + connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory())); + connect(scanAction, SIGNAL(triggered()), this, SLOT(scan())); + connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus())); + tray_menu->addAction(eventAction); + tray_menu->addAction(scanAction); + tray_menu->addAction(statAction); + tray_menu->addSeparator(); + + showAction = new QAction(tr("&Show Window"), this); + hideAction = new QAction(tr("&Hide Window"), this); + quitAction = new QAction(tr("&Quit"), this); + connect(showAction, SIGNAL(triggered()), this, SLOT(show())); + connect(hideAction, SIGNAL(triggered()), this, SLOT(hide())); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + tray_menu->addAction(showAction); + tray_menu->addAction(hideAction); + tray_menu->addSeparator(); + tray_menu->addAction(quitAction); + + tray_icon->setContextMenu(tray_menu); + + tray_icon->show(); + + if (!trayOnly) + show(); + inTray = trayOnly; +} + + +void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec, + const QString & msg) +{ + if (!QSystemTrayIcon::supportsMessages()) + return; + + if (isVisible() || !tray_icon || !tray_icon->isVisible() || quietMode) + return; + + tray_icon->showMessage(qAppName(), msg, type, sec * 1000); +} + + +void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how) + { + switch (how) { + /* use close() here instead of hide() and allow the + * custom closeEvent handler take care of children */ + case QSystemTrayIcon::Trigger: + ackTrayIcon = true; + if (isVisible()) { + close(); + inTray = true; + } else { + show(); + inTray = false; + } + break; + case QSystemTrayIcon::MiddleClick: + showTrayStatus(); + break; + default: + break; + } +} + + +void WpaGui::showTrayStatus() +{ + char buf[2048]; + size_t len; + + len = sizeof(buf) - 1; + if (ctrlRequest("STATUS", buf, &len) < 0) + return; + buf[len] = '\0'; + + QString msg, status(buf); + + QStringList lines = status.split(QRegExp("\\n")); + for (QStringList::Iterator it = lines.begin(); + it != lines.end(); it++) { + int pos = (*it).indexOf('=') + 1; + if (pos < 1) + continue; + + if ((*it).startsWith("bssid=")) + msg.append("BSSID:\t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("ssid=")) + msg.append("SSID: \t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("pairwise_cipher=")) + msg.append("PAIR: \t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("group_cipher=")) + msg.append("GROUP:\t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("key_mgmt=")) + msg.append("AUTH: \t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("wpa_state=")) + msg.append("STATE:\t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("ip_address=")) + msg.append("IP: \t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("Supplicant PAE state=")) + msg.append("PAE: \t" + (*it).mid(pos) + "\n"); + else if ((*it).startsWith("EAP state=")) + msg.append("EAP: \t" + (*it).mid(pos) + "\n"); + } + + if (!msg.isEmpty()) + showTrayMessage(QSystemTrayIcon::Information, 10, msg); +} + + +void WpaGui::updateTrayToolTip(const QString &msg) +{ + if (tray_icon) + tray_icon->setToolTip(msg); +} + + +void WpaGui::updateTrayIcon(TrayIconType type) +{ + if (!tray_icon || currentIconType == type) + return; + + QIcon fallback_icon; + QStringList names; + + if (QImageReader::supportedImageFormats().contains(QByteArray("svg"))) + fallback_icon = QIcon(":/icons/wpa_gui.svg"); + else + fallback_icon = QIcon(":/icons/wpa_gui.png"); + + switch (type) { + case TrayIconOffline: + names << "network-wireless-offline-symbolic" + << "network-wireless-offline" + << "network-wireless-signal-none-symbolic" + << "network-wireless-signal-none"; + break; + case TrayIconAcquiring: + names << "network-wireless-acquiring-symbolic" + << "network-wireless-acquiring"; + break; + case TrayIconConnected: + names << "network-wireless-connected-symbolic" + << "network-wireless-connected"; + break; + case TrayIconSignalNone: + names << "network-wireless-signal-none-symbolic" + << "network-wireless-signal-none"; + break; + case TrayIconSignalWeak: + names << "network-wireless-signal-weak-symbolic" + << "network-wireless-signal-weak"; + break; + case TrayIconSignalOk: + names << "network-wireless-signal-ok-symbolic" + << "network-wireless-signal-ok"; + break; + case TrayIconSignalGood: + names << "network-wireless-signal-good-symbolic" + << "network-wireless-signal-good"; + break; + case TrayIconSignalExcellent: + names << "network-wireless-signal-excellent-symbolic" + << "network-wireless-signal-excellent"; + break; + } + + currentIconType = type; + tray_icon->setIcon(loadThemedIcon(names, fallback_icon)); +} + + +QIcon WpaGui::loadThemedIcon(const QStringList &names, + const QIcon &fallback) +{ + QIcon icon; + + for (QStringList::ConstIterator it = names.begin(); + it != names.end(); it++) { + icon = QIcon::fromTheme(*it); + if (!icon.isNull()) + return icon; + } + + return fallback; +} + + +void WpaGui::closeEvent(QCloseEvent *event) +{ + if (eh) { + eh->close(); + delete eh; + eh = NULL; + } + + if (scanres) { + scanres->close(); + delete scanres; + scanres = NULL; + } + + if (peers) { + peers->close(); + delete peers; + peers = NULL; + } + + if (udr) { + udr->close(); + delete udr; + udr = NULL; + } + + if (tray_icon && !ackTrayIcon) { + /* give user a visual hint that the tray icon exists */ + if (QSystemTrayIcon::supportsMessages()) { + hide(); + showTrayMessage(QSystemTrayIcon::Information, 3, + qAppName() + + tr(" will keep running in " + "the system tray.")); + } else { + QMessageBox::information(this, qAppName() + + tr(" systray"), + tr("The program will keep " + "running in the system " + "tray.")); + } + ackTrayIcon = true; + } + + event->accept(); +} + + +void WpaGui::wpsDialog() +{ + wpaguiTab->setCurrentWidget(wpsTab); +} + + +void WpaGui::peersDialog() +{ + if (peers) { + peers->close(); + delete peers; + } + + peers = new Peers(); + if (peers == NULL) + return; + peers->setWpaGui(this); + peers->show(); + peers->exec(); +} + + +void WpaGui::tabChanged(int index) +{ + if (index != 2) + return; + + if (wpsRunning) + return; + + wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); + if (bssFromScan.isEmpty()) + wpsApPinButton->setEnabled(false); +} + + +void WpaGui::wpsPbc() +{ + char reply[20]; + size_t reply_len = sizeof(reply); + + if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0) + return; + + wpsPinEdit->setEnabled(false); + if (wpsStatusText->text().compare(tr("WPS AP in active PBC mode found"))) { + wpsInstructions->setText(tr("Press the push button on the AP to " + "start the PBC mode.")); + } else { + wpsInstructions->setText(tr("If you have not yet done so, press " + "the push button on the AP to start " + "the PBC mode.")); + } + wpsStatusText->setText(tr("Waiting for Registrar")); + wpsRunning = true; +} + + +void WpaGui::wpsGeneratePin() +{ + char reply[20]; + size_t reply_len = sizeof(reply) - 1; + + if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0) + return; + + reply[reply_len] = '\0'; + + wpsPinEdit->setText(reply); + wpsPinEdit->setEnabled(true); + wpsInstructions->setText(tr("Enter the generated PIN into the Registrar " + "(either the internal one in the AP or an " + "external one).")); + wpsStatusText->setText(tr("Waiting for Registrar")); + wpsRunning = true; +} + + +void WpaGui::setBssFromScan(const QString &bssid) +{ + bssFromScan = bssid; + wpsApPinEdit->setEnabled(!bssFromScan.isEmpty()); + wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8); + wpsStatusText->setText(tr("WPS AP selected from scan results")); + wpsInstructions->setText(tr("If you want to use an AP device PIN, e.g., " + "from a label in the device, enter the eight " + "digit AP PIN and click Use AP PIN button.")); +} + + +void WpaGui::wpsApPinChanged(const QString &text) +{ + wpsApPinButton->setEnabled(text.length() == 8); +} + + +void WpaGui::wpsApPin() +{ + char reply[20]; + size_t reply_len = sizeof(reply); + + QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text()); + if (ctrlRequest(cmd.toLocal8Bit().constData(), reply, &reply_len) < 0) + return; + + wpsStatusText->setText(tr("Waiting for AP/Enrollee")); + wpsRunning = true; +} + + +void WpaGui::stopWpsRun(bool success) +{ + if (wpsRunning) + wpsStatusText->setText(success ? tr("Connected to the network") : + tr("Stopped")); + else + wpsStatusText->setText(""); + wpsPinEdit->setEnabled(false); + wpsInstructions->setText(""); + wpsRunning = false; + bssFromScan = ""; + wpsApPinEdit->setEnabled(false); + wpsApPinButton->setEnabled(false); +} + + +#ifdef CONFIG_NATIVE_WINDOWS + +#ifndef WPASVC_NAME +#define WPASVC_NAME TEXT("wpasvc") +#endif + +class ErrorMsg : public QMessageBox { +public: + ErrorMsg(QWidget *parent, DWORD last_err = GetLastError()); + void showMsg(QString msg); +private: + DWORD err; +}; + +ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) : + QMessageBox(parent), err(last_err) +{ + setWindowTitle(tr("wpa_gui error")); + setIcon(QMessageBox::Warning); +} + +void ErrorMsg::showMsg(QString msg) +{ + LPTSTR buf; + + setText(msg); + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, err, 0, (LPTSTR) (void *) &buf, + 0, NULL) > 0) { + QString msg = QString::fromWCharArray(buf); + setInformativeText(QString("[%1] %2").arg(err).arg(msg)); + LocalFree(buf); + } else { + setInformativeText(QString("[%1]").arg(err)); + } + + exec(); +} + + +void WpaGui::startService() +{ + SC_HANDLE svc, scm; + + scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (!scm) { + ErrorMsg(this).showMsg(tr("OpenSCManager failed")); + return; + } + + svc = OpenService(scm, WPASVC_NAME, SERVICE_START); + if (!svc) { + ErrorMsg(this).showMsg(tr("OpenService failed")); + CloseServiceHandle(scm); + return; + } + + if (!StartService(svc, 0, NULL)) { + ErrorMsg(this).showMsg(tr("Failed to start wpa_supplicant " + "service")); + } + + CloseServiceHandle(svc); + CloseServiceHandle(scm); +} + + +void WpaGui::stopService() +{ + SC_HANDLE svc, scm; + SERVICE_STATUS status; + + scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (!scm) { + ErrorMsg(this).showMsg(tr("OpenSCManager failed")); + return; + } + + svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP); + if (!svc) { + ErrorMsg(this).showMsg(tr("OpenService failed")); + CloseServiceHandle(scm); + return; + } + + if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) { + ErrorMsg(this).showMsg(tr("Failed to stop wpa_supplicant " + "service")); + } + + CloseServiceHandle(svc); + CloseServiceHandle(scm); +} + + +bool WpaGui::serviceRunning() +{ + SC_HANDLE svc, scm; + SERVICE_STATUS status; + bool running = false; + + scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (!scm) { + debug("OpenSCManager failed: %d", (int) GetLastError()); + return false; + } + + svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS); + if (!svc) { + debug("OpenService failed: %d", (int) GetLastError()); + CloseServiceHandle(scm); + return false; + } + + if (QueryServiceStatus(svc, &status)) { + if (status.dwCurrentState != SERVICE_STOPPED) + running = true; + } + + CloseServiceHandle(svc); + CloseServiceHandle(scm); + + return running; +} + +#endif /* CONFIG_NATIVE_WINDOWS */ + + +void WpaGui::addInterface() +{ + if (add_iface) { + add_iface->close(); + delete add_iface; + } + add_iface = new AddInterface(this, this); + add_iface->show(); + add_iface->exec(); +} + + +#ifndef QT_NO_SESSIONMANAGER +void WpaGui::saveState() +{ + QSettings settings("wpa_supplicant", "wpa_gui"); + settings.beginGroup("state"); + settings.setValue("session_id", app->sessionId()); + settings.setValue("in_tray", inTray); + settings.endGroup(); +} +#endif diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.h index f0a34c97ebe8ec7a6d5bea670424a80d668f8de0..cb7c846fb6f6b92d9b01666fd12c3c7e323e4b24 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.h @@ -1,180 +1,180 @@ -/* - * wpa_gui - WpaGui class - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPAGUI_H -#define WPAGUI_H - -#include -#include -#include "ui_wpagui.h" -#include "addinterface.h" - -class UserDataRequest; - -class WpaGuiApp : public QApplication -{ - Q_OBJECT -public: - WpaGuiApp(int &argc, char **argv); - -#if !defined(QT_NO_SESSIONMANAGER) && QT_VERSION < 0x050000 - virtual void saveState(QSessionManager &manager); -#endif - - WpaGui *w; - int argc; - char **argv; -}; - -class WpaGui : public QMainWindow, public Ui::WpaGui -{ - Q_OBJECT - -public: - - enum TrayIconType { - TrayIconOffline = 0, - TrayIconAcquiring, - TrayIconConnected, - TrayIconSignalNone, - TrayIconSignalWeak, - TrayIconSignalOk, - TrayIconSignalGood, - TrayIconSignalExcellent, - }; - - WpaGui(QApplication *app, QWidget *parent = 0, const char *name = 0, - Qt::WindowFlags fl = 0); - ~WpaGui(); - - virtual int ctrlRequest(const char *cmd, char *buf, size_t *buflen); - virtual void triggerUpdate(); - virtual void editNetwork(const QString &sel); - virtual void removeNetwork(const QString &sel); - virtual void enableNetwork(const QString &sel); - virtual void disableNetwork(const QString &sel); - virtual int getNetworkDisabled(const QString &sel); - void setBssFromScan(const QString &bssid); -#ifndef QT_NO_SESSIONMANAGER - void saveState(); -#endif - -public slots: - virtual void parse_argv(); - virtual void updateStatus(); - virtual void updateNetworks(); - virtual void helpIndex(); - virtual void helpContents(); - virtual void helpAbout(); - virtual void disconnect(); - virtual void scan(); - virtual void eventHistory(); - virtual void ping(); - virtual void signalMeterUpdate(); - virtual void processMsg(char *msg); - virtual void processCtrlReq(const char *req); - virtual void receiveMsgs(); - virtual void connectB(); - virtual void selectNetwork(const QString &sel); - virtual void editSelectedNetwork(); - virtual void editListedNetwork(); - virtual void removeSelectedNetwork(); - virtual void removeListedNetwork(); - virtual void addNetwork(); - virtual void enableAllNetworks(); - virtual void disableAllNetworks(); - virtual void removeAllNetworks(); - virtual void saveConfig(); - virtual void selectAdapter(const QString &sel); - virtual void updateNetworkDisabledStatus(); - virtual void enableListedNetwork(bool); - virtual void disableListedNetwork(bool); - virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type, - int sec, const QString &msg); - virtual void showTrayStatus(); - virtual void updateTrayIcon(TrayIconType type); - virtual void updateTrayToolTip(const QString &msg); - virtual QIcon loadThemedIcon(const QStringList &names, - const QIcon &fallback); - virtual void wpsDialog(); - virtual void peersDialog(); - virtual void tabChanged(int index); - virtual void wpsPbc(); - virtual void wpsGeneratePin(); - virtual void wpsApPinChanged(const QString &text); - virtual void wpsApPin(); -#ifdef CONFIG_NATIVE_WINDOWS - virtual void startService(); - virtual void stopService(); -#endif /* CONFIG_NATIVE_WINDOWS */ - virtual void addInterface(); - -protected slots: - virtual void languageChange(); - virtual void trayActivated(QSystemTrayIcon::ActivationReason how); - virtual void closeEvent(QCloseEvent *event); - -private: - ScanResults *scanres; - Peers *peers; - bool networkMayHaveChanged; - char *ctrl_iface; - EventHistory *eh; - struct wpa_ctrl *ctrl_conn; - QSocketNotifier *msgNotifier; - QTimer *timer; - int pingsToStatusUpdate; - WpaMsgList msgs; - char *ctrl_iface_dir; - struct wpa_ctrl *monitor_conn; - UserDataRequest *udr; - QAction *disconnectAction; - QAction *reconnectAction; - QAction *eventAction; - QAction *scanAction; - QAction *statAction; - QAction *showAction; - QAction *hideAction; - QAction *quitAction; - QMenu *tray_menu; - QSystemTrayIcon *tray_icon; - TrayIconType currentIconType; - QString wpaStateTranslate(char *state); - void createTrayIcon(bool); - bool ackTrayIcon; - bool startInTray; - bool quietMode; - - int openCtrlConnection(const char *ifname); - - bool wpsRunning; - - QString bssFromScan; - - void stopWpsRun(bool success); - - QTimer *signalMeterTimer; - int signalMeterInterval; - -#ifdef CONFIG_NATIVE_WINDOWS - QAction *fileStartServiceAction; - QAction *fileStopServiceAction; - - bool serviceRunning(); -#endif /* CONFIG_NATIVE_WINDOWS */ - - QAction *addInterfaceAction; - AddInterface *add_iface; - - bool connectedToService; - - QApplication *app; - bool inTray; -}; - -#endif /* WPAGUI_H */ +/* + * wpa_gui - WpaGui class + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPAGUI_H +#define WPAGUI_H + +#include +#include +#include "ui_wpagui.h" +#include "addinterface.h" + +class UserDataRequest; + +class WpaGuiApp : public QApplication +{ + Q_OBJECT +public: + WpaGuiApp(int &argc, char **argv); + +#if !defined(QT_NO_SESSIONMANAGER) && QT_VERSION < 0x050000 + virtual void saveState(QSessionManager &manager); +#endif + + WpaGui *w; + int argc; + char **argv; +}; + +class WpaGui : public QMainWindow, public Ui::WpaGui +{ + Q_OBJECT + +public: + + enum TrayIconType { + TrayIconOffline = 0, + TrayIconAcquiring, + TrayIconConnected, + TrayIconSignalNone, + TrayIconSignalWeak, + TrayIconSignalOk, + TrayIconSignalGood, + TrayIconSignalExcellent, + }; + + WpaGui(QApplication *app, QWidget *parent = 0, const char *name = 0, + Qt::WindowFlags fl = 0); + ~WpaGui(); + + virtual int ctrlRequest(const char *cmd, char *buf, size_t *buflen); + virtual void triggerUpdate(); + virtual void editNetwork(const QString &sel); + virtual void removeNetwork(const QString &sel); + virtual void enableNetwork(const QString &sel); + virtual void disableNetwork(const QString &sel); + virtual int getNetworkDisabled(const QString &sel); + void setBssFromScan(const QString &bssid); +#ifndef QT_NO_SESSIONMANAGER + void saveState(); +#endif + +public slots: + virtual void parse_argv(); + virtual void updateStatus(); + virtual void updateNetworks(); + virtual void helpIndex(); + virtual void helpContents(); + virtual void helpAbout(); + virtual void disconnect(); + virtual void scan(); + virtual void eventHistory(); + virtual void ping(); + virtual void signalMeterUpdate(); + virtual void processMsg(char *msg); + virtual void processCtrlReq(const char *req); + virtual void receiveMsgs(); + virtual void connectB(); + virtual void selectNetwork(const QString &sel); + virtual void editSelectedNetwork(); + virtual void editListedNetwork(); + virtual void removeSelectedNetwork(); + virtual void removeListedNetwork(); + virtual void addNetwork(); + virtual void enableAllNetworks(); + virtual void disableAllNetworks(); + virtual void removeAllNetworks(); + virtual void saveConfig(); + virtual void selectAdapter(const QString &sel); + virtual void updateNetworkDisabledStatus(); + virtual void enableListedNetwork(bool); + virtual void disableListedNetwork(bool); + virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type, + int sec, const QString &msg); + virtual void showTrayStatus(); + virtual void updateTrayIcon(TrayIconType type); + virtual void updateTrayToolTip(const QString &msg); + virtual QIcon loadThemedIcon(const QStringList &names, + const QIcon &fallback); + virtual void wpsDialog(); + virtual void peersDialog(); + virtual void tabChanged(int index); + virtual void wpsPbc(); + virtual void wpsGeneratePin(); + virtual void wpsApPinChanged(const QString &text); + virtual void wpsApPin(); +#ifdef CONFIG_NATIVE_WINDOWS + virtual void startService(); + virtual void stopService(); +#endif /* CONFIG_NATIVE_WINDOWS */ + virtual void addInterface(); + +protected slots: + virtual void languageChange(); + virtual void trayActivated(QSystemTrayIcon::ActivationReason how); + virtual void closeEvent(QCloseEvent *event); + +private: + ScanResults *scanres; + Peers *peers; + bool networkMayHaveChanged; + char *ctrl_iface; + EventHistory *eh; + struct wpa_ctrl *ctrl_conn; + QSocketNotifier *msgNotifier; + QTimer *timer; + int pingsToStatusUpdate; + WpaMsgList msgs; + char *ctrl_iface_dir; + struct wpa_ctrl *monitor_conn; + UserDataRequest *udr; + QAction *disconnectAction; + QAction *reconnectAction; + QAction *eventAction; + QAction *scanAction; + QAction *statAction; + QAction *showAction; + QAction *hideAction; + QAction *quitAction; + QMenu *tray_menu; + QSystemTrayIcon *tray_icon; + TrayIconType currentIconType; + QString wpaStateTranslate(char *state); + void createTrayIcon(bool); + bool ackTrayIcon; + bool startInTray; + bool quietMode; + + int openCtrlConnection(const char *ifname); + + bool wpsRunning; + + QString bssFromScan; + + void stopWpsRun(bool success); + + QTimer *signalMeterTimer; + int signalMeterInterval; + +#ifdef CONFIG_NATIVE_WINDOWS + QAction *fileStartServiceAction; + QAction *fileStopServiceAction; + + bool serviceRunning(); +#endif /* CONFIG_NATIVE_WINDOWS */ + + QAction *addInterfaceAction; + AddInterface *add_iface; + + bool connectedToService; + + QApplication *app; + bool inTray; +}; + +#endif /* WPAGUI_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.ui b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.ui index 9f9039f6c916bafcebe46b06627f1995923afa3f..03bc51aeaa18c53dda2f94c3981446bd10e71656 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.ui +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpagui.ui @@ -1,524 +1,524 @@ - - WpaGui - - - - 0 - 0 - 345 - 330 - - - - wpa_gui - - - - :/icons/wpa_gui.svg:/icons/wpa_gui.svg - - - - - - - Adapter: - - - - - - - - - - Network: - - - - - - - - - - 0 - - - - Current Status - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - - - - Status: - - - - - - - Last message: - - - - - - - Authentication: - - - - - - - Encryption: - - - - - - - SSID: - - - - - - - BSSID: - - - - - - - IP address: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Connect - - - - - - - Disconnect - - - - - - - Scan - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - Manage Networks - - - - - - true - - - - - - - Qt::Vertical - - - - 20 - 61 - - - - - - - - Enabled - - - - - - - Edit - - - - - - - Remove - - - - - - - Qt::Vertical - - - - 20 - 61 - - - - - - - - Disabled - - - - - - - Add - - - - - - - Scan - - - - - - - - WPS - - - - - - Status: - - - - - - - - - - - - - - PBC - push button - - - - - - - Generate PIN - - - - - - - PIN: - - - - - - - false - - - true - - - - - - - false - - - Use AP PIN - - - - - - - AP PIN: - - - - - - - false - - - - - - - true - - - - - - - - - - - - - 0 - 0 - 345 - 24 - - - - - &File - - - - - - - - - - - &Network - - - - - - - - - - - - &Help - - - - - - - - - - - - - Event &History - - - - - &Save Configuration - - - Ctrl+S - - - - - E&xit - - - Ctrl+Q - - - - - &Add - - - - - &Edit - - - - - &Remove - - - - - E&nable All - - - - - &Disable All - - - - - Re&move All - - - - - false - - - &Contents... - - - - - false - - - &Index... - - - - - &About - - - - - false - - - &Wi-Fi Protected Setup - - - - - &Peers - - - - - - - qtimer.h - qsocketnotifier.h - wpamsg.h - eventhistory.h - scanresults.h - peers.h - - - - - - + + WpaGui + + + + 0 + 0 + 345 + 330 + + + + wpa_gui + + + + :/icons/wpa_gui.svg:/icons/wpa_gui.svg + + + + + + + Adapter: + + + + + + + + + + Network: + + + + + + + + + + 0 + + + + Current Status + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + Status: + + + + + + + Last message: + + + + + + + Authentication: + + + + + + + Encryption: + + + + + + + SSID: + + + + + + + BSSID: + + + + + + + IP address: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Connect + + + + + + + Disconnect + + + + + + + Scan + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Manage Networks + + + + + + true + + + + + + + Qt::Vertical + + + + 20 + 61 + + + + + + + + Enabled + + + + + + + Edit + + + + + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 61 + + + + + + + + Disabled + + + + + + + Add + + + + + + + Scan + + + + + + + + WPS + + + + + + Status: + + + + + + + + + + + + + + PBC - push button + + + + + + + Generate PIN + + + + + + + PIN: + + + + + + + false + + + true + + + + + + + false + + + Use AP PIN + + + + + + + AP PIN: + + + + + + + false + + + + + + + true + + + + + + + + + + + + + 0 + 0 + 345 + 24 + + + + + &File + + + + + + + + + + + &Network + + + + + + + + + + + + &Help + + + + + + + + + + + + + Event &History + + + + + &Save Configuration + + + Ctrl+S + + + + + E&xit + + + Ctrl+Q + + + + + &Add + + + + + &Edit + + + + + &Remove + + + + + E&nable All + + + + + &Disable All + + + + + Re&move All + + + + + false + + + &Contents... + + + + + false + + + &Index... + + + + + &About + + + + + false + + + &Wi-Fi Protected Setup + + + + + &Peers + + + + + + + qtimer.h + qsocketnotifier.h + wpamsg.h + eventhistory.h + scanresults.h + peers.h + + + + + + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpamsg.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpamsg.h index 8f2fcdc419886b60d6bb879c0d11c8a83919cf58..f22f6d5ba6281cd9c014ff3ffd0b36624faddea0 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpamsg.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_gui-qt4/wpamsg.h @@ -1,35 +1,35 @@ -/* - * wpa_gui - WpaMsg class for storing event messages - * Copyright (c) 2005-2006, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef WPAMSG_H -#define WPAMSG_H - -#include -#include - -class WpaMsg { -public: - WpaMsg(const QString &_msg, int _priority = 2) - : msg(_msg), priority(_priority) - { - timestamp = QDateTime::currentDateTime(); - } - - QString getMsg() const { return msg; } - int getPriority() const { return priority; } - QDateTime getTimestamp() const { return timestamp; } - -private: - QString msg; - int priority; - QDateTime timestamp; -}; - -typedef QLinkedList WpaMsgList; - -#endif /* WPAMSG_H */ +/* + * wpa_gui - WpaMsg class for storing event messages + * Copyright (c) 2005-2006, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPAMSG_H +#define WPAMSG_H + +#include +#include + +class WpaMsg { +public: + WpaMsg(const QString &_msg, int _priority = 2) + : msg(_msg), priority(_priority) + { + timestamp = QDateTime::currentDateTime(); + } + + QString getMsg() const { return msg; } + int getPriority() const { return priority; } + QDateTime getTimestamp() const { return timestamp; } + +private: + QString msg; + int priority; + QDateTime timestamp; +}; + +typedef QLinkedList WpaMsgList; + +#endif /* WPAMSG_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_passphrase.c index 538997e62580a33c539dc3f584288a07ff694d26..cfab4f1b55512d40d686d89cecbaaf35dbdc5a31 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_passphrase.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_passphrase.c @@ -7,6 +7,7 @@ */ #include "includes.h" +#include #include "common.h" #include "crypto/sha1.h" @@ -14,6 +15,7 @@ int main(int argc, char *argv[]) { + struct termios term; unsigned char psk[32]; int i; char *ssid, *passphrase, buf[64], *pos; @@ -31,11 +33,28 @@ int main(int argc, char *argv[]) if (argc > 2) { passphrase = argv[2]; } else { + bool ctrl_echo; + fprintf(stderr, "# reading passphrase from stdin\n"); + if (tcgetattr(STDIN_FILENO, &term) < 0) { + perror("tcgetattr"); + return 1; + } + ctrl_echo = term.c_lflag & ECHO; + term.c_lflag &= ~ECHO; + if (ctrl_echo && tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0) { + perror("tcsetattr:error disabling echo"); + return 1; + } if (fgets(buf, sizeof(buf), stdin) == NULL) { fprintf(stderr, "Failed to read passphrase\n"); return 1; } + term.c_lflag |= ECHO; + if (ctrl_echo && tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0) { + perror("tcsetattr:error enabling echo"); + return 1; + } buf[sizeof(buf) - 1] = '\0'; pos = buf; while (*pos != '\0') { @@ -58,7 +77,11 @@ int main(int argc, char *argv[]) return 1; } - pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32); + if (pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32) + != 0) { + fprintf(stderr, "Error in pbkdf2_sha1()\n"); + return 1; + } printf("network={\n"); printf("\tssid=\"%s\"\n", ssid); diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_priv.c b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_priv.c index 9feae114c3725ce405d904bec54f637ec4061468..88f3f2a523568c17f107b529d40e8659ba6004a7 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_priv.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_priv.c @@ -187,7 +187,10 @@ static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface, int val; size_t i; - res = iface->driver->get_scan_results2(iface->drv_priv); + if (iface->driver->get_scan_results) + res = iface->driver->get_scan_results(iface->drv_priv, NULL); + else + res = iface->driver->get_scan_results2(iface->drv_priv); if (res == NULL) goto fail; @@ -231,7 +234,7 @@ static void wpa_priv_cmd_get_scan_results(struct wpa_priv_interface *iface, if (iface->drv_priv == NULL) return; - if (iface->driver->get_scan_results2) + if (iface->driver->get_scan_results || iface->driver->get_scan_results2) wpa_priv_get_scan_results2(iface, from, fromlen); else sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, fromlen); @@ -414,9 +417,8 @@ static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface, p.key = params->key_len ? params->key : NULL; p.key_len = params->key_len; p.key_flag = params->key_flag; -#ifdef CONFIG_MLD_PATCH_EXT p.link_id = -1; -#endif + res = iface->driver->set_key(iface->drv_priv, &p); wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res); } @@ -1136,7 +1138,8 @@ void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event, void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len) + const u8 *buf, size_t len, + enum frame_encryption encrypted) { struct wpa_priv_interface *iface = ctx; struct msghdr msg; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant.c index 771ddba80ea6b316c7e4cebbeaf83fb6ec2ddb03..9ce702d57e84d5c0e1ea445025ba8c3f75dd7263 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - * Copyright (c) 2003-2022, Jouni Malinen + * Copyright (c) 2003-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -17,6 +17,7 @@ #endif /* CONFIG_MATCH_IFACE */ #include "common.h" +#include "crypto/crypto.h" #include "crypto/random.h" #include "crypto/sha1.h" #include "eapol_supp/eapol_supp_sm.h" @@ -67,6 +68,7 @@ #include "wapi_asue_i.h" #endif #include "dpp_supplicant.h" +#include "nan_usd.h" #ifdef CONFIG_MESH #include "ap/ap_config.h" #include "ap/hostapd.h" @@ -95,7 +97,7 @@ const char *const wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" -"Copyright (c) 2003-2022, Jouni Malinen and contributors"; +"Copyright (c) 2003-2024, Jouni Malinen and contributors"; const char *const wpa_supplicant_license = "This software may be distributed under the terms of the BSD license.\n" @@ -149,6 +151,7 @@ struct wpa_supplicant *gWpaP2p = NULL; static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx); +static void wpas_verify_ssid_beacon(void *eloop_ctx, void *timeout_ctx); #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL) static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s); #endif /* CONFIG_FILS && IEEE8021X_EAPOL */ @@ -168,11 +171,7 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) continue; set = 1; -#ifdef CONFIG_MLD_PATCH wpa_drv_set_key(wpa_s, -1, WPA_ALG_WEP, NULL, -#else - wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL, -#endif i, i == ssid->wep_tx_keyidx, NULL, 0, ssid->wep_key[i], ssid->wep_key_len[i], i == ssid->wep_tx_keyidx ? @@ -235,11 +234,8 @@ int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s, /* TODO: should actually remember the previously used seq#, both for TX * and RX from each STA.. */ -#ifdef CONFIG_MLD_PATCH + ret = wpa_drv_set_key(wpa_s, -1, alg, NULL, 0, 1, seq, 6, key, keylen, -#else - ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen, -#endif KEY_FLAG_GROUP_RX_TX_DEFAULT); os_memset(key, 0, sizeof(key)); return ret; @@ -265,6 +261,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) if (wpa_s->wpa_state == WPA_COMPLETED) return; + wpa_bssid_ignore_add(wpa_s, bssid); #if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) WpaEventReport(wpa_s->ifname, WPA_EVENT_AUTH_TIMEOUT, NULL); @@ -447,9 +444,8 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, #ifdef CONFIG_WEP int i; #endif /* CONFIG_WEP */ -#ifdef CONFIG_MLD_PATCH struct wpa_sm_mlo mlo; -#endif + if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) wpa_s->key_mgmt = WPA_KEY_MGMT_WPS; else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) @@ -487,12 +483,11 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP, wpa_s->mgmt_group_cipher); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, 0); pmksa_cache_clear_current(wpa_s->wpa); -#ifdef CONFIG_MLD_PATCH os_memset(&mlo, 0, sizeof(mlo)); wpa_sm_set_mlo_params(wpa_s->wpa, &mlo); -#endif } @@ -633,7 +628,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_tdls_deinit(wpa_s->wpa); #endif /* CONFIG_TDLS */ +#ifndef CONFIG_NO_WMM_AC wmm_ac_clear_saved_tspecs(wpa_s); +#endif /* CONFIG_NO_WMM_AC */ pmksa_candidate_free(wpa_s->wpa); ptksa_cache_deinit(wpa_s->ptksa); wpa_s->ptksa = NULL; @@ -658,6 +655,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL); + eloop_cancel_timeout(wpas_verify_ssid_beacon, wpa_s, NULL); wpas_wps_deinit(wpa_s); @@ -724,9 +722,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->disallow_aps_ssid = NULL; wnm_bss_keep_alive_deinit(wpa_s); -#ifdef CONFIG_WNM - wnm_deallocate_memory(wpa_s); -#endif /* CONFIG_WNM */ + wnm_btm_reset(wpa_s); ext_password_deinit(wpa_s->ext_pw); wpa_s->ext_pw = NULL; @@ -750,7 +746,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->vendor_elem[i] = NULL; } +#ifndef CONFIG_NO_WMM_AC wmm_ac_notify_disassoc(wpa_s); +#endif /* CONFIG_NO_WMM_AC */ wpa_s->sched_scan_plans_num = 0; os_free(wpa_s->sched_scan_plans); @@ -766,7 +764,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpabuf_free(wpa_s->lci); wpa_s->lci = NULL; +#ifndef CONFIG_NO_RRM wpas_clear_beacon_rep_data(wpa_s); +#endif /* CONFIG_NO_RRM */ #ifdef CONFIG_PMKSA_CACHE_EXTERNAL #ifdef CONFIG_MESH @@ -795,11 +795,22 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->dpp = NULL; #endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + wpas_nan_usd_deinit(wpa_s); +#endif /* CONFIG_NAN_USD */ + #ifdef CONFIG_PASN wpas_pasn_auth_stop(wpa_s); #endif /* CONFIG_PASN */ +#ifndef CONFIG_NO_ROBUST_AV wpas_scs_deinit(wpa_s); wpas_dscp_deinit(wpa_s); +#endif /* CONFIG_NO_ROBUST_AV */ + +#ifdef CONFIG_OWE + os_free(wpa_s->owe_trans_scan_freq); + wpa_s->owe_trans_scan_freq = NULL; +#endif /* CONFIG_OWE */ #ifdef CONFIG_MAGICLINK eloop_cancel_timeout(hw_magiclink_connect_timeout, wpa_s, NULL); #endif @@ -828,30 +839,18 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) for (i = 0; i < max; i++) { if (wpa_s->keys_cleared & BIT(i)) continue; - wpa_drv_set_key(wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif - WPA_ALG_NONE, NULL, i, 0, NULL, 0, + wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, NULL, i, 0, NULL, 0, NULL, 0, KEY_FLAG_GROUP); } /* Pairwise Key ID 1 for Extended Key ID is tracked in bit 15 */ if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr && !is_zero_ether_addr(addr)) { if (!(wpa_s->keys_cleared & BIT(0))) - wpa_drv_set_key(wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif - WPA_ALG_NONE, addr, 0, 0, NULL, - 0, NULL, 0, KEY_FLAG_PAIRWISE); + wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 0, 0, + NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE); if (!(wpa_s->keys_cleared & BIT(15))) - wpa_drv_set_key(wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif - WPA_ALG_NONE, addr, 1, 0, NULL, - 0, NULL, 0, KEY_FLAG_PAIRWISE); + wpa_drv_set_key(wpa_s, -1, WPA_ALG_NONE, addr, 1, 0, + NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE); /* MLME-SETPROTECTION.request(None) */ wpa_drv_mlme_setprotection( wpa_s, addr, @@ -946,7 +945,7 @@ void wpa_supplicant_reset_bgscan(struct wpa_supplicant *wpa_s) struct wpa_scan_results *scan_res; wpa_s->bgscan_ssid = wpa_s->current_ssid; scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, - 0); + 0, NULL); if (scan_res) { bgscan_notify_scan(wpa_s, scan_res); wpa_scan_results_free(scan_res); @@ -982,6 +981,91 @@ void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s) } +static void wpas_verify_ssid_beacon(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + struct wpa_bss *bss; + const u8 *ssid; + size_t ssid_len; + + if (!wpa_s->current_ssid || !wpa_s->current_bss) + return; + + ssid = wpa_s->current_bss->ssid; + ssid_len = wpa_s->current_bss->ssid_len; + + if (wpa_s->current_ssid->ssid_len && + (wpa_s->current_ssid->ssid_len != ssid_len || + os_memcmp(wpa_s->current_ssid->ssid, ssid, ssid_len) != 0)) + return; + + if (wpa_s->wpa_state < WPA_4WAY_HANDSHAKE || + !wpa_s->bigtk_set || wpa_s->ssid_verified) + return; + + wpa_printf(MSG_DEBUG, + "SSID not yet verified; check if the driver has received a verified Beacon frame"); + if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0) + return; + + bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->bssid); + if (!bss) + return; + wpa_printf(MSG_DEBUG, "The current beacon time stamp: 0x%llx", + (long long unsigned int) bss->tsf); + if (bss->tsf > wpa_s->first_beacon_tsf) { + const u8 *ie; + + wpa_printf(MSG_DEBUG, + "Verified Beacon frame has been received"); + wpa_s->beacons_checked++; + + ie = wpa_bss_get_ie_beacon(bss, WLAN_EID_SSID); + if (ie && ie[1] == ssid_len && + os_memcmp(&ie[2], ssid, ssid_len) == 0) { + wpa_printf(MSG_DEBUG, + "SSID verified based on a Beacon frame and beacon protection"); + wpa_s->ssid_verified = true; + return; + } + + /* TODO: Multiple BSSID element */ + } + + if (wpa_s->beacons_checked < 16) { + eloop_register_timeout(wpa_s->next_beacon_check, 0, + wpas_verify_ssid_beacon, wpa_s, NULL); + wpa_s->next_beacon_check++; + } +} + + +static void wpas_verify_ssid_beacon_prot(struct wpa_supplicant *wpa_s) +{ + struct wpa_bss *bss; + + wpa_printf(MSG_DEBUG, + "SSID not yet verified; try to verify using beacon protection"); + /* Fetch the current scan result which is likely based on not yet + * verified payload since the current BIGTK was just received. Any + * newer update in the future with a larger timestamp value is an + * indication that a verified Beacon frame has been received. */ + if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0) + return; + + bss = wpa_bss_get_bssid_latest(wpa_s, wpa_s->bssid); + if (!bss) + return; + wpa_printf(MSG_DEBUG, "The initial beacon time stamp: 0x%llx", + (long long unsigned int) bss->tsf); + wpa_s->first_beacon_tsf = bss->tsf; + wpa_s->beacons_checked = 0; + wpa_s->next_beacon_check = 1; + eloop_cancel_timeout(wpas_verify_ssid_beacon, wpa_s, NULL); + eloop_register_timeout(1, 0, wpas_verify_ssid_beacon, wpa_s, NULL); +} + + /** * wpa_supplicant_set_state - Set current connection state * @wpa_s: Pointer to wpa_supplicant data @@ -1065,6 +1149,13 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, if (state == WPA_COMPLETED && wpa_s->new_connection) { struct wpa_ssid *ssid = wpa_s->current_ssid; int fils_hlp_sent = 0; + char mld_addr[50]; + + mld_addr[0] = '\0'; + if (wpa_s->valid_links) + os_snprintf(mld_addr, sizeof(mld_addr), + " ap_mld_addr=" MACSTR, + MAC2STR(wpa_s->ap_mld_addr)); #ifdef CONFIG_SME if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && @@ -1077,18 +1168,18 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to " - MACSTR " completed [id=%d id_str=%s%s]", + MACSTR " completed [id=%d id_str=%s%s]%s", MAC2STR(wpa_s->bssid), ssid ? ssid->id : -1, ssid && ssid->id_str ? ssid->id_str : "", - fils_hlp_sent ? " FILS_HLP_SENT" : ""); - #if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) + fils_hlp_sent ? " FILS_HLP_SENT" : "", mld_addr); +#if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) struct WpaConnectParam wpaConnectParma; os_memcpy(wpaConnectParma.bssid, wpa_s->bssid, ETH_ALEN); wpaConnectParma.networkId = ssid ? ssid->id : -1; wpa_printf(MSG_DEBUG, "%s wpaConnectParma[0]=%x", __func__, wpaConnectParma.bssid[0]); WpaEventReport(wpa_s->ifname, WPA_EVENT_CONNECT, (void *) &wpaConnectParma); - #endif +#endif #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ wpas_clear_temp_disabled(wpa_s, ssid, 1); @@ -1142,8 +1233,14 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) wpa_supplicant_start_autoscan(wpa_s); + if (state == WPA_COMPLETED || state == WPA_INTERFACE_DISABLED || + state == WPA_INACTIVE) + wnm_btm_reset(wpa_s); + +#ifndef CONFIG_NO_WMM_AC if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED) wmm_ac_notify_disassoc(wpa_s); +#endif /* CONFIG_NO_WMM_AC */ if (wpa_s->wpa_state != old_state) { wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state); @@ -1161,6 +1258,10 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, if (wpa_s->wpa_state == WPA_COMPLETED) wpas_dpp_connected(wpa_s); #endif /* CONFIG_DPP2 */ + + if (wpa_s->wpa_state == WPA_COMPLETED && + wpa_s->bigtk_set && !wpa_s->ssid_verified) + wpas_verify_ssid_beacon_prot(wpa_s); } #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL) if (update_fils_connect_params) @@ -1235,6 +1336,7 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s) wpa_s->group_cipher = 0; wpa_s->mgmt_group_cipher = 0; wpa_s->key_mgmt = 0; + wpa_s->allowed_key_mgmts = 0; if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) wpa_supplicant_set_state(wpa_s, new_state); @@ -1262,14 +1364,14 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s) if (wpa_s->confname == NULL) return -1; - conf = wpa_config_read(wpa_s->confname, NULL); + conf = wpa_config_read(wpa_s->confname, NULL, false); if (conf == NULL) { wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration " "file '%s' - exiting", wpa_s->confname); return -1; } if (wpa_s->confanother && - !wpa_config_read(wpa_s->confanother, conf)) { + !wpa_config_read(wpa_s->confanother, conf, true)) { wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration file '%s' - exiting", wpa_s->confanother); @@ -1454,6 +1556,214 @@ void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s, wpas_get_ssid_pmf(wpa_s, ssid)); } +/** + * wpa_supplicant_get_psk - Get PSK from config or external database + * @wpa_s: Pointer to wpa_supplicant data + * @bss: Scan results for the selected BSS, or %NULL if not available + * @ssid: Configuration data for the selected network + * @psk: Buffer for the PSK + * Returns: 0 on success or -1 if configuration parsing failed + * + * This function obtains the PSK for a network, either included inline in the + * config or retrieved from an external database. + */ +static int wpa_supplicant_get_psk(struct wpa_supplicant *wpa_s, + struct wpa_bss *bss, struct wpa_ssid *ssid, + u8 *psk) +{ + if (ssid->psk_set) { + wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)", + ssid->psk, PMK_LEN); + os_memcpy(psk, ssid->psk, PMK_LEN); + return 0; + } + +#ifndef CONFIG_NO_PBKDF2 + if (bss && ssid->bssid_set && ssid->ssid_len == 0 && ssid->passphrase) { + if (pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len, + 4096, psk, PMK_LEN) != 0) { + wpa_msg(wpa_s, MSG_WARNING, "Error in pbkdf2_sha1()"); + return -1; + } + wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", + psk, PMK_LEN); + return 0; + } +#endif /* CONFIG_NO_PBKDF2 */ + +#ifdef CONFIG_EXT_PASSWORD + if (ssid->ext_psk) { + struct wpabuf *pw = ext_password_get(wpa_s->ext_pw, + ssid->ext_psk); + char pw_str[64 + 1]; + + if (!pw) { + wpa_msg(wpa_s, MSG_INFO, + "EXT PW: No PSK found from external storage"); + return -1; + } + + if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) { + wpa_msg(wpa_s, MSG_INFO, + "EXT PW: Unexpected PSK length %d in external storage", + (int) wpabuf_len(pw)); + ext_password_free(pw); + return -1; + } + + os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw)); + pw_str[wpabuf_len(pw)] = '\0'; + +#ifndef CONFIG_NO_PBKDF2 + if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss) + { + if (pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len, + 4096, psk, PMK_LEN) != 0) { + wpa_msg(wpa_s, MSG_WARNING, + "Error in pbkdf2_sha1()"); + forced_memzero(pw_str, sizeof(pw_str)); + ext_password_free(pw); + return -1; + } + wpa_hexdump_key(MSG_MSGDUMP, + "PSK (from external passphrase)", + psk, PMK_LEN); + } else +#endif /* CONFIG_NO_PBKDF2 */ + if (wpabuf_len(pw) == 2 * PMK_LEN) { + if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) { + wpa_msg(wpa_s, MSG_INFO, + "EXT PW: Invalid PSK hex string"); + forced_memzero(pw_str, sizeof(pw_str)); + ext_password_free(pw); + return -1; + } + wpa_hexdump_key(MSG_MSGDUMP, "PSK (from external PSK)", + psk, PMK_LEN); + } else { + wpa_msg(wpa_s, MSG_INFO, + "EXT PW: No suitable PSK available"); + forced_memzero(pw_str, sizeof(pw_str)); + ext_password_free(pw); + return -1; + } + + forced_memzero(pw_str, sizeof(pw_str)); + ext_password_free(pw); + + return 0; + } +#endif /* CONFIG_EXT_PASSWORD */ + + return -1; +} + + +static void wpas_update_allowed_key_mgmt(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid) +{ + int akm_count = wpa_s->max_num_akms; + u8 capab = 0; + + if (akm_count < 2) + return; + + akm_count--; + wpa_s->allowed_key_mgmts = 0; + switch (wpa_s->key_mgmt) { + case WPA_KEY_MGMT_PSK: + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + wpa_s->allowed_key_mgmts |= + WPA_KEY_MGMT_PSK_SHA256; + break; + case WPA_KEY_MGMT_PSK_SHA256: + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK; + break; + case WPA_KEY_MGMT_SAE: + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE_EXT_KEY; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + wpa_s->allowed_key_mgmts |= + WPA_KEY_MGMT_PSK_SHA256; + break; + case WPA_KEY_MGMT_SAE_EXT_KEY: + if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_SAE; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { + akm_count--; + wpa_s->allowed_key_mgmts |= WPA_KEY_MGMT_PSK; + } + if (!akm_count) + break; + if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) + wpa_s->allowed_key_mgmts |= + WPA_KEY_MGMT_PSK_SHA256; + break; + default: + return; + } + + if (wpa_s->conf->sae_pwe != SAE_PWE_HUNT_AND_PECK && + wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) + capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E); +#ifdef CONFIG_SAE_PK + if (ssid->sae_pk) + capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK); +#endif /* CONFIG_SAE_PK */ + + if (!((wpa_s->allowed_key_mgmts & + (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY)) && capab)) + return; + + if (!wpa_s->rsnxe_len) { + wpa_s->rsnxe_len = 3; + wpa_s->rsnxe[0] = WLAN_EID_RSNX; + wpa_s->rsnxe[1] = 1; + wpa_s->rsnxe[2] = 0; + } + + wpa_s->rsnxe[2] |= capab; +} + /** * wpa_supplicant_set_suites - Set authentication and encryption parameters @@ -1463,6 +1773,7 @@ void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s, * @wpa_ie: Buffer for the WPA/RSN IE * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the * used buffer length in case the functions returns success. + * @skip_default_rsne: Whether to skip setting of the default RSNE/RSNXE * Returns: 0 on success or -1 on failure * * This function is used to configure authentication and encryption parameters @@ -1471,11 +1782,14 @@ void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s, */ 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) + u8 *wpa_ie, size_t *wpa_ie_len, + bool skip_default_rsne) { struct wpa_ie_data ie; - int sel, proto, sae_pwe; + int sel, proto; + enum sae_pwe sae_pwe; const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen; + bool wmm; if (bss) { bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); @@ -1664,8 +1978,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, sel = ie.key_mgmt & ssid->key_mgmt; #ifdef CONFIG_SAE - if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) - sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY | WPA_KEY_MGMT_FT_SAE); + if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) && + !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA)) || + wpas_is_sae_avoided(wpa_s, ssid, &ie)) + sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY | + WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY); #endif /* CONFIG_SAE */ #ifdef CONFIG_IEEE80211R if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME | @@ -1705,18 +2022,26 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X with Suite B"); #endif /* CONFIG_SUITEB */ +#ifdef CONFIG_SHA384 + } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA384) { + wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA384; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: using KEY_MGMT 802.1X with SHA384"); +#endif /* CONFIG_SHA384 */ #ifdef CONFIG_FILS #ifdef CONFIG_IEEE80211R } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) { wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384"); - } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) { - wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256; - wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256"); #endif /* CONFIG_IEEE80211R */ } else if (sel & WPA_KEY_MGMT_FILS_SHA384) { wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384"); +#ifdef CONFIG_IEEE80211R + } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) { + wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256; + wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256"); +#endif /* CONFIG_IEEE80211R */ } else if (sel & WPA_KEY_MGMT_FILS_SHA256) { wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256"); @@ -1741,6 +2066,10 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP"); #endif /* CONFIG_DPP */ #ifdef CONFIG_SAE + } else if (sel & WPA_KEY_MGMT_FT_SAE_EXT_KEY) { + wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY; + wpa_dbg(wpa_s, MSG_DEBUG, + "RSN: using KEY_MGMT FT/SAE (ext key)"); } else if (sel & WPA_KEY_MGMT_SAE_EXT_KEY) { wpa_s->key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY; wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE (ext key)"); @@ -1815,7 +2144,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher); if (!(ie.capabilities & WPA_CAPABILITY_MFPC) && - wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) { + (wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED || + (bss && is_6ghz_freq(bss->freq)))) { wpa_msg(wpa_s, MSG_INFO, "RSN: Management frame protection required but the selected AP does not enable it"); return -1; @@ -1829,9 +2159,15 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, #endif /* CONFIG_OCV */ sae_pwe = wpa_s->conf->sae_pwe; if ((ssid->sae_password_id || - wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) && + wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) && sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK) sae_pwe = SAE_PWE_HASH_TO_ELEMENT; + if (bss && is_6ghz_freq(bss->freq) && + sae_pwe == SAE_PWE_HUNT_AND_PECK) { + wpa_dbg(wpa_s, MSG_DEBUG, + "RSN: Enable SAE hash-to-element mode for 6 GHz BSS"); + sae_pwe = SAE_PWE_BOTH; + } 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, @@ -1842,6 +2178,12 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, (!ssid->sae_password && ssid->passphrase && sae_pk_valid_password(ssid->passphrase)))); #endif /* CONFIG_SAE_PK */ + if (bss && is_6ghz_freq(bss->freq) && + wpas_get_ssid_pmf(wpa_s, ssid) != MGMT_FRAME_PROTECTION_REQUIRED) { + wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Force MFPR=1 on 6 GHz"); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, + MGMT_FRAME_PROTECTION_REQUIRED); + } #ifdef CONFIG_TESTING_OPTIONS wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_RSNXE_USED, wpa_s->ft_rsnxe_used); @@ -1853,6 +2195,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, 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); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX, + wpa_s->disable_eapol_g2_tx); #endif /* CONFIG_TESTING_OPTIONS */ /* Extended Key ID is only supported in infrastructure BSS so far */ @@ -1879,16 +2223,53 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0); } - if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) { - wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE"); - return -1; + /* Mark WMM enabled for any HT/VHT/HE/EHT association to get more + * appropriate advertisement of the supported number of PTKSA receive + * counters. In theory, this could be based on a driver capability, but + * in practice all cases using WMM support at least eight replay + * counters, so use a hardcoded value for now since there is no explicit + * driver capability indication for this. + * + * In addition, claim WMM to be enabled if the AP supports it since it + * is far more likely for any current device to support WMM. */ + wmm = wpa_s->connection_set && + (wpa_s->connection_ht || wpa_s->connection_vht || + wpa_s->connection_he || wpa_s->connection_eht); + if (!wmm && bss) + wmm = !!wpa_bss_get_vendor_ie(bss, WMM_IE_VENDOR_TYPE); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_WMM_ENABLED, wmm); + + if (ssid->ssid_protection && proto == WPA_PROTO_RSN) { + bool ssid_prot; + + /* Enable SSID protection based on the AP advertising support + * for it to avoid potential interoperability issues with + * incorrect AP behavior if we were to send an "unexpected" + * RSNXE with multiple octets of payload. */ + ssid_prot = ieee802_11_rsnx_capab( + bss_rsnx, WLAN_RSNX_CAPAB_SSID_PROTECTION); + if (!skip_default_rsne) + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, + proto == WPA_PROTO_RSN && ssid_prot); + } else { + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SSID_PROTECTION, false); } - wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe); - if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe, - &wpa_s->rsnxe_len)) { - wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE"); - return -1; + if (!skip_default_rsne) { + if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, + wpa_ie_len)) { + wpa_msg(wpa_s, MSG_WARNING, + "RSN: Failed to generate RSNE/WPA IE"); + return -1; + } + + wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe); + if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe, + &wpa_s->rsnxe_len)) { + wpa_msg(wpa_s, MSG_WARNING, + "RSN: Failed to generate RSNXE"); + return -1; + } } if (0) { @@ -1902,108 +2283,27 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, #endif /* CONFIG_DPP */ } else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) { int psk_set = 0; - int sae_only; - - sae_only = (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | - WPA_KEY_MGMT_FT_PSK | - WPA_KEY_MGMT_PSK_SHA256)) == 0; - - if (ssid->psk_set && !sae_only) { - wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)", - ssid->psk, PMK_LEN); - wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL, - NULL); - psk_set = 1; - } - if (wpa_key_mgmt_sae(ssid->key_mgmt) && - (ssid->sae_password || ssid->passphrase)) - psk_set = 1; - -#ifndef CONFIG_NO_PBKDF2 - if (bss && ssid->bssid_set && ssid->ssid_len == 0 && - ssid->passphrase && !sae_only) { - u8 psk[PMK_LEN]; - pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len, - 4096, psk, PMK_LEN); - wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", - psk, PMK_LEN); - wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL); - psk_set = 1; - os_memset(psk, 0, sizeof(psk)); - } -#endif /* CONFIG_NO_PBKDF2 */ -#ifdef CONFIG_EXT_PASSWORD - if (ssid->ext_psk && !sae_only) { - struct wpabuf *pw = ext_password_get(wpa_s->ext_pw, - ssid->ext_psk); - char pw_str[64 + 1]; + if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt)) { u8 psk[PMK_LEN]; - if (pw == NULL) { - wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK " - "found from external storage"); - return -1; - } - - if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) { - wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected " - "PSK length %d in external storage", - (int) wpabuf_len(pw)); - ext_password_free(pw); - return -1; - } - - os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw)); - pw_str[wpabuf_len(pw)] = '\0'; - -#ifndef CONFIG_NO_PBKDF2 - if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss) - { - pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len, - 4096, psk, PMK_LEN); - os_memset(pw_str, 0, sizeof(pw_str)); - wpa_hexdump_key(MSG_MSGDUMP, "PSK (from " - "external passphrase)", - psk, PMK_LEN); + if (wpa_supplicant_get_psk(wpa_s, bss, ssid, + psk) == 0) { wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL); psk_set = 1; - os_memset(psk, 0, sizeof(psk)); - } else -#endif /* CONFIG_NO_PBKDF2 */ - if (wpabuf_len(pw) == 2 * PMK_LEN) { - if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) { - wpa_msg(wpa_s, MSG_INFO, "EXT PW: " - "Invalid PSK hex string"); - os_memset(pw_str, 0, sizeof(pw_str)); - ext_password_free(pw); - return -1; - } - wpa_hexdump_key(MSG_MSGDUMP, - "PSK (from external PSK)", - psk, PMK_LEN); - wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, - NULL); - psk_set = 1; - os_memset(psk, 0, sizeof(psk)); - } else { - wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable " - "PSK available"); - os_memset(pw_str, 0, sizeof(pw_str)); - ext_password_free(pw); - return -1; } - - os_memset(pw_str, 0, sizeof(pw_str)); - ext_password_free(pw); + forced_memzero(psk, sizeof(psk)); } -#endif /* CONFIG_EXT_PASSWORD */ + + if (wpa_key_mgmt_sae(ssid->key_mgmt) && + (ssid->sae_password || ssid->passphrase || ssid->ext_psk)) + psk_set = 1; if (!psk_set) { wpa_msg(wpa_s, MSG_INFO, "No PSK available for association"); - wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE"); + wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE", NULL); return -1; } #ifdef CONFIG_OWE @@ -2029,13 +2329,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0); } + if (wpa_key_mgmt_cross_akm(wpa_s->key_mgmt) && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) + wpas_update_allowed_key_mgmt(wpa_s, ssid); + return 0; } -static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) +static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx, + struct wpa_bss *bss) { +#ifndef CONFIG_NO_ROBUST_AV bool scs = true, mscs = true; +#endif /* CONFIG_NO_ROBUST_AV */ *pos = 0x00; @@ -2051,7 +2358,9 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) case 2: /* Bits 16-23 */ #ifdef CONFIG_WNM *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */ - if (!wpa_s->disable_mbo_oce && !wpa_s->conf->disable_btm) + if ((wpas_driver_bss_selection(wpa_s) || + !wpa_s->disable_mbo_oce) && + !wpa_s->conf->disable_btm) *pos |= 0x08; /* Bit 19 - BSS Transition */ #endif /* CONFIG_WNM */ break; @@ -2080,12 +2389,21 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) #endif /* CONFIG_MBO */ break; case 6: /* Bits 48-55 */ +#ifndef CONFIG_NO_ROBUST_AV #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->disable_scs_support) scs = false; #endif /* CONFIG_TESTING_OPTIONS */ + if (bss && !wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_SCS)) { + /* Drop own SCS capability indication since the AP does + * not support it. This is needed to avoid + * interoperability issues with APs that get confused + * with Extended Capabilities element. */ + scs = false; + } if (scs) *pos |= 0x40; /* Bit 54 - SCS */ +#endif /* CONFIG_NO_ROBUST_AV */ break; case 7: /* Bits 56-63 */ break; @@ -2102,18 +2420,28 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx) #endif /* CONFIG_FILS */ break; case 10: /* Bits 80-87 */ +#ifndef CONFIG_NO_ROBUST_AV #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->disable_mscs_support) mscs = false; #endif /* CONFIG_TESTING_OPTIONS */ + if (bss && !wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_MSCS)) { + /* Drop own MSCS capability indication since the AP does + * not support it. This is needed to avoid + * interoperability issues with APs that get confused + * with Extended Capabilities element. */ + mscs = false; + } if (mscs) *pos |= 0x20; /* Bit 85 - Mirrored SCS */ +#endif /* CONFIG_NO_ROBUST_AV */ break; } } -int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen) +int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, + size_t buflen, struct wpa_bss *bss) { u8 *pos = buf; u8 len = 11, i; @@ -2129,7 +2457,7 @@ int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen) *pos++ = WLAN_EID_EXT_CAPAB; *pos++ = len; for (i = 0; i < len; i++, pos++) { - wpas_ext_capab_byte(wpa_s, pos, i); + wpas_ext_capab_byte(wpa_s, pos, i, bss); if (i < wpa_s->extended_capa_len) { *pos &= ~wpa_s->extended_capa_mask[i]; @@ -2210,31 +2538,52 @@ void wpas_connect_work_done(struct wpa_supplicant *wpa_s) } -int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style) +int wpas_update_random_addr(struct wpa_supplicant *wpa_s, + enum wpas_mac_addr_style style, + struct wpa_ssid *ssid) { struct os_reltime now; u8 addr[ETH_ALEN]; os_get_reltime(&now); - if (wpa_s->last_mac_addr_style == style && - wpa_s->last_mac_addr_change.sec != 0 && - !os_reltime_expired(&now, &wpa_s->last_mac_addr_change, - wpa_s->conf->rand_addr_lifetime)) { - wpa_msg(wpa_s, MSG_DEBUG, - "Previously selected random MAC address has not yet expired"); - return 0; + /* Random addresses are valid within a given ESS so check + * expiration/value only when continuing to use the same ESS. */ + if (wpa_s->last_mac_addr_style == style && wpa_s->reassoc_same_ess) { + if (style == WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS) { + /* Pregenerated addresses do not expire but their value + * might have changed, so let's check that. */ + if (ether_addr_equal(wpa_s->own_addr, ssid->mac_value)) + return 0; + } else if ((wpa_s->last_mac_addr_change.sec != 0 || + wpa_s->last_mac_addr_change.usec != 0) && + !os_reltime_expired( + &now, + &wpa_s->last_mac_addr_change, + wpa_s->conf->rand_addr_lifetime)) { + wpa_msg(wpa_s, MSG_DEBUG, + "Previously selected random MAC address has not yet expired"); + return 0; + } } switch (style) { - case 1: + case WPAS_MAC_ADDR_STYLE_RANDOM: if (random_mac_addr(addr) < 0) return -1; break; - case 2: + case WPAS_MAC_ADDR_STYLE_RANDOM_SAME_OUI: os_memcpy(addr, wpa_s->perm_addr, ETH_ALEN); if (random_mac_addr_keep_oui(addr) < 0) return -1; break; + case WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS: + if (!ssid) { + wpa_msg(wpa_s, MSG_INFO, + "Invalid 'ssid' for address policy 3"); + return -1; + } + os_memcpy(addr, ssid->mac_value, ETH_ALEN); + break; default: return -1; } @@ -2258,7 +2607,7 @@ int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style) wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR, MAC2STR(addr)); - return 0; + return 1; } @@ -2268,11 +2617,13 @@ int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s) !wpa_s->conf->preassoc_mac_addr) return 0; - return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr); + return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr, + NULL); } -void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid) +void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid, + bool force) { #ifdef CONFIG_SAE int *groups = conf->sae_groups; @@ -2287,10 +2638,12 @@ void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid) password = ssid->passphrase; if (!password || - (conf->sae_pwe == 0 && !ssid->sae_password_id && + !wpa_key_mgmt_sae(ssid->key_mgmt) || + (conf->sae_pwe == SAE_PWE_HUNT_AND_PECK && !ssid->sae_password_id && !wpa_key_mgmt_sae_ext_key(ssid->key_mgmt) && + !force && !sae_pk_valid_password(password)) || - conf->sae_pwe == 3) { + conf->sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) { /* PT derivation not needed */ sae_deinit_pt(ssid->pt); ssid->pt = NULL; @@ -2306,7 +2659,7 @@ void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid) } -static void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s) +void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s) { #if defined(CONFIG_SAE) && defined(CONFIG_SME) os_free(wpa_s->sme.sae_rejected_groups); @@ -2363,8 +2716,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit); void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid) { + bool clear_rejected = true; struct wpa_connect_work *cwork; - int rand_style; + enum wpas_mac_addr_style rand_style; wpa_s->own_disconnect_req = 0; wpa_s->own_reconnect_req = 0; @@ -2376,13 +2730,20 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, wpabuf_free(wpa_s->pending_eapol_rx); wpa_s->pending_eapol_rx = NULL; - if (ssid->mac_addr == -1) + if (ssid->mac_addr == WPAS_MAC_ADDR_STYLE_NOT_SET) rand_style = wpa_s->conf->mac_addr; else rand_style = ssid->mac_addr; + wpa_s->eapol_failed = 0; wpa_s->multi_ap_ie = 0; +#ifndef CONFIG_NO_WMM_AC wmm_ac_clear_saved_tspecs(wpa_s); +#endif /* CONFIG_NO_WMM_AC */ +#ifdef CONFIG_WNM + wpa_s->wnm_mode = 0; + wpa_s->wnm_target_bss = NULL; +#endif /* CONFIG_WNM */ wpa_s->reassoc_same_bss = 0; wpa_s->reassoc_same_ess = 0; #ifdef CONFIG_TESTING_OPTIONS @@ -2393,25 +2754,33 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS"); wpa_s->reassoc_same_ess = 1; if (wpa_s->current_bss && wpa_s->current_bss == bss) { +#ifndef CONFIG_NO_WMM_AC wmm_ac_save_tspecs(wpa_s); +#endif /* CONFIG_NO_WMM_AC */ wpa_s->reassoc_same_bss = 1; + clear_rejected = false; } else if (wpa_s->current_bss && wpa_s->current_bss != bss) { os_get_reltime(&wpa_s->roam_start); } - } else { -#ifdef CONFIG_SAE - wpa_s_clear_sae_rejected(wpa_s); -#endif /* CONFIG_SAE */ } + + if (clear_rejected) + wpa_s_clear_sae_rejected(wpa_s); + #ifdef CONFIG_SAE - wpa_s_setup_sae_pt(wpa_s->conf, ssid); + wpa_s_setup_sae_pt(wpa_s->conf, ssid, false); #endif /* CONFIG_SAE */ - if (rand_style > 0 && !wpa_s->reassoc_same_ess) { - if (wpas_update_random_addr(wpa_s, rand_style) < 0) + if (rand_style > WPAS_MAC_ADDR_STYLE_PERMANENT) { + int status = wpas_update_random_addr(wpa_s, rand_style, ssid); + + if (status < 0) return; - wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); - } else if (rand_style == 0 && wpa_s->mac_addr_changed) { + if (rand_style != WPAS_MAC_ADDR_STYLE_DEDICATED_PER_ESS && + status > 0) /* MAC changed */ + wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid); + } else if (rand_style == WPAS_MAC_ADDR_STYLE_PERMANENT && + wpa_s->mac_addr_changed) { if (wpas_restore_permanent_mac_addr(wpa_s) < 0) return; } @@ -2461,6 +2830,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, if (bss) ssid->frequency = bss->freq; if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) { + wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh"); return; } @@ -2583,116 +2953,142 @@ static bool ibss_mesh_is_80mhz_avail(int channel, struct hostapd_hw_modes *mode) } -void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, - const struct wpa_ssid *ssid, - struct hostapd_freq_params *freq) +static struct wpa_bss * ibss_find_existing_bss(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid) { - int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode); - enum hostapd_hw_mode hw_mode; - struct hostapd_hw_modes *mode = NULL; - int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157, - 184, 192 }; - int bw80[] = { 5180, 5260, 5500, 5580, 5660, 5745, 5955, - 6035, 6115, 6195, 6275, 6355, 6435, 6515, - 6595, 6675, 6755, 6835, 6915, 6995 }; - int bw160[] = { 5955, 6115, 6275, 6435, 6595, 6755, 6915 }; - struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL; - u8 channel; - int i, chan_idx, ht40 = -1, res, obss_scan = 1; - unsigned int j, k; - struct hostapd_freq_params vht_freq; - int chwidth, seg0, seg1; - u32 vht_caps = 0; - bool is_24ghz, is_6ghz; - - freq->freq = ssid->frequency; + unsigned int j; for (j = 0; j < wpa_s->last_scan_res_used; j++) { struct wpa_bss *bss = wpa_s->last_scan_res[j]; - if (ssid->mode != WPAS_MODE_IBSS) - break; - - /* Don't adjust control freq in case of fixed_freq */ - if (ssid->fixed_freq) - break; - if (!bss_is_ibss(bss)) continue; if (ssid->ssid_len == bss->ssid_len && - os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0) { - wpa_printf(MSG_DEBUG, - "IBSS already found in scan results, adjust control freq: %d", - bss->freq); - freq->freq = bss->freq; - obss_scan = 0; - break; - } + os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0) + return bss; } + return NULL; +} + +static bool ibss_mesh_can_use_ht(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + struct hostapd_hw_modes *mode) +{ /* For IBSS check HT_IBSS flag */ if (ssid->mode == WPAS_MODE_IBSS && !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS)) - return; + return false; if (wpa_s->group_cipher == WPA_CIPHER_WEP40 || wpa_s->group_cipher == WPA_CIPHER_WEP104 || wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) { wpa_printf(MSG_DEBUG, "IBSS: WEP/TKIP detected, do not try to enable HT"); - return; + return false; } - hw_mode = ieee80211_freq_to_chan(freq->freq, &channel); - for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) { - if (wpa_s->hw.modes[i].mode == hw_mode) { - mode = &wpa_s->hw.modes[i]; - break; - } - } + if (!ht_supported(mode)) + return false; - if (!mode) - return; +#ifdef CONFIG_HT_OVERRIDES + if (ssid->disable_ht) + return false; +#endif /* CONFIG_HT_OVERRIDES */ - freq->channel = channel; + return true; +} - is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G || - hw_mode == HOSTAPD_MODE_IEEE80211B; - /* HT/VHT and corresponding overrides are not applicable to 6 GHz. - * However, HE is mandatory for 6 GHz. - */ - is_6ghz = is_6ghz_freq(freq->freq); - if (is_6ghz) - goto skip_to_6ghz; +static bool ibss_mesh_can_use_vht(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + struct hostapd_hw_modes *mode) +{ + if (mode->mode != HOSTAPD_MODE_IEEE80211A) + return false; -#ifdef CONFIG_HT_OVERRIDES - if (ssid->disable_ht) { - freq->ht_enabled = 0; - return; - } -#endif /* CONFIG_HT_OVERRIDES */ + if (!drv_supports_vht(wpa_s, ssid)) + return false; - freq->ht_enabled = ht_supported(mode); - if (!freq->ht_enabled) - return; + /* For IBSS check VHT_IBSS flag */ + if (ssid->mode == WPAS_MODE_IBSS && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS)) + return false; + + if (!vht_supported(mode)) + return false; + +#ifdef CONFIG_VHT_OVERRIDES + if (ssid->disable_vht) + return false; +#endif /* CONFIG_VHT_OVERRIDES */ - /* Allow HE on 2.4 GHz without VHT: see nl80211_put_freq_params() */ - if (is_24ghz) - freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported; + return true; +} + + +static bool ibss_mesh_can_use_he(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + const struct hostapd_hw_modes *mode, + int ieee80211_mode) +{ #ifdef CONFIG_HE_OVERRIDES - if (is_24ghz && ssid->disable_he) - freq->he_enabled = 0; + if (ssid->disable_he) + return false; #endif /* CONFIG_HE_OVERRIDES */ - /* Setup higher BW only for 5 GHz */ - if (mode->mode != HOSTAPD_MODE_IEEE80211A) + switch (mode->mode) { + case HOSTAPD_MODE_IEEE80211G: + case HOSTAPD_MODE_IEEE80211B: + case HOSTAPD_MODE_IEEE80211A: + return mode->he_capab[ieee80211_mode].he_supported; + default: + return false; + } +} + + +static bool ibss_mesh_can_use_eht(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + const struct hostapd_hw_modes *mode, + int ieee80211_mode) +{ + if (ssid->disable_eht) + return false; + + switch(mode->mode) { + case HOSTAPD_MODE_IEEE80211G: + case HOSTAPD_MODE_IEEE80211B: + case HOSTAPD_MODE_IEEE80211A: + return mode->eht_capab[ieee80211_mode].eht_supported; + default: + return false; + } +} + + +static void ibss_mesh_select_40mhz(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + struct hostapd_hw_modes *mode, + struct hostapd_freq_params *freq, + int obss_scan) { + int chan_idx; + struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL; + int i, res; + unsigned int j; + static const int ht40plus[] = { + 36, 44, 52, 60, 100, 108, 116, 124, 132, 140, + 149, 157, 165, 173, 184, 192 + }; + int ht40 = -1; + + if (!freq->ht_enabled) return; for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) { pri_chan = &mode->channels[chan_idx]; - if (pri_chan->chan == channel) + if (pri_chan->chan == freq->channel) break; pri_chan = NULL; } @@ -2703,21 +3099,14 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR)) return; - freq->channel = pri_chan->chan; - #ifdef CONFIG_HT_OVERRIDES - if (ssid->disable_ht40) { -#ifdef CONFIG_VHT_OVERRIDES - if (ssid->disable_vht) - return; -#endif /* CONFIG_VHT_OVERRIDES */ - goto skip_ht40; - } -#endif /* CONFIG_HT_OVERRIDES */ + if (ssid->disable_ht40) + return; +#endif /* Check/setup HT40+/HT40- */ for (j = 0; j < ARRAY_SIZE(ht40plus); j++) { - if (ht40plus[j] == channel) { + if (ht40plus[j] == freq->channel) { ht40 = 1; break; } @@ -2726,7 +3115,7 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, /* Find secondary channel */ for (i = 0; i < mode->num_channels; i++) { sec_chan = &mode->channels[i]; - if (sec_chan->chan == channel + ht40 * 4) + if (sec_chan->chan == freq->channel + ht40 * 4) break; sec_chan = NULL; } @@ -2749,7 +3138,8 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, if (obss_scan) { struct wpa_scan_results *scan_res; - scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0); + scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0, + NULL); if (scan_res == NULL) { /* Back to HT20 */ freq->sec_channel_offset = 0; @@ -2779,38 +3169,48 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, wpa_scan_results_free(scan_res); } -#ifdef CONFIG_HT_OVERRIDES -skip_ht40: -#endif /* CONFIG_HT_OVERRIDES */ wpa_printf(MSG_DEBUG, "IBSS/mesh: setup freq channel %d, sec_channel_offset %d", freq->channel, freq->sec_channel_offset); +} - if (!drv_supports_vht(wpa_s, ssid)) - return; - /* For IBSS check VHT_IBSS flag */ - if (ssid->mode == WPAS_MODE_IBSS && - !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS)) - return; +static bool ibss_mesh_select_80_160mhz(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + struct hostapd_hw_modes *mode, + struct hostapd_freq_params *freq, + int ieee80211_mode, bool is_6ghz) { + static const int bw80[] = { + 5180, 5260, 5500, 5580, 5660, 5745, 5825, + 5955, 6035, 6115, 6195, 6275, 6355, 6435, + 6515, 6595, 6675, 6755, 6835, 6915, 6995 + }; + static const int bw160[] = { + 5955, 6115, 6275, 6435, 6595, 6755, 6915 + }; + struct hostapd_freq_params vht_freq; + int i; + unsigned int j, k; + int chwidth, seg0, seg1; + u32 vht_caps = 0; + u8 channel = freq->channel; -#ifdef CONFIG_VHT_OVERRIDES - if (ssid->disable_vht) { - freq->vht_enabled = 0; - return; - } -#endif /* CONFIG_VHT_OVERRIDES */ + if (!freq->vht_enabled && !freq->he_enabled) + return true; -skip_to_6ghz: vht_freq = *freq; - /* 6 GHz does not have VHT enabled, so allow that exception here. */ - vht_freq.vht_enabled = vht_supported(mode); - if (!vht_freq.vht_enabled && !is_6ghz) - return; - - /* Enable HE with VHT for 5 GHz */ - freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported; + chwidth = CONF_OPER_CHWIDTH_USE_HT; + seg0 = freq->channel + 2 * freq->sec_channel_offset; + seg1 = 0; + if (freq->sec_channel_offset == 0) { + seg0 = 0; + /* Don't try 80 MHz if 40 MHz failed, except in 6 GHz */ + if (freq->ht_enabled && !is_6ghz) + goto skip_80mhz; + } + if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_USE_HT) + goto skip_80mhz; /* setup center_freq1, bandwidth */ for (j = 0; j < ARRAY_SIZE(bw80); j++) { @@ -2821,36 +3221,34 @@ skip_to_6ghz: if (j == ARRAY_SIZE(bw80) || ieee80211_freq_to_chan(bw80[j], &channel) == NUM_HOSTAPD_MODES) - return; + goto skip_80mhz; - /* Back to HT configuration if channel not usable */ + /* Use 40 MHz if channel not usable */ if (!ibss_mesh_is_80mhz_avail(channel, mode)) - return; + goto skip_80mhz; - chwidth = CHANWIDTH_80MHZ; + chwidth = CONF_OPER_CHWIDTH_80MHZ; seg0 = channel + 6; seg1 = 0; + /* In 160 MHz, the initial four 20 MHz channels were validated + * above. If 160 MHz is supported, check the remaining four 20 MHz + * channels for the total of 160 MHz bandwidth for 6 GHz. + */ if ((mode->he_capab[ieee80211_mode].phy_cap[ HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & - HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G) && is_6ghz) { - /* In 160 MHz, the initial four 20 MHz channels were validated - * above; check the remaining four 20 MHz channels for the total - * of 160 MHz bandwidth. - */ - if (!ibss_mesh_is_80mhz_avail(channel + 16, mode)) - return; - + HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G) && is_6ghz && + ibss_mesh_is_80mhz_avail(channel + 16, mode)) { for (j = 0; j < ARRAY_SIZE(bw160); j++) { if (freq->freq == bw160[j]) { - chwidth = CHANWIDTH_160MHZ; + chwidth = CONF_OPER_CHWIDTH_160MHZ; seg0 = channel + 14; break; } } } - if (ssid->max_oper_chwidth == CHANWIDTH_80P80MHZ) { + if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) { /* setup center_freq2, bandwidth */ for (k = 0; k < ARRAY_SIZE(bw80); k++) { /* Only accept 80 MHz segments separated by a gap */ @@ -2859,7 +3257,7 @@ skip_to_6ghz: if (ieee80211_freq_to_chan(bw80[k], &channel) == NUM_HOSTAPD_MODES) - return; + break; for (i = channel; i < channel + 16; i += 4) { struct hostapd_channel_data *chan; @@ -2874,54 +3272,109 @@ skip_to_6ghz: continue; /* Found a suitable second segment for 80+80 */ - chwidth = CHANWIDTH_80P80MHZ; + chwidth = CONF_OPER_CHWIDTH_80P80MHZ; if (!is_6ghz) vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; seg1 = channel + 6; } - if (chwidth == CHANWIDTH_80P80MHZ) + if (chwidth == CONF_OPER_CHWIDTH_80P80MHZ) break; } - } else if (ssid->max_oper_chwidth == CHANWIDTH_160MHZ) { + } else if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) { if (freq->freq == 5180) { - chwidth = CHANWIDTH_160MHZ; + chwidth = CONF_OPER_CHWIDTH_160MHZ; vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; seg0 = 50; } else if (freq->freq == 5520) { - chwidth = CHANWIDTH_160MHZ; + chwidth = CONF_OPER_CHWIDTH_160MHZ; vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; seg0 = 114; } - } else if (ssid->max_oper_chwidth == CHANWIDTH_USE_HT) { - chwidth = CHANWIDTH_USE_HT; - seg0 = channel + 2; -#ifdef CONFIG_HT_OVERRIDES - if (ssid->disable_ht40) - seg0 = 0; -#endif /* CONFIG_HT_OVERRIDES */ } -#ifdef CONFIG_HE_OVERRIDES - if (ssid->disable_he) { - vht_freq.he_enabled = 0; - freq->he_enabled = 0; - } -#endif /* CONFIG_HE_OVERRIDES */ +skip_80mhz: if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq, freq->channel, ssid->enable_edmg, ssid->edmg_channel, freq->ht_enabled, - vht_freq.vht_enabled, freq->he_enabled, + freq->vht_enabled, freq->he_enabled, + freq->eht_enabled, freq->sec_channel_offset, chwidth, seg0, seg1, vht_caps, - &mode->he_capab[ieee80211_mode]) != 0) - return; + &mode->he_capab[ieee80211_mode], + &mode->eht_capab[ieee80211_mode], 0) != 0) + return false; *freq = vht_freq; wpa_printf(MSG_DEBUG, "IBSS: VHT setup freq cf1 %d, cf2 %d, bw %d", freq->center_freq1, freq->center_freq2, freq->bandwidth); + return true; +} + + +void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, + const struct wpa_ssid *ssid, + struct hostapd_freq_params *freq) +{ + int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode); + enum hostapd_hw_mode hw_mode; + struct hostapd_hw_modes *mode = NULL; + int obss_scan = 1; + u8 channel; + bool is_6ghz, is_24ghz; + + freq->freq = ssid->frequency; + + if (ssid->mode == WPAS_MODE_IBSS && !ssid->fixed_freq) { + struct wpa_bss *bss = ibss_find_existing_bss(wpa_s, ssid); + + if (bss) { + wpa_printf(MSG_DEBUG, + "IBSS already found in scan results, adjust control freq: %d", + bss->freq); + freq->freq = bss->freq; + obss_scan = 0; + } + } + + hw_mode = ieee80211_freq_to_chan(freq->freq, &channel); + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, + hw_mode, is_6ghz_freq(ssid->frequency)); + + if (!mode) + return; + + is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G || + hw_mode == HOSTAPD_MODE_IEEE80211B; + + is_6ghz = is_6ghz_freq(freq->freq); + + freq->ht_enabled = 0; + freq->vht_enabled = 0; + freq->he_enabled = 0; + freq->eht_enabled = 0; + + if (!is_6ghz) + freq->ht_enabled = ibss_mesh_can_use_ht(wpa_s, ssid, mode); + if (freq->ht_enabled) + freq->vht_enabled = ibss_mesh_can_use_vht(wpa_s, ssid, mode); + if (freq->vht_enabled || (freq->ht_enabled && is_24ghz) || is_6ghz) + freq->he_enabled = ibss_mesh_can_use_he(wpa_s, ssid, mode, + ieee80211_mode); + freq->channel = channel; + /* Setup higher BW only for 5 GHz */ + if (mode->mode == HOSTAPD_MODE_IEEE80211A) { + ibss_mesh_select_40mhz(wpa_s, ssid, mode, freq, obss_scan); + if (!ibss_mesh_select_80_160mhz(wpa_s, ssid, mode, freq, + ieee80211_mode, is_6ghz)) + freq->he_enabled = freq->vht_enabled = false; + } + + if (freq->he_enabled) + freq->eht_enabled = ibss_mesh_can_use_eht(wpa_s, ssid, mode, + ieee80211_mode); } @@ -3016,6 +3469,29 @@ int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s) #endif /* CONFIG_FILS */ +bool wpa_is_non_eht_scs_traffic_desc_supported(struct wpa_bss *bss) +{ + const u8 *wfa_capa; + + if (!bss) + return false; + + /* Get WFA capability from Beacon or Probe Response frame elements */ + wfa_capa = wpa_bss_get_vendor_ie(bss, WFA_CAPA_IE_VENDOR_TYPE); + if (!wfa_capa) + wfa_capa = wpa_bss_get_vendor_ie_beacon( + bss, WFA_CAPA_IE_VENDOR_TYPE); + + if (!wfa_capa || wfa_capa[1] < 6 || wfa_capa[6] < 1 || + !(wfa_capa[7] & WFA_CAPA_QM_NON_EHT_SCS_TRAFFIC_DESC)) { + /* AP does not enable QM non EHT traffic description policy */ + return false; + } + + return true; +} + + static int wpas_populate_wfa_capa(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, u8 *wpa_ie, size_t wpa_ie_len, @@ -3026,8 +3502,13 @@ static int wpas_populate_wfa_capa(struct wpa_supplicant *wpa_s, size_t wfa_ie_len, buf_len; os_memset(wfa_capa, 0, sizeof(wfa_capa)); +#ifndef CONFIG_NO_ROBUST_AV if (wpa_s->enable_dscp_policy_capa) wfa_capa[0] |= WFA_CAPA_QM_DSCP_POLICY; +#endif /* CONFIG_NO_ROBUST_AV */ + + if (wpa_is_non_eht_scs_traffic_desc_supported(bss)) + wfa_capa[0] |= WFA_CAPA_QM_NON_EHT_SCS_TRAFFIC_DESC; if (!wfa_capa[0]) return wpa_ie_len; @@ -3106,6 +3587,16 @@ static u8 * wpas_populate_assoc_ies( wpa_key_mgmt_wpa(ssid->key_mgmt)) { int try_opportunistic; const u8 *cache_id = NULL; + const u8 *addr = bss->bssid; + + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO) && + !is_zero_ether_addr(bss->mld_addr)) + addr = bss->mld_addr; + + if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) && + wpa_s->valid_links) + addr = wpa_s->ap_mld_addr; try_opportunistic = (ssid->proactive_key_caching < 0 ? wpa_s->conf->okc : @@ -3115,9 +3606,9 @@ static u8 * wpas_populate_assoc_ies( if (wpa_key_mgmt_fils(ssid->key_mgmt)) cache_id = wpa_bss_get_fils_cache_id(bss); #endif /* CONFIG_FILS */ - if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, + if (pmksa_cache_set_current(wpa_s->wpa, NULL, addr, ssid, try_opportunistic, - cache_id, 0) == 0) { + cache_id, 0, false) == 0) { eapol_sm_notify_pmkid_attempt(wpa_s->eapol); #if defined(CONFIG_SAE) || defined(CONFIG_FILS) pmksa_cached = 1; @@ -3125,7 +3616,7 @@ static u8 * wpas_populate_assoc_ies( } wpa_ie_len = max_wpa_ie_len; if (wpa_supplicant_set_suites(wpa_s, bss, ssid, - wpa_ie, &wpa_ie_len)) { + wpa_ie, &wpa_ie_len, false)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA " "key management and encryption suites"); os_free(wpa_ie); @@ -3137,7 +3628,7 @@ static u8 * wpas_populate_assoc_ies( /* No PMKSA caching, but otherwise similar to RSN/WPA */ wpa_ie_len = max_wpa_ie_len; if (wpa_supplicant_set_suites(wpa_s, bss, ssid, - wpa_ie, &wpa_ie_len)) { + wpa_ie, &wpa_ie_len, false)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA " "key management and encryption suites"); os_free(wpa_ie); @@ -3157,7 +3648,7 @@ static u8 * wpas_populate_assoc_ies( } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) { wpa_ie_len = max_wpa_ie_len; if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, - wpa_ie, &wpa_ie_len)) { + wpa_ie, &wpa_ie_len, false)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA " "key management and encryption suites (no " "scan results)"); @@ -3287,12 +3778,14 @@ skip_add_p2p_ie: #endif /* CONFIG_MAGICLINK_PC */ #endif /* CONFIG_P2P */ +#ifndef CONFIG_NO_RRM if (bss) { wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss, wpa_ie + wpa_ie_len, max_wpa_ie_len - wpa_ie_len); } +#endif /* CONFIG_NO_RRM */ /* * Workaround: Add Extended Capabilities element only if the AP @@ -3311,7 +3804,7 @@ skip_add_p2p_ie: u8 ext_capab[18]; int ext_capab_len; ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab, - sizeof(ext_capab)); + sizeof(ext_capab), bss); if (ext_capab_len > 0 && wpa_ie_len + ext_capab_len <= max_wpa_ie_len) { u8 *pos = wpa_ie; @@ -3324,6 +3817,17 @@ skip_add_p2p_ie: } } + if (ssid->max_idle && wpa_ie_len + 5 <= max_wpa_ie_len) { + u8 *pos = wpa_ie; + + *pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD; + *pos++ = 3; + WPA_PUT_LE16(pos, ssid->max_idle); + pos += 2; + *pos = 0; /* Idle Options */ + wpa_ie_len += 5; + } + #ifdef CONFIG_HS20 if (is_hs20_network(wpa_s, ssid, bss)) { struct wpabuf *hs20; @@ -3404,7 +3908,8 @@ skip_add_p2p_ie: } else #endif /* CONFIG_TESTING_OPTIONS */ if (algs == WPA_AUTH_ALG_OPEN && - ssid->key_mgmt == WPA_KEY_MGMT_OWE) { + ssid->key_mgmt == WPA_KEY_MGMT_OWE && + !(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA)) { struct wpabuf *owe_ie; u16 group; @@ -3488,7 +3993,7 @@ pfs_fail: } #ifdef CONFIG_SME if (len > 0 && wpa_s->sme.ft_used && - wpa_sm_has_ptk(wpa_s->wpa)) { + wpa_sm_has_ft_keys(wpa_s->wpa, md)) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT over-the-air"); algs |= WPA_AUTH_ALG_FT; @@ -3515,6 +4020,7 @@ pfs_fail: wpa_ie_len += wpa_s->rsnxe_len; } +#ifndef CONFIG_NO_ROBUST_AV #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->disable_mscs_support) goto mscs_end; @@ -3549,16 +4055,21 @@ pfs_fail: wpabuf_free(mscs_ie); } mscs_end: +#endif /* CONFIG_NO_ROBUST_AV */ wpa_ie_len = wpas_populate_wfa_capa(wpa_s, bss, wpa_ie, wpa_ie_len, max_wpa_ie_len); if (ssid->multi_ap_backhaul_sta) { size_t multi_ap_ie_len; + struct multi_ap_params multi_ap = { 0 }; + + multi_ap.capability = MULTI_AP_BACKHAUL_STA; + multi_ap.profile = ssid->multi_ap_profile; multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len, max_wpa_ie_len - wpa_ie_len, - MULTI_AP_BACKHAUL_STA); + &multi_ap); if (multi_ap_ie_len == 0) { wpa_printf(MSG_ERROR, "Multi-AP: Failed to build Multi-AP IE"); @@ -3776,11 +4287,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) int use_crypt, ret, bssid_changed; unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt; struct wpa_driver_associate_params params; + u8 psk[PMK_LEN]; #if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL) int wep_keys_set = 0; #endif /* CONFIG_WEP || IEEE8021X_EAPOL */ int assoc_failed = 0; - struct wpa_ssid *old_ssid; + struct wpa_ssid *old_ssid = NULL; u8 prev_bssid[ETH_ALEN]; #ifdef CONFIG_HT_OVERRIDES struct ieee80211_ht_capabilities htcaps; @@ -3817,7 +4329,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) return; } -#ifdef CONFIG_MLD_PATCH /* * Set the current AP's BSSID (for non-MLO connection) or MLD address * (for MLO connection) as the previous BSSID for reassociation requests @@ -3828,9 +4339,6 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) os_memcpy(prev_bssid, wpa_s->valid_links ? wpa_s->ap_mld_addr : wpa_s->bssid, ETH_ALEN); -#else - os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN); -#endif os_memset(¶ms, 0, sizeof(params)); wpa_s->reassociate = 0; wpa_s->eap_expected_failure = 0; @@ -3840,7 +4348,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) 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; +#ifndef CONFIG_NO_ROBUST_AV wpa_s->mscs_setup_done = false; +#endif /* CONFIG_NO_ROBUST_AV */ wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, ¶ms, NULL); if (!wpa_ie) { @@ -4009,6 +4519,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) wpa_supplicant_set_wpa_none_key(wpa_s, ssid); } + /* Set current_ssid before changing state to ASSOCIATING, so that the + * selected SSID is available to wpas_notify_state_changed(). */ + old_ssid = wpa_s->current_ssid; + wpa_s->current_ssid = ssid; + #ifdef CONFIG_WAPI if ((ssid->key_mgmt != WPA_KEY_MGMT_WAPI_PSK) || (ssid->key_mgmt != WPA_KEY_MGMT_WAPI_CERT)) { @@ -4135,6 +4650,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.group_suite = cipher_group; params.mgmt_group_suite = cipher_group_mgmt; params.key_mgmt_suite = wpa_s->key_mgmt; + params.allowed_key_mgmts = wpa_s->allowed_key_mgmts; params.wpa_proto = wpa_s->wpa_proto; wpa_s->auth_alg = params.auth_alg; params.mode = ssid->mode; @@ -4154,35 +4670,50 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) && (params.key_mgmt_suite == WPA_KEY_MGMT_PSK || - params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) { + params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK || + (params.allowed_key_mgmts & + (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)))) { params.passphrase = ssid->passphrase; - if (ssid->psk_set) - params.psk = ssid->psk; + if (wpa_supplicant_get_psk(wpa_s, bss, ssid, psk) == 0) + params.psk = psk; } if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) && (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 || params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B || - params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) + params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 || + params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384)) params.req_handshake_offload = 1; if (wpa_s->conf->key_mgmt_offload) { if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 || params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B || - params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + params.key_mgmt_suite == + WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 || + params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA384) params.req_key_mgmt_offload = ssid->proactive_key_caching < 0 ? wpa_s->conf->okc : ssid->proactive_key_caching; else params.req_key_mgmt_offload = 1; - if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK || - params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 || - params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) && - ssid->psk_set) - params.psk = ssid->psk; + if ((wpa_key_mgmt_wpa_psk_no_sae(params.key_mgmt_suite) || + wpa_key_mgmt_wpa_psk_no_sae(params.allowed_key_mgmts)) && + wpa_supplicant_get_psk(wpa_s, bss, ssid, psk) == 0) + params.psk = psk; + } + + if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA) && + wpa_key_mgmt_sae(params.key_mgmt_suite)) { + params.auth_alg = WPA_AUTH_ALG_SAE; + if (ssid->sae_password) { + params.sae_password = ssid->sae_password; + params.sae_password_id = ssid->sae_password_id; + } else if (ssid->passphrase) { + params.passphrase = ssid->passphrase; + } } params.drop_unencrypted = use_crypt; @@ -4191,7 +4722,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) { const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); struct wpa_ie_data ie; - if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 && + if (!wpas_driver_bss_selection(wpa_s) && rsn && + wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 && ie.capabilities & (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) { wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports " @@ -4230,6 +4762,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) #ifdef CONFIG_HE_OVERRIDES wpa_supplicant_apply_he_overrides(wpa_s, ssid, ¶ms); #endif /* CONFIG_HE_OVERRIDES */ + wpa_supplicant_apply_eht_overrides(wpa_s, ssid, ¶ms); #ifdef CONFIG_P2P /* @@ -4239,7 +4772,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) */ if (wpa_s->num_multichan_concurrent < 2) { int freq, num; - num = get_shared_radio_freqs(wpa_s, &freq, 1); + num = get_shared_radio_freqs(wpa_s, &freq, 1, false); if (num > 0 && freq > 0 && freq != params.freq.freq) { wpa_printf(MSG_DEBUG, "Assoc conflicting freq found (%d != %d)", @@ -4255,7 +4788,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) #endif /* CONFIG_P2P */ if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) && - wpa_s->current_ssid) + old_ssid) params.prev_bssid = prev_bssid; #ifdef CONFIG_SAE @@ -4272,6 +4805,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } #endif ret = wpa_drv_associate(wpa_s, ¶ms); + forced_memzero(psk, sizeof(psk)); os_free(wpa_ie); if (ret < 0) { wpa_msg(wpa_s, MSG_INFO, "Association request to the driver " @@ -4282,11 +4816,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) * can stop right here; the association will not * succeed. */ -#ifdef CONFIG_MLD_PATCH - wpas_connection_failed(wpa_s, wpa_s->pending_bssid, NULL); -#else - wpas_connection_failed(wpa_s, wpa_s->pending_bssid); -#endif + wpas_connection_failed(wpa_s, wpa_s->pending_bssid, + NULL); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); #ifdef CONFIG_P2P_CHR wpa_supplicant_upload_p2p_state(wpa_s, @@ -4348,7 +4879,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) } #endif /* CONFIG_WEP */ - if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) { + if (old_ssid && old_ssid != ssid) { /* * Do not allow EAP session resumption between different * network configurations. @@ -4358,10 +4889,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) #ifdef CONFIG_WAPI } #endif - old_ssid = wpa_s->current_ssid; - wpa_s->current_ssid = ssid; - if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) { + if (!wpas_driver_bss_selection(wpa_s) || +#ifdef CONFIG_P2P + wpa_s->p2p_in_invitation || +#endif /* CONFIG_P2P */ + ssid->bssid_set) { wpa_s->current_bss = bss; #ifdef CONFIG_HS20 hs20_configure_frame_filters(wpa_s); @@ -4372,12 +4905,16 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) #endif wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); + if (bss) + wpa_sm_set_ssid(wpa_s->wpa, bss->ssid, bss->ssid_len); wpa_supplicant_initiate_eapol(wpa_s); #ifdef CONFIG_WAPI } #endif if (old_ssid != wpa_s->current_ssid) wpas_notify_network_changed(wpa_s); + if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) + wpas_notify_auth_changed(wpa_s); } @@ -4386,6 +4923,8 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s, { struct wpa_ssid *old_ssid; + wpa_s->ml_connect_probe_ssid = NULL; + wpa_s->ml_connect_probe_bss = NULL; wpas_connect_work_done(wpa_s); wpa_clear_keys(wpa_s, addr); old_ssid = wpa_s->current_ssid; @@ -4395,8 +4934,10 @@ static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s, if (old_ssid != wpa_s->current_ssid) wpas_notify_network_changed(wpa_s); +#ifndef CONFIG_NO_ROBUST_AV wpas_scs_deinit(wpa_s); wpas_dscp_deinit(wpa_s); +#endif /* CONFIG_NO_ROBUST_AV */ eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); } @@ -4417,25 +4958,25 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, int zero_addr = 0; wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR - " pending_bssid=" MACSTR " reason=%d (%s) state=%s", + " pending_bssid=" MACSTR + " reason=%d (%s) state=%s valid_links=0x%x ap_mld_addr=" MACSTR, MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid), reason_code, reason2str(reason_code), - wpa_supplicant_state_txt(wpa_s->wpa_state)); + wpa_supplicant_state_txt(wpa_s->wpa_state), wpa_s->valid_links, + MAC2STR(wpa_s->ap_mld_addr)); wpa_printf(MSG_WARNING, "Request to deauthenticate - bssid=" MACSTR_SEC - " pending_bssid=" MACSTR_SEC " reason=%d (%s) state=%s", + " pending_bssid=" MACSTR_SEC + " reason=%d (%s) state=%s valid_links=0x%x ap_mld_addr=" MACSTR_SEC, MAC2STR_SEC(wpa_s->bssid), MAC2STR_SEC(wpa_s->pending_bssid), reason_code, reason2str(reason_code), - wpa_supplicant_state_txt(wpa_s->wpa_state)); + wpa_supplicant_state_txt(wpa_s->wpa_state), wpa_s->valid_links, + MAC2STR_SEC(wpa_s->ap_mld_addr)); -#ifdef CONFIG_MLD_PATCH if (wpa_s->valid_links && !is_zero_ether_addr(wpa_s->ap_mld_addr)) addr = wpa_s->ap_mld_addr; else if (!is_zero_ether_addr(wpa_s->pending_bssid) && -#else - if (!is_zero_ether_addr(wpa_s->pending_bssid) && -#endif - (wpa_s->wpa_state == WPA_AUTHENTICATING || - wpa_s->wpa_state == WPA_ASSOCIATING)) + (wpa_s->wpa_state == WPA_AUTHENTICATING || + wpa_s->wpa_state == WPA_ASSOCIATING)) addr = wpa_s->pending_bssid; else if (!is_zero_ether_addr(wpa_s->bssid)) addr = wpa_s->bssid; @@ -4553,7 +5094,7 @@ struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s) */ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id) { - struct wpa_ssid *ssid; + struct wpa_ssid *ssid, *prev = wpa_s->current_ssid; int was_disabled; ssid = wpa_config_get_network(wpa_s->conf, id); @@ -4561,10 +5102,7 @@ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id) return -1; wpas_notify_network_removed(wpa_s, ssid); - if (wpa_s->last_ssid == ssid) - wpa_s->last_ssid = NULL; - - if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) { + if (ssid == prev || !prev) { #ifdef CONFIG_SME wpa_s->sme.prev_bssid_set = 0; #endif /* CONFIG_SME */ @@ -4575,7 +5113,7 @@ int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id) eapol_sm_invalidate_cached_session(wpa_s->eapol); } - if (ssid == wpa_s->current_ssid) { + if (ssid == prev) { wpa_sm_set_config(wpa_s->wpa, NULL); eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); @@ -4616,6 +5154,11 @@ int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s) { struct wpa_ssid *ssid; + if (wpa_s->drv_flags2 & + (WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA | + WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA)) + wpa_drv_flush_pmkid(wpa_s); + if (wpa_s->sched_scanning) wpa_supplicant_cancel_sched_scan(wpa_s); @@ -4638,8 +5181,6 @@ int wpa_supplicant_remove_all_networks(struct wpa_supplicant *wpa_s) 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); } @@ -4795,7 +5336,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, wpa_s->current_ssid = ssid; eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); wpa_s->connect_without_scan = - (ssid->mode == WPAS_MODE_MESH) ? ssid : NULL; + (ssid->mode == WPAS_MODE_MESH || + ssid->mode == WPAS_MODE_AP) ? ssid : NULL; /* * Don't optimize next scan freqs since a new ESS has been @@ -4813,7 +5355,7 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, wpa_s->last_owe_group = 0; if (ssid) { ssid->owe_transition_bss_select_count = 0; - wpa_s_setup_sae_pt(wpa_s->conf, ssid); + wpa_s_setup_sae_pt(wpa_s->conf, ssid, false); } if (wpa_s->connect_without_scan || @@ -5186,29 +5728,30 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s) os_memcmp(ssid, entry->ssid, ssid_len) == 0)) || wired) && (!entry->bssid_set || - os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) + ether_addr_equal(bssid, entry->bssid))) return entry; #ifdef CONFIG_WPS if (!wpas_network_disabled(wpa_s, entry) && (entry->key_mgmt & WPA_KEY_MGMT_WPS) && (entry->ssid == NULL || entry->ssid_len == 0) && (!entry->bssid_set || - os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) + ether_addr_equal(bssid, entry->bssid))) return entry; #endif /* CONFIG_WPS */ #ifdef CONFIG_OWE if (!wpas_network_disabled(wpa_s, entry) && - owe_trans_ssid_match(wpa_s, bssid, entry->ssid, - entry->ssid_len) && + (entry->ssid && + owe_trans_ssid_match(wpa_s, bssid, entry->ssid, + entry->ssid_len)) && (!entry->bssid_set || - os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) + ether_addr_equal(bssid, entry->bssid))) return entry; #endif /* CONFIG_OWE */ if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set && entry->ssid_len == 0 && - os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0) + ether_addr_equal(bssid, entry->bssid)) return entry; entry = entry->next; @@ -5299,6 +5842,7 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s, * @src_addr: Source address of the EAPOL frame * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header) * @len: Length of the EAPOL data + * @encrypted: Whether the frame was encrypted * * This function is called for each received EAPOL frame. Most driver * interfaces rely on more generic OS mechanism for receiving frames through @@ -5307,11 +5851,15 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s, * code by calling this function. */ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len) + const u8 *buf, size_t len, + enum frame_encryption encrypted) { struct wpa_supplicant *wpa_s = ctx; + const u8 *connected_addr = wpa_s->valid_links ? + wpa_s->ap_mld_addr : wpa_s->bssid; - wpa_dbg(wpa_s, MSG_WARNING, "RX EAPOL from " MACSTR, MAC2STR(src_addr)); + wpa_dbg(wpa_s, MSG_WARNING, "RX EAPOL from " MACSTR " (encrypted=%d)", + MAC2STR(src_addr), encrypted); wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len); if (wpa_s->own_disconnect_req) { @@ -5321,7 +5869,8 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, } #ifdef CONFIG_TESTING_OPTIONS - wpa_msg_ctrl(wpa_s, MSG_INFO, "EAPOL-RX " MACSTR " %zu", MAC2STR(src_addr), len); + wpa_msg_ctrl(wpa_s, MSG_INFO, "EAPOL-RX " MACSTR " %zu", + MAC2STR(src_addr), len); if (wpa_s->ignore_auth_resp) { wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!"); return; @@ -5333,7 +5882,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, #ifdef CONFIG_AP !wpa_s->ap_iface && #endif /* CONFIG_AP */ - os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) { + !ether_addr_equal(src_addr, connected_addr))) { /* * There is possible race condition between receiving the * association event and the EAPOL frame since they are coming @@ -5346,26 +5895,29 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, * Authenticator uses BSSID as the src_addr (which is not the * case with wired IEEE 802.1X). */ - wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing " - "of received EAPOL frame (state=%s bssid=" MACSTR ")", + wpa_dbg(wpa_s, MSG_DEBUG, + "Not associated - Delay processing of received EAPOL frame (state=%s connected_addr=" + MACSTR ")", wpa_supplicant_state_txt(wpa_s->wpa_state), - MAC2STR(wpa_s->bssid)); + MAC2STR(connected_addr)); wpabuf_free(wpa_s->pending_eapol_rx); wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len); if (wpa_s->pending_eapol_rx) { os_get_reltime(&wpa_s->pending_eapol_rx_time); os_memcpy(wpa_s->pending_eapol_rx_src, src_addr, ETH_ALEN); + wpa_s->pending_eapol_encrypted = encrypted; } return; } wpa_s->last_eapol_matches_bssid = - os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0; + ether_addr_equal(src_addr, connected_addr); #ifdef CONFIG_AP if (wpa_s->ap_iface) { - wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len); + wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len, + encrypted); return; } #endif /* CONFIG_AP */ @@ -5431,7 +5983,8 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, #ifdef CONFIG_IBSS_RSN if (wpa_s->current_ssid && wpa_s->current_ssid->mode == WPAS_MODE_IBSS) { - ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len); + ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len, + encrypted); return; } #endif /* CONFIG_IBSS_RSN */ @@ -5446,11 +5999,12 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) && wpa_s->key_mgmt != WPA_KEY_MGMT_OWE && wpa_s->key_mgmt != WPA_KEY_MGMT_DPP && - eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0) + eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len, + encrypted) > 0) return; wpa_drv_poll(wpa_s); if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) - wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len); + wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len, encrypted); else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { /* * Set portValid = true here since we are going to skip 4-way @@ -5463,6 +6017,14 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, } +static void wpa_supplicant_rx_eapol_cb(void *ctx, const u8 *src_addr, + const u8 *buf, size_t len) +{ + wpa_supplicant_rx_eapol(ctx, src_addr, buf, len, + FRAME_ENCRYPTION_UNKNOWN); +} + + static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s) { return !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) || @@ -5472,6 +6034,9 @@ static int wpas_eapol_needs_l2_packet(struct wpa_supplicant *wpa_s) int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s) { + u8 prev_mac_addr[ETH_ALEN]; + + os_memcpy(prev_mac_addr, wpa_s->own_addr, ETH_ALEN); #ifndef CONFIG_DRIVER_HDF if ((!wpa_s->p2p_mgmt || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) && @@ -5496,7 +6061,7 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s) wpa_drv_get_mac_addr(wpa_s), ETH_P_EAPOL, wpas_eapol_needs_l2_packet(wpa_s) ? - wpa_supplicant_rx_eapol : NULL, + wpa_supplicant_rx_eapol_cb : NULL, wpa_s, 0); #ifdef CONFIG_WAPI if (wpa_s->l2_wapi == NULL) { @@ -5545,6 +6110,8 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s) return -1; } #endif + if (!ether_addr_equal(prev_mac_addr, wpa_s->own_addr)) + wpas_notify_mac_address_changed(wpa_s); return 0; } @@ -5560,7 +6127,7 @@ static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr, return; eth = (const struct l2_ethhdr *) buf; - if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 && + if (!ether_addr_equal(eth->h_dest, wpa_s->own_addr) && !(eth->h_dest[0] & 0x01)) { wpa_msg_only_for_cb(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR " (bridge - not for this interface - ignore)", @@ -5576,7 +6143,7 @@ static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr, wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR_SEC " to " MACSTR_SEC " (bridge)", MAC2STR_SEC(src_addr), MAC2STR_SEC(eth->h_dest)); wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth), - len - sizeof(*eth)); + len - sizeof(*eth), FRAME_ENCRYPTION_UNKNOWN); } @@ -5758,8 +6325,12 @@ static struct wpa_supplicant *wpa_supplicant_alloc(struct wpa_supplicant *parent dl_list_init(&wpa_s->fils_hlp_req); #ifdef CONFIG_TESTING_OPTIONS dl_list_init(&wpa_s->drv_signal_override); + wpa_s->test_assoc_comeback_type = -1; #endif /* CONFIG_TESTING_OPTIONS */ +#ifndef CONFIG_NO_ROBUST_AV dl_list_init(&wpa_s->active_scs_ids); +#endif /* CONFIG_NO_ROBUST_AV */ + wpa_s->ml_probe_mld_id = -1; return wpa_s; } @@ -6135,6 +6706,17 @@ void wpa_supplicant_apply_he_overrides( #endif /* CONFIG_HE_OVERRIDES */ +void wpa_supplicant_apply_eht_overrides( + struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + struct wpa_driver_associate_params *params) +{ + if (!ssid) + return; + + params->disable_eht = ssid->disable_eht; +} + + static int pcsc_reader_init(struct wpa_supplicant *wpa_s) { #ifdef PCSC_FUNCS @@ -6260,7 +6842,7 @@ static int wpas_fst_send_action_cb(void *ctx, const u8 *da, struct wpabuf *data) { struct wpa_supplicant *wpa_s = ctx; - if (os_memcmp(wpa_s->bssid, da, ETH_ALEN) != 0) { + if (!ether_addr_equal(wpa_s->bssid, da)) { wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR_SEC " != da=" MACSTR_SEC, __func__, MAC2STR_SEC(wpa_s->bssid), MAC2STR_SEC(da)); return -1; @@ -6276,7 +6858,7 @@ static const struct wpabuf * wpas_fst_get_mb_ie_cb(void *ctx, const u8 *addr) { struct wpa_supplicant *wpa_s = ctx; - WPA_ASSERT(os_memcmp(wpa_s->bssid, addr, ETH_ALEN) == 0); + WPA_ASSERT(ether_addr_equal(wpa_s->bssid, addr)); return wpa_s->received_mb_ies; } @@ -6287,7 +6869,7 @@ static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr, struct wpa_supplicant *wpa_s = ctx; struct mb_ies_info info; - WPA_ASSERT(os_memcmp(wpa_s->bssid, addr, ETH_ALEN) == 0); + WPA_ASSERT(ether_addr_equal(wpa_s->bssid, addr)); if (!mb_ies_info_by_ies(&info, buf, size)) { wpabuf_free(wpa_s->received_mb_ies); @@ -6320,6 +6902,7 @@ static const u8 * wpas_fst_get_peer_next(void *ctx, void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s, struct fst_wpa_obj *iface_obj) { + os_memset(iface_obj, 0, sizeof(*iface_obj)); iface_obj->ctx = wpa_s; iface_obj->get_bssid = wpas_fst_get_bssid_cb; iface_obj->get_channel_info = wpas_fst_get_channel_info_cb; @@ -6847,7 +7430,7 @@ static int wpas_init_driver(struct wpa_supplicant *wpa_s, next_driver: if (wpa_supplicant_set_driver(wpa_s, driver) < 0) return -1; - + if (iface != NULL && wpa_s != NULL && wpa_s->driver != NULL) { wpa_printf(MSG_INFO, "set driver success, set driver: %s, get driver: %s", iface->driver, wpa_s->driver->name); @@ -6968,7 +7551,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, #else /* CONFIG_BACKEND_FILE */ wpa_s->confname = os_strdup(iface->confname); #endif /* CONFIG_BACKEND_FILE */ - wpa_s->conf = wpa_config_read(wpa_s->confname, NULL); + wpa_s->conf = wpa_config_read(wpa_s->confname, NULL, false); if (wpa_s->conf == NULL) { wpa_printf(MSG_ERROR, "Failed to read or parse " "configuration '%s'.", wpa_s->confname); @@ -6976,7 +7559,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, } wpa_s->confanother = os_rel2abs_path(iface->confanother); if (wpa_s->confanother && - !wpa_config_read(wpa_s->confanother, wpa_s->conf)) { + !wpa_config_read(wpa_s->confanother, wpa_s->conf, true)) { wpa_printf(MSG_ERROR, "Failed to read or parse configuration '%s'.", wpa_s->confanother); @@ -6991,12 +7574,24 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, os_free(wpa_s->conf->ctrl_interface); wpa_s->conf->ctrl_interface = os_strdup(iface->ctrl_interface); + if (!wpa_s->conf->ctrl_interface) { + wpa_printf(MSG_ERROR, + "Failed to duplicate control interface '%s'.", + iface->ctrl_interface); + return -1; + } } if (iface->driver_param) { os_free(wpa_s->conf->driver_param); wpa_s->conf->driver_param = os_strdup(iface->driver_param); + if (!wpa_s->conf->driver_param) { + wpa_printf(MSG_ERROR, + "Failed to duplicate driver param '%s'.", + iface->driver_param); + return -1; + } } if (iface->p2p_mgmt && !iface->ctrl_interface) { @@ -7022,11 +7617,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_VENDOR_EXT wpa_vendor_ext_init_wpa_iface(wpa_s); #endif - #ifdef CONFIG_MATCH_IFACE wpa_s->matched = iface->matched; #endif /* CONFIG_MATCH_IFACE */ @@ -7085,6 +7678,9 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, return -1; } + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_PREPEND_PMKID, + wpa_s->conf->ft_prepend_pmkid); + wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags, @@ -7105,6 +7701,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpa_s->hw_capab == CAPAB_NO_HT_VHT) wpa_s->hw_capab = CAPAB_HT; } + wpa_s->support_6ghz = wpas_is_6ghz_supported(wpa_s, false); } capa_res = wpa_drv_get_capa(wpa_s, &capa); @@ -7114,6 +7711,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpa_s->drv_flags2 = capa.flags2; wpa_s->drv_enc = capa.enc; wpa_s->drv_rrm_flags = capa.rrm_flags; + wpa_s->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs; wpa_s->probe_resp_offloads = capa.probe_resp_offloads; wpa_s->max_scan_ssids = capa.max_scan_ssids; wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids; @@ -7131,7 +7729,10 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpa_s->extended_capa_len = capa.extended_capa_len; wpa_s->num_multichan_concurrent = capa.num_multichan_concurrent; +#ifndef CONFIG_NO_WMM_AC wpa_s->wmm_ac_supported = capa.wmm_ac_supported; +#endif /* CONFIG_NO_WMM_AC */ + wpa_s->max_num_akms = capa.max_num_akms; if (capa.mac_addr_rand_scan_supported) wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN; @@ -7146,6 +7747,12 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpa_s->extended_capa[2] & 0x40) wpa_s->multi_bss_support = 1; } +#ifdef CONFIG_PASN + wpa_pasn_sm_set_caps(wpa_s->wpa, wpa_s->drv_flags2); +#endif /* CONFIG_PASN */ + wpa_sm_set_driver_bss_selection(wpa_s->wpa, + !!(wpa_s->drv_flags & + WPA_DRIVER_FLAGS_BSS_SELECTION)); #ifdef CONFIG_OHOS_P2P uint64_t drv_flags = 0; if (WifiWpaGetDrvFlags(wpa_s->drv_priv, &drv_flags) == SUCC) { @@ -7224,6 +7831,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, return -1; #endif /* CONFIG_DPP */ +#ifdef CONFIG_NAN_USD + if (wpas_nan_usd_init(wpa_s) < 0) + return -1; +#endif /* CONFIG_NAN_USD */ + if (wpa_supplicant_init_eapol(wpa_s) < 0) return -1; wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol); @@ -7296,7 +7908,9 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, if (wpas_init_ext_pw(wpa_s) < 0) return -1; +#ifndef CONFIG_NO_RRM wpas_rrm_reset(wpa_s); +#endif /* CONFIG_NO_RRM */ wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans); @@ -7612,6 +8226,7 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global, return wpa_s; } + /** * wpa_supplicant_remove_iface - Remove a network interface * @global: Pointer to global data from wpa_supplicant_init() @@ -7835,26 +8450,63 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) global->params.daemonize = params->daemonize; global->params.wait_for_monitor = params->wait_for_monitor; global->params.dbus_ctrl_interface = params->dbus_ctrl_interface; - if (params->pid_file) + + if (params->pid_file) { global->params.pid_file = os_strdup(params->pid_file); - if (params->ctrl_interface) + if (!global->params.pid_file) { + wpa_supplicant_deinit(global); + return NULL; + } + } + + if (params->ctrl_interface) { global->params.ctrl_interface = os_strdup(params->ctrl_interface); - if (params->ctrl_interface_group) + if (!global->params.ctrl_interface) { + wpa_supplicant_deinit(global); + return NULL; + } + } + + if (params->ctrl_interface_group) { global->params.ctrl_interface_group = os_strdup(params->ctrl_interface_group); - if (params->override_driver) + if (!global->params.ctrl_interface_group) { + wpa_supplicant_deinit(global); + return NULL; + } + } + + if (params->override_driver) { global->params.override_driver = os_strdup(params->override_driver); - if (params->override_ctrl_interface) + if (!global->params.override_driver) { + wpa_supplicant_deinit(global); + return NULL; + } + } + + if (params->override_ctrl_interface) { global->params.override_ctrl_interface = os_strdup(params->override_ctrl_interface); + if (!global->params.override_ctrl_interface) { + wpa_supplicant_deinit(global); + return NULL; + } + } + #ifdef CONFIG_MATCH_IFACE global->params.match_iface_count = params->match_iface_count; if (params->match_iface_count) { global->params.match_ifaces = os_calloc(params->match_iface_count, sizeof(struct wpa_interface)); + if (!global->params.match_ifaces) { + wpa_printf(MSG_ERROR, + "Failed to allocate match interfaces"); + wpa_supplicant_deinit(global); + return NULL; + } os_memcpy(global->params.match_ifaces, params->match_ifaces, params->match_iface_count * @@ -7862,9 +8514,15 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) } #endif /* CONFIG_MATCH_IFACE */ #ifdef CONFIG_P2P - if (params->conf_p2p_dev) + if (params->conf_p2p_dev) { global->params.conf_p2p_dev = os_strdup(params->conf_p2p_dev); + if (!global->params.conf_p2p_dev) { + wpa_printf(MSG_ERROR, "Failed to allocate conf p2p"); + wpa_supplicant_deinit(global); + return NULL; + } + } #endif /* CONFIG_P2P */ wpa_debug_level = global->params.wpa_debug_level = params->wpa_debug_level; @@ -8079,6 +8737,10 @@ 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); + if (wpa_s->conf->changed_parameters & CFG_CHANGED_FT_PREPEND_PMKID) + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_FT_PREPEND_PMKID, + wpa_s->conf->ft_prepend_pmkid); + #ifdef CONFIG_BGSCAN /* * We default to global bgscan parameters only when per-network bgscan @@ -8147,11 +8809,8 @@ static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s) } -void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid -#ifdef CONFIG_MLD_PATCH - , const u8 **link_bssids -#endif -) +void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid, + const u8 **link_bssids) { int timeout; int count; @@ -8180,13 +8839,12 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid "disconnected state"); return; } -#ifdef CONFIG_MLD_PATCH + /* Also mark links as failed */ while (link_bssids && *link_bssids) { wpa_bssid_ignore_add(wpa_s, *link_bssids); link_bssids++; } -#endif /* * Add the failed BSSID into the ignore list and speed up next scan @@ -8220,7 +8878,7 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid if (wpa_s->consecutive_conn_failures > 3 && wpa_s->current_ssid) { wpa_printf(MSG_INFO, "Continuous association failures - " "consider temporary network disabling"); - wpas_auth_failed(wpa_s, "CONN_FAILED"); + wpas_auth_failed(wpa_s, "CONN_FAILED", bssid); } /* * Multiple consecutive connection failures mean that other APs are @@ -8354,6 +9012,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_EAP_IDENTITY: os_free(eap->identity); eap->identity = (u8 *) os_strdup(value); + if (!eap->identity) + return -1; eap->identity_len = os_strlen(value); eap->pending_req_identity = 0; if (ssid == wpa_s->current_ssid) @@ -8362,6 +9022,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_EAP_PASSWORD: bin_clear_free(eap->password, eap->password_len); eap->password = (u8 *) os_strdup(value); + if (!eap->password) + return -1; eap->password_len = os_strlen(value); eap->pending_req_password = 0; if (ssid == wpa_s->current_ssid) @@ -8370,6 +9032,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_EAP_NEW_PASSWORD: bin_clear_free(eap->new_password, eap->new_password_len); eap->new_password = (u8 *) os_strdup(value); + if (!eap->new_password) + return -1; eap->new_password_len = os_strlen(value); eap->pending_req_new_password = 0; if (ssid == wpa_s->current_ssid) @@ -8378,6 +9042,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_EAP_PIN: str_clear_free(eap->cert.pin); eap->cert.pin = os_strdup(value); + if (!eap->cert.pin) + return -1; eap->pending_req_pin = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; @@ -8385,6 +9051,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_EAP_OTP: bin_clear_free(eap->otp, eap->otp_len); eap->otp = (u8 *) os_strdup(value); + if (!eap->otp) + return -1; eap->otp_len = os_strlen(value); os_free(eap->pending_req_otp); eap->pending_req_otp = NULL; @@ -8393,6 +9061,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_EAP_PASSPHRASE: str_clear_free(eap->cert.private_key_passwd); eap->cert.private_key_passwd = os_strdup(value); + if (!eap->cert.private_key_passwd) + return -1; eap->pending_req_passphrase = 0; if (ssid == wpa_s->current_ssid) wpa_s->reassociate = 1; @@ -8400,6 +9070,8 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, case WPA_CTRL_REQ_SIM: str_clear_free(eap->external_sim_resp); eap->external_sim_resp = os_strdup(value); + if (!eap->external_sim_resp) + return -1; eap->pending_req_sim = 0; break; case WPA_CTRL_REQ_PSK_PASSPHRASE: @@ -8499,6 +9171,26 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) !ssid->mem_only_psk) return 1; +#ifdef IEEE8021X_EAPOL +#ifdef CRYPTO_RSA_OAEP_SHA256 + if (ssid->eap.imsi_privacy_cert) { + struct crypto_rsa_key *key; + bool failed = false; + + key = crypto_rsa_key_read(ssid->eap.imsi_privacy_cert, false); + if (!key) + failed = true; + crypto_rsa_key_free(key); + if (failed) { + wpa_printf(MSG_DEBUG, + "Invalid imsi_privacy_cert (%s) - disable network", + ssid->eap.imsi_privacy_cert); + return 1; + } + } +#endif /* CRYPTO_RSA_OAEP_SHA256 */ +#endif /* IEEE8021X_EAPOL */ + return 0; } @@ -8529,6 +9221,13 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) return NO_MGMT_FRAME_PROTECTION; } +#ifdef CONFIG_OCV + /* Enable PMF if OCV is being enabled */ + if (wpa_s->conf->pmf == NO_MGMT_FRAME_PROTECTION && + ssid && ssid->ocv) + return MGMT_FRAME_PROTECTION_OPTIONAL; +#endif /* CONFIG_OCV */ + return wpa_s->conf->pmf; } @@ -8536,12 +9235,32 @@ int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) } +#ifdef CONFIG_SAE +bool wpas_is_sae_avoided(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + const struct wpa_ie_data *ie) +{ + return wpa_s->conf->sae_check_mfp && + (!(ie->capabilities & + (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) || + wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION); +} +#endif /* CONFIG_SAE */ + + int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr) { if (wpa_s->current_ssid == NULL || - wpa_s->wpa_state < WPA_4WAY_HANDSHAKE || - os_memcmp(addr, wpa_s->bssid, ETH_ALEN) != 0) + wpa_s->wpa_state < WPA_4WAY_HANDSHAKE) return 0; + if (wpa_s->valid_links) { + if (!ether_addr_equal(addr, wpa_s->ap_mld_addr) && + !wpas_ap_link_address(wpa_s, addr)) + return 0; + } else { + if (!ether_addr_equal(addr, wpa_s->bssid)) + return 0; + } return wpa_sm_pmf_enabled(wpa_s->wpa); } @@ -8556,7 +9275,8 @@ int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s) } -void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason) +void wpas_auth_failed(struct wpa_supplicant *wpa_s, const char *reason, + const u8 *bssid) { struct wpa_ssid *ssid = wpa_s->current_ssid; int dur; @@ -8617,7 +9337,7 @@ void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason) "id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s", ssid->id, anonymize_ssid(wpa_ssid_txt(ssid->ssid, ssid->ssid_len)), ssid->auth_failures, dur, reason); - #if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) +#if defined(CONFIG_LIBWPA_VENDOR) || defined(OHOS_EUPDATER) struct WpaTempDisabledParam wpaTempDisabledParma; os_memcpy(wpaTempDisabledParma.ssid, ssid->ssid, ssid->ssid_len); wpaTempDisabledParma.networkId = ssid->id; @@ -8625,7 +9345,10 @@ void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason) wpaTempDisabledParma.duration = dur; os_memcpy(wpaTempDisabledParma.reason, reason, strlen(reason)); WpaEventReport(wpa_s->ifname, WPA_EVENT_TEMP_DISABLE, (void *) &wpaTempDisabledParma); - #endif +#endif + + if (bssid) + os_memcpy(ssid->disabled_due_to, bssid, ETH_ALEN); } @@ -8645,8 +9368,15 @@ void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s, } ssid->disabled_until.sec = 0; ssid->disabled_until.usec = 0; - if (clear_failures) + if (clear_failures) { ssid->auth_failures = 0; + } else if (!is_zero_ether_addr(ssid->disabled_due_to)) { + wpa_printf(MSG_DEBUG, "Mark BSSID " MACSTR + " ignored to allow a lower priority BSS, if any, to be tried next", + MAC2STR(ssid->disabled_due_to)); + wpa_bssid_ignore_add(wpa_s, ssid->disabled_due_to); + os_memset(ssid->disabled_due_to, 0, ETH_ALEN); + } } @@ -8658,8 +9388,8 @@ int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid) return 0; for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) { - if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN, - bssid, ETH_ALEN) == 0) + if (ether_addr_equal(wpa_s->disallow_aps_bssid + i * ETH_ALEN, + bssid)) return 1; } @@ -8726,6 +9456,7 @@ void wpas_request_disconnection(struct wpa_supplicant *wpa_s) wpa_s->disconnected = 1; wpa_supplicant_cancel_sched_scan(wpa_s); wpa_supplicant_cancel_scan(wpa_s); + wpas_abort_ongoing_scan(wpa_s); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); radio_remove_works(wpa_s, "connect", 0); @@ -8760,7 +9491,7 @@ void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title, */ int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s, struct wpa_used_freq_data *freqs_data, - unsigned int len) + unsigned int len, bool exclude_current) { struct wpa_supplicant *ifs; u8 bssid[ETH_ALEN]; @@ -8776,6 +9507,9 @@ int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s, if (idx == len) break; + if (exclude_current && ifs == wpa_s) + continue; + if (ifs->current_ssid == NULL || ifs->assoc_freq == 0) continue; @@ -8813,7 +9547,8 @@ int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s, * are using the same radio as the current interface. */ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, - int *freq_array, unsigned int len) + int *freq_array, unsigned int len, + bool exclude_current) { struct wpa_used_freq_data *freqs_data; int num, i; @@ -8824,7 +9559,8 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, if (!freqs_data) return -1; - num = get_shared_radio_freqs_data(wpa_s, freqs_data, len); + num = get_shared_radio_freqs_data(wpa_s, freqs_data, len, + exclude_current); for (i = 0; i < num; i++) freq_array[i] = freqs_data[i].freq; @@ -8930,8 +9666,7 @@ struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, if (modes[i].mode != mode || !modes[i].num_channels || !modes[i].channels) continue; - if ((!is_6ghz && !is_6ghz_freq(modes[i].channels[0].freq)) || - (is_6ghz && is_6ghz_freq(modes[i].channels[0].freq))) + if (is_6ghz == modes[i].is_6ghz) return &modes[i]; } @@ -8963,7 +9698,7 @@ wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s, dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed, struct wpa_bss_tmp_disallowed, list) { - if (os_memcmp(bssid, bss->bssid, ETH_ALEN) == 0) + if (ether_addr_equal(bssid, bss->bssid)) return bss; } @@ -9046,7 +9781,7 @@ int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed, struct wpa_bss_tmp_disallowed, list) { - if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) { + if (ether_addr_equal(bss->bssid, tmp->bssid)) { disallowed = tmp; break; } @@ -9144,22 +9879,21 @@ int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s, dl_list_for_each(dso, &wpa_s->drv_signal_override, struct driver_signal_override, list) { - if (os_memcmp(wpa_s->bssid, dso->bssid, - ETH_ALEN) != 0) + if (!ether_addr_equal(wpa_s->bssid, dso->bssid)) continue; wpa_printf(MSG_DEBUG, "Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d", - si->current_signal, + si->data.signal, dso->si_current_signal, - si->avg_signal, + si->data.avg_signal, dso->si_avg_signal, - si->avg_beacon_signal, + si->data.avg_beacon_signal, dso->si_avg_beacon_signal, si->current_noise, dso->si_current_noise); - si->current_signal = dso->si_current_signal; - si->avg_signal = dso->si_avg_signal; - si->avg_beacon_signal = dso->si_avg_beacon_signal; + si->data.signal = dso->si_current_signal; + si->data.avg_signal = dso->si_avg_signal; + si->data.avg_beacon_signal = dso->si_avg_beacon_signal; si->current_noise = dso->si_current_noise; break; } @@ -9171,17 +9905,21 @@ int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s, struct wpa_scan_results * -wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s) +wpa_drv_get_scan_results(struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wpa_scan_results *scan_res; #ifdef CONFIG_TESTING_OPTIONS size_t idx; #endif /* CONFIG_TESTING_OPTIONS */ - if (!wpa_s->driver->get_scan_results2) + if (wpa_s->driver->get_scan_results) + scan_res = wpa_s->driver->get_scan_results(wpa_s->drv_priv, + bssid); + else if (wpa_s->driver->get_scan_results2) + scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv); + else return NULL; - scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv); #ifdef CONFIG_TESTING_OPTIONS for (idx = 0; scan_res && idx < scan_res->num; idx++) { @@ -9190,7 +9928,7 @@ wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s) dl_list_for_each(dso, &wpa_s->drv_signal_override, struct driver_signal_override, list) { - if (os_memcmp(res->bssid, dso->bssid, ETH_ALEN) != 0) + if (!ether_addr_equal(res->bssid, dso->bssid)) continue; wpa_printf(MSG_DEBUG, "Override driver scan signal level %d->%d for " @@ -9221,3 +9959,60 @@ struct wpa_supplicant* getWpaP2p() return gWpaP2p; } +bool wpas_ap_link_address(struct wpa_supplicant *wpa_s, const u8 *addr) +{ + int i; + + if (!wpa_s->valid_links) + return false; + + for_each_link(wpa_s->valid_links, i) { + if (ether_addr_equal(wpa_s->links[i].bssid, addr)) + return true; + } + + return false; +} + + +int wpa_drv_send_action(struct wpa_supplicant *wpa_s, unsigned int freq, + unsigned int wait, const u8 *dst, const u8 *src, + const u8 *bssid, const u8 *data, size_t data_len, + int no_cck) +{ + if (!wpa_s->driver->send_action) + return -1; + + if (data_len > 0 && data[0] != WLAN_ACTION_PUBLIC) { + if (wpas_ap_link_address(wpa_s, dst)) + dst = wpa_s->ap_mld_addr; + + if (wpas_ap_link_address(wpa_s, bssid)) + bssid = wpa_s->ap_mld_addr; + } + + return wpa_s->driver->send_action(wpa_s->drv_priv, freq, wait, dst, src, + bssid, data, data_len, no_cck); +} + + +bool wpas_is_6ghz_supported(struct wpa_supplicant *wpa_s, bool only_enabled) +{ + struct hostapd_channel_data *chnl; + int i, j; + + for (i = 0; i < wpa_s->hw.num_modes; i++) { + if (wpa_s->hw.modes[i].mode == HOSTAPD_MODE_IEEE80211A) { + chnl = wpa_s->hw.modes[i].channels; + for (j = 0; j < wpa_s->hw.modes[i].num_channels; j++) { + if (only_enabled && + (chnl[j].flag & HOSTAPD_CHAN_DISABLED)) + continue; + if (is_6ghz_freq(chnl[j].freq)) + return true; + } + } + } + + return false; +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant.conf index d63f73c735b18f5f131fcfab846602106f34ad77..b08f5417ad88a7788bd51328c03562ceb42a2bc7 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant.conf @@ -419,6 +419,34 @@ fast_reauth=1 # RSN. #pmf=0 +# sae_check_mfp: Require PMF support to select SAE key_mgmt +# 0 = Do not check PMF for SAE (default) +# 1 = Limit SAE when PMF is not enabled +# +# When enabled SAE will not be selected if PMF will not be used +# for the connection. +# Scenarios where this check will limit SAE: +# 1) ieee80211w=0 is set for the network +# 2) The AP does not have PMF enabled. +# 3) ieee80211w is unset, pmf=1 is enabled globally, and +# the device does not support the BIP cipher. +# Consider the configuration of global parameterss sae_check_mfp=1, pmf=1 and a +# network configured with ieee80211w unset and key_mgmt=SAE WPA-PSK. +# In the example WPA-PSK will be used if the device does not support +# the BIP cipher or the AP has PMF disabled. +# Limiting SAE with this check can avoid failing to associate to an AP +# that is configured with sae_requires_mfp=1 if the device does +# not support PMF due to lack of the BIP cipher. +# +# Enabling this check helps with compliance of the WPA3 +# specification for WPA3-Personal transition mode. +# The WPA3 specification section 2.3 "WPA3-Personal transition mode" item 8 +# states "A STA shall negotiate PMF when associating to an AP using SAE". +# With this check WPA3 capable devices when connecting +# to transition mode APs that do not advertise PMF support +# will not use SAE and instead fallback to PSK. +#sae_check_mfp=0 + # Enabled SAE finite cyclic groups in preference order # By default (if this parameter is not set), the mandatory group 19 (ECC group # defined over a 256-bit prime order field, NIST P-256) is preferred and groups @@ -475,12 +503,17 @@ fast_reauth=1 # 0 = use permanent MAC address # 1 = use random MAC address for each ESS connection # 2 = like 1, but maintain OUI (with local admin bit set) +# 3 = use dedicated/pregenerated MAC address (see mac_value) # # By default, permanent MAC address is used unless policy is changed by # the per-network mac_addr parameter. Global mac_addr=1 can be used to # change this default behavior. #mac_addr=0 +# Local MAC address to use whenever connecting with this network profile +# This is used with mac_addr=3. +#mac_value=02:12:34:56:78:9a + # Lifetime of random MAC address in seconds (default: 60) #rand_addr_lifetime=60 @@ -655,7 +688,26 @@ fast_reauth=1 # be used to configure alternative FQDNs that will be considered home # networks. # +# home_ois: Home OI(s) +# This string field contains one or more comma delimited OIs (hexdump) +# identifying the access the access points that support authentication +# with this credential. There are an alternative to the use of the realm +# parameter. When using Home OIs to match the network, the EAP parameters +# need to be pre-configured with the credentials since the NAI Realm +# information may not be available or fetched. +# A successful authentication with the access point is possible as soon +# as at least one Home OI from the list matches an OI in the Roaming +# Consortium advertised by the access point. +# (Hotspot 2.0 PerProviderSubscription//HomeSP/HomeOIList//HomeOI) +# +# required_home_ois: Required Home OI(s) +# This string field contains the set of Home OI(s) (hexdump) that are +# required to be advertised by the AP for the credential to be considered +# matching. +# (Hotspot 2.0 PerProviderSubscription//HomeSP/HomeOIList//HomeOIRequired) +# # roaming_consortium: Roaming Consortium OI +# Deprecated: use home_ois instead. # If roaming_consortium_len is non-zero, this field contains the # Roaming Consortium OI that can be used to determine which access # points support authentication with this credential. This is an @@ -665,6 +717,7 @@ fast_reauth=1 # may not be available or fetched. # # required_roaming_consortium: Required Roaming Consortium OI +# Deprecated: use required_home_ois instead. # If required_roaming_consortium_len is non-zero, this field contains the # Roaming Consortium OI that is required to be advertised by the AP for # the credential to be considered matching. @@ -770,7 +823,7 @@ fast_reauth=1 # password="password" # ca_cert="/etc/wpa_supplicant/ca.pem" # domain="example.com" -# roaming_consortium=223344 +# home_ois="223344" # eap=TTLS # phase2="auth=MSCHAPV2" #} @@ -929,9 +982,11 @@ fast_reauth=1 # parameter uses following format: ":" # Following bgscan modules are available: # simple - Periodic background scans based on signal strength +# send_btm_query > 0 means do this many BTM queries before attempting a scan. # bgscan="simple::: -# " +# [:]" # bgscan="simple:30:-45:300" +# bgscan="simple:30:-45:300:3" # learn - Learn channels used by the network and try to avoid bgscans on other # channels (experimental) # bgscan="learn::: @@ -1094,6 +1149,15 @@ fast_reauth=1 # 0: No replay window, strict check (default) # 1..2^32-1: number of packets that could be misordered # +# macsec_offload - Enable MACsec hardware offload +# +# This setting applies only when MACsec is in use, i.e., +# - the key server has decided to enable MACsec +# +# 0 = MACSEC_OFFLOAD_OFF (default) +# 1 = MACSEC_OFFLOAD_PHY +# 2 = MACSEC_OFFLOAD_MAC +# # macsec_port: IEEE 802.1X/MACsec port # Port component of the SCI # Range: 1-65534 (default: 1) @@ -1234,14 +1298,6 @@ fast_reauth=1 # to blob://. # private_key_passwd: Password for private key file (if left out, this will be # asked through control interface) -# dh_file: File path to DH/DSA parameters file (in PEM format) -# This is an optional configuration file for setting parameters for an -# ephemeral DH key exchange. In most cases, the default RSA -# authentication does not use this configuration. However, it is possible -# setup RSA to use ephemeral DH key exchange. In addition, ciphers with -# DSA keys always use ephemeral DH keys. This can be used to achieve -# forward secrecy. If the file is in DSA parameters format, it will be -# automatically converted into DH params. # subject_match: Substring to be matched against the subject of the # authentication server certificate. If this string is set, the server # certificate is only accepted if it contains this string in the subject. @@ -1385,6 +1441,11 @@ fast_reauth=1 # tls_suiteb=0 - do not apply Suite B 192-bit constraints on TLS (default) # tls_suiteb=1 - apply Suite B 192-bit constraints on TLS; this is used in # particular when using Suite B with RSA keys of >= 3K (3072) bits +# allow_unsafe_renegotiation=1 - allow connection with a TLS server that does +# not support safe renegotiation (RFC 5746); please note that this +# workaround should be only when having to authenticate with an old +# authentication server that cannot be updated to use secure TLS +# implementation. # # Following certificate/private key fields are used in inner Phase2 # authentication when using EAP-TTLS or EAP-PEAP. @@ -1503,6 +1564,12 @@ fast_reauth=1 # 2: do not allow PFS to be used #dpp_pfs=0 +# DPP Network introduction type +# 0: unprotected variant from DPP R1 (default) +# 1: privacy protecting (station Connector encrypted) variant from +# DPP R3 +#dpp_connector_privacy=0 + # Whether beacon protection is enabled # This depends on management frame protection (ieee80211w) being enabled and # beacon protection support indication from the driver. @@ -1631,6 +1698,10 @@ fast_reauth=1 # 2: MCS 0-9 # 3: not supported +# disable_eht: Whether EHT should be disabled. +# 0 = EHT enabled (if supported) (default) +# 1 = EHT disabled + # multi_ap_backhaul_sta: Multi-AP backhaul STA functionality # 0 = normal STA (default) # 1 = backhaul STA @@ -1638,6 +1709,12 @@ fast_reauth=1 # support Multi-AP, and sets 4-address mode if it does. Thus, the netdev can be # added to a bridge to allow forwarding frames over this backhaul link. +# Multi-AP Profile +# Indicate the supported Multi-AP profile +# 1 = Supports Multi-AP profile 1 as defined in Wi-Fi EasyMesh specification +# 2 = Supports Multi-AP profile 2 as defined in Wi-Fi EasyMesh specification +#multi_ap_profile=2 + ##### Fast Session Transfer (FST) support ##################################### # # The options in this section are only available when the build configuration @@ -1680,6 +1757,11 @@ fast_reauth=1 # In STA mode it defines the EDMG channel for connection (if supported by AP). #edmg_channel=9 +# BSS max idle period to request +# If nonzero, request the specified number of 1000 TU (i.e., 1.024 s) +# as the maximum idle period for the STA during association. +#max_idle=600 + # Example blocks: # Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant_i.h index fa2ca6d581c7162fcdf94c5598d1d6fc5d53a66e..8ea716bd84da5f06d71173e598811f19d9df9599 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant_i.h @@ -1,6 +1,6 @@ /* * wpa_supplicant - Internal definitions - * Copyright (c) 2003-2014, Jouni Malinen + * Copyright (c) 2003-2024, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -14,11 +14,13 @@ #include "common/defs.h" #include "common/sae.h" #include "common/wpa_ctrl.h" +#include "common/dpp.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" +#include "pasn/pasn_common.h" #include "config.h" extern const char *const wpa_supplicant_version; @@ -499,6 +501,7 @@ struct beacon_rep_data { u8 bssid[ETH_ALEN]; enum beacon_report_detail report_detail; struct bitfield *eids; + struct bitfield *ext_eids; }; @@ -547,66 +550,6 @@ struct dscp_resp_data { int num_policies; }; -#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; - size_t kdk_len; - - 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; - - struct wpabuf *comeback; - u16 comeback_after; - -#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 */ - -#ifdef CONFIG_MLD_PATCH -struct ml_sta_link_info { - u8 link_id; - u8 bssid[ETH_ALEN]; - u16 status; -}; -#endif - enum ip_version { IPV4 = 4, IPV6 = 6, @@ -620,7 +563,6 @@ struct ipv4_params { u16 dst_port; u8 dscp; u8 protocol; - u8 param_mask; }; @@ -632,7 +574,6 @@ struct ipv6_params { u8 dscp; u8 next_header; u8 flow_label[3]; - u8 param_mask; }; @@ -665,6 +606,40 @@ struct tclas_element { }; +struct qos_characteristics { + bool available; + + /* Control Info Direction */ + u8 direction; + /* Presence Bitmap Of Additional Parameters */ + u16 mask; + /* Minimum Service Interval */ + u32 min_si; + /* Maximum Service Interval */ + u32 max_si; + /* Minimum Data Rate */ + u32 min_data_rate; + /* Delay Bound */ + u32 delay_bound; + /* Maximum MSDU Size */ + u16 max_msdu_size; + /* Service Start Time */ + u32 service_start_time; + /* Service Start Time LinkID */ + u8 service_start_time_link_id; + /* Mean Data Rate */ + u32 mean_data_rate; + /* Delayed Bounded Burst Size */ + u32 burst_size; + /* MSDU Lifetime */ + u16 msdu_lifetime; + /* MSDU Delivery Info */ + u8 msdu_delivery_info; + /* Medium Time */ + u16 medium_time; +}; + + struct scs_desc_elem { u8 scs_id; enum scs_request_type request_type; @@ -673,6 +648,7 @@ struct scs_desc_elem { struct tclas_element *tclas_elems; unsigned int num_tclas_elem; u8 tclas_processing; + struct qos_characteristics qos_char_elem; }; @@ -695,6 +671,12 @@ struct active_scs_elem { }; +struct ml_sta_link_info { + u8 link_id; + u8 bssid[ETH_ALEN]; + u16 status; +}; + /** * struct wpa_supplicant - Internal data for wpa_supplicant interface @@ -761,7 +743,6 @@ struct wpa_supplicant { struct wpa_bss *current_bss; int ap_ies_from_associnfo; unsigned int assoc_freq; -#ifdef CONFIG_MLD_PATCH u8 ap_mld_addr[ETH_ALEN]; u8 mlo_assoc_link_id; u16 valid_links; /* bitmap of valid MLO link IDs */ @@ -770,8 +751,8 @@ struct wpa_supplicant { u8 bssid[ETH_ALEN]; unsigned int freq; struct wpa_bss *bss; + bool disabled; } links[MAX_NUM_MLD_LINKS]; -#endif u8 *last_con_fail_realm; size_t last_con_fail_realm_len; @@ -782,6 +763,11 @@ struct wpa_supplicant { int key_mgmt; int wpa_proto; int mgmt_group_cipher; + /* + * Allowed key management suites for roaming/initial connection + * when the driver's SME is in use. + */ + int allowed_key_mgmts; void *drv_priv; /* private data used by driver_ops */ void *global_drv_priv; @@ -917,6 +903,7 @@ struct wpa_supplicant { unsigned int own_scan_requested:1; unsigned int own_scan_running:1; unsigned int clear_driver_scan_cache:1; + unsigned int manual_non_coloc_6ghz:1; unsigned int manual_scan_id; int scan_interval; /* time in sec between scans to find suitable AP */ int normal_scans; /* normal scans run before sched_scan */ @@ -929,11 +916,11 @@ struct wpa_supplicant { */ u64 curr_scan_cookie; #ifdef CONFIG_WAPI - struct wapi_config *wapi_conf; - u8 assoc_wapi_ie[256]; - u8 assoc_wapi_ie_len; - u8 ap_wapi_ie[256]; - u8 ap_wapi_ie_len; + struct wapi_config *wapi_conf; + u8 assoc_wapi_ie[256]; + u8 assoc_wapi_ie_len; + u8 ap_wapi_ie[256]; + u8 ap_wapi_ie_len; #endif #define MAX_SCAN_ID 16 int scan_id[MAX_SCAN_ID]; @@ -948,10 +935,15 @@ struct wpa_supplicant { unsigned int suitable_network; unsigned int no_suitable_network; + u8 ml_probe_bssid[ETH_ALEN]; + int ml_probe_mld_id; + u16 ml_probe_links; + u64 drv_flags; u64 drv_flags2; unsigned int drv_enc; unsigned int drv_rrm_flags; + unsigned int drv_max_acl_mac_addrs; /* * A bitmap of supported protocols for probe response offload. See @@ -972,6 +964,7 @@ struct wpa_supplicant { unsigned int max_match_sets; unsigned int max_remain_on_chan; unsigned int max_stations; + unsigned int max_num_akms; int pending_mic_error_report; int pending_mic_error_pairwise; @@ -987,7 +980,9 @@ struct wpa_supplicant { struct wpabuf *pending_eapol_rx; struct os_reltime pending_eapol_rx_time; u8 pending_eapol_rx_src[ETH_ALEN]; + enum frame_encryption pending_eapol_encrypted; unsigned int last_eapol_matches_bssid:1; + unsigned int eapol_failed:1; unsigned int eap_expected_failure:1; unsigned int reattach:1; /* reassociation to the same BSS requested */ unsigned int mac_addr_changed:1; @@ -1002,11 +997,12 @@ struct wpa_supplicant { unsigned int connection_max_nss_rx:4; unsigned int connection_max_nss_tx:4; unsigned int connection_channel_bandwidth:5; + unsigned int connection_eht:1; unsigned int disable_mbo_oce:1; unsigned int connection_11b_only:1; struct os_reltime last_mac_addr_change; - int last_mac_addr_style; + enum wpas_mac_addr_style last_mac_addr_style; struct ibss_rsn *ibss_rsn; @@ -1055,15 +1051,15 @@ struct wpa_supplicant { unsigned int sae_pmksa_caching:1; u16 seq_num; u8 ext_auth_bssid[ETH_ALEN]; + struct wpa_ssid *ext_auth_wpa_ssid; u8 ext_auth_ssid[SSID_MAX_LEN]; size_t ext_auth_ssid_len; -#ifdef CONFIG_MLD_PATCH int ext_auth_key_mgmt; u8 ext_auth_ap_mld_addr[ETH_ALEN]; bool ext_ml_auth; -#endif int *sae_rejected_groups; #endif /* CONFIG_SAE */ + u16 assoc_auth_type; } sme; #endif /* CONFIG_SME */ @@ -1082,6 +1078,7 @@ struct wpa_supplicant { unsigned int mesh_ht_enabled:1; unsigned int mesh_vht_enabled:1; unsigned int mesh_he_enabled:1; + unsigned int mesh_eht_enabled:1; struct wpa_driver_mesh_join_params *mesh_params; #ifdef CONFIG_PMKSA_CACHE_EXTERNAL /* struct external_pmksa_cache::list */ @@ -1132,6 +1129,7 @@ struct wpa_supplicant { int p2p_sd_over_ctrl_iface; int p2p_in_provisioning; int p2p_in_invitation; + int p2p_retry_limit; int p2p_invite_go_freq; int pending_invite_ssid_id; int show_group_started; @@ -1184,6 +1182,7 @@ struct wpa_supplicant { unsigned int user_initiated_pd:1; unsigned int p2p_go_group_formation_completed:1; unsigned int group_formation_reported:1; + unsigned int p2p_go_no_pri_sec_switch:1; unsigned int waiting_presence_resp; int p2p_first_connection_timeout; unsigned int p2p_nfc_tag_enabled:1; @@ -1230,6 +1229,7 @@ struct wpa_supplicant { struct wpa_ssid *bgscan_ssid; const struct bgscan_ops *bgscan; void *bgscan_priv; + int signal_threshold; const struct autoscan_ops *autoscan; struct wpa_driver_scan_params *autoscan_params; @@ -1341,14 +1341,15 @@ struct wpa_supplicant { u8 wnm_reply; u8 wnm_num_neighbor_report; u8 wnm_mode; + bool wnm_link_removal; + u8 wnm_dissoc_addr[ETH_ALEN]; u16 wnm_dissoc_timer; u8 wnm_bss_termination_duration[12]; struct neighbor_report *wnm_neighbor_report_elements; struct os_reltime wnm_cand_valid_until; - u8 wnm_cand_from_bss[ETH_ALEN]; + struct wpa_bss *wnm_target_bss; enum bss_trans_mgmt_status_code bss_tm_status; bool bss_trans_mgmt_in_progress; - struct wpabuf *coloc_intf_elems; u8 coloc_intf_dialog_token; u8 coloc_intf_auto_report; u8 coloc_intf_timeout; @@ -1402,6 +1403,8 @@ struct wpa_supplicant { unsigned int oci_freq_override_ft_assoc; unsigned int oci_freq_override_fils_assoc; unsigned int oci_freq_override_wnm_sleep; + unsigned int disable_eapol_g2_tx; + int test_assoc_comeback_type; #endif /* CONFIG_TESTING_OPTIONS */ struct wmm_ac_assoc_data *wmm_ac_assoc_info; @@ -1508,14 +1511,21 @@ struct wpa_supplicant { int dpp_netrole; int dpp_auth_ok_on_ack; int dpp_in_response_listen; + bool dpp_tx_auth_resp_on_roc_stop; + bool dpp_tx_chan_change; + bool dpp_listen_on_tx_expire; int dpp_gas_client; + int dpp_gas_server; int dpp_gas_dialog_token; u8 dpp_intro_bssid[ETH_ALEN]; void *dpp_intro_network; + u8 dpp_intro_peer_version; struct dpp_pkex *dpp_pkex; struct dpp_bootstrap_info *dpp_pkex_bi; char *dpp_pkex_code; + size_t dpp_pkex_code_len; char *dpp_pkex_identifier; + enum dpp_pkex_ver dpp_pkex_ver; char *dpp_pkex_auth_cmd; char *dpp_configurator_params; struct os_reltime dpp_last_init; @@ -1528,6 +1538,7 @@ struct wpa_supplicant { u8 dpp_last_ssid[SSID_MAX_LEN]; size_t dpp_last_ssid_len; bool dpp_conf_backup_received; + bool dpp_pkex_wait_auth_req; #ifdef CONFIG_DPP2 struct dpp_pfs *dpp_pfs; int dpp_pfs_fallback; @@ -1543,11 +1554,33 @@ struct wpa_supplicant { int dpp_reconfig_ssid_id; struct dpp_reconfig_id *dpp_reconfig_id; #endif /* CONFIG_DPP2 */ +#ifdef CONFIG_DPP3 + struct os_reltime dpp_pb_time; + bool dpp_pb_configurator; + int *dpp_pb_freqs; + unsigned int dpp_pb_freq_idx; + unsigned int dpp_pb_announce_count; + struct wpabuf *dpp_pb_announcement; + struct dpp_bootstrap_info *dpp_pb_bi; + unsigned int dpp_pb_resp_freq; + u8 dpp_pb_init_hash[SHA256_MAC_LEN]; + int dpp_pb_stop_iter; + bool dpp_pb_discovery_done; + u8 dpp_pb_c_nonce[DPP_MAX_NONCE_LEN]; + size_t dpp_pb_c_nonce_len; + bool dpp_pb_result_indicated; + struct os_reltime dpp_pb_announce_time; + struct dpp_pb_info dpp_pb[DPP_PB_INFO_COUNT]; + u8 dpp_pb_resp_hash[SHA256_MAC_LEN]; + struct os_reltime dpp_pb_last_resp; + char *dpp_pb_cmd; +#endif /* CONFIG_DPP3 */ #ifdef CONFIG_TESTING_OPTIONS char *dpp_config_obj_override; char *dpp_discovery_override; char *dpp_groups_override; unsigned int dpp_ignore_netaccesskey_mismatch:1; + unsigned int dpp_discard_public_action:1; #endif /* CONFIG_TESTING_OPTIONS */ #endif /* CONFIG_DPP */ @@ -1561,19 +1594,12 @@ struct wpa_supplicant { unsigned int multi_ap_ie:1; unsigned int multi_ap_backhaul:1; unsigned int multi_ap_fronthaul:1; + +#ifndef CONFIG_NO_ROBUST_AV 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 */ struct scs_robust_av_data scs_robust_av_req; u8 scs_dialog_token; -#ifdef CONFIG_TESTING_OPTIONS - unsigned int disable_scs_support:1; - unsigned int disable_mscs_support:1; -#endif /* CONFIG_TESTING_OPTIONS */ struct dl_list active_scs_ids; bool ongoing_scs_req; u8 dscp_req_dialog_token; @@ -1581,7 +1607,51 @@ struct wpa_supplicant { unsigned int enable_dscp_policy_capa:1; unsigned int connection_dscp:1; unsigned int wait_for_dscp_req:1; +#ifdef CONFIG_TESTING_OPTIONS + unsigned int disable_scs_support:1; + unsigned int disable_mscs_support:1; +#endif /* CONFIG_TESTING_OPTIONS */ +#endif /* CONFIG_NO_ROBUST_AV */ + bool wps_scan_done; /* Set upon receiving scan results event */ + bool supp_pbc_active; /* Set for interface when PBC is triggered */ + bool wps_overlap; + +#ifdef CONFIG_PASN + struct pasn_data pasn; + struct wpa_radio_work *pasn_auth_work; + unsigned int pasn_count; + struct pasn_auth *pasn_params; +#endif /* CONFIG_PASN */ + + bool is_6ghz_enabled; + bool crossed_6ghz_dom; + bool last_scan_all_chan; + bool last_scan_non_coloc_6ghz; + bool support_6ghz; + + struct wpa_signal_info last_signal_info; + + struct wpa_ssid *ml_connect_probe_ssid; + struct wpa_bss *ml_connect_probe_bss; + +#ifdef CONFIG_OWE + /* An array of frequencies to scan for OWE transition mode BSSs when + * owe_transition_search == 1 */ + int *owe_trans_scan_freq; +#endif /* CONFIG_OWE */ + +#ifdef CONFIG_NAN_USD + struct nan_de *nan_de; + struct wpa_radio_work *nan_usd_listen_work; + struct wpa_radio_work *nan_usd_tx_work; +#endif /* CONFIG_NAN_USD */ + + bool ssid_verified; + bool bigtk_set; + u64 first_beacon_tsf; + unsigned int beacons_checked; + unsigned int next_beacon_check; #ifdef CONFIG_VENDOR_EXT /* Vendor extension */ void *wpas_vendor_ext; @@ -1603,6 +1673,9 @@ void wpa_supplicant_apply_vht_overrides( void wpa_supplicant_apply_he_overrides( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_driver_associate_params *params); +void wpa_supplicant_apply_eht_overrides( + struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + struct wpa_driver_associate_params *params); int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s, @@ -1619,7 +1692,8 @@ void wpas_set_mgmt_group_cipher(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_ie_data *ie); 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); + u8 *wpa_ie, size_t *wpa_ie_len, + bool skip_default_rsne); int wpas_restore_permanent_mac_addr(struct wpa_supplicant *wpa_s); void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, @@ -1687,20 +1761,19 @@ void wpa_supplicant_deinit(struct wpa_global *global); int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_terminate_proc(struct wpa_global *global); -void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len); +void wpa_supplicant_rx_eapol(void *ctx, const u8 *own_addr, + const u8 *buf, size_t len, + enum frame_encryption encrypted); void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s); void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s); -void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid -#ifdef CONFIG_MLD_PATCH - , const u8 **link_bssids -#endif -); +void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid, + const u8 **link_bssids); void fils_connection_failure(struct wpa_supplicant *wpa_s); void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s); int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s); int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s); -void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason); +void wpas_auth_failed(struct wpa_supplicant *wpa_s, const char *reason, + const u8 *bssid); void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int clear_failures); int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid); @@ -1708,8 +1781,11 @@ int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid, size_t ssid_len); void wpas_request_connection(struct wpa_supplicant *wpa_s); void wpas_request_disconnection(struct wpa_supplicant *wpa_s); -int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen); -int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style); +int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen, + struct wpa_bss *bss); +int wpas_update_random_addr(struct wpa_supplicant *wpa_s, + enum wpas_mac_addr_style style, + struct wpa_ssid *ssid); int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s); void add_freq(int *freqs, int *num_freqs, int freq); @@ -1756,7 +1832,7 @@ void wpa_supplicant_terminate_with_reset_driver(struct wpa_global *global); int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len, int add_oce_capa); const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr); -const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr); +const u8 * wpas_mbo_check_assoc_disallow(struct wpa_bss *bss); void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, struct wpa_ssid *ssid); const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len, @@ -1827,6 +1903,7 @@ void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx); void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx); void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s); int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s); +int wpa_wps_supplicant_fast_associate(struct wpa_supplicant *wpa_s); struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, struct wpa_ssid **selected_ssid); int wpas_temp_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); @@ -1835,9 +1912,8 @@ void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s, int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s, struct wpa_bss *current_bss, struct wpa_bss *seleceted); -#ifdef CONFIG_MLD_PATCH void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s); -#endif + /* eap_register.c */ int eap_register_methods(void); @@ -1873,7 +1949,13 @@ static inline int wpas_mode_to_ieee80211_mode(enum wpas_mode mode) int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr); -void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid); +void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid, + bool force); +void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s); + +bool wpas_is_sae_avoided(struct wpa_supplicant *wpa_s, + struct wpa_ssid *ssid, + const struct wpa_ie_data *ie); int wpas_init_ext_pw(struct wpa_supplicant *wpa_s); @@ -1883,9 +1965,11 @@ void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title, int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s, struct wpa_used_freq_data *freqs_data, - unsigned int len); + unsigned int len, bool exclude_current); int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, - int *freq_array, unsigned int len); + int *freq_array, unsigned int len, + bool exclude_current); +int disabled_freq(struct wpa_supplicant *wpa_s, int freq); void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx); @@ -1926,7 +2010,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, enum wpa_driver_if_type if_type, unsigned int *num, - unsigned int *freq_list); + struct weighted_pcl *freq_list); int wpa_is_fils_supported(struct wpa_supplicant *wpa_s); int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s); @@ -1959,7 +2043,7 @@ void wpas_handle_assoc_resp_qos_mgmt(struct wpa_supplicant *wpa_s, int wpas_send_dscp_query(struct wpa_supplicant *wpa_s, const char *domain_name, size_t domain_name_length); -int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, +int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s, const u8 *own_addr, const u8 *bssid, int akmp, int cipher, u16 group, int network_id, const u8 *comeback, size_t comeback_len); @@ -1969,6 +2053,14 @@ int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s, const struct ieee80211_mgmt *mgmt, size_t len); -int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *bssid); +int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *own_addr, + const u8 *bssid); +void wpas_pasn_auth_trigger(struct wpa_supplicant *wpa_s, + struct pasn_auth *pasn_auth); +void wpas_pasn_auth_work_done(struct wpa_supplicant *wpa_s, int status); +bool wpas_is_6ghz_supported(struct wpa_supplicant *wpa_s, bool only_enabled); + +bool wpa_is_non_eht_scs_traffic_desc_supported(struct wpa_bss *bss); +bool wpas_ap_link_address(struct wpa_supplicant *wpa_s, const u8 *addr); #endif /* WPA_SUPPLICANT_I_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant_template.conf index f55227f82685773ded4a148f6252d04645b7696f..98d8764af1d63e55eb1479c75f4432249b349079 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant_template.conf +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpa_supplicant_template.conf @@ -5,3 +5,5 @@ ap_scan=1 fast_reauth=1 pmf=1 p2p_add_cli_chan=1 +p2p_optimize_listen_chan=1 +wowlan_disconnect_on_deinit=1 diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_glue.c b/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_glue.c index cd532ca2f387e9ed6083cf9b51eb0d028afb43f8..61187db45981823c8635083b12cdf5ede8b2a27e 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_glue.c @@ -254,11 +254,7 @@ static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx, else wpa_s->group_cipher = cipher; } - return wpa_drv_set_key(wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif - WPA_ALG_WEP, + return wpa_drv_set_key(wpa_s, -1, WPA_ALG_WEP, unicast ? wpa_s->bssid : NULL, keyidx, unicast, NULL, 0, key, keylen, unicast ? KEY_FLAG_PAIRWISE_RX_TX : @@ -294,7 +290,7 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, { struct wpa_supplicant *wpa_s = ctx; int res, pmk_len; - u8 pmk[PMK_LEN]; + u8 pmk[PMK_LEN_MAX]; wpa_printf(MSG_DEBUG, "EAPOL authentication completed - result=%s", result_str(result)); @@ -306,13 +302,21 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, EAPOL_SUPP_RESULT_EXPECTED_FAILURE; if (result != EAPOL_SUPP_RESULT_SUCCESS) { + int timeout = 2; /* * Make sure we do not get stuck here waiting for long EAPOL * timeout if the AP does not disconnect in case of * authentication failure. */ - wpa_supplicant_req_auth_timeout(wpa_s, 2, 0); + if (wpa_s->eapol_failed) { + wpa_printf(MSG_DEBUG, + "EAPOL authentication failed again and AP did not disconnect us"); + timeout = 0; + } + wpa_s->eapol_failed = 1; + wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0); } else { + wpa_s->eapol_failed = 0; ieee802_1x_notify_create_actor(wpa_s, wpa_s->last_eapol_src); } @@ -326,7 +330,11 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way " "handshake"); - pmk_len = PMK_LEN; + if (wpa_key_mgmt_sha384(wpa_s->key_mgmt)) + pmk_len = PMK_LEN_SUITE_B_192; + else + pmk_len = PMK_LEN; + if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) { #ifdef CONFIG_IEEE80211R u8 buf[2 * PMK_LEN]; @@ -341,7 +349,7 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, res = -1; #endif /* CONFIG_IEEE80211R */ } else { - res = eapol_sm_get_key(eapol, pmk, PMK_LEN); + res = eapol_sm_get_key(eapol, pmk, pmk_len); if (res) { /* * EAP-LEAP is an exception from other EAP methods: it @@ -361,11 +369,7 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way " "handshake", pmk, pmk_len); - if (wpa_drv_set_key(wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif - 0, NULL, 0, 0, NULL, 0, pmk, + if (wpa_drv_set_key(wpa_s, -1, 0, NULL, 0, 0, NULL, 0, pmk, pmk_len, KEY_FLAG_PMK)) { wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver"); } @@ -402,7 +406,7 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s) const u8 *ie; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { - if (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) != 0) + if (!ether_addr_equal(bss->bssid, wpa_s->bssid)) continue; if (ssid == NULL || ((bss->ssid_len == ssid->ssid_len && @@ -449,7 +453,7 @@ static int wpa_supplicant_get_beacon_ie(void *ctx) /* No WPA/RSN IE found in the cached scan results. Try to get updated * scan results from the driver. */ - if (wpa_supplicant_update_scan_results(wpa_s) < 0) + if (wpa_supplicant_update_scan_results(wpa_s, wpa_s->bssid) < 0) return -1; return wpa_get_beacon_ie(wpa_s); @@ -527,17 +531,15 @@ static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid) } -static int wpa_supplicant_set_key(void *_wpa_s, -#ifdef CONFIG_MLD_PATCH - int link_id, -#endif - enum wpa_alg alg, +static int wpa_supplicant_set_key(void *_wpa_s, int link_id, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, const u8 *key, size_t key_len, enum key_flag key_flag) { struct wpa_supplicant *wpa_s = _wpa_s; + int ret; + if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) { /* Clear the MIC error counter when setting a new PTK. */ wpa_s->mic_errors_seen = 0; @@ -560,12 +562,14 @@ static int wpa_supplicant_set_key(void *_wpa_s, wpa_s->last_tk_len = key_len; } #endif /* CONFIG_TESTING_OPTIONS */ - return wpa_drv_set_key(wpa_s, -#ifdef CONFIG_MLD_PATCH - link_id, -#endif - alg, addr, key_idx, set_tx, seq, seq_len, - key, key_len, key_flag); + + ret = wpa_drv_set_key(wpa_s, link_id, alg, addr, key_idx, set_tx, seq, + seq_len, key, key_len, key_flag); + if (ret == 0 && (key_idx == 6 || key_idx == 7) && + alg != WPA_ALG_NONE && key_len > 0) + wpa_s->bigtk_set = true; + + return ret; } @@ -777,12 +781,12 @@ static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, int initiator, const u8 *buf, - size_t len) + size_t len, int link_id) { struct wpa_supplicant *wpa_s = ctx; return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token, status_code, peer_capab, initiator, buf, - len); + len, link_id); } @@ -803,7 +807,9 @@ static int wpa_supplicant_tdls_peer_addset( const struct ieee80211_he_6ghz_band_cap *he_6ghz_he_capab, u8 qosinfo, int wmm, const u8 *ext_capab, size_t ext_capab_len, const u8 *supp_channels, size_t supp_channels_len, - const u8 *supp_oper_classes, size_t supp_oper_classes_len) + const u8 *supp_oper_classes, size_t supp_oper_classes_len, + const struct ieee80211_eht_capabilities *eht_capab, + size_t eht_capab_len, int mld_link_id) { struct wpa_supplicant *wpa_s = ctx; struct hostapd_sta_add_params params; @@ -838,6 +844,9 @@ static int wpa_supplicant_tdls_peer_addset( params.supp_channels_len = supp_channels_len; params.supp_oper_classes = supp_oper_classes; params.supp_oper_classes_len = supp_oper_classes_len; + params.eht_capab = eht_capab; + params.eht_capab_len = eht_capab_len; + params.mld_link_id = mld_link_id; return wpa_drv_sta_add(wpa_s, ¶ms); } @@ -950,28 +959,9 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field, void wpas_send_ctrl_req(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const char *field_name, const char *txt) { - char *buf; - size_t buflen; - int len; - - buflen = 100 + os_strlen(txt) + ssid->ssid_len; - buf = os_malloc(buflen); - if (buf == NULL) - return; - len = os_snprintf(buf, buflen, "%s-%d:%s needed for SSID ", - field_name, ssid->id, txt); - if (os_snprintf_error(buflen, len)) { - os_free(buf); - return; - } - if (ssid->ssid && buflen > len + ssid->ssid_len) { - os_memcpy(buf + len, ssid->ssid, ssid->ssid_len); - len += ssid->ssid_len; - buf[len] = '\0'; - } - buf[buflen - 1] = '\0'; - wpa_msg(wpa_s, MSG_INFO, WPA_CTRL_REQ "%s", buf); - os_free(buf); + wpa_msg(wpa_s, MSG_DEBUG, WPA_CTRL_REQ "%s-%d:%s needed for SSID %s", + field_name, ssid->id, txt, + wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); } @@ -1169,6 +1159,17 @@ static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len) } } } + + +static bool wpas_encryption_required(void *ctx) +{ + struct wpa_supplicant *wpa_s = ctx; + + return wpa_s->wpa && + wpa_sm_has_ptk_installed(wpa_s->wpa) && + wpa_sm_pmf_enabled(wpa_s->wpa); +} + #endif /* IEEE8021X_EAPOL */ @@ -1221,6 +1222,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) ctx->eap_error_cb = wpa_supplicant_eap_error_cb; ctx->confirm_auth_cb = wpa_supplicant_eap_auth_start_cb; ctx->set_anon_id = wpa_supplicant_set_anon_id; + ctx->encryption_required = wpas_encryption_required; ctx->cb_ctx = wpa_s; wpa_s->eapol = eapol_sm_init(ctx); if (wpa_s->eapol == NULL) { @@ -1255,11 +1257,7 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk, if (wpa_s->conf->key_mgmt_offload && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) - return wpa_drv_set_key(wpa_s, -#ifdef CONFIG_MLD_PATCH - -1, -#endif - 0, NULL, 0, 0, + return wpa_drv_set_key(wpa_s, -1, 0, NULL, 0, 0, NULL, 0, pmk, pmk_len, KEY_FLAG_PMK); else return 0; @@ -1309,9 +1307,8 @@ static void disable_wpa_wpa2(struct wpa_ssid *ssid) } -static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap) +void wpas_transition_disable(struct wpa_supplicant *wpa_s, u8 bitmap) { - struct wpa_supplicant *wpa_s = _wpa_s; struct wpa_ssid *ssid; int changed = 0; @@ -1324,7 +1321,7 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap) #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)) && + wpa_key_mgmt_sae(ssid->key_mgmt) && (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED || (ssid->group_cipher & WPA_CIPHER_TKIP))) { wpa_printf(MSG_DEBUG, @@ -1339,7 +1336,7 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap) 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)) && + wpa_key_mgmt_sae(ssid->key_mgmt) && (ssid->sae_pk != SAE_PK_MODE_ONLY || ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED || (ssid->group_cipher & WPA_CIPHER_TKIP))) { @@ -1355,7 +1352,8 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap) wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) && (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_FT_IEEE8021X | - WPA_KEY_MGMT_IEEE8021X_SHA256)) && + WPA_KEY_MGMT_IEEE8021X_SHA256 | + WPA_KEY_MGMT_IEEE8021X_SHA384)) && (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED || (ssid->group_cipher & WPA_CIPHER_TKIP))) { disable_wpa_wpa2(ssid); @@ -1381,17 +1379,59 @@ static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap) } -static void wpa_supplicant_store_ptk(void *ctx, u8 *addr, int cipher, +static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap) +{ + struct wpa_supplicant *wpa_s = _wpa_s; + wpas_transition_disable(wpa_s, bitmap); +} + + +static void wpa_supplicant_store_ptk(void *ctx, const 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); + ptksa_cache_add(wpa_s->ptksa, wpa_s->own_addr, addr, cipher, life_time, + ptk, NULL, NULL, 0); } #endif /* CONFIG_NO_WPA */ +#ifdef CONFIG_PASN +static int wpa_supplicant_set_ltf_keyseed(void *_wpa_s, const u8 *own_addr, + const u8 *peer_addr, + size_t ltf_keyseed_len, + const u8 *ltf_keyseed) +{ + struct wpa_supplicant *wpa_s = _wpa_s; + + return wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, peer_addr, 0, 0, + NULL, ltf_keyseed_len, + ltf_keyseed, 0); +} +#endif /* CONFIG_PASN */ + + +static void +wpa_supplicant_notify_pmksa_cache_entry(void *_wpa_s, + struct rsn_pmksa_cache_entry *entry) +{ + struct wpa_supplicant *wpa_s = _wpa_s; + + wpas_notify_pmk_cache_added(wpa_s, entry); +} + + +static void wpa_supplicant_ssid_verified(void *_wpa_s) +{ + struct wpa_supplicant *wpa_s = _wpa_s; + + wpa_s->ssid_verified = true; + wpa_msg(wpa_s, MSG_INFO, "RSN: SSID matched expected value"); +} + + int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) { #ifndef CONFIG_NO_WPA @@ -1454,6 +1494,11 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) ctx->channel_info = wpa_supplicant_channel_info; ctx->transition_disable = wpa_supplicant_transition_disable; ctx->store_ptk = wpa_supplicant_store_ptk; +#ifdef CONFIG_PASN + ctx->set_ltf_keyseed = wpa_supplicant_set_ltf_keyseed; +#endif /* CONFIG_PASN */ + ctx->notify_pmksa_cache_entry = wpa_supplicant_notify_pmksa_cache_entry; + ctx->ssid_verified = wpa_supplicant_ssid_verified; wpa_s->wpa = wpa_sm_init(ctx); if (wpa_s->wpa == NULL) { diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_glue.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_glue.h index 338af4e650a758a22d8245e20b06c46ee23b7698..dd692b90291a10f41338c84233a3d9786f7ee328 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_glue.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_glue.h @@ -27,4 +27,6 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field); void wpas_send_ctrl_req(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const char *field_name, const char *txt); +void wpas_transition_disable(struct wpa_supplicant *wpa_s, u8 bitmap); + #endif /* WPAS_GLUE_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_kay.c b/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_kay.c index c5ae544b9b393e6aab585a23cdd8982bfa9acfbb..afb01ad1599f2990270649dd3a8212fd55483276 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_kay.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_kay.c @@ -98,12 +98,17 @@ static int wpas_set_receive_lowest_pn(void *wpa_s, struct receive_sa *sa) } +static int wpas_set_offload(void *wpa_s, u8 offload) +{ + return wpa_drv_set_offload(wpa_s, offload); +} + + static unsigned int conf_offset_val(enum confidentiality_offset co) { switch (co) { case CONFIDENTIALITY_OFFSET_30: return 30; - break; case CONFIDENTIALITY_OFFSET_50: return 50; default: @@ -220,6 +225,7 @@ int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) kay_ctx->enable_protect_frames = wpas_enable_protect_frames; kay_ctx->enable_encrypt = wpas_enable_encrypt; kay_ctx->set_replay_protect = wpas_set_replay_protect; + kay_ctx->set_offload = wpas_set_offload; kay_ctx->set_current_cipher_suite = wpas_set_current_cipher_suite; kay_ctx->enable_controlled_port = wpas_enable_controlled_port; kay_ctx->get_receive_lowest_pn = wpas_get_receive_lowest_pn; @@ -240,9 +246,10 @@ int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) kay_ctx->disable_transmit_sa = wpas_disable_transmit_sa; res = ieee802_1x_kay_init(kay_ctx, policy, ssid->macsec_replay_protect, - ssid->macsec_replay_window, ssid->macsec_port, - ssid->mka_priority, wpa_s->ifname, - wpa_s->own_addr); + ssid->macsec_replay_window, + ssid->macsec_offload, ssid->macsec_port, + ssid->mka_priority, ssid->macsec_csindex, + wpa_s->ifname, wpa_s->own_addr); /* ieee802_1x_kay_init() frees kay_ctx on failure */ if (res == NULL) return -1; @@ -263,32 +270,6 @@ void ieee802_1x_dealloc_kay_sm(struct wpa_supplicant *wpa_s) } -static int ieee802_1x_auth_get_session_id(struct wpa_supplicant *wpa_s, - const u8 *addr, u8 *sid, size_t *len) -{ - const u8 *session_id; - size_t id_len, need_len; - - session_id = eapol_sm_get_session_id(wpa_s->eapol, &id_len); - if (session_id == NULL) { - wpa_printf(MSG_DEBUG, - "Failed to get SessionID from EAPOL state machines"); - return -1; - } - - need_len = 1 + 2 * 32 /* random size */; - if (need_len > id_len) { - wpa_printf(MSG_DEBUG, "EAP Session-Id not long enough"); - return -1; - } - - os_memcpy(sid, session_id, need_len); - *len = need_len; - - return 0; -} - - static int ieee802_1x_auth_get_msk(struct wpa_supplicant *wpa_s, const u8 *addr, u8 *msk, size_t *len) { @@ -321,8 +302,8 @@ static int ieee802_1x_auth_get_msk(struct wpa_supplicant *wpa_s, const u8 *addr, void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s, const u8 *peer_addr) { - u8 *sid; - size_t sid_len = 128; + const u8 *sid; + size_t sid_len; struct mka_key_name *ckn; struct mka_key *cak; struct mka_key *msk; @@ -336,10 +317,9 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s, MACSTR_SEC, MAC2STR_SEC(peer_addr)); msk = os_zalloc(sizeof(*msk)); - sid = os_zalloc(sid_len); ckn = os_zalloc(sizeof(*ckn)); cak = os_zalloc(sizeof(*cak)); - if (!msk || !sid || !ckn || !cak) + if (!msk || !ckn || !cak) goto fail; msk->len = DEFAULT_KEY_LEN; @@ -348,8 +328,8 @@ void * ieee802_1x_notify_create_actor(struct wpa_supplicant *wpa_s, goto fail; } - if (ieee802_1x_auth_get_session_id(wpa_s, wpa_s->bssid, sid, &sid_len)) - { + sid = eapol_sm_get_session_id(wpa_s->eapol, &sid_len); + if (!sid) { wpa_printf(MSG_ERROR, "IEEE 802.1X: Could not get EAP Session Id"); goto fail; @@ -383,7 +363,6 @@ fail: os_memset(msk, 0, sizeof(*msk)); os_free(msk); } - os_free(sid); os_free(ckn); if (cak) { os_memset(cak, 0, sizeof(*cak)); diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_module_tests.c b/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_module_tests.c index ce5398cb851a29e285d2fd35a306c0d43ca8663b..9e7a57c4f134cabe0e7b9a3320d74a651eeefc02 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_module_tests.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wpas_module_tests.c @@ -17,9 +17,12 @@ static int wpas_bssid_ignore_module_tests(void) { struct wpa_supplicant wpa_s; + struct wpa_global global; int ret = -1; os_memset(&wpa_s, 0, sizeof(wpa_s)); + os_memset(&global, 0, sizeof(global)); + wpa_s.global = &global; wpa_bssid_ignore_clear(&wpa_s); diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wps_supplicant.c b/wpa_supplicant-2.9_standard/wpa_supplicant/wps_supplicant.c index 2a378bb0bf379df1629c6c40ab28bca5a3962e86..44ca03ab2609c4673040d8393d0cf1ea9a790a92 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wps_supplicant.c @@ -33,7 +33,6 @@ #include "p2p/p2p.h" #include "p2p_supplicant.h" #include "wps_supplicant.h" - #ifdef CONFIG_P2P_CHR #include "wpa_hw_p2p_chr.h" #endif @@ -42,6 +41,10 @@ #include "hilink_okc.h" #endif + + + + #ifndef WPS_PIN_SCAN_IGNORE_SEL_REG #define WPS_PIN_SCAN_IGNORE_SEL_REG 3 #endif /* WPS_PIN_SCAN_IGNORE_SEL_REG */ @@ -94,6 +97,18 @@ static void wpas_wps_assoc_with_cred_cancel(struct wpa_supplicant *wpa_s) } +static struct wpabuf * wpas_wps_get_wps_ie(struct wpa_bss *bss) +{ + /* Return the latest receive WPS IE from the AP regardless of whether + * it was from a Beacon frame or Probe Response frame to avoid using + * stale information. */ + if (bss->beacon_newer) + return wpa_bss_get_vendor_ie_multi_beacon(bss, + WPS_IE_VENDOR_TYPE); + return wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); +} + + int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) { if (wpas_p2p_wps_eapol_cb(wpa_s) > 0) @@ -168,8 +183,7 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) struct wpabuf *wps; struct wps_parse_attr attr; - wps = wpa_bss_get_vendor_ie_multi(bss, - WPS_IE_VENDOR_TYPE); + wps = wpas_wps_get_wps_ie(bss); if (wps && wps_parse_msg(wps, &attr) == 0 && attr.wps_state && *attr.wps_state == WPS_STATE_CONFIGURED) @@ -315,8 +329,7 @@ static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s, if (ssid->bssid_set || new_ssid->bssid_set) { if (ssid->bssid_set != new_ssid->bssid_set) continue; - if (os_memcmp(ssid->bssid, new_ssid->bssid, ETH_ALEN) != - 0) + if (!ether_addr_equal(ssid->bssid, new_ssid->bssid)) continue; } @@ -387,8 +400,6 @@ static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s, /* Remove the duplicated older network entry. */ wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id); wpas_notify_network_removed(wpa_s, ssid); - if (wpa_s->current_ssid == ssid) - wpa_s->current_ssid = NULL; wpa_config_remove_network(wpa_s->conf, ssid->id); } } @@ -1044,6 +1055,8 @@ static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx) * during an EAP-WSC exchange). */ wpas_notify_wps_event_fail(wpa_s, &data.fail); + wpa_s->supp_pbc_active = false; + wpa_s->wps_overlap = false; wpas_clear_wps(wpa_s); } @@ -1091,7 +1104,7 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s, */ #ifndef CONFIG_P2P dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { - if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0) + if (!ether_addr_equal(bssid, bss->bssid)) continue; os_free(ssid->ssid); @@ -1238,14 +1251,21 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, } } #endif /* CONFIG_P2P */ - os_snprintf(phase1, sizeof(phase1), "pbc=1%s", - multi_ap_backhaul_sta ? " multi_ap=1" : ""); + if (multi_ap_backhaul_sta) + os_snprintf(phase1, sizeof(phase1), "pbc=1 multi_ap=%d", + multi_ap_backhaul_sta); + else + os_snprintf(phase1, sizeof(phase1), "pbc=1"); if (wpa_config_set_quoted(ssid, "phase1", phase1) < 0) return -1; if (wpa_s->wps_fragment_size) ssid->eap.fragment_size = wpa_s->wps_fragment_size; - if (multi_ap_backhaul_sta) + if (multi_ap_backhaul_sta) { ssid->multi_ap_backhaul_sta = 1; + ssid->multi_ap_profile = multi_ap_backhaul_sta; + } + wpa_s->supp_pbc_active = true; + wpa_s->wps_overlap = false; wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL); eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); @@ -1413,6 +1433,8 @@ int wpas_wps_cancel(struct wpa_supplicant *wpa_s) wpas_clear_wps(wpa_s); } + wpa_s->supp_pbc_active = false; + wpa_s->wps_overlap = false; wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CANCEL); wpa_s->after_wps = 0; @@ -1747,7 +1769,7 @@ int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s, if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS)) return -1; - wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + wps_ie = wpas_wps_get_wps_ie(bss); if (eap_is_wps_pbc_enrollee(&ssid->eap)) { if (!wps_ie) { wpa_printf(MSG_DEBUG, " skip - non-WPS AP"); @@ -1821,13 +1843,13 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, int ret = 0; if (eap_is_wps_pbc_enrollee(&ssid->eap)) { - wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + wps_ie = wpas_wps_get_wps_ie(bss); if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) { /* allow wildcard SSID for WPS PBC */ ret = 1; } } else if (eap_is_wps_pin_enrollee(&ssid->eap)) { - wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + wps_ie = wpas_wps_get_wps_ie(bss); if (wps_ie && (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1) || wpa_s->scan_runs >= WPS_PIN_SCAN_IGNORE_SEL_REG)) { @@ -1837,7 +1859,7 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, } if (!ret && ssid->bssid_set && - os_memcmp(ssid->bssid, bss->bssid, ETH_ALEN) == 0) { + ether_addr_equal(ssid->bssid, bss->bssid)) { /* allow wildcard SSID due to hardcoded BSSID match */ ret = 1; } @@ -1870,9 +1892,40 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s, } +static bool wpas_wps_is_pbc_overlap(struct wps_ap_info *ap, + struct wpa_bss *selected, + struct wpa_ssid *ssid, + const u8 *sel_uuid) +{ + if (!ap->pbc_active || + ether_addr_equal(selected->bssid, ap->bssid)) + return false; + + if (!is_zero_ether_addr(ssid->bssid) && + !ether_addr_equal(ap->bssid, ssid->bssid)) { + wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR + " in active PBC mode due to local BSSID limitation", + MAC2STR(ap->bssid)); + return 0; + } + + wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: " MACSTR, + MAC2STR(ap->bssid)); + wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS", + ap->uuid, UUID_LEN); + if (!sel_uuid || os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0) + return true; + + /* TODO: verify that this is reasonable dual-band situation */ + + return false; +} + + int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid) { + struct wpa_supplicant *iface; const u8 *sel_uuid; struct wpabuf *wps_ie; int ret = 0; @@ -1901,40 +1954,24 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, sel_uuid = NULL; } - for (i = 0; i < wpa_s->num_wps_ap; i++) { - struct wps_ap_info *ap = &wpa_s->wps_ap[i]; - - if (!ap->pbc_active || - os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0) - continue; - - if (!is_zero_ether_addr(ssid->bssid) && - os_memcmp(ap->bssid, ssid->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR_SEC - " in active PBC mode due to local BSSID limitation", - MAC2STR_SEC(ap->bssid)); - continue; - } - - wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: " - MACSTR_SEC, MAC2STR_SEC(ap->bssid)); - wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS", - ap->uuid, UUID_LEN); - if (sel_uuid == NULL || - os_memcmp(sel_uuid, ap->uuid, UUID_LEN) != 0) { - ret = 1; /* PBC overlap */ - wpa_msg_only_for_cb(wpa_s, MSG_INFO, "WPS: PBC overlap detected: " - MACSTR " and " MACSTR, - MAC2STR(selected->bssid), - MAC2STR(ap->bssid)); - wpa_printf(MSG_INFO, "WPS: PBC overlap detected: " - MACSTR_SEC " and " MACSTR_SEC, - MAC2STR_SEC(selected->bssid), - MAC2STR_SEC(ap->bssid)); - break; + for (iface = wpa_s->global->ifaces; iface; iface = iface->next) { + for (i = 0; i < iface->num_wps_ap; i++) { + struct wps_ap_info *ap = &iface->wps_ap[i]; + + if (wpas_wps_is_pbc_overlap(ap, selected, ssid, + sel_uuid)) { + ret = 1; /* PBC overlap */ + wpa_msg_only_for_cb(wpa_s, MSG_INFO, "WPS: PBC overlap detected: " + MACSTR " and " MACSTR, + MAC2STR(selected->bssid), + MAC2STR(ap->bssid)); + wpa_printf(MSG_INFO, "WPS: PBC overlap detected: " + MACSTR_SEC " and " MACSTR_SEC, + MAC2STR_SEC(selected->bssid), + MAC2STR_SEC(ap->bssid)); + break; + } } - - /* TODO: verify that this is reasonable dual-band situation */ } wpabuf_free(wps_ie); @@ -1953,7 +1990,8 @@ void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s) dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { struct wpabuf *ie; - ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE); + + ie = wpas_wps_get_wps_ie(bss); if (!ie) continue; if (wps_is_selected_pbc_registrar(ie)) @@ -2955,7 +2993,7 @@ static struct wps_ap_info * wpas_wps_get_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]; - if (os_memcmp(ap->bssid, bssid, ETH_ALEN) == 0) + if (ether_addr_equal(ap->bssid, bssid)) return ap; } @@ -3041,6 +3079,48 @@ void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, } +bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s) +{ + struct wpa_global *global = wpa_s->global; + struct wpa_supplicant *iface; + + for (iface = global->ifaces; iface; iface = iface->next) { + if (iface == wpa_s) + continue; + + if (!iface->supp_pbc_active) + continue; + + /* Scan results are available for both links. While the current + * link will proceed for network selection, ensure the partner + * link also gets an attempt at network selection and connect + * with the selected BSS. */ + if (iface->wps_scan_done) + wpa_wps_supplicant_fast_associate(iface); + else + return false; + } + + return true; +} + + +bool wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s) +{ + struct wpa_global *global = wpa_s->global; + struct wpa_supplicant *iface; + + for (iface = global->ifaces; iface; iface = iface->next) { + if (iface == wpa_s) + continue; + if (iface->wps_overlap) + return true; + } + + return false; +} + + void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid) { struct wps_ap_info *ap; diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/wps_supplicant.h b/wpa_supplicant-2.9_standard/wpa_supplicant/wps_supplicant.h index c55936ceeaafe471b0686ce5fc98bc617e528cac..aae3f7cb594a7e50e800d622eceeed0d43149c07 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/wps_supplicant.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/wps_supplicant.h @@ -85,6 +85,8 @@ int wpas_er_wps_nfc_report_handover(struct wpa_supplicant *wpa_s, const struct wpabuf *sel); void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); +bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s); +bool wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s); void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid); int wpas_wps_reenable_networks_pending(struct wpa_supplicant *wpa_s); @@ -144,6 +146,17 @@ static inline void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s, { } +static inline bool wpas_wps_partner_link_scan_done(struct wpa_supplicant *wpa_s) +{ + return true; +} + +static inline bool +wpas_wps_partner_link_overlap_detect(struct wpa_supplicant *wpa_s) +{ + return false; +} + static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid) { diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cert_manager_api.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cert_manager_api.h index df0246dd0d231185e2f194039bc5dca774995569..b74656f263a38a6bda9c17919a7ba794cdc251aa 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cert_manager_api.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cert_manager_api.h @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CERT_MANGAGER_API_H -#define CERT_MANGAGER_API_H - -#include "cm_type.h" - -#ifdef __cplusplus -extern "C" { -#endif - -CM_API_EXPORT int32_t CmGetAppCert(const struct CmBlob *keyUri, const uint32_t store, struct Credential *certificate); - -CM_API_EXPORT int32_t CmInit(const struct CmBlob *authUri, const struct CmSignatureSpec *spec, struct CmBlob *handle); - -CM_API_EXPORT int32_t CmUpdate(const struct CmBlob *handle, const struct CmBlob *inData); - -CM_API_EXPORT int32_t CmFinish(const struct CmBlob *handle, const struct CmBlob *inData, struct CmBlob *outData); - -CM_API_EXPORT int32_t CmAbort(const struct CmBlob *handle); - -#ifdef __cplusplus -} -#endif - +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CERT_MANGAGER_API_H +#define CERT_MANGAGER_API_H + +#include "cm_type.h" + +#ifdef __cplusplus +extern "C" { +#endif + +CM_API_EXPORT int32_t CmGetAppCert(const struct CmBlob *keyUri, const uint32_t store, struct Credential *certificate); + +CM_API_EXPORT int32_t CmInit(const struct CmBlob *authUri, const struct CmSignatureSpec *spec, struct CmBlob *handle); + +CM_API_EXPORT int32_t CmUpdate(const struct CmBlob *handle, const struct CmBlob *inData); + +CM_API_EXPORT int32_t CmFinish(const struct CmBlob *handle, const struct CmBlob *inData, struct CmBlob *outData); + +CM_API_EXPORT int32_t CmAbort(const struct CmBlob *handle); + +#ifdef __cplusplus +} +#endif + #endif /* CERT_MANGAGER_API_H */ \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cert_manager_service_ipc_interface_code.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cert_manager_service_ipc_interface_code.h index e3050d7b34f5330e97acdd33230e595f7fc1dd10..91b6a2e9f26fe231ddb9fcf20bb7683b127a7515 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cert_manager_service_ipc_interface_code.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cert_manager_service_ipc_interface_code.h @@ -1,59 +1,59 @@ -/* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CM_IPC_MSG_CODE_H -#define CM_IPC_MSG_CODE_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* SAID: 3512 */ -enum CertManagerInterfaceCode { - CM_MSG_BASE = 0, - - CM_MSG_GEN_KEY = CM_MSG_BASE, - CM_MSG_GET_CERTIFICATE_LIST, - CM_MSG_GET_CERTIFICATE_INFO, - CM_MSG_SET_CERTIFICATE_STATUS, - CM_MSG_INSTALL_APP_CERTIFICATE, - CM_MSG_UNINSTALL_APP_CERTIFICATE, - CM_MSG_UNINSTALL_ALL_APP_CERTIFICATE, - CM_MSG_GET_APP_CERTIFICATE_LIST, - CM_MSG_GET_CALLING_APP_CERTIFICATE_LIST, - CM_MSG_GET_APP_CERTIFICATE, - CM_MSG_GRANT_APP_CERT, - CM_MSG_GET_AUTHED_LIST, - CM_MSG_CHECK_IS_AUTHED_APP, - CM_MSG_REMOVE_GRANT_APP, - CM_MSG_INIT, - CM_MSG_UPDATE, - CM_MSG_FINISH, - CM_MSG_ABORT, - CM_MSG_GET_USER_CERTIFICATE_LIST, - CM_MSG_GET_USER_CERTIFICATE_INFO, - CM_MSG_SET_USER_CERTIFICATE_STATUS, - CM_MSG_INSTALL_USER_CERTIFICATE, - CM_MSG_UNINSTALL_USER_CERTIFICATE, - CM_MSG_UNINSTALL_ALL_USER_CERTIFICATE, - - /* new cmd type must be added before CM_MSG_MAX */ - CM_MSG_MAX, -}; - -#ifdef __cplusplus -} -#endif -#endif +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CM_IPC_MSG_CODE_H +#define CM_IPC_MSG_CODE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* SAID: 3512 */ +enum CertManagerInterfaceCode { + CM_MSG_BASE = 0, + + CM_MSG_GEN_KEY = CM_MSG_BASE, + CM_MSG_GET_CERTIFICATE_LIST, + CM_MSG_GET_CERTIFICATE_INFO, + CM_MSG_SET_CERTIFICATE_STATUS, + CM_MSG_INSTALL_APP_CERTIFICATE, + CM_MSG_UNINSTALL_APP_CERTIFICATE, + CM_MSG_UNINSTALL_ALL_APP_CERTIFICATE, + CM_MSG_GET_APP_CERTIFICATE_LIST, + CM_MSG_GET_CALLING_APP_CERTIFICATE_LIST, + CM_MSG_GET_APP_CERTIFICATE, + CM_MSG_GRANT_APP_CERT, + CM_MSG_GET_AUTHED_LIST, + CM_MSG_CHECK_IS_AUTHED_APP, + CM_MSG_REMOVE_GRANT_APP, + CM_MSG_INIT, + CM_MSG_UPDATE, + CM_MSG_FINISH, + CM_MSG_ABORT, + CM_MSG_GET_USER_CERTIFICATE_LIST, + CM_MSG_GET_USER_CERTIFICATE_INFO, + CM_MSG_SET_USER_CERTIFICATE_STATUS, + CM_MSG_INSTALL_USER_CERTIFICATE, + CM_MSG_UNINSTALL_USER_CERTIFICATE, + CM_MSG_UNINSTALL_ALL_USER_CERTIFICATE, + + /* new cmd type must be added before CM_MSG_MAX */ + CM_MSG_MAX, +}; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_ipc_client.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_ipc_client.h index 31b28054be13ea6fbe2eaa797b853a812075abe1..0c1560233bd93e76b8c4822b5dad9502ae3b1906 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_ipc_client.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_ipc_client.h @@ -1,42 +1,42 @@ -/* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CM_CLIENT_IPC_H -#define CM_CLIENT_IPC_H - -#include "cm_request.h" -#include "cm_type_inner.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -int32_t CmClientGetAppCert(const struct CmBlob *keyUri, const uint32_t store, struct Credential *certificate); - -int32_t CmClientInit(const struct CmBlob *authUri, const struct CmSignatureSpec *spec, struct CmBlob *handle); - -int32_t CmClientUpdate(const struct CmBlob *handle, const struct CmBlob *inData); - -int32_t CmClientFinish(const struct CmBlob *handle, const struct CmBlob *inData, struct CmBlob *outData); - -int32_t CmClientAbort(const struct CmBlob *handle); - - -#ifdef __cplusplus -} -#endif - -#endif /* CM_CLIENT_IPC_H */ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CM_CLIENT_IPC_H +#define CM_CLIENT_IPC_H + +#include "cm_request.h" +#include "cm_type_inner.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +int32_t CmClientGetAppCert(const struct CmBlob *keyUri, const uint32_t store, struct Credential *certificate); + +int32_t CmClientInit(const struct CmBlob *authUri, const struct CmSignatureSpec *spec, struct CmBlob *handle); + +int32_t CmClientUpdate(const struct CmBlob *handle, const struct CmBlob *inData); + +int32_t CmClientFinish(const struct CmBlob *handle, const struct CmBlob *inData, struct CmBlob *outData); + +int32_t CmClientAbort(const struct CmBlob *handle); + + +#ifdef __cplusplus +} +#endif + +#endif /* CM_CLIENT_IPC_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_ipc_client_serialization.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_ipc_client_serialization.h index dbdd4e526aae96988736649b2be55b8aed8d6f2b..2c0663f049fca752e2604e418d7aaeebf87c20ba 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_ipc_client_serialization.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_ipc_client_serialization.h @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CM_IPC_CLIENT_SERIALIZATION_H -#define CM_IPC_CLIENT_SERIALIZATION_H - -#include "cm_type_inner.h" - -#define MAX_IPC_BUF_SIZE 0x10000 /* Maximun IPC message buffer size. */ -#define MAX_IPC_RSV_SIZE 0x400 /* Reserve IPC message buffer size */ -#define MAX_PROCESS_SIZE (MAX_IPC_BUF_SIZE - MAX_IPC_RSV_SIZE) - -#ifdef __cplusplus -extern "C" { -#endif - -int32_t GetUint32FromBuffer(uint32_t *value, const struct CmBlob *srcBlob, uint32_t *srcOffset); - -int32_t CmGetBlobFromBuffer(struct CmBlob *blob, const struct CmBlob *srcBlob, uint32_t *srcOffset); - -int32_t CmParamsToParamSet(struct CmParam *params, uint32_t cnt, struct CmParamSet **outParamSet); - -#ifdef __cplusplus -} -#endif - +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CM_IPC_CLIENT_SERIALIZATION_H +#define CM_IPC_CLIENT_SERIALIZATION_H + +#include "cm_type_inner.h" + +#define MAX_IPC_BUF_SIZE 0x10000 /* Maximun IPC message buffer size. */ +#define MAX_IPC_RSV_SIZE 0x400 /* Reserve IPC message buffer size */ +#define MAX_PROCESS_SIZE (MAX_IPC_BUF_SIZE - MAX_IPC_RSV_SIZE) + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t GetUint32FromBuffer(uint32_t *value, const struct CmBlob *srcBlob, uint32_t *srcOffset); + +int32_t CmGetBlobFromBuffer(struct CmBlob *blob, const struct CmBlob *srcBlob, uint32_t *srcOffset); + +int32_t CmParamsToParamSet(struct CmParam *params, uint32_t cnt, struct CmParamSet **outParamSet); + +#ifdef __cplusplus +} +#endif + #endif /* CM_IPC_CLIENT_SERIALIZATION_H */ \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_load_sa.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_load_sa.h index c0567f342fd3af38aa6c87033bdbe8e0744f57f7..6a488c9182517f05ab7bb9562aaf82e0bc8dbda0 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_load_sa.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_load_sa.h @@ -1,36 +1,36 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CM_LOAD_SA_H -#define CM_LOAD_SA_H - -#include -#include -#include "iremote_object.h" -#include "system_ability_load_callback_stub.h" - -class OnDemandLoadCertManagerCallback : public OHOS::SystemAbilityLoadCallbackStub { -public: - OnDemandLoadCertManagerCallback(std::string servers); - void OnLoadSystemAbilitySuccess(int32_t systemAbilityId, - const OHOS::sptr& remoteObject) override; - void OnLoadSystemAbilityFail(int32_t systemAbilityId) override; - OHOS::sptr Promise(void); -private: - std::string servers; - std::promise> promise_; -}; - +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CM_LOAD_SA_H +#define CM_LOAD_SA_H + +#include +#include +#include "iremote_object.h" +#include "system_ability_load_callback_stub.h" + +class OnDemandLoadCertManagerCallback : public OHOS::SystemAbilityLoadCallbackStub { +public: + OnDemandLoadCertManagerCallback(std::string servers); + void OnLoadSystemAbilitySuccess(int32_t systemAbilityId, + const OHOS::sptr& remoteObject) override; + void OnLoadSystemAbilityFail(int32_t systemAbilityId) override; + OHOS::sptr Promise(void); +private: + std::string servers; + std::promise> promise_; +}; + #endif /* CM_LOAD_SA_H */ \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_log.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_log.h index a1df0daa3f01d6cf09f56149b93f7bb81cd6883d..db95a2e76815f71450bbbd0b60a3544275963a1e 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_log.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_log.h @@ -1,57 +1,57 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CM_LOG_H -#define CM_LOG_H - -#include "cm_type.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef _CM_LOG_ENABLE_ -#undef LOG_TAG -#define LOG_TAG "CertManager" -#undef LOG_DOMAIN -#define LOG_DOMAIN 0xD002F09 /* CertManager's domain id */ -#endif - -enum CmLogLevel { - CM_LOG_LEVEL_I, - CM_LOG_LEVEL_E, - CM_LOG_LEVEL_W, - CM_LOG_LEVEL_D, -}; - -#ifdef _CM_LOG_ENABLE_ -void CmLog(uint32_t logLevel, const char *funcName, uint32_t lineNo, const char *format, ...); - -#define CM_LOG_I(...) CmLog(CM_LOG_LEVEL_I, __func__, __LINE__, __VA_ARGS__) -#define CM_LOG_W(...) CmLog(CM_LOG_LEVEL_W, __func__, __LINE__, __VA_ARGS__) -#define CM_LOG_E(...) CmLog(CM_LOG_LEVEL_E, __func__, __LINE__, __VA_ARGS__) -#define CM_LOG_D(...) CmLog(CM_LOG_LEVEL_D, __func__, __LINE__, __VA_ARGS__) -#else -#define CM_LOG_I(...) -#define CM_LOG_W(...) -#define CM_LOG_E(...) -#define CM_LOG_D(...) -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* CM_LOG_H */ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CM_LOG_H +#define CM_LOG_H + +#include "cm_type.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _CM_LOG_ENABLE_ +#undef LOG_TAG +#define LOG_TAG "CertManager" +#undef LOG_DOMAIN +#define LOG_DOMAIN 0xD002F09 /* CertManager's domain id */ +#endif + +enum CmLogLevel { + CM_LOG_LEVEL_I, + CM_LOG_LEVEL_E, + CM_LOG_LEVEL_W, + CM_LOG_LEVEL_D, +}; + +#ifdef _CM_LOG_ENABLE_ +void CmLog(uint32_t logLevel, const char *funcName, uint32_t lineNo, const char *format, ...); + +#define CM_LOG_I(...) CmLog(CM_LOG_LEVEL_I, __func__, __LINE__, __VA_ARGS__) +#define CM_LOG_W(...) CmLog(CM_LOG_LEVEL_W, __func__, __LINE__, __VA_ARGS__) +#define CM_LOG_E(...) CmLog(CM_LOG_LEVEL_E, __func__, __LINE__, __VA_ARGS__) +#define CM_LOG_D(...) CmLog(CM_LOG_LEVEL_D, __func__, __LINE__, __VA_ARGS__) +#else +#define CM_LOG_I(...) +#define CM_LOG_W(...) +#define CM_LOG_E(...) +#define CM_LOG_D(...) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CM_LOG_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_mem.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_mem.h index a861eaae8c3ca6049cb5f48a74f921a3d07062d4..fd38b23ded1162139ba5bafd93c3947b4be86672 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_mem.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_mem.h @@ -1,51 +1,51 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CM_MEM_H -#define CM_MEM_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void *CmMalloc(size_t size); -void CmFree(void *ptr); - -#define SELF_FREE_PTR(PTR, FREE_FUNC) \ -{ \ - if ((PTR) != NULL) { \ - FREE_FUNC(PTR); \ - (PTR) = NULL; \ - } \ -} - -#define CM_FREE_PTR(p) SELF_FREE_PTR(p, CmFree) - -#define CM_FREE_BLOB(blob) do { \ - if ((blob).data != NULL) { \ - CmFree((blob).data); \ - (blob).data = NULL; \ - } \ - (blob).size = 0; \ -} while (0) - -#ifdef __cplusplus -} -#endif - +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CM_MEM_H +#define CM_MEM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void *CmMalloc(size_t size); +void CmFree(void *ptr); + +#define SELF_FREE_PTR(PTR, FREE_FUNC) \ +{ \ + if ((PTR) != NULL) { \ + FREE_FUNC(PTR); \ + (PTR) = NULL; \ + } \ +} + +#define CM_FREE_PTR(p) SELF_FREE_PTR(p, CmFree) + +#define CM_FREE_BLOB(blob) do { \ + if ((blob).data != NULL) { \ + CmFree((blob).data); \ + (blob).data = NULL; \ + } \ + (blob).size = 0; \ +} while (0) + +#ifdef __cplusplus +} +#endif + #endif /* CM_MEM_H */ \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_param.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_param.h index 1814f647c31c86a91ed450c5ee3a299b8b2ca3cd..ce7cee16eb57f4db497288316453edbddb8df351 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_param.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_param.h @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CM_PARAM_H -#define CM_PARAM_H - -#include "cm_type.h" - -#define CM_PARAM_SET_MAX_SIZE (4 * 1024 * 1024) -#define CM_DEFAULT_PARAM_SET_SIZE 512 -#define CM_DEFAULT_PARAM_CNT ((uint32_t)((CM_DEFAULT_PARAM_SET_SIZE - sizeof(struct CmParamSet)) / \ - sizeof(struct CmParam))) -#define CM_TAG_TYPE_MASK (0xF << 28) - -#ifdef __cplusplus -extern "C" { -#endif - -enum CmTagType GetTagType(enum CmTag tag); - -int32_t CmInitParamSet(struct CmParamSet **paramSet); - -int32_t CmBuildParamSet(struct CmParamSet **paramSet); - -void CmFreeParamSet(struct CmParamSet **paramSet); - -int32_t CmAddParams(struct CmParamSet *paramSet, const struct CmParam *params, uint32_t paramCnt); - -#ifdef __cplusplus -} -#endif +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CM_PARAM_H +#define CM_PARAM_H + +#include "cm_type.h" + +#define CM_PARAM_SET_MAX_SIZE (4 * 1024 * 1024) +#define CM_DEFAULT_PARAM_SET_SIZE 512 +#define CM_DEFAULT_PARAM_CNT ((uint32_t)((CM_DEFAULT_PARAM_SET_SIZE - sizeof(struct CmParamSet)) / \ + sizeof(struct CmParam))) +#define CM_TAG_TYPE_MASK (0xF << 28) + +#ifdef __cplusplus +extern "C" { +#endif + +enum CmTagType GetTagType(enum CmTag tag); + +int32_t CmInitParamSet(struct CmParamSet **paramSet); + +int32_t CmBuildParamSet(struct CmParamSet **paramSet); + +void CmFreeParamSet(struct CmParamSet **paramSet); + +int32_t CmAddParams(struct CmParamSet *paramSet, const struct CmParam *params, uint32_t paramCnt); + +#ifdef __cplusplus +} +#endif #endif \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_request.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_request.h index 110a189d4986904a87cc2c1b0419d21eec860993..fcb407ca86029537e41a8164d86a1e1d0dee667b 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_request.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_request.h @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CM_REQUEST_H -#define CM_REQUEST_H - -#include "cert_manager_service_ipc_interface_code.h" -#include "cm_type_inner.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * SendRequest - Send the request message to target module by function call or ipc or other ways. - * @type: the request message type. - * @inBlob: the input serialized data blob. - * @outBlob: the output serialized data blob, can be null. - */ -int32_t SendRequest(enum CertManagerInterfaceCode type, const struct CmBlob *inBlob, - struct CmBlob *outBlob); - -#ifdef __cplusplus -} -#endif - +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CM_REQUEST_H +#define CM_REQUEST_H + +#include "cert_manager_service_ipc_interface_code.h" +#include "cm_type_inner.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SendRequest - Send the request message to target module by function call or ipc or other ways. + * @type: the request message type. + * @inBlob: the input serialized data blob. + * @outBlob: the output serialized data blob, can be null. + */ +int32_t SendRequest(enum CertManagerInterfaceCode type, const struct CmBlob *inBlob, + struct CmBlob *outBlob); + +#ifdef __cplusplus +} +#endif + #endif /* CM_REQUEST_H */ \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_type.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_type.h index ce222b1d822948318db47cce57e1f12158de6f4c..44295ad4d575caf4127be797bb627704ef41ae66 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_type.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_type.h @@ -1,229 +1,229 @@ -/* - * Copyright (c) 2022-2024 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CM_TYPE_H -#define CM_TYPE_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif -#ifndef CM_API_PUBLIC - #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__ICCARM__) /* __ICCARM__ for iar */ - #define CM_API_EXPORT - #else - #define CM_API_EXPORT __attribute__ ((visibility("default"))) - #endif -#else - #define CM_API_EXPORT __attribute__ ((visibility("default"))) -#endif - -#define MAX_LEN_CERTIFICATE 8196 - -#define MAX_LEN_CERTIFICATE_CHAIN (3 * MAX_LEN_CERTIFICATE) - -#define MAX_SUFFIX_LEN 16 -#define MAX_COUNT_CERTIFICATE 256 -#define MAX_LEN_URI 256 -#define MAX_AUTH_LEN_URI 256 -#define MAX_LEN_CERT_ALIAS 129 /* include 1 byte: the terminator('\0') */ -#define MAX_LEN_SUBJECT_NAME 1025 -#define MAX_LEN_PACKGE_NAME 64 -#define MAX_UINT32_LEN 16 - -#define CM_ARRAY_SIZE(arr) ((sizeof(arr)) / (sizeof((arr)[0]))) - -/* - * Align to 4-tuple - * Before calling this function, ensure that the size does not overflow after 3 is added. - */ -#define ALIGN_SIZE(size) ((((uint32_t)(size) + 3) >> 2) << 2) - -#define CM_BITS_PER_BYTE 8 - -#define CM_CREDENTIAL_STORE 0 -#define CM_SYSTEM_TRUSTED_STORE 1 -#define CM_USER_TRUSTED_STORE 2 -#define CM_PRI_CREDENTIAL_STORE 3 -#define CM_SYS_CREDENTIAL_STORE 4 - -enum CmKeyDigest { - CM_DIGEST_NONE = 0, - CM_DIGEST_MD5 = 1, - CM_DIGEST_SHA1 = 10, - CM_DIGEST_SHA224 = 11, - CM_DIGEST_SHA256 = 12, - CM_DIGEST_SHA384 = 13, - CM_DIGEST_SHA512 = 14, -}; - -enum CmKeyPurpose { - CM_KEY_PURPOSE_ENCRYPT = 1, /* Usable with RSA, EC, AES, and SM4 keys. */ - CM_KEY_PURPOSE_DECRYPT = 2, /* Usable with RSA, EC, AES, and SM4 keys. */ - CM_KEY_PURPOSE_SIGN = 4, /* Usable with RSA, EC keys. */ - CM_KEY_PURPOSE_VERIFY = 8, /* Usable with RSA, EC keys. */ - CM_KEY_PURPOSE_DERIVE = 16, /* Usable with EC keys. */ - CM_KEY_PURPOSE_WRAP = 32, /* Usable with wrap key. */ - CM_KEY_PURPOSE_UNWRAP = 64, /* Usable with unwrap key. */ - CM_KEY_PURPOSE_MAC = 128, /* Usable with mac. */ - CM_KEY_PURPOSE_AGREE = 256, /* Usable with agree. */ -}; - -enum CmKeyPadding { - CM_PADDING_NONE = 0, - CM_PADDING_OAEP = 1, - CM_PADDING_PSS = 2, - CM_PADDING_PKCS1_V1_5 = 3, - CM_PADDING_PKCS5 = 4, - CM_PADDING_PKCS7 = 5, -}; - -enum CmErrorCode { - CM_SUCCESS = 0, - CM_FAILURE = -1, - - CMR_ERROR_NOT_PERMITTED = -2, - CMR_ERROR_NOT_SUPPORTED = -3, - CMR_ERROR_STORAGE = -4, - CMR_ERROR_NOT_FOUND = -5, - CMR_ERROR_NULL_POINTER = -6, - CMR_ERROR_INVALID_ARGUMENT = -7, - CMR_ERROR_MAKE_DIR_FAIL = -8, - CMR_ERROR_INVALID_OPERATION = -9, - CMR_ERROR_OPEN_FILE_FAIL = -10, - CMR_ERROR_READ_FILE_ERROR = -11, - CMR_ERROR_WRITE_FILE_FAIL = -12, - CMR_ERROR_REMOVE_FILE_FAIL = -13, - CMR_ERROR_CLOSE_FILE_FAIL = -14, - CMR_ERROR_MALLOC_FAIL = -15, - CMR_ERROR_NOT_EXIST = -16, - CMR_ERROR_ALREADY_EXISTS = -17, - CMR_ERROR_INSUFFICIENT_DATA = -18, - CMR_ERROR_BUFFER_TOO_SMALL = -19, - CMR_ERROR_INVALID_CERT_FORMAT = -20, - CMR_ERROR_PARAM_NOT_EXIST = -21, - CMR_ERROR_SESSION_REACHED_LIMIT = -22, - CMR_ERROR_PERMISSION_DENIED = -23, - CMR_ERROR_AUTH_CHECK_FAILED = -24, - CMR_ERROR_KEY_OPERATION_FAILED = -25, - CMR_ERROR_NOT_SYSTEMP_APP = -26, - CMR_ERROR_CERT_NUM_REACHED_LIMIT = -27, - CMR_ERROR_ALIAS_LENGTH_REACHED_LIMIT = -28, -}; - -enum CMErrorCode { /* temp use */ - CMR_OK = 0, - CMR_ERROR = -1, -}; - -enum CmTagType { - CM_TAG_TYPE_INVALID = 0 << 28, - CM_TAG_TYPE_INT = 1 << 28, - CM_TAG_TYPE_UINT = 2 << 28, - CM_TAG_TYPE_ULONG = 3 << 28, - CM_TAG_TYPE_BOOL = 4 << 28, - CM_TAG_TYPE_BYTES = 5 << 28, -}; - -enum CmTag { - /* Inner-use TAGS used for ipc serialization */ - CM_TAG_PARAM0_BUFFER = CM_TAG_TYPE_BYTES | 30001, - CM_TAG_PARAM1_BUFFER = CM_TAG_TYPE_BYTES | 30002, - CM_TAG_PARAM2_BUFFER = CM_TAG_TYPE_BYTES | 30003, - CM_TAG_PARAM3_BUFFER = CM_TAG_TYPE_BYTES | 30004, - CM_TAG_PARAM4_BUFFER = CM_TAG_TYPE_BYTES | 30005, - CM_TAG_PARAM0_UINT32 = CM_TAG_TYPE_UINT | 30006, - CM_TAG_PARAM1_UINT32 = CM_TAG_TYPE_UINT | 30007, - CM_TAG_PARAM2_UINT32 = CM_TAG_TYPE_UINT | 30008, - CM_TAG_PARAM3_UINT32 = CM_TAG_TYPE_UINT | 30009, - CM_TAG_PARAM4_UINT32 = CM_TAG_TYPE_UINT | 30010, - CM_TAG_PARAM0_BOOL = CM_TAG_TYPE_BOOL | 30011, - CM_TAG_PARAM1_BOOL = CM_TAG_TYPE_BOOL | 30012, - CM_TAG_PARAM2_BOOL = CM_TAG_TYPE_BOOL | 30013, - CM_TAG_PARAM3_BOOL = CM_TAG_TYPE_BOOL | 30014, - CM_TAG_PARAM4_BOOL = CM_TAG_TYPE_BOOL | 30015, - CM_TAG_PARAM0_NULL = CM_TAG_TYPE_BYTES | 30016, - CM_TAG_PARAM1_NULL = CM_TAG_TYPE_BYTES | 30017, - CM_TAG_PARAM2_NULL = CM_TAG_TYPE_BYTES | 30018, - CM_TAG_PARAM3_NULL = CM_TAG_TYPE_BYTES | 30019, - CM_TAG_PARAM4_NULL = CM_TAG_TYPE_BYTES | 30020, -}; - -#define CM_PARAM_BUFFER_NULL_INTERVAL ((CM_TAG_PARAM0_NULL) - (CM_TAG_PARAM0_BUFFER)) - -enum CmSendType { - CM_SEND_TYPE_ASYNC = 0, - CM_SEND_TYPE_SYNC, -}; - -struct CmBlob { - uint32_t size; - uint8_t *data; -}; - -struct Credential { - uint32_t isExist; - char type[MAX_LEN_SUBJECT_NAME]; - char alias[MAX_LEN_CERT_ALIAS]; - char keyUri[MAX_LEN_URI]; - uint32_t certNum; - uint32_t keyNum; - struct CmBlob credData; -}; - -struct CmParam { - uint32_t tag; - union { - bool boolParam; - int32_t int32Param; - uint32_t uint32Param; - uint64_t uint64Param; - struct CmBlob blob; - }; -}; - -struct CmParamSet { - uint32_t paramSetSize; - uint32_t paramsCnt; - struct CmParam params[]; -}; - -struct CmSignatureSpec { - uint32_t purpose; - uint32_t padding; - uint32_t digest; -}; - -static inline bool CmIsAdditionOverflow(uint32_t a, uint32_t b) -{ - return (UINT32_MAX - a) < b; -} - -static inline int32_t CmCheckBlob(const struct CmBlob *blob) -{ - if ((blob == NULL) || (blob->data == NULL) || (blob->size == 0)) { - return CMR_ERROR_INVALID_ARGUMENT; - } - return CM_SUCCESS; -} - -#ifdef __cplusplus -} -#endif - -#endif /* CM_TYPE_H */ +/* + * Copyright (c) 2022-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CM_TYPE_H +#define CM_TYPE_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#ifndef CM_API_PUBLIC + #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__ICCARM__) /* __ICCARM__ for iar */ + #define CM_API_EXPORT + #else + #define CM_API_EXPORT __attribute__ ((visibility("default"))) + #endif +#else + #define CM_API_EXPORT __attribute__ ((visibility("default"))) +#endif + +#define MAX_LEN_CERTIFICATE 8196 + +#define MAX_LEN_CERTIFICATE_CHAIN (3 * MAX_LEN_CERTIFICATE) + +#define MAX_SUFFIX_LEN 16 +#define MAX_COUNT_CERTIFICATE 256 +#define MAX_LEN_URI 256 +#define MAX_AUTH_LEN_URI 256 +#define MAX_LEN_CERT_ALIAS 129 /* include 1 byte: the terminator('\0') */ +#define MAX_LEN_SUBJECT_NAME 1025 +#define MAX_LEN_PACKGE_NAME 64 +#define MAX_UINT32_LEN 16 + +#define CM_ARRAY_SIZE(arr) ((sizeof(arr)) / (sizeof((arr)[0]))) + +/* + * Align to 4-tuple + * Before calling this function, ensure that the size does not overflow after 3 is added. + */ +#define ALIGN_SIZE(size) ((((uint32_t)(size) + 3) >> 2) << 2) + +#define CM_BITS_PER_BYTE 8 + +#define CM_CREDENTIAL_STORE 0 +#define CM_SYSTEM_TRUSTED_STORE 1 +#define CM_USER_TRUSTED_STORE 2 +#define CM_PRI_CREDENTIAL_STORE 3 +#define CM_SYS_CREDENTIAL_STORE 4 + +enum CmKeyDigest { + CM_DIGEST_NONE = 0, + CM_DIGEST_MD5 = 1, + CM_DIGEST_SHA1 = 10, + CM_DIGEST_SHA224 = 11, + CM_DIGEST_SHA256 = 12, + CM_DIGEST_SHA384 = 13, + CM_DIGEST_SHA512 = 14, +}; + +enum CmKeyPurpose { + CM_KEY_PURPOSE_ENCRYPT = 1, /* Usable with RSA, EC, AES, and SM4 keys. */ + CM_KEY_PURPOSE_DECRYPT = 2, /* Usable with RSA, EC, AES, and SM4 keys. */ + CM_KEY_PURPOSE_SIGN = 4, /* Usable with RSA, EC keys. */ + CM_KEY_PURPOSE_VERIFY = 8, /* Usable with RSA, EC keys. */ + CM_KEY_PURPOSE_DERIVE = 16, /* Usable with EC keys. */ + CM_KEY_PURPOSE_WRAP = 32, /* Usable with wrap key. */ + CM_KEY_PURPOSE_UNWRAP = 64, /* Usable with unwrap key. */ + CM_KEY_PURPOSE_MAC = 128, /* Usable with mac. */ + CM_KEY_PURPOSE_AGREE = 256, /* Usable with agree. */ +}; + +enum CmKeyPadding { + CM_PADDING_NONE = 0, + CM_PADDING_OAEP = 1, + CM_PADDING_PSS = 2, + CM_PADDING_PKCS1_V1_5 = 3, + CM_PADDING_PKCS5 = 4, + CM_PADDING_PKCS7 = 5, +}; + +enum CmErrorCode { + CM_SUCCESS = 0, + CM_FAILURE = -1, + + CMR_ERROR_NOT_PERMITTED = -2, + CMR_ERROR_NOT_SUPPORTED = -3, + CMR_ERROR_STORAGE = -4, + CMR_ERROR_NOT_FOUND = -5, + CMR_ERROR_NULL_POINTER = -6, + CMR_ERROR_INVALID_ARGUMENT = -7, + CMR_ERROR_MAKE_DIR_FAIL = -8, + CMR_ERROR_INVALID_OPERATION = -9, + CMR_ERROR_OPEN_FILE_FAIL = -10, + CMR_ERROR_READ_FILE_ERROR = -11, + CMR_ERROR_WRITE_FILE_FAIL = -12, + CMR_ERROR_REMOVE_FILE_FAIL = -13, + CMR_ERROR_CLOSE_FILE_FAIL = -14, + CMR_ERROR_MALLOC_FAIL = -15, + CMR_ERROR_NOT_EXIST = -16, + CMR_ERROR_ALREADY_EXISTS = -17, + CMR_ERROR_INSUFFICIENT_DATA = -18, + CMR_ERROR_BUFFER_TOO_SMALL = -19, + CMR_ERROR_INVALID_CERT_FORMAT = -20, + CMR_ERROR_PARAM_NOT_EXIST = -21, + CMR_ERROR_SESSION_REACHED_LIMIT = -22, + CMR_ERROR_PERMISSION_DENIED = -23, + CMR_ERROR_AUTH_CHECK_FAILED = -24, + CMR_ERROR_KEY_OPERATION_FAILED = -25, + CMR_ERROR_NOT_SYSTEMP_APP = -26, + CMR_ERROR_CERT_NUM_REACHED_LIMIT = -27, + CMR_ERROR_ALIAS_LENGTH_REACHED_LIMIT = -28, +}; + +enum CMErrorCode { /* temp use */ + CMR_OK = 0, + CMR_ERROR = -1, +}; + +enum CmTagType { + CM_TAG_TYPE_INVALID = 0 << 28, + CM_TAG_TYPE_INT = 1 << 28, + CM_TAG_TYPE_UINT = 2 << 28, + CM_TAG_TYPE_ULONG = 3 << 28, + CM_TAG_TYPE_BOOL = 4 << 28, + CM_TAG_TYPE_BYTES = 5 << 28, +}; + +enum CmTag { + /* Inner-use TAGS used for ipc serialization */ + CM_TAG_PARAM0_BUFFER = CM_TAG_TYPE_BYTES | 30001, + CM_TAG_PARAM1_BUFFER = CM_TAG_TYPE_BYTES | 30002, + CM_TAG_PARAM2_BUFFER = CM_TAG_TYPE_BYTES | 30003, + CM_TAG_PARAM3_BUFFER = CM_TAG_TYPE_BYTES | 30004, + CM_TAG_PARAM4_BUFFER = CM_TAG_TYPE_BYTES | 30005, + CM_TAG_PARAM0_UINT32 = CM_TAG_TYPE_UINT | 30006, + CM_TAG_PARAM1_UINT32 = CM_TAG_TYPE_UINT | 30007, + CM_TAG_PARAM2_UINT32 = CM_TAG_TYPE_UINT | 30008, + CM_TAG_PARAM3_UINT32 = CM_TAG_TYPE_UINT | 30009, + CM_TAG_PARAM4_UINT32 = CM_TAG_TYPE_UINT | 30010, + CM_TAG_PARAM0_BOOL = CM_TAG_TYPE_BOOL | 30011, + CM_TAG_PARAM1_BOOL = CM_TAG_TYPE_BOOL | 30012, + CM_TAG_PARAM2_BOOL = CM_TAG_TYPE_BOOL | 30013, + CM_TAG_PARAM3_BOOL = CM_TAG_TYPE_BOOL | 30014, + CM_TAG_PARAM4_BOOL = CM_TAG_TYPE_BOOL | 30015, + CM_TAG_PARAM0_NULL = CM_TAG_TYPE_BYTES | 30016, + CM_TAG_PARAM1_NULL = CM_TAG_TYPE_BYTES | 30017, + CM_TAG_PARAM2_NULL = CM_TAG_TYPE_BYTES | 30018, + CM_TAG_PARAM3_NULL = CM_TAG_TYPE_BYTES | 30019, + CM_TAG_PARAM4_NULL = CM_TAG_TYPE_BYTES | 30020, +}; + +#define CM_PARAM_BUFFER_NULL_INTERVAL ((CM_TAG_PARAM0_NULL) - (CM_TAG_PARAM0_BUFFER)) + +enum CmSendType { + CM_SEND_TYPE_ASYNC = 0, + CM_SEND_TYPE_SYNC, +}; + +struct CmBlob { + uint32_t size; + uint8_t *data; +}; + +struct Credential { + uint32_t isExist; + char type[MAX_LEN_SUBJECT_NAME]; + char alias[MAX_LEN_CERT_ALIAS]; + char keyUri[MAX_LEN_URI]; + uint32_t certNum; + uint32_t keyNum; + struct CmBlob credData; +}; + +struct CmParam { + uint32_t tag; + union { + bool boolParam; + int32_t int32Param; + uint32_t uint32Param; + uint64_t uint64Param; + struct CmBlob blob; + }; +}; + +struct CmParamSet { + uint32_t paramSetSize; + uint32_t paramsCnt; + struct CmParam params[]; +}; + +struct CmSignatureSpec { + uint32_t purpose; + uint32_t padding; + uint32_t digest; +}; + +static inline bool CmIsAdditionOverflow(uint32_t a, uint32_t b) +{ + return (UINT32_MAX - a) < b; +} + +static inline int32_t CmCheckBlob(const struct CmBlob *blob) +{ + if ((blob == NULL) || (blob->data == NULL) || (blob->size == 0)) { + return CMR_ERROR_INVALID_ARGUMENT; + } + return CM_SUCCESS; +} + +#ifdef __cplusplus +} +#endif + +#endif /* CM_TYPE_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_type_inner.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_type_inner.h index 6ab7782815de2f91dd6283b77cdac2d89d93eceb..42f849170c70f0cf5fba4c79a8a5903da7f613c3 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_type_inner.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/include/cm_type_inner.h @@ -1,22 +1,22 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CM_TYPE_INNER_H -#define CM_TYPE_INNER_H - -#include "cm_type.h" -#include "securec.h" - -#endif /* CM_TYPE_INNER_H */ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CM_TYPE_INNER_H +#define CM_TYPE_INNER_H + +#include "cm_type.h" +#include "securec.h" + +#endif /* CM_TYPE_INNER_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cert_manager_api.c b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cert_manager_api.c index 47aafa1b4aafabeb68ddd605d532391cd8e41b9b..1d8506e023bbc0f01da6a61ea3bf7e45a7fbbda5 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cert_manager_api.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cert_manager_api.c @@ -1,87 +1,87 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cert_manager_api.h" - -#include "cm_log.h" -#include "cm_mem.h" -#include "cm_ipc_client.h" -#include "cm_type.h" - -CM_API_EXPORT int32_t CmGetAppCert(const struct CmBlob *keyUri, const uint32_t store, - struct Credential *certificate) -{ - CM_LOG_D("enter get app certificate"); - if (keyUri == NULL || certificate == NULL || (store != CM_CREDENTIAL_STORE && - store != CM_PRI_CREDENTIAL_STORE && store != CM_SYS_CREDENTIAL_STORE)) { - return CMR_ERROR_INVALID_ARGUMENT; - } - - int32_t ret = CmClientGetAppCert(keyUri, store, certificate); - CM_LOG_D("leave get app certificate, result = %d", ret); - return ret; -} - -CM_API_EXPORT int32_t CmInit(const struct CmBlob *authUri, const struct CmSignatureSpec *spec, struct CmBlob *handle) -{ - CM_LOG_D("enter cert manager init"); - if ((authUri == NULL) || (spec == NULL) || (handle == NULL)) { - CM_LOG_E("invalid input arguments"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - int32_t ret = CmClientInit(authUri, spec, handle); - CM_LOG_D("leave cert manager init, result = %d", ret); - return ret; -} - -CM_API_EXPORT int32_t CmUpdate(const struct CmBlob *handle, const struct CmBlob *inData) -{ - CM_LOG_D("enter cert manager update"); - if ((handle == NULL) || (inData == NULL)) { - CM_LOG_E("invalid input arguments"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - int32_t ret = CmClientUpdate(handle, inData); - CM_LOG_D("leave cert manager update, result = %d", ret); - return ret; -} - -CM_API_EXPORT int32_t CmFinish(const struct CmBlob *handle, const struct CmBlob *inData, struct CmBlob *outData) -{ - CM_LOG_D("enter cert manager finish"); - if ((handle == NULL) || (inData == NULL) || (outData == NULL)) { - CM_LOG_E("invalid input arguments"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - int32_t ret = CmClientFinish(handle, inData, outData); - CM_LOG_D("leave cert manager finish, result = %d", ret); - return ret; -} - -CM_API_EXPORT int32_t CmAbort(const struct CmBlob *handle) -{ - CM_LOG_D("enter cert manager abort"); - if (handle == NULL) { - CM_LOG_E("invalid input arguments"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - int32_t ret = CmClientAbort(handle); - CM_LOG_D("leave cert manager abort, result = %d", ret); - return ret; +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cert_manager_api.h" + +#include "cm_log.h" +#include "cm_mem.h" +#include "cm_ipc_client.h" +#include "cm_type.h" + +CM_API_EXPORT int32_t CmGetAppCert(const struct CmBlob *keyUri, const uint32_t store, + struct Credential *certificate) +{ + CM_LOG_D("enter get app certificate"); + if (keyUri == NULL || certificate == NULL || (store != CM_CREDENTIAL_STORE && + store != CM_PRI_CREDENTIAL_STORE && store != CM_SYS_CREDENTIAL_STORE)) { + return CMR_ERROR_INVALID_ARGUMENT; + } + + int32_t ret = CmClientGetAppCert(keyUri, store, certificate); + CM_LOG_D("leave get app certificate, result = %d", ret); + return ret; +} + +CM_API_EXPORT int32_t CmInit(const struct CmBlob *authUri, const struct CmSignatureSpec *spec, struct CmBlob *handle) +{ + CM_LOG_D("enter cert manager init"); + if ((authUri == NULL) || (spec == NULL) || (handle == NULL)) { + CM_LOG_E("invalid input arguments"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + int32_t ret = CmClientInit(authUri, spec, handle); + CM_LOG_D("leave cert manager init, result = %d", ret); + return ret; +} + +CM_API_EXPORT int32_t CmUpdate(const struct CmBlob *handle, const struct CmBlob *inData) +{ + CM_LOG_D("enter cert manager update"); + if ((handle == NULL) || (inData == NULL)) { + CM_LOG_E("invalid input arguments"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + int32_t ret = CmClientUpdate(handle, inData); + CM_LOG_D("leave cert manager update, result = %d", ret); + return ret; +} + +CM_API_EXPORT int32_t CmFinish(const struct CmBlob *handle, const struct CmBlob *inData, struct CmBlob *outData) +{ + CM_LOG_D("enter cert manager finish"); + if ((handle == NULL) || (inData == NULL) || (outData == NULL)) { + CM_LOG_E("invalid input arguments"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + int32_t ret = CmClientFinish(handle, inData, outData); + CM_LOG_D("leave cert manager finish, result = %d", ret); + return ret; +} + +CM_API_EXPORT int32_t CmAbort(const struct CmBlob *handle) +{ + CM_LOG_D("enter cert manager abort"); + if (handle == NULL) { + CM_LOG_E("invalid input arguments"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + int32_t ret = CmClientAbort(handle); + CM_LOG_D("leave cert manager abort, result = %d", ret); + return ret; } \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_ipc_client.c b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_ipc_client.c index bb3f6805c66a1d540ce1bf2e9ad358c8505b3a88..730e7504761870899d4d164c118ea7da2533e0fa 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_ipc_client.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_ipc_client.c @@ -1,275 +1,275 @@ -/* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cm_ipc_client.h" -#include "cm_ipc_client_serialization.h" -#include "cm_log.h" -#include "cm_mem.h" -#include "cm_param.h" -#include "cm_request.h" - -static int32_t GetAppCertInitBlob(struct CmBlob *outBlob) -{ - uint32_t buffSize = sizeof(uint32_t) + sizeof(uint32_t) + MAX_LEN_SUBJECT_NAME + - sizeof(uint32_t) + MAX_LEN_CERT_ALIAS + sizeof(uint32_t) + MAX_LEN_URI + - sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + MAX_LEN_CERTIFICATE_CHAIN; - - outBlob->data = (uint8_t *)CmMalloc(buffSize); - if (outBlob->data == NULL) { - return CMR_ERROR_MALLOC_FAIL; - } - outBlob->size = buffSize; - - return CM_SUCCESS; -} - -static int32_t CmGetAppCertFromBuffer(struct Credential *certificateInfo, - const struct CmBlob *outData, uint32_t *offset) -{ - struct CmBlob blob; - int32_t ret = CmGetBlobFromBuffer(&blob, outData, offset); - if (ret != CM_SUCCESS) { - CM_LOG_E("Get type blob failed"); - return ret; - } - if (memcpy_s(certificateInfo->type, MAX_LEN_SUBJECT_NAME, blob.data, blob.size) != EOK) { - CM_LOG_E("copy type failed"); - return CMR_ERROR_INVALID_OPERATION; - } - - ret = CmGetBlobFromBuffer(&blob, outData, offset); - if (ret != CM_SUCCESS) { - CM_LOG_E("Get keyUri blob failed"); - return ret; - } - if (memcpy_s(certificateInfo->keyUri, MAX_LEN_URI, blob.data, blob.size) != EOK) { - CM_LOG_E("copy keyUri failed"); - return CMR_ERROR_INVALID_OPERATION; - } - - ret = CmGetBlobFromBuffer(&blob, outData, offset); - if (ret != CM_SUCCESS) { - CM_LOG_E("Get alias blob failed"); - return ret; - } - if (memcpy_s(certificateInfo->alias, MAX_LEN_CERT_ALIAS, blob.data, blob.size) != EOK) { - CM_LOG_E("copy alias failed"); - return CMR_ERROR_INVALID_OPERATION; - } - - return ret; -} - -static int32_t CmAppCertInfoUnpackFromService(const struct CmBlob *outData, struct Credential *certificateInfo) -{ - uint32_t offset = 0; - struct CmBlob blob = { 0, NULL }; - - if ((outData == NULL) || (certificateInfo == NULL) || (outData->data == NULL) || - (certificateInfo->credData.data == NULL)) { - return CMR_ERROR_NULL_POINTER; - } - - int32_t ret = GetUint32FromBuffer(&certificateInfo->isExist, outData, &offset); - if (ret != CM_SUCCESS || certificateInfo->isExist == 0) { - CM_LOG_E("Get certificateInfo->isExist failed ret:%d, is exist:%u", ret, certificateInfo->isExist); - return ret; - } - - ret = CmGetAppCertFromBuffer(certificateInfo, outData, &offset); - if (ret != CM_SUCCESS) { - CM_LOG_E("Get AppCert failed"); - return ret; - } - - ret = GetUint32FromBuffer(&certificateInfo->certNum, outData, &offset); - if (ret != CM_SUCCESS) { - CM_LOG_E("Get certificateInfo->certNum failed"); - return ret; - } - - ret = GetUint32FromBuffer(&certificateInfo->keyNum, outData, &offset); - if (ret != CM_SUCCESS) { - CM_LOG_E("Get certificateInfo->keyNum failed"); - return ret; - } - - ret = CmGetBlobFromBuffer(&blob, outData, &offset); - if (ret != CM_SUCCESS) { - CM_LOG_E("Get certificateInfo->credData failed"); - return ret; - } - - if ((blob.size > certificateInfo->credData.size) || memcpy_s(certificateInfo->credData.data, - certificateInfo->credData.size, blob.data, blob.size) != EOK) { - CM_LOG_E("copy credData failed"); - return CMR_ERROR_INVALID_OPERATION; - } - certificateInfo->credData.size = blob.size; - - return CM_SUCCESS; -} - -static int32_t GetAppCert(enum CertManagerInterfaceCode type, const struct CmBlob *certUri, const uint32_t store, - struct Credential *certificate) -{ - int32_t ret; - struct CmBlob outBlob = { 0, NULL }; - struct CmParamSet *sendParamSet = NULL; - - struct CmParam params[] = { - { .tag = CM_TAG_PARAM0_BUFFER, - .blob = *certUri }, - { .tag = CM_TAG_PARAM0_UINT32, - .uint32Param = store }, - }; - do { - ret = CmParamsToParamSet(params, CM_ARRAY_SIZE(params), &sendParamSet); - if (ret != CM_SUCCESS) { - CM_LOG_E("GetAppCert CmParamSetPack fail"); - break; - } - - struct CmBlob parcelBlob = { - .size = sendParamSet->paramSetSize, - .data = (uint8_t *)sendParamSet - }; - - ret = GetAppCertInitBlob(&outBlob); - if (ret != CM_SUCCESS) { - CM_LOG_E("GetAppCertInitBlob fail"); - break; - } - - ret = SendRequest(type, &parcelBlob, &outBlob); - if (ret != CM_SUCCESS) { - CM_LOG_E("GetAppCert request fail"); - break; - } - - ret = CmAppCertInfoUnpackFromService(&outBlob, certificate); - if (ret != CM_SUCCESS) { - CM_LOG_E("CmAppCertInfoUnpackFromService fail"); - } - } while (0); - - CmFreeParamSet(&sendParamSet); - CM_FREE_BLOB(outBlob); - return ret; -} - -int32_t CmClientGetAppCert(const struct CmBlob *keyUri, const uint32_t store, struct Credential *certificate) -{ - return GetAppCert(CM_MSG_GET_APP_CERTIFICATE, keyUri, store, certificate); -} - -static int32_t ClientSerializationAndSend(enum CertManagerInterfaceCode message, struct CmParam *params, - uint32_t paramCount, struct CmBlob *outBlob) -{ - struct CmParamSet *sendParamSet = NULL; - int32_t ret = CmParamsToParamSet(params, paramCount, &sendParamSet); - if (ret != CM_SUCCESS) { - CM_LOG_E("pack params failed, ret = %d", ret); - return ret; - } - - struct CmBlob parcelBlob = { sendParamSet->paramSetSize, (uint8_t *)sendParamSet }; - ret = SendRequest(message, &parcelBlob, outBlob); - if (ret != CM_SUCCESS) { - CM_LOG_E("send request failed, ret = %d", ret); - } - CmFreeParamSet(&sendParamSet); - - return ret; -} - -int32_t CmClientInit(const struct CmBlob *authUri, const struct CmSignatureSpec *spec, struct CmBlob *handle) -{ - if (CmCheckBlob(authUri) != CM_SUCCESS || CmCheckBlob(handle) != CM_SUCCESS) { - CM_LOG_E("invalid handle or inData"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - struct CmBlob signSpec = { sizeof(struct CmSignatureSpec), (uint8_t *)spec }; - struct CmParam params[] = { - { .tag = CM_TAG_PARAM0_BUFFER, .blob = *authUri }, - { .tag = CM_TAG_PARAM1_BUFFER, .blob = signSpec }, - }; - - int32_t ret = ClientSerializationAndSend(CM_MSG_INIT, params, CM_ARRAY_SIZE(params), handle); - if (ret != CM_SUCCESS) { - CM_LOG_E("update serialization and send failed, ret = %d", ret); - } - return ret; -} - -int32_t CmClientUpdate(const struct CmBlob *handle, const struct CmBlob *inData) -{ - if (CmCheckBlob(handle) != CM_SUCCESS || CmCheckBlob(inData) != CM_SUCCESS) { - CM_LOG_E("invalid handle or inData"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - struct CmParam params[] = { - { .tag = CM_TAG_PARAM0_BUFFER, .blob = *handle }, - { .tag = CM_TAG_PARAM1_BUFFER, .blob = *inData }, - }; - - struct CmBlob outBlob = { 0, NULL }; - int32_t ret = ClientSerializationAndSend(CM_MSG_UPDATE, params, CM_ARRAY_SIZE(params), &outBlob); - if (ret != CM_SUCCESS) { - CM_LOG_E("update serialization and send failed, ret = %d", ret); - } - return ret; -} - -int32_t CmClientFinish(const struct CmBlob *handle, const struct CmBlob *inData, struct CmBlob *outData) -{ - if (CmCheckBlob(handle) != CM_SUCCESS) { /* finish: inData and outData can be {0, NULL} */ - CM_LOG_E("invalid handle"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - struct CmParam params[] = { - { .tag = CM_TAG_PARAM0_BUFFER, .blob = *handle }, - { .tag = CM_TAG_PARAM1_BUFFER, .blob = *inData }, - }; - - int32_t ret = ClientSerializationAndSend(CM_MSG_FINISH, params, CM_ARRAY_SIZE(params), outData); - if (ret != CM_SUCCESS) { - CM_LOG_E("finish serialization and send failed, ret = %d", ret); - } - return ret; -} - -int32_t CmClientAbort(const struct CmBlob *handle) -{ - if (CmCheckBlob(handle) != CM_SUCCESS) { - CM_LOG_E("invalid handle"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - struct CmParam params[] = { - { .tag = CM_TAG_PARAM0_BUFFER, .blob = *handle }, - }; - - struct CmBlob outBlob = { 0, NULL }; - int32_t ret = ClientSerializationAndSend(CM_MSG_ABORT, params, CM_ARRAY_SIZE(params), &outBlob); - if (ret != CM_SUCCESS) { - CM_LOG_E("abort serialization and send failed, ret = %d", ret); - } - return ret; -} - +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cm_ipc_client.h" +#include "cm_ipc_client_serialization.h" +#include "cm_log.h" +#include "cm_mem.h" +#include "cm_param.h" +#include "cm_request.h" + +static int32_t GetAppCertInitBlob(struct CmBlob *outBlob) +{ + uint32_t buffSize = sizeof(uint32_t) + sizeof(uint32_t) + MAX_LEN_SUBJECT_NAME + + sizeof(uint32_t) + MAX_LEN_CERT_ALIAS + sizeof(uint32_t) + MAX_LEN_URI + + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + MAX_LEN_CERTIFICATE_CHAIN; + + outBlob->data = (uint8_t *)CmMalloc(buffSize); + if (outBlob->data == NULL) { + return CMR_ERROR_MALLOC_FAIL; + } + outBlob->size = buffSize; + + return CM_SUCCESS; +} + +static int32_t CmGetAppCertFromBuffer(struct Credential *certificateInfo, + const struct CmBlob *outData, uint32_t *offset) +{ + struct CmBlob blob; + int32_t ret = CmGetBlobFromBuffer(&blob, outData, offset); + if (ret != CM_SUCCESS) { + CM_LOG_E("Get type blob failed"); + return ret; + } + if (memcpy_s(certificateInfo->type, MAX_LEN_SUBJECT_NAME, blob.data, blob.size) != EOK) { + CM_LOG_E("copy type failed"); + return CMR_ERROR_INVALID_OPERATION; + } + + ret = CmGetBlobFromBuffer(&blob, outData, offset); + if (ret != CM_SUCCESS) { + CM_LOG_E("Get keyUri blob failed"); + return ret; + } + if (memcpy_s(certificateInfo->keyUri, MAX_LEN_URI, blob.data, blob.size) != EOK) { + CM_LOG_E("copy keyUri failed"); + return CMR_ERROR_INVALID_OPERATION; + } + + ret = CmGetBlobFromBuffer(&blob, outData, offset); + if (ret != CM_SUCCESS) { + CM_LOG_E("Get alias blob failed"); + return ret; + } + if (memcpy_s(certificateInfo->alias, MAX_LEN_CERT_ALIAS, blob.data, blob.size) != EOK) { + CM_LOG_E("copy alias failed"); + return CMR_ERROR_INVALID_OPERATION; + } + + return ret; +} + +static int32_t CmAppCertInfoUnpackFromService(const struct CmBlob *outData, struct Credential *certificateInfo) +{ + uint32_t offset = 0; + struct CmBlob blob = { 0, NULL }; + + if ((outData == NULL) || (certificateInfo == NULL) || (outData->data == NULL) || + (certificateInfo->credData.data == NULL)) { + return CMR_ERROR_NULL_POINTER; + } + + int32_t ret = GetUint32FromBuffer(&certificateInfo->isExist, outData, &offset); + if (ret != CM_SUCCESS || certificateInfo->isExist == 0) { + CM_LOG_E("Get certificateInfo->isExist failed ret:%d, is exist:%u", ret, certificateInfo->isExist); + return ret; + } + + ret = CmGetAppCertFromBuffer(certificateInfo, outData, &offset); + if (ret != CM_SUCCESS) { + CM_LOG_E("Get AppCert failed"); + return ret; + } + + ret = GetUint32FromBuffer(&certificateInfo->certNum, outData, &offset); + if (ret != CM_SUCCESS) { + CM_LOG_E("Get certificateInfo->certNum failed"); + return ret; + } + + ret = GetUint32FromBuffer(&certificateInfo->keyNum, outData, &offset); + if (ret != CM_SUCCESS) { + CM_LOG_E("Get certificateInfo->keyNum failed"); + return ret; + } + + ret = CmGetBlobFromBuffer(&blob, outData, &offset); + if (ret != CM_SUCCESS) { + CM_LOG_E("Get certificateInfo->credData failed"); + return ret; + } + + if ((blob.size > certificateInfo->credData.size) || memcpy_s(certificateInfo->credData.data, + certificateInfo->credData.size, blob.data, blob.size) != EOK) { + CM_LOG_E("copy credData failed"); + return CMR_ERROR_INVALID_OPERATION; + } + certificateInfo->credData.size = blob.size; + + return CM_SUCCESS; +} + +static int32_t GetAppCert(enum CertManagerInterfaceCode type, const struct CmBlob *certUri, const uint32_t store, + struct Credential *certificate) +{ + int32_t ret; + struct CmBlob outBlob = { 0, NULL }; + struct CmParamSet *sendParamSet = NULL; + + struct CmParam params[] = { + { .tag = CM_TAG_PARAM0_BUFFER, + .blob = *certUri }, + { .tag = CM_TAG_PARAM0_UINT32, + .uint32Param = store }, + }; + do { + ret = CmParamsToParamSet(params, CM_ARRAY_SIZE(params), &sendParamSet); + if (ret != CM_SUCCESS) { + CM_LOG_E("GetAppCert CmParamSetPack fail"); + break; + } + + struct CmBlob parcelBlob = { + .size = sendParamSet->paramSetSize, + .data = (uint8_t *)sendParamSet + }; + + ret = GetAppCertInitBlob(&outBlob); + if (ret != CM_SUCCESS) { + CM_LOG_E("GetAppCertInitBlob fail"); + break; + } + + ret = SendRequest(type, &parcelBlob, &outBlob); + if (ret != CM_SUCCESS) { + CM_LOG_E("GetAppCert request fail"); + break; + } + + ret = CmAppCertInfoUnpackFromService(&outBlob, certificate); + if (ret != CM_SUCCESS) { + CM_LOG_E("CmAppCertInfoUnpackFromService fail"); + } + } while (0); + + CmFreeParamSet(&sendParamSet); + CM_FREE_BLOB(outBlob); + return ret; +} + +int32_t CmClientGetAppCert(const struct CmBlob *keyUri, const uint32_t store, struct Credential *certificate) +{ + return GetAppCert(CM_MSG_GET_APP_CERTIFICATE, keyUri, store, certificate); +} + +static int32_t ClientSerializationAndSend(enum CertManagerInterfaceCode message, struct CmParam *params, + uint32_t paramCount, struct CmBlob *outBlob) +{ + struct CmParamSet *sendParamSet = NULL; + int32_t ret = CmParamsToParamSet(params, paramCount, &sendParamSet); + if (ret != CM_SUCCESS) { + CM_LOG_E("pack params failed, ret = %d", ret); + return ret; + } + + struct CmBlob parcelBlob = { sendParamSet->paramSetSize, (uint8_t *)sendParamSet }; + ret = SendRequest(message, &parcelBlob, outBlob); + if (ret != CM_SUCCESS) { + CM_LOG_E("send request failed, ret = %d", ret); + } + CmFreeParamSet(&sendParamSet); + + return ret; +} + +int32_t CmClientInit(const struct CmBlob *authUri, const struct CmSignatureSpec *spec, struct CmBlob *handle) +{ + if (CmCheckBlob(authUri) != CM_SUCCESS || CmCheckBlob(handle) != CM_SUCCESS) { + CM_LOG_E("invalid handle or inData"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + struct CmBlob signSpec = { sizeof(struct CmSignatureSpec), (uint8_t *)spec }; + struct CmParam params[] = { + { .tag = CM_TAG_PARAM0_BUFFER, .blob = *authUri }, + { .tag = CM_TAG_PARAM1_BUFFER, .blob = signSpec }, + }; + + int32_t ret = ClientSerializationAndSend(CM_MSG_INIT, params, CM_ARRAY_SIZE(params), handle); + if (ret != CM_SUCCESS) { + CM_LOG_E("update serialization and send failed, ret = %d", ret); + } + return ret; +} + +int32_t CmClientUpdate(const struct CmBlob *handle, const struct CmBlob *inData) +{ + if (CmCheckBlob(handle) != CM_SUCCESS || CmCheckBlob(inData) != CM_SUCCESS) { + CM_LOG_E("invalid handle or inData"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + struct CmParam params[] = { + { .tag = CM_TAG_PARAM0_BUFFER, .blob = *handle }, + { .tag = CM_TAG_PARAM1_BUFFER, .blob = *inData }, + }; + + struct CmBlob outBlob = { 0, NULL }; + int32_t ret = ClientSerializationAndSend(CM_MSG_UPDATE, params, CM_ARRAY_SIZE(params), &outBlob); + if (ret != CM_SUCCESS) { + CM_LOG_E("update serialization and send failed, ret = %d", ret); + } + return ret; +} + +int32_t CmClientFinish(const struct CmBlob *handle, const struct CmBlob *inData, struct CmBlob *outData) +{ + if (CmCheckBlob(handle) != CM_SUCCESS) { /* finish: inData and outData can be {0, NULL} */ + CM_LOG_E("invalid handle"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + struct CmParam params[] = { + { .tag = CM_TAG_PARAM0_BUFFER, .blob = *handle }, + { .tag = CM_TAG_PARAM1_BUFFER, .blob = *inData }, + }; + + int32_t ret = ClientSerializationAndSend(CM_MSG_FINISH, params, CM_ARRAY_SIZE(params), outData); + if (ret != CM_SUCCESS) { + CM_LOG_E("finish serialization and send failed, ret = %d", ret); + } + return ret; +} + +int32_t CmClientAbort(const struct CmBlob *handle) +{ + if (CmCheckBlob(handle) != CM_SUCCESS) { + CM_LOG_E("invalid handle"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + struct CmParam params[] = { + { .tag = CM_TAG_PARAM0_BUFFER, .blob = *handle }, + }; + + struct CmBlob outBlob = { 0, NULL }; + int32_t ret = ClientSerializationAndSend(CM_MSG_ABORT, params, CM_ARRAY_SIZE(params), &outBlob); + if (ret != CM_SUCCESS) { + CM_LOG_E("abort serialization and send failed, ret = %d", ret); + } + return ret; +} + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_ipc_client_serialization.c b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_ipc_client_serialization.c index e9cc835f344d2679b790eb0dea8a45267c193d6f..f5823bfea5b4870db87bf32e04a281d635f9eec9 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_ipc_client_serialization.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_ipc_client_serialization.c @@ -1,96 +1,96 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cm_ipc_client_serialization.h" - -#include "cm_log.h" -#include "cm_mem.h" - -#include "cm_param.h" - -int32_t GetUint32FromBuffer(uint32_t *value, const struct CmBlob *srcBlob, uint32_t *srcOffset) -{ - if ((*srcOffset > srcBlob->size) || (srcBlob->size - *srcOffset < sizeof(uint32_t))) { - return CMR_ERROR_BUFFER_TOO_SMALL; - } - - if (memcpy_s(value, sizeof(uint32_t), srcBlob->data + *srcOffset, sizeof(uint32_t)) != EOK) { - return CMR_ERROR_INVALID_OPERATION; - } - - *srcOffset += sizeof(uint32_t); - return CM_SUCCESS; -} - -int32_t CmGetBlobFromBuffer(struct CmBlob *blob, const struct CmBlob *srcBlob, uint32_t *srcOffset) -{ - if ((*srcOffset > srcBlob->size) || ((srcBlob->size - *srcOffset) < sizeof(uint32_t))) { - return CMR_ERROR_BUFFER_TOO_SMALL; - } - - uint32_t size = *((uint32_t *)(srcBlob->data + *srcOffset)); - if (ALIGN_SIZE(size) > srcBlob->size - *srcOffset - sizeof(uint32_t)) { - return CMR_ERROR_BUFFER_TOO_SMALL; - } - - blob->size = size; - *srcOffset += sizeof(blob->size); - blob->data = (uint8_t *)(srcBlob->data + *srcOffset); - *srcOffset += ALIGN_SIZE(blob->size); - return CM_SUCCESS; -} - -int32_t CmParamsToParamSet(struct CmParam *params, uint32_t cnt, struct CmParamSet **outParamSet) -{ - struct CmParamSet *newParamSet = NULL; - - int32_t ret = CmInitParamSet(&newParamSet); - if (ret != CM_SUCCESS) { - CM_LOG_E("init param set failed"); - return ret; - } - - do { - uint8_t tmpData = 0; - struct CmBlob tmpBlob = { sizeof(tmpData), &tmpData }; - for (uint32_t i = 0; i < cnt; ++i) { - if ((GetTagType(params[i].tag) == CM_TAG_TYPE_BYTES) && - (params[i].blob.size == 0 || params[i].blob.data == NULL)) { - params[i].tag += CM_PARAM_BUFFER_NULL_INTERVAL; - params[i].blob = tmpBlob; - } - } - - ret = CmAddParams(newParamSet, params, cnt); - if (ret != CM_SUCCESS) { - CM_LOG_E("add in params failed"); - break; - } - - ret = CmBuildParamSet(&newParamSet); - if (ret != CM_SUCCESS) { - CM_LOG_E("build paramset failed!"); - break; - } - } while (0); - if (ret != CM_SUCCESS) { - CmFreeParamSet(&newParamSet); - return ret; - } - - *outParamSet = newParamSet; - - return ret; -} +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cm_ipc_client_serialization.h" + +#include "cm_log.h" +#include "cm_mem.h" + +#include "cm_param.h" + +int32_t GetUint32FromBuffer(uint32_t *value, const struct CmBlob *srcBlob, uint32_t *srcOffset) +{ + if ((*srcOffset > srcBlob->size) || (srcBlob->size - *srcOffset < sizeof(uint32_t))) { + return CMR_ERROR_BUFFER_TOO_SMALL; + } + + if (memcpy_s(value, sizeof(uint32_t), srcBlob->data + *srcOffset, sizeof(uint32_t)) != EOK) { + return CMR_ERROR_INVALID_OPERATION; + } + + *srcOffset += sizeof(uint32_t); + return CM_SUCCESS; +} + +int32_t CmGetBlobFromBuffer(struct CmBlob *blob, const struct CmBlob *srcBlob, uint32_t *srcOffset) +{ + if ((*srcOffset > srcBlob->size) || ((srcBlob->size - *srcOffset) < sizeof(uint32_t))) { + return CMR_ERROR_BUFFER_TOO_SMALL; + } + + uint32_t size = *((uint32_t *)(srcBlob->data + *srcOffset)); + if (ALIGN_SIZE(size) > srcBlob->size - *srcOffset - sizeof(uint32_t)) { + return CMR_ERROR_BUFFER_TOO_SMALL; + } + + blob->size = size; + *srcOffset += sizeof(blob->size); + blob->data = (uint8_t *)(srcBlob->data + *srcOffset); + *srcOffset += ALIGN_SIZE(blob->size); + return CM_SUCCESS; +} + +int32_t CmParamsToParamSet(struct CmParam *params, uint32_t cnt, struct CmParamSet **outParamSet) +{ + struct CmParamSet *newParamSet = NULL; + + int32_t ret = CmInitParamSet(&newParamSet); + if (ret != CM_SUCCESS) { + CM_LOG_E("init param set failed"); + return ret; + } + + do { + uint8_t tmpData = 0; + struct CmBlob tmpBlob = { sizeof(tmpData), &tmpData }; + for (uint32_t i = 0; i < cnt; ++i) { + if ((GetTagType(params[i].tag) == CM_TAG_TYPE_BYTES) && + (params[i].blob.size == 0 || params[i].blob.data == NULL)) { + params[i].tag += CM_PARAM_BUFFER_NULL_INTERVAL; + params[i].blob = tmpBlob; + } + } + + ret = CmAddParams(newParamSet, params, cnt); + if (ret != CM_SUCCESS) { + CM_LOG_E("add in params failed"); + break; + } + + ret = CmBuildParamSet(&newParamSet); + if (ret != CM_SUCCESS) { + CM_LOG_E("build paramset failed!"); + break; + } + } while (0); + if (ret != CM_SUCCESS) { + CmFreeParamSet(&newParamSet); + return ret; + } + + *outParamSet = newParamSet; + + return ret; +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_load_sa.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_load_sa.cpp index 132e7332f357aca1826a6371ca089a663ac7eda0..d34390cad8dd2aec57d4f59d4356217187545e4f 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_load_sa.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_load_sa.cpp @@ -1,23 +1,23 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "cm_load_sa.h" -#include "cm_log.h" - -using namespace std; - -OnDemandLoadCertManagerCallback::OnDemandLoadCertManagerCallback(string servers) : servers(servers) -{ - CM_LOG_E("Servers %s on demand Callback constructor success", servers.c_str()); -} +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "cm_load_sa.h" +#include "cm_log.h" + +using namespace std; + +OnDemandLoadCertManagerCallback::OnDemandLoadCertManagerCallback(string servers) : servers(servers) +{ + CM_LOG_E("Servers %s on demand Callback constructor success", servers.c_str()); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_log.c b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_log.c index 51356f91e66c5d2b6ac168f68838b41eb592f3de..9022123c9c3c375d35b43bfbe1f193b494e27cfa 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_log.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_log.c @@ -1,63 +1,63 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cm_log.h" - -#include "securec.h" - -#include "hilog/log.h" -#include "cm_mem.h" - -#define MAX_LOG_BUFF_LEN 512 - -void CmLog(uint32_t logLevel, const char *funcName, uint32_t lineNo, const char *format, ...) -{ - char *buf = (char *)CmMalloc(MAX_LOG_BUFF_LEN); - if (buf == NULL) { - HILOG_ERROR(LOG_CORE, "certificate manager log malloc fail"); - return; - } - (void)memset_s(buf, MAX_LOG_BUFF_LEN, 0, MAX_LOG_BUFF_LEN); - - va_list ap; - va_start(ap, format); - int32_t ret = vsnprintf_s(buf, MAX_LOG_BUFF_LEN, MAX_LOG_BUFF_LEN - 1, format, ap); - va_end(ap); - if (ret < 0) { - HILOG_ERROR(LOG_CORE, "certificate manager log concatenate error."); - CM_FREE_PTR(buf); - return; - } - - switch (logLevel) { - case CM_LOG_LEVEL_I: - HILOG_INFO(LOG_CORE, "%{public}s[%{public}u]: %{public}s\n", funcName, lineNo, buf); - break; - case CM_LOG_LEVEL_E: - HILOG_ERROR(LOG_CORE, "%{public}s[%{public}u]: %{public}s\n", funcName, lineNo, buf); - break; - case CM_LOG_LEVEL_W: - HILOG_WARN(LOG_CORE, "%{public}s[%{public}u]: %{public}s\n", funcName, lineNo, buf); - break; - case CM_LOG_LEVEL_D: - HILOG_DEBUG(LOG_CORE, "%{public}s[%{public}u]: %{private}s\n", funcName, lineNo, buf); - break; - default: - CM_FREE_PTR(buf); - return; - } - - CM_FREE_PTR(buf); -} +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cm_log.h" + +#include "securec.h" + +#include "hilog/log.h" +#include "cm_mem.h" + +#define MAX_LOG_BUFF_LEN 512 + +void CmLog(uint32_t logLevel, const char *funcName, uint32_t lineNo, const char *format, ...) +{ + char *buf = (char *)CmMalloc(MAX_LOG_BUFF_LEN); + if (buf == NULL) { + HILOG_ERROR(LOG_CORE, "certificate manager log malloc fail"); + return; + } + (void)memset_s(buf, MAX_LOG_BUFF_LEN, 0, MAX_LOG_BUFF_LEN); + + va_list ap; + va_start(ap, format); + int32_t ret = vsnprintf_s(buf, MAX_LOG_BUFF_LEN, MAX_LOG_BUFF_LEN - 1, format, ap); + va_end(ap); + if (ret < 0) { + HILOG_ERROR(LOG_CORE, "certificate manager log concatenate error."); + CM_FREE_PTR(buf); + return; + } + + switch (logLevel) { + case CM_LOG_LEVEL_I: + HILOG_INFO(LOG_CORE, "%{public}s[%{public}u]: %{public}s\n", funcName, lineNo, buf); + break; + case CM_LOG_LEVEL_E: + HILOG_ERROR(LOG_CORE, "%{public}s[%{public}u]: %{public}s\n", funcName, lineNo, buf); + break; + case CM_LOG_LEVEL_W: + HILOG_WARN(LOG_CORE, "%{public}s[%{public}u]: %{public}s\n", funcName, lineNo, buf); + break; + case CM_LOG_LEVEL_D: + HILOG_DEBUG(LOG_CORE, "%{public}s[%{public}u]: %{private}s\n", funcName, lineNo, buf); + break; + default: + CM_FREE_PTR(buf); + return; + } + + CM_FREE_PTR(buf); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_mem.c b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_mem.c index 991b74af1e2cb0fe141f6b418371b82bbb640fcb..833ece152b2c89dfac727ee76eba376650086374 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_mem.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_mem.c @@ -1,42 +1,42 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cm_mem.h" - -#include - -#ifdef CM_SUPPORT_PRODUCT_GT_WATCH -#include "ohos_mem_pool.h" - -void *CmMalloc(size_t size) -{ - return OhosMalloc(MEM_TYPE_HICHAIN, size); -} - -void CmFree(void *ptr) -{ - OhosFree(ptr); -} -#else -void *CmMalloc(size_t size) -{ - return malloc(size); -} - -void CmFree(void *ptr) -{ - free(ptr); -} +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cm_mem.h" + +#include + +#ifdef CM_SUPPORT_PRODUCT_GT_WATCH +#include "ohos_mem_pool.h" + +void *CmMalloc(size_t size) +{ + return OhosMalloc(MEM_TYPE_HICHAIN, size); +} + +void CmFree(void *ptr) +{ + OhosFree(ptr); +} +#else +void *CmMalloc(size_t size) +{ + return malloc(size); +} + +void CmFree(void *ptr) +{ + free(ptr); +} #endif \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_param.c b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_param.c index 9d91403b5c6a98d69f9e08ebdc2dee2868d05171..81a273e425ae4afdd2db7eea42d03c63543187d6 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_param.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_param.c @@ -1,194 +1,194 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cm_param.h" - -#include -#include -#include - -#include "cm_log.h" -#include "cm_mem.h" -#include "cm_type_inner.h" - -enum CmTagType GetTagType(enum CmTag tag) -{ - return (enum CmTagType)((uint32_t)tag & CM_TAG_TYPE_MASK); -} - -int32_t CmInitParamSet(struct CmParamSet **paramSet) -{ - if (paramSet == NULL) { - CM_LOG_E("invalid init params!"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - *paramSet = (struct CmParamSet *)CmMalloc(CM_DEFAULT_PARAM_SET_SIZE); - if (*paramSet == NULL) { - CM_LOG_E("malloc init param set failed!"); - return CMR_ERROR_MALLOC_FAIL; - } - (*paramSet)->paramsCnt = 0; - (*paramSet)->paramSetSize = sizeof(struct CmParamSet); - return CM_SUCCESS; -} - -static int32_t CmCheckParamSet(const struct CmParamSet *paramSet, uint32_t size) -{ - if (paramSet == NULL) { - return CMR_ERROR_NULL_POINTER; - } - - if ((size < sizeof(struct CmParamSet)) || (size > CM_PARAM_SET_MAX_SIZE) || - (paramSet->paramSetSize != size) || - (paramSet->paramsCnt > ((size - sizeof(struct CmParamSet)) / sizeof(struct CmParam)))) { - CM_LOG_E("invalid param set!"); - return CMR_ERROR_INVALID_ARGUMENT; - } - return CM_SUCCESS; -} - -static int32_t CmFreshParamSet(struct CmParamSet *paramSet, bool isCopy) -{ - if (paramSet == NULL) { - CM_LOG_E("invalid NULL paramSet"); - return CMR_ERROR_NULL_POINTER; - } - int32_t ret = CmCheckParamSet(paramSet, paramSet->paramSetSize); - if (ret != CM_SUCCESS) { - CM_LOG_E("invalid fresh paramSet"); - return ret; - } - - uint32_t size = paramSet->paramSetSize; - uint32_t offset = sizeof(struct CmParamSet) + sizeof(struct CmParam) * paramSet->paramsCnt; - - for (uint32_t i = 0; i < paramSet->paramsCnt; i++) { - if (offset > size) { - CM_LOG_E("invalid param set offset!"); - return CMR_ERROR_INVALID_ARGUMENT; - } - if (GetTagType(paramSet->params[i].tag) == CM_TAG_TYPE_BYTES) { - if (CmIsAdditionOverflow(offset, paramSet->params[i].blob.size)) { - CM_LOG_E("blob size overflow!"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - if (isCopy && (memcpy_s((uint8_t *)paramSet + offset, size - offset, - paramSet->params[i].blob.data, paramSet->params[i].blob.size) != EOK)) { - CM_LOG_E("copy param blob failed!"); - return CMR_ERROR_INVALID_OPERATION; - } - paramSet->params[i].blob.data = (uint8_t *)paramSet + offset; - offset += paramSet->params[i].blob.size; - } - } - - if (paramSet->paramSetSize != offset) { - CM_LOG_E("invalid param set size!"); - return CMR_ERROR_INVALID_ARGUMENT; - } - return CM_SUCCESS; -} - -static int32_t BuildParamSet(struct CmParamSet **paramSet) -{ - struct CmParamSet *freshParamSet = *paramSet; - uint32_t size = freshParamSet->paramSetSize; - uint32_t offset = sizeof(struct CmParamSet) + sizeof(struct CmParam) * freshParamSet->paramsCnt; - - if (size > CM_DEFAULT_PARAM_SET_SIZE) { - freshParamSet = (struct CmParamSet *)CmMalloc(size); - if (freshParamSet == NULL) { - CM_LOG_E("malloc params failed!"); - return CMR_ERROR_MALLOC_FAIL; - } - if (memcpy_s(freshParamSet, size, *paramSet, offset) != EOK) { - CM_FREE_PTR(freshParamSet); - CM_LOG_E("copy params failed!"); - return CMR_ERROR_INVALID_OPERATION; - } - CM_FREE_PTR(*paramSet); - *paramSet = freshParamSet; - } - - return CmFreshParamSet(freshParamSet, true); -} - -int32_t CmBuildParamSet(struct CmParamSet **paramSet) -{ - if ((paramSet == NULL) || (*paramSet == NULL)) { - return CMR_ERROR_NULL_POINTER; - } - - int ret = CmCheckParamSet(*paramSet, (*paramSet)->paramSetSize); - if (ret != CM_SUCCESS) { - CM_LOG_E("invalid build params!"); - return ret; - } - - return BuildParamSet(paramSet); -} - -void CmFreeParamSet(struct CmParamSet **paramSet) -{ - if (paramSet == NULL) { - CM_LOG_E("invalid free paramset!"); - return; - } - CM_FREE_PTR(*paramSet); -} - -static int32_t CheckBeforeAddParams(const struct CmParamSet *paramSet, const struct CmParam *params, - uint32_t paramCnt) -{ - if ((params == NULL) || (paramSet == NULL) || (paramSet->paramSetSize > CM_PARAM_SET_MAX_SIZE) || - (paramCnt > CM_DEFAULT_PARAM_CNT) || ((paramSet->paramsCnt + paramCnt) > CM_DEFAULT_PARAM_CNT)) { - CM_LOG_E("invalid params or paramset!"); - return CMR_ERROR_INVALID_ARGUMENT; - } - - for (uint32_t i = 0; i < paramCnt; i++) { - if ((GetTagType(params[i].tag) == CM_TAG_TYPE_BYTES) && - (params[i].blob.data == NULL)) { - CM_LOG_E("invalid blob param!"); - return CMR_ERROR_INVALID_ARGUMENT; - } - } - return CM_SUCCESS; -} - -int32_t CmAddParams(struct CmParamSet *paramSet, const struct CmParam *params, uint32_t paramCnt) -{ - int32_t ret = CheckBeforeAddParams(paramSet, params, paramCnt); - if (ret != CM_SUCCESS) { - return ret; - } - - for (uint32_t i = 0; i < paramCnt; i++) { - paramSet->paramSetSize += sizeof(struct CmParam); - if (GetTagType(params[i].tag) == CM_TAG_TYPE_BYTES) { - if (CmIsAdditionOverflow(paramSet->paramSetSize, params[i].blob.size)) { - CM_LOG_E("params size overflow!"); - paramSet->paramSetSize -= sizeof(struct CmParam); - return CMR_ERROR_INVALID_ARGUMENT; - } - paramSet->paramSetSize += params[i].blob.size; - } - (void)memcpy_s(¶mSet->params[paramSet->paramsCnt++], sizeof(struct CmParam), ¶ms[i], - sizeof(struct CmParam)); - } - return CM_SUCCESS; -} +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cm_param.h" + +#include +#include +#include + +#include "cm_log.h" +#include "cm_mem.h" +#include "cm_type_inner.h" + +enum CmTagType GetTagType(enum CmTag tag) +{ + return (enum CmTagType)((uint32_t)tag & CM_TAG_TYPE_MASK); +} + +int32_t CmInitParamSet(struct CmParamSet **paramSet) +{ + if (paramSet == NULL) { + CM_LOG_E("invalid init params!"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + *paramSet = (struct CmParamSet *)CmMalloc(CM_DEFAULT_PARAM_SET_SIZE); + if (*paramSet == NULL) { + CM_LOG_E("malloc init param set failed!"); + return CMR_ERROR_MALLOC_FAIL; + } + (*paramSet)->paramsCnt = 0; + (*paramSet)->paramSetSize = sizeof(struct CmParamSet); + return CM_SUCCESS; +} + +static int32_t CmCheckParamSet(const struct CmParamSet *paramSet, uint32_t size) +{ + if (paramSet == NULL) { + return CMR_ERROR_NULL_POINTER; + } + + if ((size < sizeof(struct CmParamSet)) || (size > CM_PARAM_SET_MAX_SIZE) || + (paramSet->paramSetSize != size) || + (paramSet->paramsCnt > ((size - sizeof(struct CmParamSet)) / sizeof(struct CmParam)))) { + CM_LOG_E("invalid param set!"); + return CMR_ERROR_INVALID_ARGUMENT; + } + return CM_SUCCESS; +} + +static int32_t CmFreshParamSet(struct CmParamSet *paramSet, bool isCopy) +{ + if (paramSet == NULL) { + CM_LOG_E("invalid NULL paramSet"); + return CMR_ERROR_NULL_POINTER; + } + int32_t ret = CmCheckParamSet(paramSet, paramSet->paramSetSize); + if (ret != CM_SUCCESS) { + CM_LOG_E("invalid fresh paramSet"); + return ret; + } + + uint32_t size = paramSet->paramSetSize; + uint32_t offset = sizeof(struct CmParamSet) + sizeof(struct CmParam) * paramSet->paramsCnt; + + for (uint32_t i = 0; i < paramSet->paramsCnt; i++) { + if (offset > size) { + CM_LOG_E("invalid param set offset!"); + return CMR_ERROR_INVALID_ARGUMENT; + } + if (GetTagType(paramSet->params[i].tag) == CM_TAG_TYPE_BYTES) { + if (CmIsAdditionOverflow(offset, paramSet->params[i].blob.size)) { + CM_LOG_E("blob size overflow!"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + if (isCopy && (memcpy_s((uint8_t *)paramSet + offset, size - offset, + paramSet->params[i].blob.data, paramSet->params[i].blob.size) != EOK)) { + CM_LOG_E("copy param blob failed!"); + return CMR_ERROR_INVALID_OPERATION; + } + paramSet->params[i].blob.data = (uint8_t *)paramSet + offset; + offset += paramSet->params[i].blob.size; + } + } + + if (paramSet->paramSetSize != offset) { + CM_LOG_E("invalid param set size!"); + return CMR_ERROR_INVALID_ARGUMENT; + } + return CM_SUCCESS; +} + +static int32_t BuildParamSet(struct CmParamSet **paramSet) +{ + struct CmParamSet *freshParamSet = *paramSet; + uint32_t size = freshParamSet->paramSetSize; + uint32_t offset = sizeof(struct CmParamSet) + sizeof(struct CmParam) * freshParamSet->paramsCnt; + + if (size > CM_DEFAULT_PARAM_SET_SIZE) { + freshParamSet = (struct CmParamSet *)CmMalloc(size); + if (freshParamSet == NULL) { + CM_LOG_E("malloc params failed!"); + return CMR_ERROR_MALLOC_FAIL; + } + if (memcpy_s(freshParamSet, size, *paramSet, offset) != EOK) { + CM_FREE_PTR(freshParamSet); + CM_LOG_E("copy params failed!"); + return CMR_ERROR_INVALID_OPERATION; + } + CM_FREE_PTR(*paramSet); + *paramSet = freshParamSet; + } + + return CmFreshParamSet(freshParamSet, true); +} + +int32_t CmBuildParamSet(struct CmParamSet **paramSet) +{ + if ((paramSet == NULL) || (*paramSet == NULL)) { + return CMR_ERROR_NULL_POINTER; + } + + int ret = CmCheckParamSet(*paramSet, (*paramSet)->paramSetSize); + if (ret != CM_SUCCESS) { + CM_LOG_E("invalid build params!"); + return ret; + } + + return BuildParamSet(paramSet); +} + +void CmFreeParamSet(struct CmParamSet **paramSet) +{ + if (paramSet == NULL) { + CM_LOG_E("invalid free paramset!"); + return; + } + CM_FREE_PTR(*paramSet); +} + +static int32_t CheckBeforeAddParams(const struct CmParamSet *paramSet, const struct CmParam *params, + uint32_t paramCnt) +{ + if ((params == NULL) || (paramSet == NULL) || (paramSet->paramSetSize > CM_PARAM_SET_MAX_SIZE) || + (paramCnt > CM_DEFAULT_PARAM_CNT) || ((paramSet->paramsCnt + paramCnt) > CM_DEFAULT_PARAM_CNT)) { + CM_LOG_E("invalid params or paramset!"); + return CMR_ERROR_INVALID_ARGUMENT; + } + + for (uint32_t i = 0; i < paramCnt; i++) { + if ((GetTagType(params[i].tag) == CM_TAG_TYPE_BYTES) && + (params[i].blob.data == NULL)) { + CM_LOG_E("invalid blob param!"); + return CMR_ERROR_INVALID_ARGUMENT; + } + } + return CM_SUCCESS; +} + +int32_t CmAddParams(struct CmParamSet *paramSet, const struct CmParam *params, uint32_t paramCnt) +{ + int32_t ret = CheckBeforeAddParams(paramSet, params, paramCnt); + if (ret != CM_SUCCESS) { + return ret; + } + + for (uint32_t i = 0; i < paramCnt; i++) { + paramSet->paramSetSize += sizeof(struct CmParam); + if (GetTagType(params[i].tag) == CM_TAG_TYPE_BYTES) { + if (CmIsAdditionOverflow(paramSet->paramSetSize, params[i].blob.size)) { + CM_LOG_E("params size overflow!"); + paramSet->paramSetSize -= sizeof(struct CmParam); + return CMR_ERROR_INVALID_ARGUMENT; + } + paramSet->paramSetSize += params[i].blob.size; + } + (void)memcpy_s(¶mSet->params[paramSet->paramsCnt++], sizeof(struct CmParam), ¶ms[i], + sizeof(struct CmParam)); + } + return CM_SUCCESS; +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_request.cpp b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_request.cpp index 276ce464e1b598b90958eb3f3f94f4074f73e74c..54947b7cde265c4f38665010e755fd53a9a0db2a 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_request.cpp +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/cert_mgr_deps/src/cm_request.cpp @@ -1,156 +1,156 @@ -/* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cm_request.h" - -#include -#include -#include - -#include "securec.h" - -#include "cm_load_sa.h" -#include "cm_log.h" - -#include "iservice_registry.h" - -using namespace std; -using namespace OHOS; - -namespace { - constexpr int SA_ID_KEYSTORE_SERVICE = 3512; - constexpr uint32_t MAX_SA_BOOT_DELAY_TIME = 30; - const std::u16string SA_KEYSTORE_SERVICE_DESCRIPTOR = u"ohos.security.cm.service"; -} - -static sptr CmLoadSystemAbility(void) -{ - auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); - if (saManager == nullptr) { - CM_LOG_E("GetCmProxy registry is null"); - return {}; - } - - auto object = saManager->CheckSystemAbility(SA_ID_KEYSTORE_SERVICE); - if (object != nullptr) { - return object; - } - - string servers = "CertManager"; - sptr loadCallBack = new (std::nothrow)OnDemandLoadCertManagerCallback(servers); - if (loadCallBack == nullptr) { - CM_LOG_E("new OnDemandLoadCertManagerCallback failed"); - return {}; - } - - int32_t ret = saManager->LoadSystemAbility(SA_ID_KEYSTORE_SERVICE, loadCallBack); - if (ret != ERR_OK) { - CM_LOG_E("systemAbilityId:%d load failed,result code:%d", SA_ID_KEYSTORE_SERVICE, ret); - return {}; - } - - return loadCallBack->Promise(); -} - -static int32_t CmReadRequestReply(MessageParcel &reply, struct CmBlob *outBlob) -{ - int32_t ret = reply.ReadInt32(); - if (ret != CM_SUCCESS) { - CM_LOG_D("CmReadRequestReply start"); - return ret; - } - - size_t outLen = reply.ReadUint32(); - if (outLen == 0) { - if (outBlob != nullptr) { - outBlob->size = 0; - } - return ret; - } - if (CmCheckBlob(outBlob) != CM_SUCCESS) { - return CMR_ERROR_INVALID_ARGUMENT; - } - - const uint8_t *outData = reply.ReadBuffer(outLen); - if (outData == nullptr) { - return CMR_ERROR_NULL_POINTER; - } - if (outBlob->size < outLen) { - CM_LOG_E("outBlob size[%u] smaller than outLen[%u]", outBlob->size, outLen); - return CMR_ERROR_BUFFER_TOO_SMALL; - } - if (memcpy_s(outBlob->data, outBlob->size, outData, outLen) != EOK) { - return CMR_ERROR_INVALID_OPERATION; - } - outBlob->size = outLen; - return CM_SUCCESS; -} - -int32_t SendRequest(enum CertManagerInterfaceCode type, const struct CmBlob *inBlob, - struct CmBlob *outBlob) -{ - uint32_t i = 0; - sptr cmProxy = CmLoadSystemAbility(); - while ((cmProxy == nullptr) && i < MAX_SA_BOOT_DELAY_TIME) { - CM_LOG_E("cmProxy is nullptr, i = %u", i); - std::this_thread::sleep_for(std::chrono::milliseconds(100)); /* 100 is time */ - i++; - } - - cmProxy = CmLoadSystemAbility(); - if (cmProxy == nullptr) { - CM_LOG_E("Certtificate manager Proxy is null."); - return CMR_ERROR_NULL_POINTER; - } - - MessageParcel data; - MessageParcel reply; - MessageOption option = MessageOption::TF_SYNC; - - data.WriteInterfaceToken(SA_KEYSTORE_SERVICE_DESCRIPTOR); - if (outBlob == nullptr) { - data.WriteUint32(0); - } else { - data.WriteUint32(outBlob->size); - } - data.WriteUint32(inBlob->size); - data.WriteBuffer(inBlob->data, static_cast(inBlob->size)); - - int error = cmProxy->SendRequest(static_cast(type), data, reply, option); - if (error != 0) { - CM_LOG_E("SendRequest error:%d", error); - return error; - } - return CmReadRequestReply(reply, outBlob); -} - -void OnDemandLoadCertManagerCallback::OnLoadSystemAbilitySuccess(int32_t systemAbilityId, - const sptr &remoteObject) -{ - CM_LOG_D("OnLoadSystemAbility Success systemAbilityId: %d, IRemoteObject result:%s", - systemAbilityId, ((remoteObject != nullptr) ? "succeed" : "failed")); - promise_.set_value(remoteObject); -} - -void OnDemandLoadCertManagerCallback::OnLoadSystemAbilityFail(int32_t systemAbilityId) -{ - CM_LOG_E("OnLoadSystemAbility Fail systemAbilityId: %d", systemAbilityId); - promise_.set_value(nullptr); -} - -sptr OnDemandLoadCertManagerCallback::Promise(void) -{ - return promise_.get_future().get(); -} +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cm_request.h" + +#include +#include +#include + +#include "securec.h" + +#include "cm_load_sa.h" +#include "cm_log.h" + +#include "iservice_registry.h" + +using namespace std; +using namespace OHOS; + +namespace { + constexpr int SA_ID_KEYSTORE_SERVICE = 3512; + constexpr uint32_t MAX_SA_BOOT_DELAY_TIME = 30; + const std::u16string SA_KEYSTORE_SERVICE_DESCRIPTOR = u"ohos.security.cm.service"; +} + +static sptr CmLoadSystemAbility(void) +{ + auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (saManager == nullptr) { + CM_LOG_E("GetCmProxy registry is null"); + return {}; + } + + auto object = saManager->CheckSystemAbility(SA_ID_KEYSTORE_SERVICE); + if (object != nullptr) { + return object; + } + + string servers = "CertManager"; + sptr loadCallBack = new (std::nothrow)OnDemandLoadCertManagerCallback(servers); + if (loadCallBack == nullptr) { + CM_LOG_E("new OnDemandLoadCertManagerCallback failed"); + return {}; + } + + int32_t ret = saManager->LoadSystemAbility(SA_ID_KEYSTORE_SERVICE, loadCallBack); + if (ret != ERR_OK) { + CM_LOG_E("systemAbilityId:%d load failed,result code:%d", SA_ID_KEYSTORE_SERVICE, ret); + return {}; + } + + return loadCallBack->Promise(); +} + +static int32_t CmReadRequestReply(MessageParcel &reply, struct CmBlob *outBlob) +{ + int32_t ret = reply.ReadInt32(); + if (ret != CM_SUCCESS) { + CM_LOG_D("CmReadRequestReply start"); + return ret; + } + + size_t outLen = reply.ReadUint32(); + if (outLen == 0) { + if (outBlob != nullptr) { + outBlob->size = 0; + } + return ret; + } + if (CmCheckBlob(outBlob) != CM_SUCCESS) { + return CMR_ERROR_INVALID_ARGUMENT; + } + + const uint8_t *outData = reply.ReadBuffer(outLen); + if (outData == nullptr) { + return CMR_ERROR_NULL_POINTER; + } + if (outBlob->size < outLen) { + CM_LOG_E("outBlob size[%u] smaller than outLen[%u]", outBlob->size, outLen); + return CMR_ERROR_BUFFER_TOO_SMALL; + } + if (memcpy_s(outBlob->data, outBlob->size, outData, outLen) != EOK) { + return CMR_ERROR_INVALID_OPERATION; + } + outBlob->size = outLen; + return CM_SUCCESS; +} + +int32_t SendRequest(enum CertManagerInterfaceCode type, const struct CmBlob *inBlob, + struct CmBlob *outBlob) +{ + uint32_t i = 0; + sptr cmProxy = CmLoadSystemAbility(); + while ((cmProxy == nullptr) && i < MAX_SA_BOOT_DELAY_TIME) { + CM_LOG_E("cmProxy is nullptr, i = %u", i); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); /* 100 is time */ + i++; + } + + cmProxy = CmLoadSystemAbility(); + if (cmProxy == nullptr) { + CM_LOG_E("Certtificate manager Proxy is null."); + return CMR_ERROR_NULL_POINTER; + } + + MessageParcel data; + MessageParcel reply; + MessageOption option = MessageOption::TF_SYNC; + + data.WriteInterfaceToken(SA_KEYSTORE_SERVICE_DESCRIPTOR); + if (outBlob == nullptr) { + data.WriteUint32(0); + } else { + data.WriteUint32(outBlob->size); + } + data.WriteUint32(inBlob->size); + data.WriteBuffer(inBlob->data, static_cast(inBlob->size)); + + int error = cmProxy->SendRequest(static_cast(type), data, reply, option); + if (error != 0) { + CM_LOG_E("SendRequest error:%d", error); + return error; + } + return CmReadRequestReply(reply, outBlob); +} + +void OnDemandLoadCertManagerCallback::OnLoadSystemAbilitySuccess(int32_t systemAbilityId, + const sptr &remoteObject) +{ + CM_LOG_D("OnLoadSystemAbility Success systemAbilityId: %d, IRemoteObject result:%s", + systemAbilityId, ((remoteObject != nullptr) ? "succeed" : "failed")); + promise_.set_value(remoteObject); +} + +void OnDemandLoadCertManagerCallback::OnLoadSystemAbilityFail(int32_t systemAbilityId) +{ + CM_LOG_E("OnLoadSystemAbility Fail systemAbilityId: %d", systemAbilityId); + promise_.set_value(nullptr); +} + +sptr OnDemandLoadCertManagerCallback::Promise(void) +{ + return promise_.get_future().get(); +} diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/driver_nl80211_hisi.c b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/driver_nl80211_hisi.c index 8b4fcf65bca868be31b82ad35c32dc6d4265bb7f..75a3d848eeeb049f942176f27f0d6283f39a2489 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/driver_nl80211_hisi.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/driver_nl80211_hisi.c @@ -1,703 +1,702 @@ -/* - * Copyright (c) 2020 Huawei Device Co., Ltd. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ -#include "includes.h" -#include "driver_nl80211_hisi.h" -#include "driver_nl80211.h" -#include "wpa_supplicant_i.h" -#include "config.h" -#include "android_drv.h" -#include "securec.h" - -#if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) -#include "hm_miracast_sink.h" -#endif - -#define WPA_PS_ENABLED 0 -#define WPA_PS_DISABLED 1 - -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, - int (*ack_handler_custom)(struct nl_msg *, void *), - void *ack_data); - -static int drv_errors = 0; - -static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) -{ - drv_errors++; - if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { - drv_errors = 0; - wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); - } -} - -static int wpa_driver_set_power_save(void *priv, int state) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret = -1; - enum nl80211_ps_state ps_state; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - genlmsg_put(msg, 0, 0, drv->global->nl80211_id, 0, 0, - NL80211_CMD_SET_POWER_SAVE, 0); - - if (state == WPA_PS_ENABLED) - ps_state = NL80211_PS_ENABLED; - else - ps_state = NL80211_PS_DISABLED; - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); - - ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); - msg = NULL; - if (ret < 0) - wpa_printf(MSG_ERROR, "nl80211: Set power mode fail: %d", ret); -nla_put_failure: - nlmsg_free(msg); - return ret; -} - -static int get_power_mode_handler(struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - int *state = (int *) arg; - - nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - - if (!tb[NL80211_ATTR_PS_STATE]) - return NL_SKIP; - - if (state) { - *state = (int) nla_get_u32(tb[NL80211_ATTR_PS_STATE]); - wpa_printf(MSG_DEBUG, "nl80211: Get power mode = %d", *state); - *state = (*state == NL80211_PS_ENABLED) ? WPA_PS_ENABLED : WPA_PS_DISABLED; - } - - return NL_SKIP; -} - -static int wpa_driver_get_power_save(void *priv, int *state) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct nl_msg *msg; - int ret = -1; - - msg = nlmsg_alloc(); - if (!msg) - return -1; - - genlmsg_put(msg, 0, 0, drv->global->nl80211_id, 0, 0, - NL80211_CMD_GET_POWER_SAVE, 0); - - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - - ret = send_and_recv_msgs(drv, msg, get_power_mode_handler, state, NULL, - NULL); - msg = NULL; - if (ret < 0) - wpa_printf(MSG_ERROR, "nl80211: Get power mode fail: %d", ret); -nla_put_failure: - nlmsg_free(msg); - return ret; -} - -int g_is_jp = 0; -int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct ifreq ifr; - int ret = 0; - int ret_s; -#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK - char temp_cmd[MAX_PRIV_CMD_SIZE] = {0}; -#endif - - wpa_printf(MSG_ERROR, "wpa_driver_nl80211_driver_cmd:cmd = %s", cmd); - if (os_strcasecmp(cmd, "STOP") == 0) { - linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); - wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); - } else if (os_strcasecmp(cmd, "START") == 0) { - linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); - wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); - } else if (os_strcasecmp(cmd, "MACADDR") == 0) { - u8 macaddr[ETH_ALEN] = {}; - - ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr); - if (!ret) { - ret_s = snprintf_s(buf, buf_len, buf_len - 1, - "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); - if (ret_s == -1) { - wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, ret_s); - } - } - } else if (os_strcasecmp(cmd, "RELOAD") == 0) { - wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); - } else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) { - int state; - - state = atoi(cmd + 10); - ret = wpa_driver_set_power_save(priv, state); - if (ret < 0) { - wpa_driver_send_hang_msg(drv); - } else { - drv_errors = 0; - } - } else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0) { - int state = -1; - - ret = wpa_driver_get_power_save(priv, &state); - if (!ret && (state != -1)) { - ret_s = snprintf_s(buf, buf_len, buf_len - 1, "POWERMODE = %d\n", state); - if (ret_s == -1) { - wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, ret_s); - } - drv_errors = 0; - } else { - wpa_driver_send_hang_msg(drv); - } - } else { - /* Use private command */ - wifi_priv_cmd priv_cmd = {0}; - uint32 ret_len = 0; - size_t buf_len_tmp; - - if (buf_len > MAX_PRIV_CMD_SIZE || strlen(cmd) >= MAX_PRIV_CMD_SIZE) { - wpa_printf(MSG_ERROR, "%s: too long priavte command, strlen(cmd)=%zu buf_len=%zu", __func__, strlen(cmd), buf_len); - return -1; - } - buf_len_tmp = buf_len; - if (MAX_PRIV_CMD_SIZE == buf_len) { - buf_len = strlen(cmd); /* default driver xxx cmd */ - } - - /* Hisi private data structure cmd should use buf_len, rather than strlen(cmd) */ -#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK - priv_cmd.buf = temp_cmd; - ret_s = memcpy_s(temp_cmd, buf_len_tmp, cmd, buf_len); -#else - ret_s = memcpy_s(buf, buf_len_tmp, cmd, buf_len); -#endif /* CONFIG_DRIVER_NL80211_HISI_TRUNK */ - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); - } - - ret_s = memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr)); - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s); - } - - ret_s = memcpy_s(priv_cmd.buf, MAX_PRIV_CMD_SIZE, cmd, buf_len); - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); - } - -#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK - priv_cmd.total_len = sizeof(temp_cmd); -#else - priv_cmd.total_len = buf_len; /* MAX_PRIV_CMD_SIZE */ -#endif /* CONFIG_DRIVER_NL80211_HISI_TRUNK */ - priv_cmd.used_len = buf_len; /* strlen(cmd) */ - - ifr.ifr_data = (void *) &priv_cmd; - os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); - - wpa_printf(MSG_EXCESSIVE, "%s: 1:ifr_name=%s, len=%zu, buf_len=%zu", __func__, ifr.ifr_name, strlen(buf), buf_len); - - ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); - if (ret < 0) { - wpa_printf(MSG_ERROR, "%s: failed to issue private commands\n", __func__); - wpa_driver_send_hang_msg(drv); - } else { - drv_errors = 0; - ret_len = os_strlen(priv_cmd.buf); - ret_len = (ret_len < MAX_PRIV_CMD_SIZE) ? ret_len : (MAX_PRIV_CMD_SIZE - 1); - /* SET Command return 0 which means OK, GET Command return string length */ - if (os_strncasecmp(buf, priv_cmd.buf, ret_len) != 0) { - ret = 0; - } - ret_s = memset_s(buf, buf_len, 0, buf_len); - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s); - } - - ret_s = memcpy_s(buf, buf_len, priv_cmd.buf, ret_len); /* copy kernel space return string to user space */ - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); - } - buf[ret_len] = '\0'; - - if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { - union wpa_event_data event = {0}; - g_is_jp = (os_strncasecmp(cmd + 8, "JP", 2) == 0) ? 1 : 0; - - event.channel_list_changed.initiator = REGDOM_SET_BY_USER; - event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; - wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &event); - - wpa_printf(MSG_DEBUG, "%s:set country code end. len=%zu, ret_len=%d ret=%d", __func__, strlen(buf), ret_len, ret); - return ret; - } -#ifdef OPEN_HARMONY_MIRACAST_SINK_OPT - hisi_miracast_sink_log("%s:%.15s len=%zu, ret_len=%d ret=%d", __func__, buf, strlen(buf), ret_len, ret); -#else -#ifdef HW_WPA_REDUCE_LOG - wpa_printf(MSG_EXCESSIVE, "%s:%.15s len=%zu, ret_len=%d ret=%d", __func__, buf, strlen(buf), ret_len, ret); -#else - wpa_printf(MSG_DEBUG, "%s:%.15s len=%zu, ret_len=%d ret=%d", __func__, buf, strlen(buf), ret_len, ret); -#endif -#endif - } - } - return ret; -} - -int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) -{ - char buf[MAX_DRV_CMD_SIZE] = {0}; - char *pbuf; - oal_p2p_noa_param_stru *pst_p2p_noa = NULL; - char *_cmd = "P2P_SET_NOA"; - int ret_s; - - wpa_printf(MSG_ERROR, "%s: Entry", __func__); - pbuf = buf; - ret_s = sprintf_s(pbuf, MAX_DRV_CMD_SIZE, "%s", _cmd); - if (ret_s == -1) { - wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); - } - pbuf += ret_s; - *pbuf++ = '\0'; - pst_p2p_noa = (oal_p2p_noa_param_stru *) pbuf; - pst_p2p_noa->uc_count = count; - pst_p2p_noa->ul_duration = duration; - pst_p2p_noa->ul_start_time = start; - - return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(_cmd) + 1 + sizeof(oal_p2p_noa_param_stru)); -} - -int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) -{ - /* Return 0 till we handle p2p_presence request completely in the device side */ - return 0; -} - -int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) -{ - char buf[MAX_DRV_CMD_SIZE] = {0}; - char *pbuf; - oal_p2p_ops_param_stru *pst_p2p_ops = NULL; - char *_cmd = "P2P_SET_PS"; - int ret_s; - - wpa_printf(MSG_ERROR, "%s: Entry", __func__); - pbuf = buf; - ret_s = sprintf_s(pbuf, MAX_DRV_CMD_SIZE, "%s", _cmd); - if (ret_s == -1) { - wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); - } - pbuf += ret_s; - *pbuf++ = '\0'; - pst_p2p_ops = (oal_p2p_ops_param_stru *) pbuf; - pst_p2p_ops->en_ops_ctrl = opp_ps; - pst_p2p_ops->uc_ct_window = ctwindow; - - return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(_cmd) + 1 + sizeof(oal_p2p_ops_param_stru)); -} - -int wpa_driver_set_ap_wps_p2p_ie(void *priv, - const struct wpabuf *beacon, - const struct wpabuf *proberesp, - const struct wpabuf *assocresp) -{ - char buf[MAX_WPSP2PIE_CMD_SIZE] = {0}; - struct wpabuf *ap_wps_p2p_ie = NULL; - char *_cmd = "SET_AP_WPS_P2P_IE"; - char *pbuf; - int ret = 0; - int i; - int ret_s; - oal_app_ie_stru *pst_app_ie = NULL; - struct cmd_desc { - int cmd; - const struct wpabuf *src; - } cmd_arr[] = { - {0x0, beacon}, - {0x2, proberesp}, - {0x4, assocresp}, - {-1, NULL} - }; - - wpa_printf(MSG_ERROR, "%s: Entry", __func__); - for (i = 0; cmd_arr[i].cmd != -1; i++) { - ret_s = memset_s(buf, sizeof(buf), 0, sizeof(buf)); - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s); - } - pbuf = buf; - ret_s = sprintf_s(pbuf, MAX_WPSP2PIE_CMD_SIZE, "%s", _cmd); - if (ret_s == -1) { - wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s); - } - pbuf += ret_s; - *pbuf++ = '\0'; - ap_wps_p2p_ie = cmd_arr[i].src ? wpabuf_dup(cmd_arr[i].src) : NULL; - if (ap_wps_p2p_ie) { - if (wpabuf_len(ap_wps_p2p_ie) > WLAN_WPS_IE_MAX_SIZE) { - wpa_printf(MSG_ERROR, "%s: app ie too large to wifi driver buffer.app_ie_len %d, auc_ie len %ul", - __func__, (int) wpabuf_len(ap_wps_p2p_ie), WLAN_WPS_IE_MAX_SIZE); - wpabuf_free(ap_wps_p2p_ie); - return -1; - } - - pst_app_ie = (oal_app_ie_stru *) pbuf; - pst_app_ie->en_app_ie_type = cmd_arr[i].cmd; - pst_app_ie->ul_ie_len = wpabuf_len(ap_wps_p2p_ie); - - ret_s = memcpy_s(pst_app_ie->auc_ie, sizeof(pst_app_ie->auc_ie), wpabuf_head(ap_wps_p2p_ie), wpabuf_len(ap_wps_p2p_ie)); - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); - } -#if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) - hisi_miracast_sink_log("cmd:%s, type %d, ie_len %d\r\n", - _cmd, - pst_app_ie->en_app_ie_type, - pst_app_ie->ul_ie_len); -#else -#ifdef HW_WPA_REDUCE_LOG - wpa_printf(MSG_EXCESSIVE, "cmd:%s, type %d, ie_len %d\r\n", - _cmd, - pst_app_ie->en_app_ie_type, - pst_app_ie->ul_ie_len); -#else - wpa_printf(MSG_DEBUG, "cmd:%s, type %d, ie_len %d\r\n", - _cmd, - pst_app_ie->en_app_ie_type, - pst_app_ie->ul_ie_len); -#endif /* HW_WPA_REDUCE_LOG */ -#endif - wpa_printf(MSG_EXCESSIVE, "ie %p\r\n", - pst_app_ie->auc_ie); - - wpa_hexdump(MSG_EXCESSIVE, "P2P: set p2p wps ie", (const char *) pbuf, pst_app_ie->ul_ie_len + 8); - - if (strlen(_cmd) + sizeof(oal_app_ie_stru) + 1 < sizeof(buf)) { - ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf, - strlen(_cmd) + sizeof(oal_app_ie_stru) + 1); - } else { - wpa_printf(MSG_ERROR, "%s:error.app total length to large!, cmd_len = %zu, buffer = %d", __func__, strlen(_cmd) + sizeof(oal_app_ie_stru) + 1, (int) sizeof(buf)); - ret = -1; - } - wpabuf_free(ap_wps_p2p_ie); - if (ret < 0) - break; - } - } - return ret; -} - -int wpa_driver_set_power_on(void *priv, int on) -{ - char buf[MAX_PRIV_CMD_SIZE] = {0}; - char *pbuf; - char *_cmd = "SET_POWER_ON"; - int ret_s; - - wpa_printf(MSG_DEBUG, "%s: Entry,power flag:%d", __func__, on); - pbuf = buf; - ret_s = sprintf_s(pbuf, MAX_PRIV_CMD_SIZE, "%s %d", _cmd, on); - if (ret_s == -1) { - wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); - } - wpa_printf(MSG_DEBUG, "%s:buf is %s", __func__, buf); - - return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)); -} - -int wpa_driver_set_powermgmt_on(void *priv, int powermgmt_on) -{ - char buf[MAX_PRIV_CMD_SIZE] = {0}; - char *pbuf; - char *_cmd = "SET_POWER_MGMT_ON"; - int ret_s; - - wpa_printf(MSG_DEBUG, "%s: Entry,power mgmt flag:%d", __func__, powermgmt_on); - pbuf = buf; - ret_s = sprintf_s(pbuf, MAX_PRIV_CMD_SIZE, "%s %d", _cmd, powermgmt_on); - if (ret_s == -1) { - wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); - } - wpa_printf(MSG_DEBUG, "%s:buf is %s", __func__, buf); - - return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)); -} - -int wpa_driver_set_qos_map(void *priv, const u8 *qos_map_set, - u8 qos_map_set_len) -{ - char buf[MAX_DRV_CMD_SIZE] = {0}; - char *pbuf; - int i, up_start; - int ret = 0; - int ret_s; - oal_qos_map_param_stru *pst_qos_map = NULL; - char *_cmd = "SET_QOS_MAP"; - - if (qos_map_set_len < 16 || qos_map_set_len > 58 || qos_map_set_len & 1) { - wpa_printf(MSG_ERROR, "Invalid QoS Map"); - return -1; - } - - wpa_printf(MSG_ERROR, "%s: Entry,set_qos_map", __func__); - pbuf = buf; - ret_s = sprintf_s(pbuf, MAX_DRV_CMD_SIZE, "%s", _cmd); - if (ret_s == -1) { - wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); - } - pbuf += ret_s; - *pbuf++ = '\0'; - - pst_qos_map = (oal_qos_map_param_stru *) pbuf; - pst_qos_map->valid = 1; - pst_qos_map->num_dscp_except = (qos_map_set_len - 16) / 2; - if (pst_qos_map->num_dscp_except) { - for (i = 0; i < pst_qos_map->num_dscp_except; i++) { - pst_qos_map->dscp_exception[i] = qos_map_set[i * 2]; - pst_qos_map->dscp_exception_up[i] = qos_map_set[i * 2 + 1]; - } - } - up_start = qos_map_set_len - 16; - for (i = 0; i < MAX_QOS_UP_RANGE; i++) { - pst_qos_map->up_low[i] = qos_map_set[up_start + (i * 2)]; - pst_qos_map->up_high[i] = qos_map_set[up_start + (i * 2) + 1]; - } - - ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(_cmd) + 1 + sizeof(oal_qos_map_param_stru)); - return ret; -} - -int wpa_driver_set_tx_power(void *priv, int power) -{ - char buf[MAX_PRIV_CMD_SIZE] = {0}; - int len = 0; - - wpa_printf(MSG_ERROR, "%s: Entry,power limit:%d", __func__, power); - if (power <= 0 || power > 100) { - wpa_printf(MSG_ERROR, "%s: Entry,invalid power, valid power should in range(0,100]!", __func__); - return -1; - } - len = snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "TX_POWER %d", power); - if (len == -1) { - wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, len); - } - buf[len] = '\0'; - wpa_printf(MSG_DEBUG, "%s:buf is %s", __func__, buf); - - return wpa_driver_nl80211_driver_cmd(priv, buf, buf, len); -} - -#ifdef CONFIG_OWE -int wpa_driver_nl80211_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr, - int reassoc, u16 status, const u8 *pst_assoc_rsp_ie, size_t len) -{ - char buf[MAX_WPSP2PIE_CMD_SIZE] = {0}; - char *pbuf; - char *_cmd = "SET_MLME_IE"; - int ret = 0; - int ret_s; - set_mlme_stru *pst_mlme_ie = NULL; - - if (NULL == pst_assoc_rsp_ie) { - wpa_printf(MSG_WARNING, "%s[%d]: buf is null.\n", __FUNCTION__, __LINE__); - return -1; - } - - if (len > WLAN_WPS_IE_MAX_SIZE) { - /* ����·�ie ���ȴ����¼��ڴ��С����ʾ���� */ - wpa_printf(MSG_ERROR, "%s[%d]: assoc rsp ie too large to wifi driver buffer. ie_len %zu, MAX len %d", - __FUNCTION__, __LINE__, len, WLAN_WPS_IE_MAX_SIZE); - return -1; - } - - pbuf = buf; - ret_s = sprintf_s(pbuf, MAX_WPSP2PIE_CMD_SIZE, "%s", _cmd); - if (ret_s == -1) { - wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); - } - pbuf += ret_s; - *pbuf++ = '\0'; - - pst_mlme_ie = (set_mlme_stru *) pbuf; - if (reassoc) { - pst_mlme_ie->en_mlme_type = OAL_IEEE80211_MLME_REASSOC_RSP; - } else { - pst_mlme_ie->en_mlme_type = OAL_IEEE80211_MLME_ASSOC_RSP; - } - pst_mlme_ie->us_status = status; - ret_s = memcpy_s(pst_mlme_ie->uc_macaddr, sizeof(pst_mlme_ie->uc_macaddr), addr, ETH_ALEN); - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); - } - - pst_mlme_ie->us_ie_len = len; - ret_s = memcpy_s(pst_mlme_ie->auc_ie, sizeof(pst_mlme_ie->auc_ie), pst_assoc_rsp_ie, len); - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); - } - - wpa_printf(MSG_ERROR, "%s[%d]: sta_assoc begin send assoc rsp ie len[%zu] to driver", __FUNCTION__, __LINE__, len); - - wpa_printf(MSG_ERROR, "cmd:%s, type %d, status %d, ie_len %d", - _cmd, - pst_mlme_ie->en_mlme_type, - pst_mlme_ie->us_status, - pst_mlme_ie->us_ie_len); - - wpa_hexdump(MSG_ERROR, "MLME: set sta_assoc ie", (const char *) pbuf, pst_mlme_ie->us_ie_len + 8); - - if (os_strlen(_cmd) + sizeof(set_mlme_stru) + 1 < sizeof(buf)) { - ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf, - os_strlen(_cmd) + sizeof(set_mlme_stru) + 1); - } else { - wpa_printf(MSG_ERROR, "%s:error. app total length to large! cmd_len = %zu, buffer = %d", - __func__, os_strlen(_cmd) + sizeof(set_mlme_stru) + 1, (int)sizeof(buf)); - ret = -1; - } - - return ret; -} -#endif - -#ifdef CONFIG_HW_GET_P2P_SIGNAL_POLL -int wpa_drv_get_p2p_link_noise(void *priv, struct wpa_signal_info *si) -{ - if (priv == NULL || si == NULL) { - return -1; - } - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - os_memset(si, 0, sizeof(struct wpa_signal_info)); - return nl80211_get_link_noise(drv, si); -} -#endif /* CONFIG_HW_GET_P2P_SIGNAL_POLL */ - -static int wpa_sockets_open(void) -{ - int skfd; - - skfd = socket(PF_INET, SOCK_DGRAM, 0); - if (skfd < 0) { - wpa_printf(MSG_ERROR, - "nl80211: socket open failed."); - return -1; - } - return skfd; -} -static void wpa_sockets_close(int32 skfd) -{ - close(skfd); -} -static int wpa_send_cmd_to_driver(int skfd, s8 *ifname, wifi_priv_cmd *ioctl_data) -{ - struct ifreq ifr; - int ret; - int ret_s; - - ret_s = memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr)); - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s); - } - - ret_s = strncpy_s(ifr.ifr_name, IFNAMSIZ, "wlan0", strlen("wlan0")); - if (ret_s != EOK) { - wpa_printf(MSG_ERROR, "%s:%d, strncpy failed, ret=%d", __func__, __LINE__, ret_s); - } - ifr.ifr_name[IFNAMSIZ - 1] = '\0'; - ifr.ifr_data = (void *) ioctl_data; - - ret = ioctl(skfd, SIOCDEVPRIVATE + 1, &ifr); - - if (ret < 0) { - wpa_printf(MSG_ERROR, - "%s: failed to issue ioctl cmd.\n", __func__); - } - - return ret; -} - -static cust_data_stru global_cust_data = {0, 0}; - -static void get_cust_config_params(void) -{ - int skfd; - wifi_priv_cmd ioctl_data = {0}; - int ret; - int len; -#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK - char buff[MAX_PRIV_CMD_SIZE] = {0}; -#endif /* CONFIG_DRIVER_NL80211_HISI_TRUNK */ - - if (-1 == (skfd = wpa_sockets_open())) { - wpa_printf(MSG_ERROR, - "%s: failed create socket.\n", __func__); - return; - } - -#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK - ioctl_data.buf = buff; - len = snprintf_s(buff, MAX_PRIV_CMD_SIZE, MAX_PRIV_CMD_SIZE - 1, "WPAS_GET_CUST"); -#else - len = snprintf_s(ioctl_data.buf, MAX_PRIV_CMD_SIZE, MAX_PRIV_CMD_SIZE - 1, "WPAS_GET_CUST"); -#endif - if (len == -1) { - wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, len); - } - ioctl_data.total_len = MAX_PRIV_CMD_SIZE; - ioctl_data.used_len = len; -#ifdef HW_WPA_REDUCE_LOG - wpa_printf(MSG_ERROR, "%s:ioctl_data cmd is %s", __func__, ioctl_data.buf); -#else - wpa_printf(MSG_ERROR, "%s:ioctl_data cmd is %s", __func__, ioctl_data.buf); -#endif - - ret = wpa_send_cmd_to_driver(skfd, (s8 *) "wlan0", &ioctl_data); - - if (ret < 0) { - wpa_printf(MSG_ERROR, - "%s: send cmd to driver failed.\n", __func__); - wpa_sockets_close(skfd); - return; - } - - drv_errors = 0; - - global_cust_data.read = 1; - global_cust_data.disable_capab_2ght40 = (u32) (*ioctl_data.buf); - wpa_printf(MSG_ERROR, - "%s: update wps global cust data: [disable_capab_2ght40:%d]\n", __func__, global_cust_data.disable_capab_2ght40); - - wpa_sockets_close(skfd); -} - -u32 get_cust_disable_capab_2ght40(void) -{ - if (!global_cust_data.read) { - get_cust_config_params(); - } - - return global_cust_data.disable_capab_2ght40; +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "includes.h" +#include "driver_nl80211_hisi.h" +#include "driver_nl80211.h" +#include "wpa_supplicant_i.h" +#include "config.h" +#include "android_drv.h" +#include "securec.h" + +#if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) +#include "hm_miracast_sink.h" +#endif + +#define WPA_PS_ENABLED 0 +#define WPA_PS_DISABLED 1 + +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, + int (*ack_handler_custom)(struct nl_msg *, void *), + void *ack_data); + +static int drv_errors = 0; + +static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv) +{ + drv_errors++; + if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) { + drv_errors = 0; + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); + } +} + +static int wpa_driver_set_power_save(void *priv, int state) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -1; + enum nl80211_ps_state ps_state; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, drv->global->nl80211_id, 0, 0, + NL80211_CMD_SET_POWER_SAVE, 0); + + if (state == WPA_PS_ENABLED) + ps_state = NL80211_PS_ENABLED; + else + ps_state = NL80211_PS_DISABLED; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); + + ret = send_and_recv_cmd(drv, msg); + msg = NULL; + if (ret < 0) + wpa_printf(MSG_ERROR, "nl80211: Set power mode fail: %d", ret); +nla_put_failure: + nlmsg_free(msg); + return ret; +} + +static int get_power_mode_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + int *state = (int *) arg; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!tb[NL80211_ATTR_PS_STATE]) + return NL_SKIP; + + if (state) { + *state = (int) nla_get_u32(tb[NL80211_ATTR_PS_STATE]); + wpa_printf(MSG_DEBUG, "nl80211: Get power mode = %d", *state); + *state = (*state == NL80211_PS_ENABLED) ? WPA_PS_ENABLED : WPA_PS_DISABLED; + } + + return NL_SKIP; +} + +static int wpa_driver_get_power_save(void *priv, int *state) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret = -1; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, drv->global->nl80211_id, 0, 0, + NL80211_CMD_GET_POWER_SAVE, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + ret = send_and_recv_resp(drv, msg, get_power_mode_handler, state); + msg = NULL; + if (ret < 0) + wpa_printf(MSG_ERROR, "nl80211: Get power mode fail: %d", ret); +nla_put_failure: + nlmsg_free(msg); + return ret; +} + +int g_is_jp = 0; +int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct ifreq ifr; + int ret = 0; + int ret_s; +#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK + char temp_cmd[MAX_PRIV_CMD_SIZE] = {0}; +#endif + + wpa_printf(MSG_ERROR, "wpa_driver_nl80211_driver_cmd:cmd = %s", cmd); + if (os_strcasecmp(cmd, "STOP") == 0) { + linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); + } else if (os_strcasecmp(cmd, "START") == 0) { + linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); + } else if (os_strcasecmp(cmd, "MACADDR") == 0) { + u8 macaddr[ETH_ALEN] = {}; + + ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr); + if (!ret) { + ret_s = snprintf_s(buf, buf_len, buf_len - 1, + "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); + if (ret_s == -1) { + wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, ret_s); + } + } + } else if (os_strcasecmp(cmd, "RELOAD") == 0) { + wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); + } else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) { + int state; + + state = atoi(cmd + 10); + ret = wpa_driver_set_power_save(priv, state); + if (ret < 0) { + wpa_driver_send_hang_msg(drv); + } else { + drv_errors = 0; + } + } else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0) { + int state = -1; + + ret = wpa_driver_get_power_save(priv, &state); + if (!ret && (state != -1)) { + ret_s = snprintf_s(buf, buf_len, buf_len - 1, "POWERMODE = %d\n", state); + if (ret_s == -1) { + wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, ret_s); + } + drv_errors = 0; + } else { + wpa_driver_send_hang_msg(drv); + } + } else { + /* Use private command */ + wifi_priv_cmd priv_cmd = {0}; + uint32 ret_len = 0; + size_t buf_len_tmp; + + if (buf_len > MAX_PRIV_CMD_SIZE || strlen(cmd) >= MAX_PRIV_CMD_SIZE) { + wpa_printf(MSG_ERROR, "%s: too long priavte command, strlen(cmd)=%zu buf_len=%zu", __func__, strlen(cmd), buf_len); + return -1; + } + buf_len_tmp = buf_len; + if (MAX_PRIV_CMD_SIZE == buf_len) { + buf_len = strlen(cmd); /* default driver xxx cmd */ + } + + /* Hisi private data structure cmd should use buf_len, rather than strlen(cmd) */ +#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK + priv_cmd.buf = temp_cmd; + ret_s = memcpy_s(temp_cmd, buf_len_tmp, cmd, buf_len); +#else + ret_s = memcpy_s(buf, buf_len_tmp, cmd, buf_len); +#endif /* CONFIG_DRIVER_NL80211_HISI_TRUNK */ + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); + } + + ret_s = memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr)); + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s); + } + + ret_s = memcpy_s(priv_cmd.buf, MAX_PRIV_CMD_SIZE, cmd, buf_len); + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); + } + +#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK + priv_cmd.total_len = sizeof(temp_cmd); +#else + priv_cmd.total_len = buf_len; /* MAX_PRIV_CMD_SIZE */ +#endif /* CONFIG_DRIVER_NL80211_HISI_TRUNK */ + priv_cmd.used_len = buf_len; /* strlen(cmd) */ + + ifr.ifr_data = (void *) &priv_cmd; + os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); + + wpa_printf(MSG_EXCESSIVE, "%s: 1:ifr_name=%s, len=%zu, buf_len=%zu", __func__, ifr.ifr_name, strlen(buf), buf_len); + + ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr); + if (ret < 0) { + wpa_printf(MSG_ERROR, "%s: failed to issue private commands\n", __func__); + wpa_driver_send_hang_msg(drv); + } else { + drv_errors = 0; + ret_len = os_strlen(priv_cmd.buf); + ret_len = (ret_len < MAX_PRIV_CMD_SIZE) ? ret_len : (MAX_PRIV_CMD_SIZE - 1); + /* SET Command return 0 which means OK, GET Command return string length */ + if (os_strncasecmp(buf, priv_cmd.buf, ret_len) != 0) { + ret = 0; + } + ret_s = memset_s(buf, buf_len, 0, buf_len); + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s); + } + + ret_s = memcpy_s(buf, buf_len, priv_cmd.buf, ret_len); /* copy kernel space return string to user space */ + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); + } + buf[ret_len] = '\0'; + + if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { + union wpa_event_data event = {0}; + g_is_jp = (os_strncasecmp(cmd + 8, "JP", 2) == 0) ? 1 : 0; + + event.channel_list_changed.initiator = REGDOM_SET_BY_USER; + event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; + wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &event); + + wpa_printf(MSG_DEBUG, "%s:set country code end. len=%zu, ret_len=%d ret=%d", __func__, strlen(buf), ret_len, ret); + return ret; + } +#ifdef OPEN_HARMONY_MIRACAST_SINK_OPT + hisi_miracast_sink_log("%s:%.15s len=%zu, ret_len=%d ret=%d", __func__, buf, strlen(buf), ret_len, ret); +#else +#ifdef HW_WPA_REDUCE_LOG + wpa_printf(MSG_EXCESSIVE, "%s:%.15s len=%zu, ret_len=%d ret=%d", __func__, buf, strlen(buf), ret_len, ret); +#else + wpa_printf(MSG_DEBUG, "%s:%.15s len=%zu, ret_len=%d ret=%d", __func__, buf, strlen(buf), ret_len, ret); +#endif +#endif + } + } + return ret; +} + +int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) +{ + char buf[MAX_DRV_CMD_SIZE] = {0}; + char *pbuf; + oal_p2p_noa_param_stru *pst_p2p_noa = NULL; + char *_cmd = "P2P_SET_NOA"; + int ret_s; + + wpa_printf(MSG_ERROR, "%s: Entry", __func__); + pbuf = buf; + ret_s = sprintf_s(pbuf, MAX_DRV_CMD_SIZE, "%s", _cmd); + if (ret_s == -1) { + wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); + } + pbuf += ret_s; + *pbuf++ = '\0'; + pst_p2p_noa = (oal_p2p_noa_param_stru *) pbuf; + pst_p2p_noa->uc_count = count; + pst_p2p_noa->ul_duration = duration; + pst_p2p_noa->ul_start_time = start; + + return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(_cmd) + 1 + sizeof(oal_p2p_noa_param_stru)); +} + +int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) +{ + /* Return 0 till we handle p2p_presence request completely in the device side */ + return 0; +} + +int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) +{ + char buf[MAX_DRV_CMD_SIZE] = {0}; + char *pbuf; + oal_p2p_ops_param_stru *pst_p2p_ops = NULL; + char *_cmd = "P2P_SET_PS"; + int ret_s; + + wpa_printf(MSG_ERROR, "%s: Entry", __func__); + pbuf = buf; + ret_s = sprintf_s(pbuf, MAX_DRV_CMD_SIZE, "%s", _cmd); + if (ret_s == -1) { + wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); + } + pbuf += ret_s; + *pbuf++ = '\0'; + pst_p2p_ops = (oal_p2p_ops_param_stru *) pbuf; + pst_p2p_ops->en_ops_ctrl = opp_ps; + pst_p2p_ops->uc_ct_window = ctwindow; + + return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(_cmd) + 1 + sizeof(oal_p2p_ops_param_stru)); +} + +int wpa_driver_set_ap_wps_p2p_ie(void *priv, + const struct wpabuf *beacon, + const struct wpabuf *proberesp, + const struct wpabuf *assocresp) +{ + char buf[MAX_WPSP2PIE_CMD_SIZE] = {0}; + struct wpabuf *ap_wps_p2p_ie = NULL; + char *_cmd = "SET_AP_WPS_P2P_IE"; + char *pbuf; + int ret = 0; + int i; + int ret_s; + oal_app_ie_stru *pst_app_ie = NULL; + struct cmd_desc { + int cmd; + const struct wpabuf *src; + } cmd_arr[] = { + {0x0, beacon}, + {0x2, proberesp}, + {0x4, assocresp}, + {-1, NULL} + }; + + wpa_printf(MSG_ERROR, "%s: Entry", __func__); + for (i = 0; cmd_arr[i].cmd != -1; i++) { + ret_s = memset_s(buf, sizeof(buf), 0, sizeof(buf)); + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s); + } + pbuf = buf; + ret_s = sprintf_s(pbuf, MAX_WPSP2PIE_CMD_SIZE, "%s", _cmd); + if (ret_s == -1) { + wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s); + } + pbuf += ret_s; + *pbuf++ = '\0'; + ap_wps_p2p_ie = cmd_arr[i].src ? wpabuf_dup(cmd_arr[i].src) : NULL; + if (ap_wps_p2p_ie) { + if (wpabuf_len(ap_wps_p2p_ie) > WLAN_WPS_IE_MAX_SIZE) { + wpa_printf(MSG_ERROR, "%s: app ie too large to wifi driver buffer.app_ie_len %d, auc_ie len %ul", + __func__, (int) wpabuf_len(ap_wps_p2p_ie), WLAN_WPS_IE_MAX_SIZE); + wpabuf_free(ap_wps_p2p_ie); + return -1; + } + + pst_app_ie = (oal_app_ie_stru *) pbuf; + pst_app_ie->en_app_ie_type = cmd_arr[i].cmd; + pst_app_ie->ul_ie_len = wpabuf_len(ap_wps_p2p_ie); + + ret_s = memcpy_s(pst_app_ie->auc_ie, sizeof(pst_app_ie->auc_ie), wpabuf_head(ap_wps_p2p_ie), wpabuf_len(ap_wps_p2p_ie)); + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); + } +#if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT) + hisi_miracast_sink_log("cmd:%s, type %d, ie_len %d\r\n", + _cmd, + pst_app_ie->en_app_ie_type, + pst_app_ie->ul_ie_len); +#else +#ifdef HW_WPA_REDUCE_LOG + wpa_printf(MSG_EXCESSIVE, "cmd:%s, type %d, ie_len %d\r\n", + _cmd, + pst_app_ie->en_app_ie_type, + pst_app_ie->ul_ie_len); +#else + wpa_printf(MSG_DEBUG, "cmd:%s, type %d, ie_len %d\r\n", + _cmd, + pst_app_ie->en_app_ie_type, + pst_app_ie->ul_ie_len); +#endif /* HW_WPA_REDUCE_LOG */ +#endif + wpa_printf(MSG_EXCESSIVE, "ie %p\r\n", + pst_app_ie->auc_ie); + + wpa_hexdump(MSG_EXCESSIVE, "P2P: set p2p wps ie", (const char *) pbuf, pst_app_ie->ul_ie_len + 8); + + if (strlen(_cmd) + sizeof(oal_app_ie_stru) + 1 < sizeof(buf)) { + ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf, + strlen(_cmd) + sizeof(oal_app_ie_stru) + 1); + } else { + wpa_printf(MSG_ERROR, "%s:error.app total length to large!, cmd_len = %zu, buffer = %d", __func__, strlen(_cmd) + sizeof(oal_app_ie_stru) + 1, (int) sizeof(buf)); + ret = -1; + } + wpabuf_free(ap_wps_p2p_ie); + if (ret < 0) + break; + } + } + return ret; +} + +int wpa_driver_set_power_on(void *priv, int on) +{ + char buf[MAX_PRIV_CMD_SIZE] = {0}; + char *pbuf; + char *_cmd = "SET_POWER_ON"; + int ret_s; + + wpa_printf(MSG_DEBUG, "%s: Entry,power flag:%d", __func__, on); + pbuf = buf; + ret_s = sprintf_s(pbuf, MAX_PRIV_CMD_SIZE, "%s %d", _cmd, on); + if (ret_s == -1) { + wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); + } + wpa_printf(MSG_DEBUG, "%s:buf is %s", __func__, buf); + + return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)); +} + +int wpa_driver_set_powermgmt_on(void *priv, int powermgmt_on) +{ + char buf[MAX_PRIV_CMD_SIZE] = {0}; + char *pbuf; + char *_cmd = "SET_POWER_MGMT_ON"; + int ret_s; + + wpa_printf(MSG_DEBUG, "%s: Entry,power mgmt flag:%d", __func__, powermgmt_on); + pbuf = buf; + ret_s = sprintf_s(pbuf, MAX_PRIV_CMD_SIZE, "%s %d", _cmd, powermgmt_on); + if (ret_s == -1) { + wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); + } + wpa_printf(MSG_DEBUG, "%s:buf is %s", __func__, buf); + + return wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(buf)); +} + +int wpa_driver_set_qos_map(void *priv, const u8 *qos_map_set, + u8 qos_map_set_len) +{ + char buf[MAX_DRV_CMD_SIZE] = {0}; + char *pbuf; + int i, up_start; + int ret = 0; + int ret_s; + oal_qos_map_param_stru *pst_qos_map = NULL; + char *_cmd = "SET_QOS_MAP"; + + if (qos_map_set_len < 16 || qos_map_set_len > 58 || qos_map_set_len & 1) { + wpa_printf(MSG_ERROR, "Invalid QoS Map"); + return -1; + } + + wpa_printf(MSG_ERROR, "%s: Entry,set_qos_map", __func__); + pbuf = buf; + ret_s = sprintf_s(pbuf, MAX_DRV_CMD_SIZE, "%s", _cmd); + if (ret_s == -1) { + wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); + } + pbuf += ret_s; + *pbuf++ = '\0'; + + pst_qos_map = (oal_qos_map_param_stru *) pbuf; + pst_qos_map->valid = 1; + pst_qos_map->num_dscp_except = (qos_map_set_len - 16) / 2; + if (pst_qos_map->num_dscp_except) { + for (i = 0; i < pst_qos_map->num_dscp_except; i++) { + pst_qos_map->dscp_exception[i] = qos_map_set[i * 2]; + pst_qos_map->dscp_exception_up[i] = qos_map_set[i * 2 + 1]; + } + } + up_start = qos_map_set_len - 16; + for (i = 0; i < MAX_QOS_UP_RANGE; i++) { + pst_qos_map->up_low[i] = qos_map_set[up_start + (i * 2)]; + pst_qos_map->up_high[i] = qos_map_set[up_start + (i * 2) + 1]; + } + + ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf, strlen(_cmd) + 1 + sizeof(oal_qos_map_param_stru)); + return ret; +} + +int wpa_driver_set_tx_power(void *priv, int power) +{ + char buf[MAX_PRIV_CMD_SIZE] = {0}; + int len = 0; + + wpa_printf(MSG_ERROR, "%s: Entry,power limit:%d", __func__, power); + if (power <= 0 || power > 100) { + wpa_printf(MSG_ERROR, "%s: Entry,invalid power, valid power should in range(0,100]!", __func__); + return -1; + } + len = snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "TX_POWER %d", power); + if (len == -1) { + wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, len); + } + buf[len] = '\0'; + wpa_printf(MSG_DEBUG, "%s:buf is %s", __func__, buf); + + return wpa_driver_nl80211_driver_cmd(priv, buf, buf, len); +} + +#ifdef CONFIG_OWE +int wpa_driver_nl80211_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr, + int reassoc, u16 status, const u8 *pst_assoc_rsp_ie, size_t len) +{ + char buf[MAX_WPSP2PIE_CMD_SIZE] = {0}; + char *pbuf; + char *_cmd = "SET_MLME_IE"; + int ret = 0; + int ret_s; + set_mlme_stru *pst_mlme_ie = NULL; + + if (NULL == pst_assoc_rsp_ie) { + wpa_printf(MSG_WARNING, "%s[%d]: buf is null.\n", __FUNCTION__, __LINE__); + return -1; + } + + if (len > WLAN_WPS_IE_MAX_SIZE) { + /* ����·�ie ���ȴ����¼��ڴ��С����ʾ���� */ + wpa_printf(MSG_ERROR, "%s[%d]: assoc rsp ie too large to wifi driver buffer. ie_len %zu, MAX len %d", + __FUNCTION__, __LINE__, len, WLAN_WPS_IE_MAX_SIZE); + return -1; + } + + pbuf = buf; + ret_s = sprintf_s(pbuf, MAX_WPSP2PIE_CMD_SIZE, "%s", _cmd); + if (ret_s == -1) { + wpa_printf(MSG_ERROR, "%s:%d, sprintf failed, ret=%d", __func__, __LINE__, ret_s); + } + pbuf += ret_s; + *pbuf++ = '\0'; + + pst_mlme_ie = (set_mlme_stru *) pbuf; + if (reassoc) { + pst_mlme_ie->en_mlme_type = OAL_IEEE80211_MLME_REASSOC_RSP; + } else { + pst_mlme_ie->en_mlme_type = OAL_IEEE80211_MLME_ASSOC_RSP; + } + pst_mlme_ie->us_status = status; + ret_s = memcpy_s(pst_mlme_ie->uc_macaddr, sizeof(pst_mlme_ie->uc_macaddr), addr, ETH_ALEN); + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); + } + + pst_mlme_ie->us_ie_len = len; + ret_s = memcpy_s(pst_mlme_ie->auc_ie, sizeof(pst_mlme_ie->auc_ie), pst_assoc_rsp_ie, len); + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, memcpy failed, ret=%d", __func__, __LINE__, ret_s); + } + + wpa_printf(MSG_ERROR, "%s[%d]: sta_assoc begin send assoc rsp ie len[%zu] to driver", __FUNCTION__, __LINE__, len); + + wpa_printf(MSG_ERROR, "cmd:%s, type %d, status %d, ie_len %d", + _cmd, + pst_mlme_ie->en_mlme_type, + pst_mlme_ie->us_status, + pst_mlme_ie->us_ie_len); + + wpa_hexdump(MSG_ERROR, "MLME: set sta_assoc ie", (const char *) pbuf, pst_mlme_ie->us_ie_len + 8); + + if (os_strlen(_cmd) + sizeof(set_mlme_stru) + 1 < sizeof(buf)) { + ret = wpa_driver_nl80211_driver_cmd(priv, buf, buf, + os_strlen(_cmd) + sizeof(set_mlme_stru) + 1); + } else { + wpa_printf(MSG_ERROR, "%s:error. app total length to large! cmd_len = %zu, buffer = %d", + __func__, os_strlen(_cmd) + sizeof(set_mlme_stru) + 1, (int)sizeof(buf)); + ret = -1; + } + + return ret; +} +#endif + +#ifdef CONFIG_HW_GET_P2P_SIGNAL_POLL +int wpa_drv_get_p2p_link_noise(void *priv, struct wpa_signal_info *si) +{ + if (priv == NULL || si == NULL) { + return -1; + } + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + os_memset(si, 0, sizeof(struct wpa_signal_info)); + return nl80211_get_link_noise(drv, si); +} +#endif /* CONFIG_HW_GET_P2P_SIGNAL_POLL */ + +static int wpa_sockets_open(void) +{ + int skfd; + + skfd = socket(PF_INET, SOCK_DGRAM, 0); + if (skfd < 0) { + wpa_printf(MSG_ERROR, + "nl80211: socket open failed."); + return -1; + } + return skfd; +} +static void wpa_sockets_close(int32 skfd) +{ + close(skfd); +} +static int wpa_send_cmd_to_driver(int skfd, s8 *ifname, wifi_priv_cmd *ioctl_data) +{ + struct ifreq ifr; + int ret; + int ret_s; + + ret_s = memset_s(&ifr, sizeof(ifr), 0, sizeof(ifr)); + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, memset failed, ret=%d", __func__, __LINE__, ret_s); + } + + ret_s = strncpy_s(ifr.ifr_name, IFNAMSIZ, "wlan0", strlen("wlan0")); + if (ret_s != EOK) { + wpa_printf(MSG_ERROR, "%s:%d, strncpy failed, ret=%d", __func__, __LINE__, ret_s); + } + ifr.ifr_name[IFNAMSIZ - 1] = '\0'; + ifr.ifr_data = (void *) ioctl_data; + + ret = ioctl(skfd, SIOCDEVPRIVATE + 1, &ifr); + + if (ret < 0) { + wpa_printf(MSG_ERROR, + "%s: failed to issue ioctl cmd.\n", __func__); + } + + return ret; +} + +static cust_data_stru global_cust_data = {0, 0}; + +static void get_cust_config_params(void) +{ + int skfd; + wifi_priv_cmd ioctl_data = {0}; + int ret; + int len; +#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK + char buff[MAX_PRIV_CMD_SIZE] = {0}; +#endif /* CONFIG_DRIVER_NL80211_HISI_TRUNK */ + + if (-1 == (skfd = wpa_sockets_open())) { + wpa_printf(MSG_ERROR, + "%s: failed create socket.\n", __func__); + return; + } + +#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK + ioctl_data.buf = buff; + len = snprintf_s(buff, MAX_PRIV_CMD_SIZE, MAX_PRIV_CMD_SIZE - 1, "WPAS_GET_CUST"); +#else + len = snprintf_s(ioctl_data.buf, MAX_PRIV_CMD_SIZE, MAX_PRIV_CMD_SIZE - 1, "WPAS_GET_CUST"); +#endif + if (len == -1) { + wpa_printf(MSG_ERROR, "%s:%d, snprintf failed, ret=%d", __func__, __LINE__, len); + } + ioctl_data.total_len = MAX_PRIV_CMD_SIZE; + ioctl_data.used_len = len; +#ifdef HW_WPA_REDUCE_LOG + wpa_printf(MSG_ERROR, "%s:ioctl_data cmd is %s", __func__, ioctl_data.buf); +#else + wpa_printf(MSG_ERROR, "%s:ioctl_data cmd is %s", __func__, ioctl_data.buf); +#endif + + ret = wpa_send_cmd_to_driver(skfd, (s8 *) "wlan0", &ioctl_data); + + if (ret < 0) { + wpa_printf(MSG_ERROR, + "%s: send cmd to driver failed.\n", __func__); + wpa_sockets_close(skfd); + return; + } + + drv_errors = 0; + + global_cust_data.read = 1; + global_cust_data.disable_capab_2ght40 = (u32) (*ioctl_data.buf); + wpa_printf(MSG_ERROR, + "%s: update wps global cust data: [disable_capab_2ght40:%d]\n", __func__, global_cust_data.disable_capab_2ght40); + + wpa_sockets_close(skfd); +} + +u32 get_cust_disable_capab_2ght40(void) +{ + if (!global_cust_data.read) { + get_cust_config_params(); + } + + return global_cust_data.disable_capab_2ght40; } \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/driver_nl80211_hisi.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/driver_nl80211_hisi.h index f3433f488ab652987f2084e58d8f145a38f41b06..8f15915428917e55d06e26e5ff857a86d81d520e 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/driver_nl80211_hisi.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/driver_nl80211_hisi.h @@ -1,147 +1,147 @@ -/* - * Copyright (c) 2020 Huawei Device Co., Ltd. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#ifndef DRIVER_NL80211_HISI_H -#define DRIVER_NL80211_HISI_H - -#include "includes.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "nl80211_copy.h" - -#include "common.h" -#include "eloop.h" -#include "utils/list.h" -#include "common/ieee802_11_defs.h" -#include "netlink.h" -#include "linux_ioctl.h" -#include "radiotap.h" -#include "radiotap_iter.h" -#include "rfkill.h" -#include "driver.h" - -#ifdef CONFIG_LIBNL20 -/* libnl 2.0 compatibility code */ -#define nl_handle nl_sock -#define nl80211_handle_alloc nl_socket_alloc_cb -#define nl80211_handle_destroy nl_socket_free -#endif /* CONFIG_LIBNL20 */ - -#ifndef IFF_LOWER_UP -#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ -#endif -#ifndef IFF_DORMANT -#define IFF_DORMANT 0x20000 /* driver signals dormant */ -#endif - -#ifndef IF_OPER_DORMANT -#define IF_OPER_DORMANT 5 -#endif -#ifndef IF_OPER_UP -#define IF_OPER_UP 6 -#endif - -#define MAX_QOS_UP_RANGE 8 -#define MAX_DSCP_EXCEPT 21 /* maximum of DSCP Exception fields for QoS Map set */ -#define MAX_PRIV_CMD_SIZE 4096 -#define WLAN_WPS_IE_MAX_SIZE 608 -#define MAX_WPSP2PIE_CMD_SIZE (WLAN_WPS_IE_MAX_SIZE + 8 + 32) /* IE body + IE header + cmd length */ -//#error duankaiyong 512 -typedef unsigned char uint8; -typedef char int8; -typedef short int16; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef int int32; -typedef unsigned long long uint64; - -typedef struct wifi_priv_cmd { -#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK - char *buf; - int total_len; - int used_len; -#else - int total_len; - int used_len; - char buf[MAX_PRIV_CMD_SIZE]; -#endif -} wifi_priv_cmd; - -typedef struct -{ - uint32 ul_ie_len; - uint8 en_app_ie_type; - uint8 auc_rsv[3]; - uint8 auc_ie[WLAN_WPS_IE_MAX_SIZE]; -}oal_app_ie_stru; - -enum SET_MLME_TYPE -{ - OAL_IEEE80211_MLME_AUTH = 0, - OAL_IEEE80211_MLME_ASSOC_RSP = 1, - OAL_IEEE80211_MLME_REASSOC_RSP = 2, - OAL_IEEE80211_MLME_NUM -}; -typedef u8 en_set_mlme_type_uint8; - -typedef struct -{ - en_set_mlme_type_uint8 en_mlme_type; - u8 uc_seq; - u16 us_status; - u8 uc_macaddr[6]; - u16 us_ie_len; - u8 auc_ie[WLAN_WPS_IE_MAX_SIZE]; -}set_mlme_stru; - -/* P2P OPS parameter*/ -typedef struct -{ - uint8 en_ops_ctrl; - uint8 uc_ct_window; - uint8 auc_rsv[2]; -}oal_p2p_ops_param_stru; - -/* P2P NOA parameter */ -typedef struct -{ - uint32 ul_start_time; - uint32 ul_duration; - uint32 ul_interval; - uint8 uc_count; - uint8 auc_rsv[3]; -}oal_p2p_noa_param_stru; - -/* QoS Map SET ELEMENT */ -typedef struct -{ - uint8 valid; - uint8 num_dscp_except; - uint8 up_low[MAX_QOS_UP_RANGE]; - uint8 up_high[MAX_QOS_UP_RANGE]; - uint8 dscp_exception_up[MAX_DSCP_EXCEPT]; - uint8 dscp_exception[MAX_DSCP_EXCEPT]; -}oal_qos_map_param_stru; - - -/* supplicant customized struct. */ -typedef struct cust_data_stru -{ - u32 read; - u32 disable_capab_2ght40; -}cust_data_stru; - -#endif /* DRIVER_NL80211_HISI_H */ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef DRIVER_NL80211_HISI_H +#define DRIVER_NL80211_HISI_H + +#include "includes.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nl80211_copy.h" + +#include "common.h" +#include "eloop.h" +#include "utils/list.h" +#include "common/ieee802_11_defs.h" +#include "netlink.h" +#include "linux_ioctl.h" +#include "radiotap.h" +#include "radiotap_iter.h" +#include "rfkill.h" +#include "driver.h" + +#ifdef CONFIG_LIBNL20 +/* libnl 2.0 compatibility code */ +#define nl_handle nl_sock +#define nl80211_handle_alloc nl_socket_alloc_cb +#define nl80211_handle_destroy nl_socket_free +#endif /* CONFIG_LIBNL20 */ + +#ifndef IFF_LOWER_UP +#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ +#endif +#ifndef IFF_DORMANT +#define IFF_DORMANT 0x20000 /* driver signals dormant */ +#endif + +#ifndef IF_OPER_DORMANT +#define IF_OPER_DORMANT 5 +#endif +#ifndef IF_OPER_UP +#define IF_OPER_UP 6 +#endif + +#define MAX_QOS_UP_RANGE 8 +#define MAX_DSCP_EXCEPT 21 /* maximum of DSCP Exception fields for QoS Map set */ +#define MAX_PRIV_CMD_SIZE 4096 +#define WLAN_WPS_IE_MAX_SIZE 608 +#define MAX_WPSP2PIE_CMD_SIZE (WLAN_WPS_IE_MAX_SIZE + 8 + 32) /* IE body + IE header + cmd length */ +//#error duankaiyong 512 +typedef unsigned char uint8; +typedef char int8; +typedef short int16; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef int int32; +typedef unsigned long long uint64; + +typedef struct wifi_priv_cmd { +#ifdef CONFIG_DRIVER_NL80211_HISI_TRUNK + char *buf; + int total_len; + int used_len; +#else + int total_len; + int used_len; + char buf[MAX_PRIV_CMD_SIZE]; +#endif +} wifi_priv_cmd; + +typedef struct +{ + uint32 ul_ie_len; + uint8 en_app_ie_type; + uint8 auc_rsv[3]; + uint8 auc_ie[WLAN_WPS_IE_MAX_SIZE]; +}oal_app_ie_stru; + +enum SET_MLME_TYPE +{ + OAL_IEEE80211_MLME_AUTH = 0, + OAL_IEEE80211_MLME_ASSOC_RSP = 1, + OAL_IEEE80211_MLME_REASSOC_RSP = 2, + OAL_IEEE80211_MLME_NUM +}; +typedef u8 en_set_mlme_type_uint8; + +typedef struct +{ + en_set_mlme_type_uint8 en_mlme_type; + u8 uc_seq; + u16 us_status; + u8 uc_macaddr[6]; + u16 us_ie_len; + u8 auc_ie[WLAN_WPS_IE_MAX_SIZE]; +}set_mlme_stru; + +/* P2P OPS parameter*/ +typedef struct +{ + uint8 en_ops_ctrl; + uint8 uc_ct_window; + uint8 auc_rsv[2]; +}oal_p2p_ops_param_stru; + +/* P2P NOA parameter */ +typedef struct +{ + uint32 ul_start_time; + uint32 ul_duration; + uint32 ul_interval; + uint8 uc_count; + uint8 auc_rsv[3]; +}oal_p2p_noa_param_stru; + +/* QoS Map SET ELEMENT */ +typedef struct +{ + uint8 valid; + uint8 num_dscp_except; + uint8 up_low[MAX_QOS_UP_RANGE]; + uint8 up_high[MAX_QOS_UP_RANGE]; + uint8 dscp_exception_up[MAX_DSCP_EXCEPT]; + uint8 dscp_exception[MAX_DSCP_EXCEPT]; +}oal_qos_map_param_stru; + + +/* supplicant customized struct. */ +typedef struct cust_data_stru +{ + u32 read; + u32 disable_capab_2ght40; +}cust_data_stru; + +#endif /* DRIVER_NL80211_HISI_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/wpa_magiclink.c b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/wpa_magiclink.c index 9c6b707254ed82c86500a7b069603ce5e07c0ecc..c592020670182745502150012deab2b31b6344c0 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/wpa_magiclink.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/wpa_magiclink.c @@ -1,406 +1,406 @@ -/* - * Copyright (c) 2020 Huawei Device Co., Ltd. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ -#include "wpa_magiclink.h" -#include -#include "includes.h" -#include "common.h" -#include "common/ieee802_11_common.h" -#include "common/ieee802_11_defs.h" -#include "wps/wps_i.h" -#include "eap_peer/eap.h" - -#include "wpa_supplicant_i.h" -#include "p2p_supplicant.h" -#include "bss.h" -#include "ctrl_iface.h" -#include "../wpa_supplicant/config.h" -#include "notify.h" -#include "securec.h" -#ifdef BRCM_VE -#include "wpa.h" -#include "wpa_i.h" -#include "wpa_supplicant_i.h" -#include "driver_i.h" -#endif /* BRCM_VE */ -#ifdef CONFIG_LIBWPA_VENDOR -#include "wpa_client.h" -#endif - -#define MANUFACTURER_LEN 32 -#define MODEL_NAME_LEN 32 -#define MODEL_NUMBER_LEN 16 -#define DEVICE_NAME_LEN 64 - -#define HW_PENDING_EAPOL_EXPIRE_TIME_DEF 500 /* ms */ -/* - * used in wps_vendor_specific_ies(wpa_supplicant/scan.c) - * wps vendor specific ies, - */ -struct wps_vendor_ies { - char manufacturer[MANUFACTURER_LEN]; - char model_name[MODEL_NAME_LEN]; - char model_number[MODEL_NUMBER_LEN]; - char device_name[DEVICE_NAME_LEN]; -}; - -#if defined(CONFIG_MAGICLINK) -/*lint -restore*/ -#ifdef CONFIG_MAGICLINK_PC -static struct wpa_scan_res *hw_magiclink_gen_scan_res(const u8 *bssid, int freqency, int noGc) -{ -#else -static struct wpa_scan_res *hw_magiclink_gen_scan_res(const u8 *bssid, int freqency) -{ -#endif - struct wpa_scan_res* res = NULL; - unsigned char ie_data[] = { - 48, 20, 1, 0, 0, 15, 172, 4, 1, 0, 0, - 15, 172, 4, 1, 0, 0, 15, 172, 2, 12, 0 }; // RSN IE - - res = os_zalloc(sizeof(*res) + sizeof(ie_data) + sizeof(ie_data)); - if (!res) { - wpa_printf(MSG_ERROR, "P2P: Failed to allocate memory for magiclink"); - return NULL; - } - - res->flags = 11; -#ifdef CONFIG_MAGICLINK_PC - if (noGc == 1) { - res->legacyGO = 1; - } else { - res->legacyGO = 0; - } -#endif - os_memcpy(res->bssid, bssid, ETH_ALEN); - - res->freq = freqency; - res->beacon_int = 100; - res->caps = 1297; - res->qual = 0; - res->noise = 0; - res->level = 0; - res->tsf = 0; - res->age = 0; - res->ie_len = sizeof(ie_data); - res->beacon_ie_len = sizeof(ie_data); - os_memcpy(res + 1, ie_data, sizeof(ie_data)); - os_memcpy((char*)(res + 1) + res->ie_len, ie_data, sizeof(ie_data)); - - return res; -} - -static int hw_magiclink_get_ht40_mode(int channel) -{ - for (int op = 0; global_op_class[op].op_class; op++) { - const struct oper_class_map *o = &global_op_class[op]; - u8 ch; - - if (o->mode != HOSTAPD_MODE_IEEE80211A) - continue; - - for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { - if ((o->bw != BW40PLUS && o->bw != BW40MINUS) || - ch != channel) - continue; - return (o->bw == BW40MINUS) ? -1 : 1; - } - } - return 0; -} - -static int hw_magiclink_scan_param(struct wpa_supplicant *wpa_s) -{ - if (wpa_s == NULL) { - wpa_printf(MSG_ERROR, "Parameter error,wpa_s == NULL"); - return -1; - } - - wpa_s->scan_req = MANUAL_SCAN_REQ; - - int pri_chan = 0; - enum hostapd_hw_mode hw_mode = ieee80211_freq_to_chan(wpa_s->magic_link_freq, - (u8 *)&pri_chan); - if (hw_mode == NUM_HOSTAPD_MODES) { - wpa_printf(MSG_ERROR, "frequency(%d MHz) error", wpa_s->magic_link_freq); - return -1; - } - os_free(wpa_s->manual_scan_freqs); - // 3:Number of channels:primary channel,secondary channel,0 - wpa_s->manual_scan_freqs = os_zalloc(3 * sizeof(int)); - if (wpa_s->manual_scan_freqs == NULL) { - wpa_printf(MSG_ERROR, "alloc wpa_s->manual_scan_freqs failed"); - return -1; - } - wpa_s->manual_scan_freqs[0] = wpa_s->magic_link_freq; - if (wpa_s->normal_scans && hw_mode == HOSTAPD_MODE_IEEE80211A) { - int behavior = hw_magiclink_get_ht40_mode(pri_chan); - // 5G channel to freq - int sec_freq = 5000 + (pri_chan + behavior * 4) * 5; - - switch (behavior) { - case -1: - wpa_s->manual_scan_freqs[0] = sec_freq; - wpa_s->manual_scan_freqs[1] = wpa_s->magic_link_freq; - break; - case 1: - wpa_s->manual_scan_freqs[1] = sec_freq; - break; - default: - break; - } - } - wpa_printf(MSG_DEBUG, "%s: freq[0]=%d, freq[1]=%d", __func__, wpa_s->manual_scan_freqs[0], - wpa_s->manual_scan_freqs[1]); - return 0; -} - -void hw_magiclink_scan(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s) { - wpa_msg(wpa_s, MSG_DEBUG, - "magiclink: Start scan for network selection fail"); - return; - } - wpa_s->normal_scans = 0; - hw_magiclink_scan_param(wpa_s); - wpa_supplicant_req_scan(wpa_s, 0, 0); - return; -} - -void magiclink_prepare_scan(struct wpa_supplicant *wpa_s, int *timeout_usec) -{ - if (!wpa_s) { - wpa_printf(MSG_ERROR, "Parameter error"); - return; - } - if (timeout_usec != NULL) { - *timeout_usec = 50000; - } - if (wpa_s->normal_scans > 4) { - return; - } - hw_magiclink_scan_param(wpa_s); -} - -static int hw_magiclink_add_new_scan_res(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int freq, int noGc) -{ -#define DEFAULT_SCAN_RES_SIZE 32 - struct os_reltime fetch_time; - struct wpa_bss *bss = NULL; - struct wpa_scan_res *res = NULL; - struct wpa_bss **n = NULL; - unsigned int siz = DEFAULT_SCAN_RES_SIZE; - -#ifdef CONFIG_MAGICLINK_PC - res = hw_magiclink_gen_scan_res(ssid->bssid, freq, noGc); -#else - res = hw_magiclink_gen_scan_res(ssid->bssid, freq); -#endif - - if (!res) { - wpa_printf(MSG_ERROR, "P2P: Failed to generate scan result"); - return -1; - } - - os_get_reltime(&fetch_time); - bss = hw_magiclink_bss_add(wpa_s, ssid->ssid, ssid->ssid_len, res, &fetch_time); - if (!bss) { - os_free(res); - return -1; - } - - n = os_realloc_array(wpa_s->last_scan_res, siz, sizeof(struct wpa_bss *)); - if (!n) { - os_free(res); - return -1; - } - wpa_s->last_scan_res = n; - wpa_s->last_scan_res_size = siz; - wpa_s->last_scan_res[0] = bss; - wpa_s->last_scan_res_used = 1; - os_free(res); - return 0; -} - -static int hw_magiclink_connect_parse_param(struct wpa_supplicant *wpa_s, const char *cmd, - char **ppsk, char **pbssid, char **pfreq, int *noGc) -{ - char *pos = NULL; - - if (!wpa_s || !cmd || !ppsk || !pbssid || !pfreq || !noGc) { - wpa_printf(MSG_ERROR, "%s param is null", __func__); - return -1; - } - // ssid - pos = os_strstr(cmd, "\n"); - if (!pos) { - return -1; - } - *pos = '\0'; - - // bssid - *pbssid = pos + 1; - pos = os_strstr(pos + 1, "\n"); - if (!pos) { - return -1; - } - *pos = '\0'; - - // password - *ppsk = pos + 1; - pos = os_strstr(pos + 1, "\n"); - if (!pos) { - return -1; - } - *pos = '\0'; - // frequency - *pfreq = pos + 1; - -#ifdef CONFIG_MAGICLINK_PC - // noGc - pos = os_strstr(pos + 1, "\n"); - if (pos != NULL) { - *pos = '\0'; - *noGc = atoi(pos + 1); - wpa_msg(wpa_s, MSG_INFO, "wpa_magiclink noGc is %d", *noGc); - } -#endif - - return 0; -} - -static struct wpa_ssid *hw_magiclink_add_network(struct wpa_supplicant *wpa_s, char *pssid, - const char *pbssid, char *ppsk) -{ - struct wpa_ssid *ssid = wpa_config_add_network(wpa_s->conf); - if (!ssid) { - return NULL; - } - - wpa_config_set_network_defaults(ssid); - hw_magiclink_ctrl_iface_update_network(wpa_s, ssid, "ssid", pssid); - hw_magiclink_ctrl_iface_update_network(wpa_s, ssid, "priority", "0"); - - if (strcmp(ppsk, "\"\"") == 0) { - wpa_printf(MSG_DEBUG, "key_mgmt is NONE"); - hw_magiclink_ctrl_iface_update_network(wpa_s, ssid, "key_mgmt", "NONE"); - } else { - hw_magiclink_ctrl_iface_update_network(wpa_s, ssid, "key_mgmt", "WPA-PSK"); - hw_magiclink_ctrl_iface_update_network(wpa_s, ssid, "psk", ppsk); - } - if (hwaddr_aton(pbssid, ssid->bssid)) { - wpa_printf(MSG_ERROR, "fail to parser bssid"); - return NULL; - } - ssid->bssid_set = 1; - return ssid; -} - -static int hw_magiclink_connect_known_ap(struct wpa_supplicant *wpa_s, char *cmd) -{ - /* cmd: "SSID BSSID PASSWORD FREQUENCY" - "P"DIRECT-xx-xxxx" xx:xx:xx:xx:xx:xx "xxxxxxxx" 2412|2437|2462" - "P\"DIRECT-XA-send\" 5a:7f:66:ae:a1:66 \"d9hHbPv0\" 2412" */ - char *pfreq = NULL; - char *ppsk = NULL; - char *pbssid = NULL; - char *pssid = cmd; - int freq; - int noGc = 0xFF; - - if (hw_magiclink_connect_parse_param(wpa_s, cmd, &ppsk, &pbssid, &pfreq, &noGc)) { - wpa_printf(MSG_DEBUG, "hw_magiclink_connect_parse_param failed"); - return -1; - } - struct wpa_ssid *ssid = hw_magiclink_add_network(wpa_s, pssid, pbssid, ppsk); - if (!ssid) { - wpa_printf(MSG_ERROR, "hw_magiclink_add_network failed"); - return -1; - } - freq = atoi(pfreq); - if (hw_magiclink_add_new_scan_res(wpa_s, ssid, freq, noGc)) { - wpa_printf(MSG_ERROR, "hw_magiclink_add_new_scan_res failed"); - return -1; - } - - struct os_reltime now; - os_get_reltime(&now); - wpa_s->last_scan = now; - wpa_s->magic_link_freq = freq; - hw_magiclink_scan(wpa_s); - wpa_s->disconnected = 0; - wpa_s->reassociate = 1; - ssid->p2p_group = 1; - wpa_s->show_group_started = 1; - return 0; -} - -int hw_magiclink_p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd) -{ - enum wpa_driver_if_type iftype; - char p[256]; - wpa_printf(MSG_ERROR, "hw_magiclink_p2p_ctrl_connect"); - if (!wpa_s || !cmd) { - wpa_printf(MSG_ERROR, "%s:wpa_s or cmd is null", __func__); - return -1; - } - - os_memset(p, 0, sizeof(p)); - wpa_s->create_p2p_iface = hw_magiclink_create_iface(wpa_s); - iftype = WPA_IF_P2P_GROUP; - /* - * reltek chip don not support create p2p interface, use p2p0 - */ -#ifdef CONFIG_SUPPORT_PLATEFORM_REALTEK - struct wpa_supplicant *magiclink_wpa_s = wpa_s; -#else - if (hw_magiclink_add_group_interface(wpa_s, iftype) < 0) { - wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new " - "interface for the group"); - return -1; - } - - struct wpa_supplicant *magiclink_wpa_s = hw_magiclink_init_group_interface(wpa_s, 0); - if (!magiclink_wpa_s) { - wpa_printf(MSG_ERROR, "P2P: Failed to get magiclink interface"); - return -1; - } -#endif - - wpa_msg(wpa_s, MSG_INFO, "P2P-INTERFACE-CREATED GC %s", magiclink_wpa_s->ifname); - os_snprintf(p, sizeof(p), "P2P-INTERFACE-CREATED GC %s", magiclink_wpa_s->ifname); -#ifdef CONFIG_LIBWPA_VENDOR - struct P2pIfaceCreatedParam p2pIfaceCreatedParam = {}; - p2pIfaceCreatedParam.isGo = 0; - wpa_printf(MSG_INFO, "WPA_EVENT_IFACE_CREATED GC %d, ifname %s", - p2pIfaceCreatedParam.isGo, magiclink_wpa_s->ifname); - WpaEventReport(magiclink_wpa_s->ifname, WPA_EVENT_IFACE_CREATED, (void *) &p2pIfaceCreatedParam); -#endif - -#ifdef MTK_SET_MAGIC_LINK_FLAG - magiclink_wpa_s->is_magic_link = 1; -#endif - wpa_s->global->p2p_group_formation = NULL; - return hw_magiclink_connect_known_ap(magiclink_wpa_s, cmd); -} - -int hw_wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int network_id, - int persistent, int freq, int max_band) { - int vht = wpa_s->conf->p2p_go_vht; - int ht40 = wpa_s->conf->p2p_go_ht40 || vht; - struct wpa_ssid *ssid = wpa_config_get_network(wpa_s->conf, network_id); - if (ssid == NULL) { - return wpas_p2p_group_add(wpa_s, persistent, freq, 0, ht40, vht, max_band, - 0, 0, false); - } else if (ssid->disabled == 2) { - return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, ht40, vht, - max_band, 0, 0, NULL, 0, 0, false); - } - return -1; -} -#endif - +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#include "wpa_magiclink.h" +#include +#include "includes.h" +#include "common.h" +#include "common/ieee802_11_common.h" +#include "common/ieee802_11_defs.h" +#include "wps/wps_i.h" +#include "eap_peer/eap.h" + +#include "wpa_supplicant_i.h" +#include "p2p_supplicant.h" +#include "bss.h" +#include "ctrl_iface.h" +#include "../wpa_supplicant/config.h" +#include "notify.h" +#include "securec.h" +#ifdef BRCM_VE +#include "wpa.h" +#include "wpa_i.h" +#include "wpa_supplicant_i.h" +#include "driver_i.h" +#endif /* BRCM_VE */ +#ifdef CONFIG_LIBWPA_VENDOR +#include "wpa_client.h" +#endif + +#define MANUFACTURER_LEN 32 +#define MODEL_NAME_LEN 32 +#define MODEL_NUMBER_LEN 16 +#define DEVICE_NAME_LEN 64 + +#define HW_PENDING_EAPOL_EXPIRE_TIME_DEF 500 /* ms */ +/* + * used in wps_vendor_specific_ies(wpa_supplicant/scan.c) + * wps vendor specific ies, + */ +struct wps_vendor_ies { + char manufacturer[MANUFACTURER_LEN]; + char model_name[MODEL_NAME_LEN]; + char model_number[MODEL_NUMBER_LEN]; + char device_name[DEVICE_NAME_LEN]; +}; + +#if defined(CONFIG_MAGICLINK) +/*lint -restore*/ +#ifdef CONFIG_MAGICLINK_PC +static struct wpa_scan_res *hw_magiclink_gen_scan_res(const u8 *bssid, int freqency, int noGc) +{ +#else +static struct wpa_scan_res *hw_magiclink_gen_scan_res(const u8 *bssid, int freqency) +{ +#endif + struct wpa_scan_res* res = NULL; + unsigned char ie_data[] = { + 48, 20, 1, 0, 0, 15, 172, 4, 1, 0, 0, + 15, 172, 4, 1, 0, 0, 15, 172, 2, 12, 0 }; // RSN IE + + res = os_zalloc(sizeof(*res) + sizeof(ie_data) + sizeof(ie_data)); + if (!res) { + wpa_printf(MSG_ERROR, "P2P: Failed to allocate memory for magiclink"); + return NULL; + } + + res->flags = 11; +#ifdef CONFIG_MAGICLINK_PC + if (noGc == 1) { + res->legacyGO = 1; + } else { + res->legacyGO = 0; + } +#endif + os_memcpy(res->bssid, bssid, ETH_ALEN); + + res->freq = freqency; + res->beacon_int = 100; + res->caps = 1297; + res->qual = 0; + res->noise = 0; + res->level = 0; + res->tsf = 0; + res->age = 0; + res->ie_len = sizeof(ie_data); + res->beacon_ie_len = sizeof(ie_data); + os_memcpy(res + 1, ie_data, sizeof(ie_data)); + os_memcpy((char*)(res + 1) + res->ie_len, ie_data, sizeof(ie_data)); + + return res; +} + +static int hw_magiclink_get_ht40_mode(int channel) +{ + for (int op = 0; global_op_class[op].op_class; op++) { + const struct oper_class_map *o = &global_op_class[op]; + u8 ch; + + if (o->mode != HOSTAPD_MODE_IEEE80211A) + continue; + + for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { + if ((o->bw != BW40PLUS && o->bw != BW40MINUS) || + ch != channel) + continue; + return (o->bw == BW40MINUS) ? -1 : 1; + } + } + return 0; +} + +static int hw_magiclink_scan_param(struct wpa_supplicant *wpa_s) +{ + if (wpa_s == NULL) { + wpa_printf(MSG_ERROR, "Parameter error,wpa_s == NULL"); + return -1; + } + + wpa_s->scan_req = MANUAL_SCAN_REQ; + + int pri_chan = 0; + enum hostapd_hw_mode hw_mode = ieee80211_freq_to_chan(wpa_s->magic_link_freq, + (u8 *)&pri_chan); + if (hw_mode == NUM_HOSTAPD_MODES) { + wpa_printf(MSG_ERROR, "frequency(%d MHz) error", wpa_s->magic_link_freq); + return -1; + } + os_free(wpa_s->manual_scan_freqs); + // 3:Number of channels:primary channel,secondary channel,0 + wpa_s->manual_scan_freqs = os_zalloc(3 * sizeof(int)); + if (wpa_s->manual_scan_freqs == NULL) { + wpa_printf(MSG_ERROR, "alloc wpa_s->manual_scan_freqs failed"); + return -1; + } + wpa_s->manual_scan_freqs[0] = wpa_s->magic_link_freq; + if (wpa_s->normal_scans && hw_mode == HOSTAPD_MODE_IEEE80211A) { + int behavior = hw_magiclink_get_ht40_mode(pri_chan); + // 5G channel to freq + int sec_freq = 5000 + (pri_chan + behavior * 4) * 5; + + switch (behavior) { + case -1: + wpa_s->manual_scan_freqs[0] = sec_freq; + wpa_s->manual_scan_freqs[1] = wpa_s->magic_link_freq; + break; + case 1: + wpa_s->manual_scan_freqs[1] = sec_freq; + break; + default: + break; + } + } + wpa_printf(MSG_DEBUG, "%s: freq[0]=%d, freq[1]=%d", __func__, wpa_s->manual_scan_freqs[0], + wpa_s->manual_scan_freqs[1]); + return 0; +} + +void hw_magiclink_scan(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s) { + wpa_msg(wpa_s, MSG_DEBUG, + "magiclink: Start scan for network selection fail"); + return; + } + wpa_s->normal_scans = 0; + hw_magiclink_scan_param(wpa_s); + wpa_supplicant_req_scan(wpa_s, 0, 0); + return; +} + +void magiclink_prepare_scan(struct wpa_supplicant *wpa_s, int *timeout_usec) +{ + if (!wpa_s) { + wpa_printf(MSG_ERROR, "Parameter error"); + return; + } + if (timeout_usec != NULL) { + *timeout_usec = 50000; + } + if (wpa_s->normal_scans > 4) { + return; + } + hw_magiclink_scan_param(wpa_s); +} + +static int hw_magiclink_add_new_scan_res(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, int freq, int noGc) +{ +#define DEFAULT_SCAN_RES_SIZE 32 + struct os_reltime fetch_time; + struct wpa_bss *bss = NULL; + struct wpa_scan_res *res = NULL; + struct wpa_bss **n = NULL; + unsigned int siz = DEFAULT_SCAN_RES_SIZE; + +#ifdef CONFIG_MAGICLINK_PC + res = hw_magiclink_gen_scan_res(ssid->bssid, freq, noGc); +#else + res = hw_magiclink_gen_scan_res(ssid->bssid, freq); +#endif + + if (!res) { + wpa_printf(MSG_ERROR, "P2P: Failed to generate scan result"); + return -1; + } + + os_get_reltime(&fetch_time); + bss = hw_magiclink_bss_add(wpa_s, ssid->ssid, ssid->ssid_len, res, &fetch_time); + if (!bss) { + os_free(res); + return -1; + } + + n = os_realloc_array(wpa_s->last_scan_res, siz, sizeof(struct wpa_bss *)); + if (!n) { + os_free(res); + return -1; + } + wpa_s->last_scan_res = n; + wpa_s->last_scan_res_size = siz; + wpa_s->last_scan_res[0] = bss; + wpa_s->last_scan_res_used = 1; + os_free(res); + return 0; +} + +static int hw_magiclink_connect_parse_param(struct wpa_supplicant *wpa_s, const char *cmd, + char **ppsk, char **pbssid, char **pfreq, int *noGc) +{ + char *pos = NULL; + + if (!wpa_s || !cmd || !ppsk || !pbssid || !pfreq || !noGc) { + wpa_printf(MSG_ERROR, "%s param is null", __func__); + return -1; + } + // ssid + pos = os_strstr(cmd, "\n"); + if (!pos) { + return -1; + } + *pos = '\0'; + + // bssid + *pbssid = pos + 1; + pos = os_strstr(pos + 1, "\n"); + if (!pos) { + return -1; + } + *pos = '\0'; + + // password + *ppsk = pos + 1; + pos = os_strstr(pos + 1, "\n"); + if (!pos) { + return -1; + } + *pos = '\0'; + // frequency + *pfreq = pos + 1; + +#ifdef CONFIG_MAGICLINK_PC + // noGc + pos = os_strstr(pos + 1, "\n"); + if (pos != NULL) { + *pos = '\0'; + *noGc = atoi(pos + 1); + wpa_msg(wpa_s, MSG_INFO, "wpa_magiclink noGc is %d", *noGc); + } +#endif + + return 0; +} + +static struct wpa_ssid *hw_magiclink_add_network(struct wpa_supplicant *wpa_s, char *pssid, + const char *pbssid, char *ppsk) +{ + struct wpa_ssid *ssid = wpa_config_add_network(wpa_s->conf); + if (!ssid) { + return NULL; + } + + wpa_config_set_network_defaults(ssid); + hw_magiclink_ctrl_iface_update_network(wpa_s, ssid, "ssid", pssid); + hw_magiclink_ctrl_iface_update_network(wpa_s, ssid, "priority", "0"); + + if (strcmp(ppsk, "\"\"") == 0) { + wpa_printf(MSG_DEBUG, "key_mgmt is NONE"); + hw_magiclink_ctrl_iface_update_network(wpa_s, ssid, "key_mgmt", "NONE"); + } else { + hw_magiclink_ctrl_iface_update_network(wpa_s, ssid, "key_mgmt", "WPA-PSK"); + hw_magiclink_ctrl_iface_update_network(wpa_s, ssid, "psk", ppsk); + } + if (hwaddr_aton(pbssid, ssid->bssid)) { + wpa_printf(MSG_ERROR, "fail to parser bssid"); + return NULL; + } + ssid->bssid_set = 1; + return ssid; +} + +static int hw_magiclink_connect_known_ap(struct wpa_supplicant *wpa_s, char *cmd) +{ + /* cmd: "SSID BSSID PASSWORD FREQUENCY" + "P"DIRECT-xx-xxxx" xx:xx:xx:xx:xx:xx "xxxxxxxx" 2412|2437|2462" + "P\"DIRECT-XA-send\" 5a:7f:66:ae:a1:66 \"d9hHbPv0\" 2412" */ + char *pfreq = NULL; + char *ppsk = NULL; + char *pbssid = NULL; + char *pssid = cmd; + int freq; + int noGc = 0xFF; + + if (hw_magiclink_connect_parse_param(wpa_s, cmd, &ppsk, &pbssid, &pfreq, &noGc)) { + wpa_printf(MSG_DEBUG, "hw_magiclink_connect_parse_param failed"); + return -1; + } + struct wpa_ssid *ssid = hw_magiclink_add_network(wpa_s, pssid, pbssid, ppsk); + if (!ssid) { + wpa_printf(MSG_ERROR, "hw_magiclink_add_network failed"); + return -1; + } + freq = atoi(pfreq); + if (hw_magiclink_add_new_scan_res(wpa_s, ssid, freq, noGc)) { + wpa_printf(MSG_ERROR, "hw_magiclink_add_new_scan_res failed"); + return -1; + } + + struct os_reltime now; + os_get_reltime(&now); + wpa_s->last_scan = now; + wpa_s->magic_link_freq = freq; + hw_magiclink_scan(wpa_s); + wpa_s->disconnected = 0; + wpa_s->reassociate = 1; + ssid->p2p_group = 1; + wpa_s->show_group_started = 1; + return 0; +} + +int hw_magiclink_p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd) +{ + enum wpa_driver_if_type iftype; + char p[256]; + wpa_printf(MSG_ERROR, "hw_magiclink_p2p_ctrl_connect"); + if (!wpa_s || !cmd) { + wpa_printf(MSG_ERROR, "%s:wpa_s or cmd is null", __func__); + return -1; + } + + os_memset(p, 0, sizeof(p)); + wpa_s->create_p2p_iface = hw_magiclink_create_iface(wpa_s); + iftype = WPA_IF_P2P_GROUP; + /* + * reltek chip don not support create p2p interface, use p2p0 + */ +#ifdef CONFIG_SUPPORT_PLATEFORM_REALTEK + struct wpa_supplicant *magiclink_wpa_s = wpa_s; +#else + if (hw_magiclink_add_group_interface(wpa_s, iftype) < 0) { + wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new " + "interface for the group"); + return -1; + } + + struct wpa_supplicant *magiclink_wpa_s = hw_magiclink_init_group_interface(wpa_s, 0); + if (!magiclink_wpa_s) { + wpa_printf(MSG_ERROR, "P2P: Failed to get magiclink interface"); + return -1; + } +#endif + + wpa_msg(wpa_s, MSG_INFO, "P2P-INTERFACE-CREATED GC %s", magiclink_wpa_s->ifname); + os_snprintf(p, sizeof(p), "P2P-INTERFACE-CREATED GC %s", magiclink_wpa_s->ifname); +#ifdef CONFIG_LIBWPA_VENDOR + struct P2pIfaceCreatedParam p2pIfaceCreatedParam = {}; + p2pIfaceCreatedParam.isGo = 0; + wpa_printf(MSG_INFO, "WPA_EVENT_IFACE_CREATED GC %d, ifname %s", + p2pIfaceCreatedParam.isGo, magiclink_wpa_s->ifname); + WpaEventReport(magiclink_wpa_s->ifname, WPA_EVENT_IFACE_CREATED, (void *) &p2pIfaceCreatedParam); +#endif + +#ifdef MTK_SET_MAGIC_LINK_FLAG + magiclink_wpa_s->is_magic_link = 1; +#endif + wpa_s->global->p2p_group_formation = NULL; + return hw_magiclink_connect_known_ap(magiclink_wpa_s, cmd); +} + +int hw_wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int network_id, + int persistent, int freq, int max_band) { + int vht = wpa_s->conf->p2p_go_vht; + int ht40 = wpa_s->conf->p2p_go_ht40 || vht; + struct wpa_ssid *ssid = wpa_config_get_network(wpa_s->conf, network_id); + if (ssid == NULL) { + return wpas_p2p_group_add(wpa_s, persistent, freq, 0, ht40, vht, max_band, + 0, 0, false); + } else if (ssid->disabled == 2) { + return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, ht40, vht, + max_band, 0, 0, NULL, 0, 0, false, 0, NULL); + } + return -1; +} +#endif + diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/wpa_magiclink.h b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/wpa_magiclink.h index b2bf8b076fd69b948ab4350ba7e3a625224ff62e..e0146ab277bca4d2ab4fd9e4c462d13d4d16db75 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant_lib/wpa_magiclink.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant_lib/wpa_magiclink.h @@ -1,37 +1,37 @@ -/* - * Copyright (c) 2020 Huawei Device Co., Ltd. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ -#ifndef _WPA_MAGICLINK_H -#define _WPA_MAGICLINK_H - -#include "includes.h" -#include "common.h" -#include "utils/list.h" -#include "wpa_supplicant_i.h" -#include "bss.h" -#include "drivers/driver.h" -#include "driver_i.h" -#include "scan.h" -#include "eap_peer/eap_i.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef CONFIG_MAGICLINK -/* - * hw_magiclink_p2p_ctrl_connect is for magic link connect - * connect AP with cmd indicated. - */ -int hw_magiclink_p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd); -void magiclink_prepare_scan(struct wpa_supplicant *wpas, int *timeout_usec); -int hw_wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int network_id, int persistent, int freq, int max_oper_chwidth); -#endif /* CONFIG_MAGICLINK */ - -#ifdef __cplusplus -} -#endif -#endif /* _WPA_MAGICLINK_H */ +/* + * Copyright (c) 2020 Huawei Device Co., Ltd. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ +#ifndef _WPA_MAGICLINK_H +#define _WPA_MAGICLINK_H + +#include "includes.h" +#include "common.h" +#include "utils/list.h" +#include "wpa_supplicant_i.h" +#include "bss.h" +#include "drivers/driver.h" +#include "driver_i.h" +#include "scan.h" +#include "eap_peer/eap_i.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_MAGICLINK +/* + * hw_magiclink_p2p_ctrl_connect is for magic link connect + * connect AP with cmd indicated. + */ +int hw_magiclink_p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd); +void magiclink_prepare_scan(struct wpa_supplicant *wpas, int *timeout_usec); +int hw_wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int network_id, int persistent, int freq, int max_oper_chwidth); +#endif /* CONFIG_MAGICLINK */ + +#ifdef __cplusplus +} +#endif +#endif /* _WPA_MAGICLINK_H */ diff --git a/wpa_supplicant-2.9_standard/wpa_vendor_ext.gni b/wpa_supplicant-2.9_standard/wpa_vendor_ext.gni index 72ed9364c8771a18cc4e0d7b3b5d88e507834dd4..fdaa2edeb10b0920da4820949cae9118e2d675be 100644 --- a/wpa_supplicant-2.9_standard/wpa_vendor_ext.gni +++ b/wpa_supplicant-2.9_standard/wpa_vendor_ext.gni @@ -33,8 +33,8 @@ if (wpa_supplicant_vendor_ext && wpa_vendor_gni != "") { "-DCONFIG_P2P_CHR", "-DCONFIG_P2P_OPT", "-DCONFIG_MIRACAST_SOURCE_OPT", - "-DDFR_HANDLER", "-DHARMONY_CONNECTIVITY_PATCH", + "-DDFR_HANDLER", "-DHARMONY_P2P_CONNECTIVITY_PATCH", "-DOPEN_HARMONY_P2P_ONEHOP_FIND", ]