Merge tag 'android-15.0.0_r32' of https://android.googlesource.com/platform/external/wpa_supplicant_8 into HEAD
Android 15.0.0 Release 32 (BP1A.250505.005)
Change-Id: I1023752cdc6908365b54743f1e1e00355b624d96
# -----BEGIN PGP SIGNATURE-----
#
# iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCaBqG7gAKCRDorT+BmrEO
# eNpOAKCGlOyzS+ABi/Kb4G2+Co4PhRgEmgCfbuW+6b4X3jbANjHcBuiTZGwTAMw=
# =lde7
# -----END PGP SIGNATURE-----
# gpg: Signature faite le mar 06 mai 2025 18:02:22 EDT
# gpg: avec la clef DSA 4340D13570EF945E83810964E8AD3F819AB10E78
# gpg: Impossible de vérifier la signature : Pas de clef publique
diff --git a/Android.bp b/Android.bp
index 068630b..a083f89 100644
--- a/Android.bp
+++ b/Android.bp
@@ -64,3 +64,40 @@
"src/wps/http_server.c",
],
}
+
+filegroup {
+ name: "wpa_supplicant_macsec_extra_driver_srcs",
+ srcs: [
+ "src/drivers/driver_macsec_linux.c",
+ "src/drivers/driver_wired_common.c",
+ ],
+}
+
+filegroup {
+ name: "hs20_client_srcs",
+ srcs: [
+ "hs20/client/est.c",
+ "hs20/client/oma_dm_client.c",
+ "hs20/client/osu_client.c",
+ "hs20/client/spp_client.c",
+ "src/common/wpa_ctrl.c",
+ "src/common/wpa_helpers.c",
+ "src/crypto/crypto_internal.c",
+ "src/crypto/md5-internal.c",
+ "src/crypto/sha1-internal.c",
+ "src/crypto/sha256-internal.c",
+ "src/crypto/tls_openssl_ocsp.c",
+ "src/utils/base64.c",
+ "src/utils/browser-wpadebug.c",
+ "src/utils/common.c",
+ "src/utils/eloop.c",
+ "src/utils/http_curl.c",
+ "src/utils/os_unix.c",
+ "src/utils/wpa_debug.c",
+ "src/utils/wpabuf.c",
+ "src/utils/xml-utils.c",
+ "src/utils/xml_libxml2.c",
+ "src/wps/http_server.c",
+ "src/wps/httpread.c",
+ ],
+}
diff --git a/Android.mk b/Android.mk
index bb8326c..ca7a620 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,5 +1,6 @@
S_LOCAL_PATH := $(call my-dir)
+ifdef FORCE_USE_ANDROIDMK_FOR_WPA
ifneq ($(filter VER_0_8_X VER_2_1_DEVEL,$(WPA_SUPPLICANT_VERSION)),)
# The order of the 2 Android.mks does matter!
# TODO: Clean up the Android.mks, reset all the temporary variables at the
@@ -13,3 +14,4 @@
endif #End of Check for platform version
endif #End of Check for target build variant
endif
+endif
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..321bab6
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,2 @@
+[Builtin Hooks]
+bpfmt = true
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..e9ea3dd
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "libhostapd_aidl_bp_unittest"
+ }
+ ]
+}
diff --git a/hostapd/Android.bp b/hostapd/Android.bp
index 8b79dd5..4f76a30 100644
--- a/hostapd/Android.bp
+++ b/hostapd/Android.bp
@@ -355,3 +355,352 @@
"src/utils/wpa_debug.c",
],
}
+
+prebuilt_etc {
+ name: "android.hardware.wifi.hostapd.xml.prebuilt",
+ src: "android.hardware.wifi.hostapd.xml",
+ relative_install_path: "vintf",
+ installable: false,
+}
+
+// For converting the default to soong
+cc_defaults {
+ name: "hostapd_driver_srcs_default",
+ srcs: [
+ "src/drivers/driver_nl80211.c",
+ "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/linux_ioctl.c",
+ "src/drivers/netlink.c",
+ "src/drivers/rfkill.c",
+ "src/utils/radiotap.c",
+ ],
+}
+
+cc_defaults {
+ name: "hostapd_driver_cflags_default",
+ cflags: [
+ "-DCONFIG_DRIVER_NL80211",
+ ] + select(soong_config_variable("wpa_supplicant_8", "board_wlan_device"), {
+ "bcmdhd": ["-DCONFIG_DRIVER_NL80211_BRCM"],
+ "synadhd": ["-DCONFIG_DRIVER_NL80211_SYNA"],
+ default: ["-DCONFIG_DRIVER_NL80211_QCA"],
+ }),
+}
+
+soong_config_module_type {
+ name: "hostapd_cc_defaults_type",
+ module_type: "cc_defaults",
+ config_namespace: "wpa_supplicant_8",
+ value_variables: [
+ "platform_version",
+ ],
+ properties: ["cflags"],
+}
+
+// Hostap related module share the same CFLAGS
+hostapd_cc_defaults_type {
+ name: "hostapd_cflags_default",
+ cflags: [
+ "-DWPA_IGNORE_CONFIG_ERRORS",
+ "-DANDROID_LOG_NAME=\"hostapd\"",
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wno-unused-variable",
+ "-Wno-macro-redefined",
+ "-DANDROID_P2P",
+ "-DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/vendor/wifi/hostapd/sockets\"",
+ "-DCONFIG_CTRL_IFACE_DIR=\"/data/vendor/wifi/hostapd/ctrl\"",
+ "-DCONFIG_HOSTAPD_CLI_HISTORY_DIR=\"/data/vendor/wifi/hostapd\"",
+ "-DHOSTAPD",
+ "-DHOSTAPD_DUMP_STATE",
+ "-DCONFIG_NO_RADIUS",
+ "-DCONFIG_NO_ACCOUNTING",
+ "-DCONFIG_CTRL_IFACE",
+ "-DCONFIG_CTRL_IFACE_UNIX",
+ "-DCONFIG_SAE",
+ "-DCONFIG_IEEE80211AC",
+ "-DCONFIG_WEP",
+ "-DCONFIG_WPS",
+ "-DEAP_SERVER_WSC",
+ "-DCONFIG_DPP",
+ "-DEAP_SERVER_IDENTITY",
+ "-DEAP_SERVER",
+ "-DPKCS12_FUNCS",
+ "-DCRYPTO_RSA_OAEP_SHA256",
+ "-DTLS_DEFAULT_CIPHERS=\"DEFAULT:!EXP:!LOW\"",
+ "-DCONFIG_SHA256",
+ "-DCONFIG_SHA384",
+ "-DCONFIG_SHA512",
+ "-DCONFIG_ECC",
+ "-DCONFIG_NO_RANDOM_POOL",
+ "-DCONFIG_IPV6",
+ "-DCONFIG_JSON",
+ "-DNEED_AP_MLME",
+ "-DCONFIG_INTERWORKING",
+ "-DCONFIG_ACS",
+ "-DCONFIG_ANDROID_LOG",
+ "-DCONFIG_CTRL_IFACE_AIDL",
+ ] + select(soong_config_variable("wpa_supplicant_8", "hostapd_use_stub_lib"), {
+ true: ["-DANDROID_LIB_STUB"],
+ default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "hostapd_11ax"), {
+ true: ["-DCONFIG_IEEE80211AX"],
+ default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "board_hostapd_config_80211w_mfp_optional"), {
+ true: ["-DENABLE_HOSTAPD_CONFIG_80211W_MFP_OPTIONAL"],
+ default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "board_hostapd_private_lib_event"), {
+ true: ["-DANDROID_LIB_EVENT"],
+ default: [],
+ }),
+ arch: {
+ arm: {
+ cflags: [
+ "-mabi=aapcs-linux",
+ ],
+ },
+ },
+ defaults: [
+ "hostapd_driver_cflags_default",
+ ],
+ soong_config_variables: {
+ platform_version: {
+ cflags: ["-DVERSION_STR_POSTFIX=\"-%s\""],
+ },
+ },
+ enabled: select(soong_config_variable("wpa_supplicant_8", "wpa_build_hostapd"), {
+ true: true,
+ default: false,
+ }),
+}
+
+cc_defaults {
+ name: "hostapd_includes_default",
+ local_include_dirs: [
+ ".",
+ "src",
+ "src/utils",
+ ],
+ include_dirs: [
+ // There's an if condition for external/libnl but current code base should always have this.
+ "external/libnl/include",
+ "system/security/keystore/include",
+ ],
+}
+
+cc_defaults {
+ name: "hostapd_srcs_default",
+ srcs: [
+ "main.c",
+ "config_file.c",
+ "src/ap/hostapd.c",
+ "src/ap/wpa_auth_glue.c",
+ "src/ap/drv_callbacks.c",
+ "src/ap/ap_drv_ops.c",
+ "src/ap/utils.c",
+ "src/ap/authsrv.c",
+ "src/ap/ieee802_1x.c",
+ "src/ap/ap_config.c",
+ "src/ap/eap_user_db.c",
+ "src/ap/ieee802_11_auth.c",
+ "src/ap/sta_info.c",
+ "src/ap/wpa_auth.c",
+ "src/ap/tkip_countermeasures.c",
+ "src/ap/ap_mlme.c",
+ "src/ap/wpa_auth_ie.c",
+ "src/ap/preauth_auth.c",
+ "src/ap/pmksa_cache_auth.c",
+ "src/ap/ieee802_11_shared.c",
+ "src/ap/beacon.c",
+ "src/ap/bss_load.c",
+ "src/ap/neighbor_db.c",
+ "src/ap/rrm.c",
+ "src/drivers/drivers.c",
+ "src/utils/eloop.c",
+ "src/utils/common.c",
+ "src/utils/wpa_debug.c",
+ "src/utils/wpabuf.c",
+ "src/utils/os_unix.c",
+ "src/utils/ip_addr.c",
+ "src/utils/crc32.c",
+ "src/common/ieee802_11_common.c",
+ "src/common/wpa_common.c",
+ "src/common/hw_features_common.c",
+ "src/common/ptksa_cache.c",
+ "src/eapol_auth/eapol_auth_sm.c",
+ "src/eapol_auth/eapol_auth_dump.c",
+ "src/ap/vlan_init.c",
+ "src/ap/vlan_ifconfig.c",
+ "src/ap/vlan.c",
+ "src/common/ctrl_iface_common.c",
+ "ctrl_iface.c",
+ "src/ap/ctrl_iface_ap.c",
+ "src/common/sae.c",
+ "src/l2_packet/l2_packet_none.c",
+ "src/utils/uuid.c",
+ "src/ap/wps_hostapd.c",
+ "src/eap_server/eap_server_wsc.c",
+ "src/eap_common/eap_wsc_common.c",
+ "src/wps/wps.c",
+ "src/wps/wps_common.c",
+ "src/wps/wps_attr_parse.c",
+ "src/wps/wps_attr_build.c",
+ "src/wps/wps_attr_process.c",
+ "src/wps/wps_dev_attr.c",
+ "src/wps/wps_enrollee.c",
+ "src/wps/wps_registrar.c",
+ "src/common/dpp.c",
+ "src/common/dpp_auth.c",
+ "src/common/dpp_backup.c",
+ "src/common/dpp_crypto.c",
+ "src/common/dpp_pkex.c",
+ "src/common/dpp_reconfig.c",
+ "src/common/dpp_tcp.c",
+ "src/ap/dpp_hostapd.c",
+ "src/ap/gas_query_ap.c",
+ "eap_register.c",
+ "src/eap_server/eap_server.c",
+ "src/eap_common/eap_common.c",
+ "src/eap_server/eap_server_methods.c",
+ "src/eap_server/eap_server_identity.c",
+ "src/common/dragonfly.c",
+ "src/crypto/crypto_openssl.c",
+ "src/crypto/tls_none.c",
+ "src/crypto/aes-siv.c",
+ "src/crypto/aes-ctr.c",
+ "src/crypto/sha1-prf.c",
+ "src/crypto/sha256-prf.c",
+ "src/crypto/sha256-tlsprf.c",
+ "src/crypto/sha256-kdf.c",
+ "src/crypto/sha384-kdf.c",
+ "src/crypto/sha512-kdf.c",
+ "src/crypto/sha384-prf.c",
+ "src/crypto/sha512-prf.c",
+ "src/tls/asn1.c",
+ "src/crypto/dh_groups.c",
+ "src/utils/base64.c",
+ "src/utils/json.c",
+ "src/ap/wmm.c",
+ "src/ap/ap_list.c",
+ "src/ap/comeback_token.c",
+ "src/pasn/pasn_common.c",
+ "src/pasn/pasn_responder.c",
+ "src/ap/ieee802_11.c",
+ "src/ap/hw_features.c",
+ "src/ap/dfs.c",
+ "src/ap/ieee802_11_ht.c",
+ "src/ap/ieee802_11_vht.c",
+ "src/common/gas.c",
+ "src/ap/gas_serv.c",
+ "src/drivers/driver_common.c",
+ "src/ap/acs.c",
+ ] + select(soong_config_variable("wpa_supplicant_8", "hostapd_11ax"), {
+ true: ["src/ap/ieee802_11_he.c"],
+ default: [],
+ }),
+ defaults: [
+ "hostapd_driver_srcs_default",
+ ],
+}
+
+cc_binary {
+ name: "hostapd_cli",
+ proprietary: true,
+ srcs: [
+ "hostapd_cli.c",
+ "src/common/cli.c",
+ "src/common/wpa_ctrl.c",
+ "src/utils/common.c",
+ "src/utils/edit.c",
+ "src/utils/eloop.c",
+ "src/utils/os_unix.c",
+ "src/utils/wpa_debug.c",
+ ],
+ shared_libs: [
+ "libc",
+ "libcutils",
+ "liblog",
+ ],
+ defaults: [
+ "hostapd_cflags_default",
+ "hostapd_includes_default",
+ ],
+}
+
+soong_config_module_type {
+ name: "hostapd_cc_binary",
+ module_type: "cc_binary",
+ config_namespace: "wpa_supplicant_8",
+ value_variables: [
+ "board_hostapd_private_lib",
+ ],
+ properties: ["static_libs"],
+}
+
+hostapd_cc_binary {
+ name: "hostapd",
+ proprietary: true,
+ relative_install_path: "hw",
+ //vintf_fragments: ["android.hardware.wifi.hostapd.xml"],
+ required: [
+ "android.hardware.wifi.hostapd.xml",
+ ],
+ static_libs: [
+ "libhostapd_aidl",
+ ],
+ shared_libs: [
+ "libc",
+ "libcutils",
+ "liblog",
+ "libcrypto",
+ "libssl",
+ "libnl",
+ "android.hardware.wifi.hostapd-V3-ndk",
+ "android.hardware.wifi.common-V2-ndk",
+ "libbase",
+ "libutils",
+ "libbinder_ndk",
+ ],
+ init_rc: ["hostapd.android.rc"],
+ defaults: [
+ "hostapd_srcs_default",
+ "hostapd_cflags_default",
+ "hostapd_includes_default",
+ ],
+ soong_config_variables: {
+ board_hostapd_private_lib: {
+ static_libs: ["%s"],
+ },
+ },
+}
+
+cc_library_static {
+ name: "libhostapd_aidl",
+ soc_specific: true,
+ srcs: [
+ "aidl/aidl.cpp",
+ "aidl/hostapd.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.wifi.hostapd-V3-ndk",
+ "android.hardware.wifi.common-V2-ndk",
+ "libbinder_ndk",
+ "libbase",
+ "libutils",
+ "liblog",
+ ],
+ export_include_dirs: ["aidl"],
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ defaults: [
+ "hostapd_cflags_default",
+ "hostapd_includes_default",
+ ],
+}
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index d5d1190..680c572 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -1209,7 +1209,7 @@
endif
ifeq ($(HOSTAPD_USE_AIDL), y)
LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd-V3-ndk
-LOCAL_SHARED_LIBRARIES += android.hardware.wifi.common-V1-ndk
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.common-V2-ndk
LOCAL_SHARED_LIBRARIES += libbase libutils
LOCAL_SHARED_LIBRARIES += libbinder_ndk
LOCAL_STATIC_LIBRARIES += libhostapd_aidl
@@ -1264,7 +1264,7 @@
aidl/hostapd.cpp
LOCAL_SHARED_LIBRARIES := \
android.hardware.wifi.hostapd-V3-ndk \
- android.hardware.wifi.common-V1-ndk \
+ android.hardware.wifi.common-V2-ndk \
libbinder_ndk \
libbase \
libutils \
diff --git a/hostapd/aidl/hostapd.cpp b/hostapd/aidl/hostapd.cpp
index afb4147..12d0d9e 100644
--- a/hostapd/aidl/hostapd.cpp
+++ b/hostapd/aidl/hostapd.cpp
@@ -35,6 +35,11 @@
#include "drivers/linux_ioctl.h"
}
+
+#ifdef ANDROID_HOSTAPD_UNITTEST
+#include "tests/unittest_overrides.h"
+#endif
+
// The AIDL implementation for hostapd creates a hostapd.conf dynamically for
// each interface. This file can then be used to hook onto the normal config
// file parsing logic in hostapd code. Helps us to avoid duplication of code
@@ -43,9 +48,78 @@
namespace {
constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf";
+/**
+ * To add an overlay file, add
+ *
+ * PRODUCT_COPY_FILES += \
+ * <your/path/here>/hostapd_unmetered_overlay.conf:/vendor/etc/wifi/hostapd_unmetered_overlay.conf
+ *
+ * to the build file for your device, with the <your/path/here> being the path to your overlay in
+ * your repo. See the resolveVendorConfPath function in this file for more specifics on where this
+ * overlay file will wind up on your device.
+ *
+ * This overlay may configure any of the parameters listed in kOverlayableKeys. The kOverlayableKeys
+ * list is subject to change over time, as certain parameters may be added as APIs instead in the
+ * future.
+ *
+ * Example of what an overlay file might look like:
+ * $> cat hostapd_unmetered_overlay.conf
+ * dtim_period=2
+ * ap_max_inactivity=300
+ *
+ * Anything added to this overlay will be prepended to the hostapd.conf for unmetered (typically
+ * local only hotspots) interfaces.
+ */
+constexpr char kUnmeteredIfaceOverlayPath[] = "/etc/wifi/hostapd_unmetered_overlay.conf";
+
+/**
+ * Allow-list of hostapd.conf parameters (keys) that can be set via overlay.
+ *
+ * If introducing new APIs, be sure to remove keys from this list that would otherwise be
+ * controlled by the new API. This way we can avoid conflicting settings.
+ * Please file an FR to add new keys to this list.
+ */
+static const std::set<std::string> kOverlayableKeys = {
+ "ap_max_inactivity",
+ "assocresp_elements"
+ "beacon_int",
+ "disassoc_low_ack",
+ "dtim_period",
+ "fragm_threshold",
+ "max_listen_interval",
+ "max_num_sta",
+ "rts_threshold",
+ "skip_inactivity_poll",
+ "uapsd_advertisement_enabled",
+ "wmm_enabled",
+ "wmm_ac_vo_aifs",
+ "wmm_ac_vo_cwmin",
+ "wmm_ac_vo_cwmax",
+ "wmm_ac_vo_txop_limit",
+ "wmm_ac_vo_acm",
+ "wmm_ac_vi_aifs",
+ "wmm_ac_vi_cwmin",
+ "wmm_ac_vi_cwmax",
+ "wmm_ac_vi_txop_limit",
+ "wmm_ac_vi_acm",
+ "wmm_ac_bk_cwmin"
+ "wmm_ac_bk_cwmax"
+ "wmm_ac_bk_aifs",
+ "wmm_ac_bk_txop_limit",
+ "wmm_ac_bk_acm",
+ "wmm_ac_be_aifs",
+ "wmm_ac_be_cwmin",
+ "wmm_ac_be_cwmax",
+ "wmm_ac_be_txop_limit",
+ "wmm_ac_be_acm",
+};
+
using android::base::RemoveFileIfExists;
using android::base::StringPrintf;
+#ifndef ANDROID_HOSTAPD_UNITTEST
+using android::base::ReadFileToString;
using android::base::WriteStringToFile;
+#endif
using aidl::android::hardware::wifi::hostapd::BandMask;
using aidl::android::hardware::wifi::hostapd::ChannelBandwidth;
using aidl::android::hardware::wifi::hostapd::ChannelParams;
@@ -79,6 +153,12 @@
return expected_version <= aidl_client_version;
}
+inline int32_t areAidlServiceAndClientAtLeastVersion(int32_t expected_version)
+{
+ return isAidlServiceVersionAtLeast(expected_version)
+ && isAidlClientVersionAtLeast(expected_version);
+}
+
#define MAX_PORTS 1024
bool GetInterfacesInBridge(std::string br_name,
std::vector<std::string>* interfaces) {
@@ -119,11 +199,42 @@
return true;
}
-std::string WriteHostapdConfig(
- const std::string& interface_name, const std::string& config)
+std::string resolveVendorConfPath(const std::string& conf_path)
{
+#if defined(__ANDROID_APEX__)
+ // returns "/apex/<apexname>" + conf_path
+ std::string path = android::base::GetExecutablePath();
+ return path.substr(0, path.find_first_of('/', strlen("/apex/"))) + conf_path;
+#else
+ return std::string("/vendor") + conf_path;
+#endif
+}
+
+void logHostapdConfigError(int error, const std::string& file_path) {
+ wpa_printf(MSG_ERROR, "Cannot read/write hostapd config %s, error: %s", file_path.c_str(),
+ strerror(error));
+ struct stat st;
+ int result = stat(file_path.c_str(), &st);
+ if (result == 0) {
+ wpa_printf(MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d",st.st_uid,
+ st.st_gid, st.st_mode);
+ } else {
+ wpa_printf(MSG_ERROR, "Error calling stat() on hostapd config file: %s",
+ strerror(errno));
+ }
+}
+
+std::string WriteHostapdConfig(
+ const std::string& instance_name, const std::string& config,
+ const std::string br_name, const bool usesMlo)
+{
+ std::string conf_name_as_string = instance_name;
+ if (usesMlo) {
+ conf_name_as_string = StringPrintf(
+ "%s-%s", br_name.c_str(), instance_name.c_str());
+ }
const std::string file_path =
- StringPrintf(kConfFileNameFmt, interface_name.c_str());
+ StringPrintf(kConfFileNameFmt, conf_name_as_string.c_str());
if (WriteStringToFile(
config, file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
getuid(), getgid())) {
@@ -131,21 +242,7 @@
}
// Diagnose failure
int error = errno;
- wpa_printf(
- MSG_ERROR, "Cannot write hostapd config to %s, error: %s",
- file_path.c_str(), strerror(error));
- struct stat st;
- int result = stat(file_path.c_str(), &st);
- if (result == 0) {
- wpa_printf(
- MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d",
- st.st_uid, st.st_gid, st.st_mode);
- } else {
- wpa_printf(
- MSG_ERROR,
- "Error calling stat() on hostapd config file: %s",
- strerror(errno));
- }
+ logHostapdConfigError(errno, file_path);
return "";
}
@@ -339,6 +436,14 @@
return mac_addr;
}
+std::string trimWhitespace(const std::string& str) {
+ size_t pos = 0;
+ size_t len = str.size();
+ for (pos; pos < str.size() && std::isspace(str[pos]); ++pos){}
+ for (len; len - 1 > 0 && std::isspace(str[len-1]); --len){}
+ return str.substr(pos, len);
+}
+
std::string CreateHostapdConfig(
const IfaceParams& iface_params,
const ChannelParams& channelParams,
@@ -587,17 +692,25 @@
#ifdef CONFIG_IEEE80211BE
if (iface_params.hwModeParams.enable80211BE && !is_60Ghz_used) {
eht_params_as_string = "ieee80211be=1\n";
- if (isAidlServiceVersionAtLeast(2) && isAidlClientVersionAtLeast(2)) {
- std::string interface_mac_addr = getInterfaceMacAddress(iface_params.name);
+ if (areAidlServiceAndClientAtLeastVersion(2)) {
+ std::string interface_mac_addr = getInterfaceMacAddress(
+ iface_params.usesMlo ? br_name : iface_params.name);
if (interface_mac_addr.empty()) {
wpa_printf(MSG_ERROR,
"Unable to set interface mac address as bssid for 11BE SAP");
return "";
}
- eht_params_as_string += StringPrintf(
- "bssid=%s\n"
- "mld_ap=1",
- interface_mac_addr.c_str());
+ if (iface_params.usesMlo) {
+ eht_params_as_string += StringPrintf(
+ "mld_addr=%s\n"
+ "mld_ap=1",
+ interface_mac_addr.c_str());
+ } else {
+ eht_params_as_string += StringPrintf(
+ "bssid=%s\n"
+ "mld_ap=1",
+ interface_mac_addr.c_str());
+ }
}
/* TODO set eht_su_beamformer, eht_su_beamformee, eht_mu_beamformer */
} else {
@@ -714,7 +827,7 @@
#endif /* CONFIG_INTERWORKING */
std::string bridge_as_string;
- if (!br_name.empty()) {
+ if (!br_name.empty() && !iface_params.usesMlo) {
bridge_as_string = StringPrintf("bridge=%s", br_name.c_str());
}
@@ -736,10 +849,33 @@
"owe_transition_ifname=%s", owe_transition_ifname.c_str());
}
+ std::string ap_isolation_as_string = StringPrintf("ap_isolate=%s",
+ isAidlServiceVersionAtLeast(3) && nw_params.isClientIsolationEnabled ?
+ "1" : "0");
+
+ // Overlay for LOHS (unmetered SoftAP)
+ std::string overlay_path = resolveVendorConfPath(kUnmeteredIfaceOverlayPath);
+ std::string overlay_string;
+ if (!nw_params.isMetered
+ && 0 == access(overlay_path.c_str(), R_OK)
+ && !ReadFileToString(overlay_path, &overlay_string)) {
+ logHostapdConfigError(errno, overlay_path);
+ return "";
+ }
+ std::string sanitized_overlay = "";
+ std::istringstream overlay_stream(overlay_string);
+ for (std::string line; std::getline(overlay_stream, line);) {
+ std::string overlay_key = trimWhitespace(line.substr(0, line.find("=")));
+ if (kOverlayableKeys.contains(overlay_key)) {
+ sanitized_overlay.append(line + "\n");
+ }
+ }
+
return StringPrintf(
+ "%s\n"
"interface=%s\n"
"driver=nl80211\n"
- "ctrl_interface=/data/vendor/wifi/hostapd/ctrl\n"
+ "ctrl_interface=/data/vendor/wifi/hostapd/ctrl_%s\n"
// ssid2 signals to hostapd that the value is not a literal value
// for use as a SSID. In this case, we're giving it a hex
// std::string and hostapd needs to expect that.
@@ -761,8 +897,12 @@
"%s\n"
"%s\n"
"%s\n"
+ "%s\n"
"%s\n",
- iface_params.name.c_str(), ssid_as_string.c_str(),
+ sanitized_overlay.c_str(),
+ iface_params.usesMlo ? br_name.c_str() : iface_params.name.c_str(),
+ iface_params.name.c_str(),
+ ssid_as_string.c_str(),
channel_config_as_string.c_str(),
iface_params.hwModeParams.enable80211N ? 1 : 0,
iface_params.hwModeParams.enable80211AC ? 1 : 0,
@@ -778,7 +918,8 @@
owe_transition_ifname_as_string.c_str(),
enable_edmg_as_string.c_str(),
edmg_channel_as_string.c_str(),
- vendor_elements_as_string.c_str());
+ vendor_elements_as_string.c_str(),
+ ap_isolation_as_string.c_str());
}
Generation getGeneration(hostapd_hw_modes *current_mode)
@@ -839,23 +980,39 @@
}
}
+std::optional<struct sta_info*> getStaInfoByMacAddr(const struct hostapd_data* iface_hapd,
+ const u8 *mac_addr) {
+ if (iface_hapd == nullptr || mac_addr == nullptr){
+ wpa_printf(MSG_ERROR, "nullptr passsed to getStaInfoByMacAddr!");
+ return std::nullopt;
+ }
+
+ for (struct sta_info* sta_ptr = iface_hapd->sta_list; sta_ptr; sta_ptr = sta_ptr->next) {
+ int res;
+ res = memcmp(sta_ptr->addr, mac_addr, ETH_ALEN);
+ if (res == 0) {
+ return sta_ptr;
+ }
+ }
+ return std::nullopt;
+}
+
bool forceStaDisconnection(struct hostapd_data* hapd,
const std::vector<uint8_t>& client_address,
const uint16_t reason_code) {
- struct sta_info *sta;
if (client_address.size() != ETH_ALEN) {
return false;
}
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- int res;
- res = memcmp(sta->addr, client_address.data(), ETH_ALEN);
- if (res == 0) {
- wpa_printf(MSG_INFO, "Force client:" MACSTR " disconnect with reason: %d",
- MAC2STR(client_address.data()), reason_code);
- ap_sta_disconnect(hapd, sta, sta->addr, reason_code);
- return true;
- }
+
+ auto sta_ptr_optional = getStaInfoByMacAddr(hapd, client_address.data());
+ if (sta_ptr_optional.has_value()) {
+ wpa_printf(MSG_INFO, "Force client:" MACSTR " disconnect with reason: %d",
+ MAC2STR(client_address.data()), reason_code);
+ ap_sta_disconnect(hapd, sta_ptr_optional.value(), sta_ptr_optional.value()->addr,
+ reason_code);
+ return true;
}
+
return false;
}
@@ -979,6 +1136,12 @@
return setDebugParamsInternal(level);
}
+::ndk::ScopedAStatus Hostapd::removeLinkFromMultipleLinkBridgedApIface(
+ const std::string& iface_name, const std::string& linkIdentity)
+{
+ return removeLinkFromMultipleLinkBridgedApIfaceInternal(iface_name, linkIdentity);
+}
+
::ndk::ScopedAStatus Hostapd::addAccessPointInternal(
const IfaceParams& iface_params,
const NetworkParams& nw_params)
@@ -1011,35 +1174,58 @@
return vssid;
}
+
+// Both of bridged dual APs and MLO AP will be treated as concurrenct APs.
+// -----------------------------------------
+// | br_name | instance#1 | instance#2 |
+// ___________________________________________________________
+// bridged dual APs | ap_br_wlanX | wlan X | wlanY |
+// ___________________________________________________________
+// MLO AP | wlanX | 0 | 1 |
+// ___________________________________________________________
+// Both will be added in br_interfaces_[$br_name] and use instance's name
+// to be iface_params_new.name to create single Access point.
::ndk::ScopedAStatus Hostapd::addConcurrentAccessPoints(
const IfaceParams& iface_params, const NetworkParams& nw_params)
{
int channelParamsListSize = iface_params.channelParams.size();
// Get available interfaces in bridge
- std::vector<std::string> managed_interfaces;
- std::string br_name = StringPrintf(
- "%s", iface_params.name.c_str());
- if (!GetInterfacesInBridge(br_name, &managed_interfaces)) {
- return createStatusWithMsg(HostapdStatusCode::FAILURE_UNKNOWN,
- "Get interfaces in bridge failed.");
+ std::vector<std::string> managed_instances;
+ std::string br_name = StringPrintf("%s", iface_params.name.c_str());
+ if (iface_params.usesMlo) {
+ // MLO AP is using link id as instance.
+ for (std::size_t i = 0; i < iface_params.instanceIdentities->size(); i++) {
+ managed_instances.push_back(iface_params.instanceIdentities->at(i)->c_str());
+ }
+ } else {
+ if (!GetInterfacesInBridge(br_name, &managed_instances)) {
+ return createStatusWithMsg(HostapdStatusCode::FAILURE_UNKNOWN,
+ "Get interfaces in bridge failed.");
+ }
}
- if (managed_interfaces.size() < channelParamsListSize) {
+ // Either bridged AP or MLO AP should have two instances.
+ if (managed_instances.size() < channelParamsListSize) {
return createStatusWithMsg(HostapdStatusCode::FAILURE_UNKNOWN,
- "Available interfaces less than requested bands");
+ "Available interfaces less than requested bands");
+ }
+
+ if (iface_params.usesMlo
+ && nw_params.encryptionType == EncryptionType::WPA3_OWE_TRANSITION) {
+ return createStatusWithMsg(HostapdStatusCode::FAILURE_UNKNOWN,
+ "Invalid encryptionType (OWE transition) for MLO SAP.");
}
// start BSS on specified bands
for (std::size_t i = 0; i < channelParamsListSize; i ++) {
IfaceParams iface_params_new = iface_params;
NetworkParams nw_params_new = nw_params;
- iface_params_new.name = managed_interfaces[i];
-
std::string owe_transition_ifname = "";
+ iface_params_new.name = managed_instances[i];
if (nw_params.encryptionType == EncryptionType::WPA3_OWE_TRANSITION) {
if (i == 0 && i+1 < channelParamsListSize) {
- owe_transition_ifname = managed_interfaces[i+1];
+ owe_transition_ifname = managed_instances[i+1];
nw_params_new.encryptionType = EncryptionType::NONE;
} else {
- owe_transition_ifname = managed_interfaces[0];
+ owe_transition_ifname = managed_instances[0];
nw_params_new.isHidden = true;
nw_params_new.ssid = generateRandomOweSsid();
}
@@ -1050,15 +1236,61 @@
br_name, owe_transition_ifname);
if (!status.isOk()) {
wpa_printf(MSG_ERROR, "Failed to addAccessPoint %s",
- managed_interfaces[i].c_str());
+ managed_instances[i].c_str());
return status;
}
}
+
+ if (iface_params.usesMlo) {
+ std::size_t i = 0;
+ std::size_t j = 0;
+ for (i = 0; i < interfaces_->count; i++) {
+ struct hostapd_iface *iface = interfaces_->iface[i];
+
+ for (j = 0; j < iface->num_bss; j++) {
+ struct hostapd_data *iface_hapd = iface->bss[j];
+ if (hostapd_enable_iface(iface_hapd->iface) < 0) {
+ wpa_printf(
+ MSG_ERROR, "Enabling interface %s failed on %zu",
+ iface_params.name.c_str(), i);
+ return createStatus(HostapdStatusCode::FAILURE_UNKNOWN);
+ }
+ }
+ }
+ }
// Save bridge interface info
- br_interfaces_[br_name] = managed_interfaces;
+ br_interfaces_[br_name] = managed_instances;
return ndk::ScopedAStatus::ok();
}
+struct hostapd_data * hostapd_get_iface_by_link_id(struct hapd_interfaces *interfaces,
+ const size_t link_id)
+{
+#ifdef CONFIG_IEEE80211BE
+ size_t i, j;
+
+ for (i = 0; i < interfaces->count; i++) {
+ struct hostapd_iface *iface = interfaces->iface[i];
+
+ for (j = 0; j < iface->num_bss; j++) {
+ struct hostapd_data *hapd = iface->bss[j];
+
+ if (link_id == hapd->mld_link_id)
+ return hapd;
+ }
+ }
+#endif
+ return NULL;
+}
+
+// Both of bridged dual APs and MLO AP will be treated as concurrenct APs.
+// -----------------------------------------
+// | br_name | iface_params.name
+// _______________________________________________________________
+// bridged dual APs | bridged interface name | interface name
+// _______________________________________________________________
+// MLO AP | AP interface name | mld link id as instance name
+// _______________________________________________________________
::ndk::ScopedAStatus Hostapd::addSingleAccessPoint(
const IfaceParams& iface_params,
const ChannelParams& channelParams,
@@ -1066,10 +1298,19 @@
const std::string br_name,
const std::string owe_transition_ifname)
{
- if (hostapd_get_iface(interfaces_, iface_params.name.c_str())) {
+ if (iface_params.usesMlo) { // the mlo case, iface name is instance name which is mld_link_id
+ if (hostapd_get_iface_by_link_id(interfaces_, (size_t) iface_params.name.c_str())) {
+ wpa_printf(
+ MSG_ERROR, "Instance link id %s already present",
+ iface_params.name.c_str());
+ return createStatus(HostapdStatusCode::FAILURE_IFACE_EXISTS);
+ }
+ }
+ if (hostapd_get_iface(interfaces_,
+ iface_params.usesMlo ? br_name.c_str() : iface_params.name.c_str())) {
wpa_printf(
- MSG_ERROR, "Interface %s already present",
- iface_params.name.c_str());
+ MSG_ERROR, "Instance interface %s already present",
+ iface_params.usesMlo ? br_name.c_str() : iface_params.name.c_str());
return createStatus(HostapdStatusCode::FAILURE_IFACE_EXISTS);
}
const auto conf_params = CreateHostapdConfig(iface_params, channelParams, nw_params,
@@ -1079,26 +1320,46 @@
return createStatus(HostapdStatusCode::FAILURE_ARGS_INVALID);
}
const auto conf_file_path =
- WriteHostapdConfig(iface_params.name, conf_params);
+ WriteHostapdConfig(iface_params.name, conf_params, br_name, iface_params.usesMlo);
if (conf_file_path.empty()) {
wpa_printf(MSG_ERROR, "Failed to write config file");
return createStatus(HostapdStatusCode::FAILURE_UNKNOWN);
}
std::string add_iface_param_str = StringPrintf(
- "%s config=%s", iface_params.name.c_str(),
+ "%s config=%s", iface_params.usesMlo ? br_name.c_str(): iface_params.name.c_str(),
conf_file_path.c_str());
std::vector<char> add_iface_param_vec(
add_iface_param_str.begin(), add_iface_param_str.end() + 1);
if (hostapd_add_iface(interfaces_, add_iface_param_vec.data()) < 0) {
wpa_printf(
- MSG_ERROR, "Adding interface %s failed",
+ MSG_ERROR, "Adding hostapd iface %s failed",
add_iface_param_str.c_str());
return createStatus(HostapdStatusCode::FAILURE_UNKNOWN);
}
- struct hostapd_data* iface_hapd =
- hostapd_get_iface(interfaces_, iface_params.name.c_str());
+
+ // find the iface and set up callback.
+ struct hostapd_data* iface_hapd = iface_params.usesMlo ?
+ hostapd_get_iface_by_link_id(interfaces_, (size_t) iface_params.name.c_str()) :
+ hostapd_get_iface(interfaces_, iface_params.name.c_str());
WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr);
+ if (iface_params.usesMlo) {
+ memcmp(iface_hapd->conf->iface, br_name.c_str(), br_name.size());
+ }
+
+ // Callback discrepancy between bridged dual APs and MLO AP
+ // Note: Only bridged dual APs will have "iface_hapd->conf->bridge" and
+ // Only MLO AP will have "iface_hapd->mld_link_id"
// Register the setup complete callbacks
+ // -----------------------------------------
+ // | bridged dual APs | bridged single link MLO | MLO SAP
+ // _________________________________________________________________________________________
+ // hapd->conf->bridge | bridged interface name | bridged interface nam | N/A
+ // _________________________________________________________________________________________
+ // hapd->conf->iface | AP interface name | AP interface name | AP interface name
+ // _________________________________________________________________________________________
+ // hapd->mld_link_id | 0 (default value) | link id (0) | link id (0 or 1)
+ // _________________________________________________________________________________________
+ // hapd->mld_ap | 0 | 1 | 1
on_setup_complete_internal_callback =
[this](struct hostapd_data* iface_hapd) {
wpa_printf(
@@ -1107,11 +1368,18 @@
if (iface_hapd->iface->state == HAPD_IFACE_DISABLED) {
// Invoke the failure callback on all registered
// clients.
+ std::string instanceName = iface_hapd->conf->iface;
+#ifdef CONFIG_IEEE80211BE
+ if (iface_hapd->conf->mld_ap
+ && strlen(iface_hapd->conf->bridge) == 0) {
+ instanceName = std::to_string(iface_hapd->mld_link_id);
+ }
+#endif
for (const auto& callback : callbacks_) {
auto status = callback->onFailure(
strlen(iface_hapd->conf->bridge) > 0 ?
iface_hapd->conf->bridge : iface_hapd->conf->iface,
- iface_hapd->conf->iface);
+ instanceName);
if (!status.isOk()) {
wpa_printf(MSG_ERROR, "Failed to invoke onFailure");
}
@@ -1129,9 +1397,25 @@
ClientInfo info;
info.ifaceName = strlen(iface_hapd->conf->bridge) > 0 ?
iface_hapd->conf->bridge : iface_hapd->conf->iface;
- info.apIfaceInstance = iface_hapd->conf->iface;
+ std::string instanceName = iface_hapd->conf->iface;
+#ifdef CONFIG_IEEE80211BE
+ if (iface_hapd->conf->mld_ap
+ && strlen(iface_hapd->conf->bridge) == 0) {
+ instanceName = std::to_string(iface_hapd->mld_link_id);
+ }
+#endif
+ info.apIfaceInstance = instanceName;
info.clientAddress.assign(mac_addr, mac_addr + ETH_ALEN);
info.isConnected = authorized;
+ if(isAidlServiceVersionAtLeast(3) && !authorized) {
+ u16 disconnect_reason_code = WLAN_REASON_UNSPECIFIED;
+ auto sta_ptr_optional = getStaInfoByMacAddr(iface_hapd, mac_addr);
+ if (sta_ptr_optional.has_value()){
+ disconnect_reason_code = sta_ptr_optional.value()->deauth_reason;
+ }
+ info.disconnectReasonCode =
+ static_cast<common::DeauthenticationReasonCode>(disconnect_reason_code);
+ }
for (const auto &callback : callbacks_) {
auto status = callback->onConnectedClientsChanged(info);
if (!status.isOk()) {
@@ -1150,10 +1434,16 @@
strlen(AP_EVENT_ENABLED)) == 0 ||
os_strncmp(txt, WPA_EVENT_CHANNEL_SWITCH,
strlen(WPA_EVENT_CHANNEL_SWITCH)) == 0) {
+ std::string instanceName = iface_hapd->conf->iface;
+#ifdef CONFIG_IEEE80211BE
+ if (iface_hapd->conf->mld_ap && strlen(iface_hapd->conf->bridge) == 0) {
+ instanceName = std::to_string(iface_hapd->mld_link_id);
+ }
+#endif
ApInfo info;
info.ifaceName = strlen(iface_hapd->conf->bridge) > 0 ?
iface_hapd->conf->bridge : iface_hapd->conf->iface,
- info.apIfaceInstance = iface_hapd->conf->iface;
+ info.apIfaceInstance = instanceName;
info.freqMhz = iface_hapd->iface->freq;
info.channelBandwidth = getChannelBandwidth(iface_hapd->iconf);
info.generation = getGeneration(iface_hapd->iface->current_mode);
@@ -1169,11 +1459,18 @@
} else if (os_strncmp(txt, AP_EVENT_DISABLED, strlen(AP_EVENT_DISABLED)) == 0
|| os_strncmp(txt, INTERFACE_DISABLED, strlen(INTERFACE_DISABLED)) == 0)
{
+ std::string instanceName = iface_hapd->conf->iface;
+#ifdef CONFIG_IEEE80211BE
+ if (iface_hapd->conf->mld_ap && strlen(iface_hapd->conf->bridge) == 0) {
+ instanceName = std::to_string(iface_hapd->mld_link_id);
+ }
+#endif
// Invoke the failure callback on all registered clients.
for (const auto& callback : callbacks_) {
- auto status = callback->onFailure(strlen(iface_hapd->conf->bridge) > 0 ?
+ auto status =
+ callback->onFailure(strlen(iface_hapd->conf->bridge) > 0 ?
iface_hapd->conf->bridge : iface_hapd->conf->iface,
- iface_hapd->conf->iface);
+ instanceName);
if (!status.isOk()) {
wpa_printf(MSG_ERROR, "Failed to invoke onFailure");
}
@@ -1188,7 +1485,8 @@
iface_hapd->sta_authorized_cb_ctx = iface_hapd;
wpa_msg_register_aidl_cb(onAsyncWpaEventCb);
- if (hostapd_enable_iface(iface_hapd->iface) < 0) {
+ // Multi-link MLO should enable iface after both links have been set.
+ if (!iface_params.usesMlo && hostapd_enable_iface(iface_hapd->iface) < 0) {
wpa_printf(
MSG_ERROR, "Enabling interface %s failed",
iface_params.name.c_str());
@@ -1288,6 +1586,23 @@
return ndk::ScopedAStatus::ok();
}
+::ndk::ScopedAStatus Hostapd::removeLinkFromMultipleLinkBridgedApIfaceInternal(
+const std::string& iface_name, const std::string& linkIdentity)
+{
+ if (!hostapd_get_iface(interfaces_, iface_name.c_str())) {
+ wpa_printf(MSG_ERROR, "Interface %s doesn't exist", iface_name.c_str());
+ return createStatus(HostapdStatusCode::FAILURE_IFACE_UNKNOWN);
+ }
+ struct hostapd_data* iface_hapd =
+ hostapd_get_iface_by_link_id(interfaces_, (size_t) linkIdentity.c_str());
+ if (iface_hapd) {
+ if (0 == hostapd_link_remove(iface_hapd, 1)) {
+ return ndk::ScopedAStatus::ok();
+ }
+ }
+ return createStatus(HostapdStatusCode::FAILURE_ARGS_INVALID);
+}
+
} // namespace hostapd
} // namespace wifi
} // namespace hardware
diff --git a/hostapd/aidl/hostapd.h b/hostapd/aidl/hostapd.h
index ffdbd8e..ba47810 100644
--- a/hostapd/aidl/hostapd.h
+++ b/hostapd/aidl/hostapd.h
@@ -55,6 +55,8 @@
const std::vector<uint8_t>& client_address,
Ieee80211ReasonCode reason_code) override;
::ndk::ScopedAStatus setDebugParams(DebugLevel level) override;
+ ::ndk::ScopedAStatus removeLinkFromMultipleLinkBridgedApIface(
+ const std::string& iface_name, const std::string& linkIdentity) override;
private:
// Corresponding worker functions for the AIDL methods.
::ndk::ScopedAStatus addAccessPointInternal(
@@ -77,7 +79,8 @@
const std::vector<uint8_t>& client_address,
Ieee80211ReasonCode reason_code);
::ndk::ScopedAStatus setDebugParamsInternal(DebugLevel level);
-
+ ::ndk::ScopedAStatus removeLinkFromMultipleLinkBridgedApIfaceInternal(
+ const std::string& iface_name, const std::string& linkIdentity);
// Raw pointer to the global structure maintained by the core.
struct hapd_interfaces* interfaces_;
// Callbacks registered.
diff --git a/hostapd/aidl/tests/Android.bp b/hostapd/aidl/tests/Android.bp
new file mode 100644
index 0000000..51444d2
--- /dev/null
+++ b/hostapd/aidl/tests/Android.bp
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// 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.
+
+package {
+ default_team: "trendy_team_fwk_wifi_hal",
+ default_applicable_licenses: [
+ "external_wpa_supplicant_8_license",
+ "external_wpa_supplicant_8_hostapd_license",
+ ],
+}
+
+cc_test {
+ name: "libhostapd_aidl_bp_unittest",
+ defaults: [
+ "hostapd_cflags_defaults",
+ ],
+ require_root: true,
+ soc_specific: true,
+ srcs: [
+ "unittests.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.wifi.hostapd-V3-ndk",
+ "libbinder_ndk",
+ "libbase",
+ "libutils",
+ "liblog",
+ ],
+ static_libs: [
+ "libgtest",
+ ],
+ header_libs: [
+ "hostapd_headers",
+ "libhostapd_aidl_headers",
+ ],
+ cppflags: [
+ "-DANDROID_HOSTAPD_UNITTEST",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+ test_suites: [
+ "general-tests",
+ ],
+}
diff --git a/hostapd/aidl/tests/unittest_overrides.h b/hostapd/aidl/tests/unittest_overrides.h
new file mode 100644
index 0000000..a5be178
--- /dev/null
+++ b/hostapd/aidl/tests/unittest_overrides.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+
+static ::android::base::LogSeverity wpa_to_android_level(int level)
+{
+ if (level == MSG_ERROR)
+ return ::android::base::ERROR;
+ if (level == MSG_WARNING)
+ return ::android::base::WARNING;
+ if (level == MSG_INFO)
+ return ::android::base::INFO;
+ return ::android::base::DEBUG;
+}
+
+// don't use hostapd's wpa_printf for unit testing. It won't compile otherwise
+void wpa_printf(int level, const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ LOG(wpa_to_android_level(level)) << ::android::base::StringPrintf(fmt, ap);
+ va_end(ap);
+}
+
+static int hostapd_unittest_stat_ret = 0;
+int stat(const char* pathname, struct stat* stabuf) {
+ if (hostapd_unittest_stat_ret != 0) {
+ errno = EINVAL;
+ }
+ return hostapd_unittest_stat_ret;
+}
+
+static int hostapd_unittest_accessRet = 0;
+int access(const char* pathname, int mode) {
+ if (hostapd_unittest_accessRet != 0) {
+ errno = EINVAL;
+ }
+ return hostapd_unittest_accessRet;
+}
+
+
+// You can inspect the string here to see what we tried to write to a file
+static std::string hostapd_unittest_config_output = "";
+static bool hostapd_unittest_WriteStringToFileRet = true;
+bool WriteStringToFile(const std::string& content, const std::string& path, mode_t mode,
+ uid_t owner, gid_t group) {
+ if (!hostapd_unittest_WriteStringToFileRet) {
+ errno = EINVAL;
+ } else {
+ hostapd_unittest_config_output = content;
+ }
+ return hostapd_unittest_WriteStringToFileRet;
+}
+
+// You can simulate a file having content with this string
+static std::string hostapd_unittest_overlay_content = "";
+static bool hostapd_unittest_ReadFileToStringRet = true;
+bool ReadFileToString(const std::string& path, std::string* content) {
+ *content = hostapd_unittest_overlay_content;
+ LOG(INFO) << "*content = " << *content;
+ return hostapd_unittest_ReadFileToStringRet;
+}
+
+/**
+ * We can simulate I/O operations failing by re-defining the calls.
+ *
+ * By default, all files are empty, and all calls succeed.
+ */
+void resetOverrides() {
+ hostapd_unittest_stat_ret = 0;
+ hostapd_unittest_WriteStringToFileRet = true;
+ hostapd_unittest_config_output = "";
+ hostapd_unittest_accessRet = 0;
+ hostapd_unittest_overlay_content = "";
+ hostapd_unittest_ReadFileToStringRet = true;
+}
diff --git a/hostapd/aidl/tests/unittests.cpp b/hostapd/aidl/tests/unittests.cpp
new file mode 100644
index 0000000..696e123
--- /dev/null
+++ b/hostapd/aidl/tests/unittests.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * 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 <cstring>
+
+#include <gtest/gtest.h>
+#include "../hostapd.cpp"
+
+namespace aidl::android::hardware::wifi::hostapd {
+unsigned char kTestSsid[] = {0x31, 0x32, 0x33, 0x61, 0x62, 0x63, 0x64};
+
+class HostapdConfigTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ resetOverrides();
+
+ mIface_params = {
+ .name = "wlan42",
+ .hwModeParams = {
+ .enable80211N = true,
+ .enable80211AC = false,
+ .enable80211AX = false,
+ .enable6GhzBand = false,
+ .enableHeSingleUserBeamformer = false,
+ .enableHeSingleUserBeamformee = false,
+ .enableHeMultiUserBeamformer = false,
+ .enableHeTargetWakeTime = false,
+ .enableEdmg = false,
+ .enable80211BE = false,
+ .maximumChannelBandwidth = ChannelBandwidth::BANDWIDTH_AUTO,
+ },
+ .channelParams = {}, // not used in config creation
+ .vendorData = {}, // not used in config creation
+ .instanceIdentities = {}, // not used in config creation
+ .usesMlo = false,
+ };
+ mChannel_params = {
+ .bandMask = BandMask::BAND_2_GHZ,
+ .acsChannelFreqRangesMhz = {},
+ .enableAcs = false,
+ .acsShouldExcludeDfs = false,
+ .channel = 6,
+ };
+ mNetwork_params = {
+ .ssid = std::vector<uint8_t>(kTestSsid, kTestSsid + sizeof(kTestSsid)),
+ .isHidden = false,
+ .encryptionType = EncryptionType::WPA2,
+ .passphrase = "verysecurewowe",
+ .isMetered = true, // default for tethered softap, change to false for lohs.
+ .vendorElements = {},
+ };
+ }
+
+ std::string mWlan42_tethered_config = "\ninterface=wlan42\n"
+ "driver=nl80211\n"
+ "ctrl_interface=/data/vendor/wifi/hostapd/ctrl_wlan42\n"
+ "ssid2=31323361626364\n"
+ "channel=6\n"
+ "op_class=83\n"
+ "ieee80211n=1\n"
+ "ieee80211ac=0\n\n\n"
+ "hw_mode=g\n\n"
+ "ignore_broadcast_ssid=0\n"
+ "wowlan_triggers=any\n"
+ "interworking=1\n"
+ "access_network_type=2\n\n"
+ "wpa=2\n"
+ "rsn_pairwise=CCMP\n"
+ "wpa_passphrase=verysecurewowe\n\n\n\n\n\n"
+ "ap_isolate=0\n";
+
+ std::string mWlan42_lohs_config = "dtim_period=2 \n"
+ " ap_max_inactivity=300\n"
+ "skip_inactivity_poll = 1\n\n"
+ "interface=wlan42\n"
+ "driver=nl80211\n"
+ "ctrl_interface=/data/vendor/wifi/hostapd/ctrl_wlan42\n"
+ "ssid2=31323361626364\n"
+ "channel=6\n"
+ "op_class=83\n"
+ "ieee80211n=1\n"
+ "ieee80211ac=0\n\n\n"
+ "hw_mode=g\n\n"
+ "ignore_broadcast_ssid=0\n"
+ "wowlan_triggers=any\n"
+ "interworking=0\n\n"
+ "wpa=2\n"
+ "rsn_pairwise=CCMP\n"
+ "wpa_passphrase=verysecurewowe\n\n\n\n\n\n"
+ "ap_isolate=0\n";
+
+ std::string mWlan42_lohs_config_no_overlay = "\ninterface=wlan42\n"
+ "driver=nl80211\n"
+ "ctrl_interface=/data/vendor/wifi/hostapd/ctrl_wlan42\n"
+ "ssid2=31323361626364\n"
+ "channel=6\n"
+ "op_class=83\n"
+ "ieee80211n=1\n"
+ "ieee80211ac=0\n\n\n"
+ "hw_mode=g\n\n"
+ "ignore_broadcast_ssid=0\n"
+ "wowlan_triggers=any\n"
+ "interworking=0\n\n"
+ "wpa=2\n"
+ "rsn_pairwise=CCMP\n"
+ "wpa_passphrase=verysecurewowe\n\n\n\n\n\n"
+ "ap_isolate=0\n";
+
+ IfaceParams mIface_params;
+ ChannelParams mChannel_params;
+ NetworkParams mNetwork_params;
+ std::string mBr_name = "";
+ std::string mOwe_transition_ifname = "";
+};
+
+/**
+ * Null hostapd_data* and null mac address (u8*)
+ * There's an || check on these that should return nullopt
+ */
+TEST(getStaInfoByMacAddrTest, NullArguments) {
+ EXPECT_EQ(std::nullopt, getStaInfoByMacAddr(nullptr, nullptr));
+}
+
+
+/**
+ * We pass valid arguments to get past the nullptr check, but hostapd_data->sta_list is nullptr.
+ * Don't loop through the sta_info* list, just return nullopt.
+ */
+TEST(getStaInfoByMacAddrTest, NullStaList) {
+ struct hostapd_data iface_hapd = {};
+ u8 mac_addr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xD0, 0x0D};
+ EXPECT_EQ(std::nullopt, getStaInfoByMacAddr(&iface_hapd, mac_addr));
+}
+
+/**
+ * Mac doesn't match, and we hit the end of the sta_info list.
+ * Don't run over the end of the list and return nullopt.
+ */
+TEST(getStaInfoByMacAddrTest, NoMatchingMac) {
+ struct hostapd_data iface_hapd = {};
+ struct sta_info sta0 = {};
+ struct sta_info sta1 = {};
+ struct sta_info sta2 = {};
+ iface_hapd.sta_list = &sta0;
+ sta0.next = &sta1;
+ sta1.next = &sta2;
+ u8 mac_addr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xD0, 0x0D};
+ EXPECT_EQ(std::nullopt, getStaInfoByMacAddr(&iface_hapd, mac_addr));
+}
+
+/**
+ * There is a matching address and we return it.
+ */
+TEST(getStaInfoByMacAddrTest, MatchingMac) {
+ struct hostapd_data iface_hapd = {};
+ struct sta_info sta0 = {};
+ struct sta_info sta1 = {};
+ struct sta_info sta2 = {};
+ iface_hapd.sta_list = &sta0;
+ sta0.next = &sta1;
+ sta1.next = &sta2;
+ u8 sta0_addr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xD0, 0x0C}; // off by 1 bit
+ std::memcpy(sta0.addr, sta0_addr, ETH_ALEN);
+ u8 sta1_addr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xD0, 0x0D};
+ std::memcpy(sta1.addr, sta1_addr, ETH_ALEN);
+ u8 mac_addr[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xD0, 0x0D};
+ auto sta_ptr_optional = getStaInfoByMacAddr(&iface_hapd, mac_addr);
+ EXPECT_TRUE(sta_ptr_optional.has_value());
+ EXPECT_EQ(0, std::memcmp(sta_ptr_optional.value()->addr, sta1_addr, ETH_ALEN));
+}
+
+
+TEST_F(HostapdConfigTest, tetheredApConfig) {
+ // instance name, config string, br_name, usesMlo
+ std::string config_path = WriteHostapdConfig("wlan42", mWlan42_tethered_config, "", false);
+ std::string expected_path = "/data/vendor/wifi/hostapd/hostapd_wlan42.conf";
+ EXPECT_EQ(expected_path, config_path);
+ EXPECT_EQ(mWlan42_tethered_config, hostapd_unittest_config_output);
+}
+
+TEST_F(HostapdConfigTest, tetheredApConfigStatFails) {
+ hostapd_unittest_WriteStringToFileRet = false;
+ hostapd_unittest_stat_ret = -1;
+ // instance name, config string, br_name, usesMlo
+ std::string config_path = WriteHostapdConfig("wlan42", mWlan42_tethered_config, "", false);
+ std::string expected_path = "";
+ EXPECT_EQ(expected_path, config_path);
+}
+
+TEST_F(HostapdConfigTest, tetheredApConfigWriteFails) {
+ hostapd_unittest_WriteStringToFileRet = false;
+ // instance name, config string, br_name, usesMlo
+ std::string config_path = WriteHostapdConfig("wlan42", mWlan42_tethered_config, "", false);
+ std::string expected_path = "";
+ EXPECT_EQ(expected_path, config_path);
+}
+
+TEST_F(HostapdConfigTest, tetheredAp) {
+ std::string config_string = CreateHostapdConfig(mIface_params, mChannel_params, mNetwork_params,
+ mBr_name, mOwe_transition_ifname);
+ EXPECT_EQ(mWlan42_tethered_config, config_string);
+}
+
+TEST_F(HostapdConfigTest, lohsAp) {
+ mNetwork_params.isMetered = false;
+ hostapd_unittest_overlay_content =
+ "invalid_key=this_should_not_be_here\n"
+ "dtim_period=2 \n"
+ " ap_max_inactivity=300\n"
+ "another_invalid_key_dtim_period=-10000\n"
+ "skip_inactivity_poll = 1";
+ std::string config_string = CreateHostapdConfig(mIface_params, mChannel_params, mNetwork_params,
+ mBr_name, mOwe_transition_ifname);
+ EXPECT_EQ(mWlan42_lohs_config, config_string);
+}
+
+TEST_F(HostapdConfigTest, lohsApAccessFails) {
+ mNetwork_params.isMetered = false;
+ hostapd_unittest_accessRet = -1;
+ std::string config_string = CreateHostapdConfig(mIface_params, mChannel_params, mNetwork_params,
+ mBr_name, mOwe_transition_ifname);
+ EXPECT_EQ(mWlan42_lohs_config_no_overlay, config_string);
+}
+
+TEST_F(HostapdConfigTest, lohsApReadFails) {
+ mNetwork_params.isMetered = false;
+ hostapd_unittest_ReadFileToStringRet = false;
+ std::string config_string = CreateHostapdConfig(mIface_params, mChannel_params, mNetwork_params,
+ mBr_name, mOwe_transition_ifname);
+ EXPECT_EQ("", config_string);
+}
+
+} // namespace aidl::android::hardware::wifi::hostapd
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 1d2bdb8..9470cae 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2436,6 +2436,31 @@
#endif /* CONFIG_IEEE80211BE */
+#ifdef CONFIG_TESTING_OPTIONS
+static bool get_hexstream(const char *val, struct wpabuf **var,
+ const char *name, int line)
+{
+ struct wpabuf *tmp;
+ size_t len = os_strlen(val) / 2;
+
+ tmp = wpabuf_alloc(len);
+ if (!tmp)
+ return false;
+
+ if (hexstr2bin(val, wpabuf_put(tmp, len), len)) {
+ wpabuf_free(tmp);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid %s '%s'",
+ line, name, val);
+ return false;
+ }
+
+ wpabuf_free(*var);
+ *var = tmp;
+ return true;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
const char *buf, char *pos, int line)
@@ -3244,6 +3269,8 @@
os_free(bss->rsn_preauth_interfaces);
bss->rsn_preauth_interfaces = os_strdup(pos);
#endif /* CONFIG_RSN_PREAUTH */
+ } else if (os_strcmp(buf, "rsn_override_omit_rsnxe") == 0) {
+ bss->rsn_override_omit_rsnxe = atoi(pos);
} else if (os_strcmp(buf, "peerkey") == 0) {
wpa_printf(MSG_INFO,
"Line %d: Obsolete peerkey parameter ignored", line);
@@ -4502,23 +4529,29 @@
bss->radio_measurements[0] |=
WLAN_RRM_CAPS_NEIGHBOR_REPORT;
} else if (os_strcmp(buf, "own_ie_override") == 0) {
- struct wpabuf *tmp;
- size_t len = os_strlen(pos) / 2;
-
- tmp = wpabuf_alloc(len);
- if (!tmp)
+ if (!get_hexstream(pos, &bss->own_ie_override,
+ "own_ie_override", line))
return 1;
-
- if (hexstr2bin(pos, wpabuf_put(tmp, len), len)) {
- wpabuf_free(tmp);
- wpa_printf(MSG_ERROR,
- "Line %d: Invalid own_ie_override '%s'",
- line, pos);
+ } else if (os_strcmp(buf, "rsne_override") == 0) {
+ if (!get_hexstream(pos, &bss->rsne_override,
+ "rsne_override", line))
return 1;
- }
-
- wpabuf_free(bss->own_ie_override);
- bss->own_ie_override = tmp;
+ } else if (os_strcmp(buf, "rsnoe_override") == 0) {
+ if (!get_hexstream(pos, &bss->rsnoe_override,
+ "rsnoe_override", line))
+ return 1;
+ } else if (os_strcmp(buf, "rsno2e_override") == 0) {
+ if (!get_hexstream(pos, &bss->rsno2e_override,
+ "rsno2e_override", line))
+ return 1;
+ } else if (os_strcmp(buf, "rsnxe_override") == 0) {
+ if (!get_hexstream(pos, &bss->rsnxe_override,
+ "rsnxe_override", line))
+ return 1;
+ } else if (os_strcmp(buf, "rsnxoe_override") == 0) {
+ if (!get_hexstream(pos, &bss->rsnxoe_override,
+ "rsnxoe_override", line))
+ return 1;
} else if (os_strcmp(buf, "sae_reflection_attack") == 0) {
bss->sae_reflection_attack = atoi(pos);
} else if (os_strcmp(buf, "sae_commit_status") == 0) {
@@ -4584,6 +4617,8 @@
return 1;
} else if (os_strcmp(buf, "eapol_m3_no_encrypt") == 0) {
bss->eapol_m3_no_encrypt = atoi(pos);
+ } else if (os_strcmp(buf, "eapol_key_reserved_random") == 0) {
+ bss->eapol_key_reserved_random = 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) {
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 8e2b8bd..ea19ba7 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -2458,6 +2458,31 @@
#ifdef NEED_AP_MLME
+
+static bool
+hostapd_ctrl_is_freq_in_cmode(struct hostapd_hw_modes *mode,
+ struct hostapd_multi_hw_info *current_hw_info,
+ int freq)
+{
+ struct hostapd_channel_data *chan;
+ int i;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ chan = &mode->channels[i];
+
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ continue;
+
+ if (!chan_in_current_hw_info(current_hw_info, chan))
+ continue;
+
+ if (chan->freq == freq)
+ return true;
+ }
+ return false;
+}
+
+
static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params,
u16 punct_bitmap)
{
@@ -2672,6 +2697,15 @@
settings.link_id = iface->bss[0]->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
+ if (iface->num_hw_features > 1 &&
+ !hostapd_ctrl_is_freq_in_cmode(iface->current_mode,
+ iface->current_hw_info,
+ settings.freq_params.freq)) {
+ wpa_printf(MSG_INFO,
+ "chanswitch: Invalid frequency settings provided for multi band phy");
+ return -1;
+ }
+
ret = hostapd_ctrl_check_freq_params(&settings.freq_params,
settings.punct_bitmap);
if (ret) {
@@ -2739,6 +2773,12 @@
return 0;
}
+ if (iface->cac_started) {
+ wpa_printf(MSG_DEBUG,
+ "CAC is in progress - switching channel without CSA");
+ return hostapd_force_channel_switch(iface, &settings);
+ }
+
for (i = 0; i < iface->num_bss; i++) {
/* Save CHAN_SWITCH VHT, HE, and EHT config */
@@ -3709,6 +3749,7 @@
struct wpabuf *ssi = NULL;
int ret = -1;
enum nan_service_protocol_type srv_proto_type = 0;
+ bool p2p = false;
os_memset(¶ms, 0, sizeof(params));
/* USD shall use both solicited and unsolicited transmissions */
@@ -3742,6 +3783,11 @@
continue;
}
+ if (os_strcmp(token, "p2p=1") == 0) {
+ p2p = true;
+ continue;
+ }
+
if (os_strcmp(token, "solicited=0") == 0) {
params.solicited = false;
continue;
@@ -3763,7 +3809,7 @@
}
publish_id = hostapd_nan_usd_publish(hapd, service_name, srv_proto_type,
- ssi, ¶ms);
+ ssi, ¶ms, p2p);
if (publish_id > 0)
ret = os_snprintf(buf, buflen, "%d", publish_id);
fail:
@@ -3846,6 +3892,7 @@
struct wpabuf *ssi = NULL;
int ret = -1;
enum nan_service_protocol_type srv_proto_type = 0;
+ bool p2p = false;
os_memset(¶ms, 0, sizeof(params));
@@ -3879,6 +3926,11 @@
continue;
}
+ if (os_strcmp(token, "p2p=1") == 0) {
+ p2p = true;
+ continue;
+ }
+
wpa_printf(MSG_INFO,
"CTRL: Invalid NAN_SUBSCRIBE parameter: %s",
token);
@@ -3887,7 +3939,7 @@
subscribe_id = hostapd_nan_usd_subscribe(hapd, service_name,
srv_proto_type, ssi,
- ¶ms);
+ ¶ms, p2p);
if (subscribe_id > 0)
ret = os_snprintf(buf, buflen, "%d", subscribe_id);
fail:
@@ -4686,23 +4738,360 @@
}
+#ifdef CONFIG_IEEE80211BE
+#ifndef CONFIG_CTRL_IFACE_UDP
+
+static int hostapd_mld_ctrl_iface_receive_process(struct hostapd_mld *mld,
+ char *buf, char *reply,
+ size_t reply_size,
+ struct sockaddr_storage *from,
+ socklen_t fromlen)
+{
+ struct hostapd_data *link_hapd, *link_itr;
+ int reply_len = -1, link_id = -1;
+ char *cmd;
+ bool found = false;
+
+ os_memcpy(reply, "OK\n", 3);
+ reply_len = 3;
+
+ cmd = buf;
+
+ /* Check whether the link ID is provided in the command */
+ if (os_strncmp(cmd, "LINKID ", 7) == 0) {
+ cmd += 7;
+ link_id = atoi(cmd);
+ if (link_id < 0 || link_id >= 15) {
+ os_memcpy(reply, "INVALID LINK ID\n", 16);
+ reply_len = 16;
+ goto out;
+ }
+
+ cmd = os_strchr(cmd, ' ');
+ if (!cmd)
+ goto out;
+ cmd++;
+ }
+ if (link_id >= 0) {
+ link_hapd = mld->fbss;
+ if (!link_hapd) {
+ os_memcpy(reply, "NO LINKS ACTIVE\n", 16);
+ reply_len = 16;
+ goto out;
+ }
+
+ for_each_mld_link(link_itr, link_hapd) {
+ if (link_itr->mld_link_id == link_id) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ goto out;
+
+ link_hapd = link_itr;
+ } else {
+ link_hapd = mld->fbss;
+ }
+
+ if (os_strcmp(cmd, "PING") == 0) {
+ os_memcpy(reply, "PONG\n", 5);
+ reply_len = 5;
+ } else if (os_strcmp(cmd, "ATTACH") == 0) {
+ if (ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, NULL))
+ reply_len = -1;
+ } else if (os_strncmp(cmd, "ATTACH ", 7) == 0) {
+ if (ctrl_iface_attach(&mld->ctrl_dst, from, fromlen, cmd + 7))
+ reply_len = -1;
+ } else if (os_strcmp(cmd, "DETACH") == 0) {
+ if (ctrl_iface_detach(&mld->ctrl_dst, from, fromlen))
+ reply_len = -1;
+ } else {
+ if (link_id == -1)
+ wpa_printf(MSG_DEBUG,
+ "Link ID not provided, using the first link BSS (if available)");
+
+ if (!link_hapd)
+ reply_len = -1;
+ else
+ reply_len =
+ hostapd_ctrl_iface_receive_process(
+ link_hapd, cmd, reply, reply_size,
+ from, fromlen);
+ }
+
+out:
+ if (reply_len < 0) {
+ os_memcpy(reply, "FAIL\n", 5);
+ reply_len = 5;
+ }
+
+ return reply_len;
+}
+
+
+static void hostapd_mld_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct hostapd_mld *mld = eloop_ctx;
+ char buf[4096];
+ int res;
+ struct sockaddr_storage from;
+ socklen_t fromlen = sizeof(from);
+ char *reply, *pos = buf;
+ const size_t reply_size = 4096;
+ int reply_len;
+ int level = MSG_DEBUG;
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "recvfrom(mld ctrl_iface): %s",
+ strerror(errno));
+ return;
+ }
+ buf[res] = '\0';
+
+ reply = os_malloc(reply_size);
+ if (!reply) {
+ if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s",
+ strerror(errno));
+ }
+ return;
+ }
+
+ if (os_strcmp(pos, "PING") == 0)
+ level = MSG_EXCESSIVE;
+
+ wpa_hexdump_ascii(level, "RX MLD ctrl_iface", pos, res);
+
+ reply_len = hostapd_mld_ctrl_iface_receive_process(mld, pos,
+ reply, reply_size,
+ &from, fromlen);
+
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "MLD CTRL: sendto failed: %s",
+ strerror(errno));
+ }
+ os_free(reply);
+}
+
+
+static char * hostapd_mld_ctrl_iface_path(struct hostapd_mld *mld)
+{
+ size_t len;
+ char *buf;
+ int ret;
+
+ if (!mld->ctrl_interface)
+ return NULL;
+
+ len = os_strlen(mld->ctrl_interface) + os_strlen(mld->name) + 2;
+
+ buf = os_malloc(len);
+ if (!buf)
+ return NULL;
+
+ ret = os_snprintf(buf, len, "%s/%s", mld->ctrl_interface, mld->name);
+ if (os_snprintf_error(len, ret)) {
+ os_free(buf);
+ return NULL;
+ }
+
+ return buf;
+}
+
+#endif /* !CONFIG_CTRL_IFACE_UDP */
+
+
+int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld)
+{
+#ifndef CONFIG_CTRL_IFACE_UDP
+ struct sockaddr_un addr;
+ int s = -1;
+ char *fname = NULL;
+
+ if (!mld)
+ return -1;
+
+ if (mld->ctrl_sock > -1) {
+ wpa_printf(MSG_DEBUG, "MLD %s ctrl_iface already exists!",
+ mld->name);
+ return 0;
+ }
+
+ dl_list_init(&mld->ctrl_dst);
+
+ if (!mld->ctrl_interface)
+ return 0;
+
+ if (mkdir(mld->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+ if (errno == EEXIST) {
+ wpa_printf(MSG_DEBUG,
+ "Using existing control interface directory.");
+ } else {
+ wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
+ strerror(errno));
+ goto fail;
+ }
+ }
+
+ if (os_strlen(mld->ctrl_interface) + 1 + os_strlen(mld->name) >=
+ sizeof(addr.sun_path))
+ goto fail;
+
+ s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
+ goto fail;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+ addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+ addr.sun_family = AF_UNIX;
+
+ fname = hostapd_mld_ctrl_iface_path(mld);
+ if (!fname)
+ goto fail;
+
+ os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+
+ wpa_printf(MSG_DEBUG, "Setting up MLD %s ctrl_iface", mld->name);
+
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+ strerror(errno));
+ if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not allow connections - assuming it was left over from forced program termination");
+ if (unlink(fname) < 0) {
+ wpa_printf(MSG_ERROR,
+ "Could not unlink existing ctrl_iface socket '%s': %s",
+ fname, strerror(errno));
+ goto fail;
+ }
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+ 0) {
+ wpa_printf(MSG_ERROR,
+ "hostapd-ctrl-iface: bind(PF_UNIX): %s",
+ strerror(errno));
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG,
+ "Successfully replaced leftover ctrl_iface socket '%s'",
+ fname);
+ } else {
+ wpa_printf(MSG_INFO,
+ "ctrl_iface exists and seems to be in use - cannot override it");
+ wpa_printf(MSG_INFO,
+ "Delete '%s' manually if it is not used anymore", fname);
+ os_free(fname);
+ fname = NULL;
+ goto fail;
+ }
+ }
+
+ if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+ wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
+ strerror(errno));
+ goto fail;
+ }
+ os_free(fname);
+
+ mld->ctrl_sock = s;
+
+ if (eloop_register_read_sock(s, hostapd_mld_ctrl_iface_receive, mld,
+ NULL) < 0)
+ return -1;
+
+ return 0;
+
+fail:
+ if (s >= 0)
+ close(s);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+ return -1;
+#endif /* !CONFIG_CTRL_IFACE_UDP */
+ return 0;
+}
+
+
+void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld)
+{
+#ifndef CONFIG_CTRL_IFACE_UDP
+ struct wpa_ctrl_dst *dst, *prev;
+
+ if (mld->ctrl_sock > -1) {
+ char *fname;
+
+ eloop_unregister_read_sock(mld->ctrl_sock);
+ close(mld->ctrl_sock);
+ mld->ctrl_sock = -1;
+
+ fname = hostapd_mld_ctrl_iface_path(mld);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+
+ if (mld->ctrl_interface &&
+ rmdir(mld->ctrl_interface) < 0) {
+ if (errno == ENOTEMPTY) {
+ wpa_printf(MSG_DEBUG,
+ "MLD control interface directory not empty - leaving it behind");
+ } else {
+ wpa_printf(MSG_ERROR,
+ "rmdir[ctrl_interface=%s]: %s",
+ mld->ctrl_interface,
+ strerror(errno));
+ }
+ }
+ }
+
+ dl_list_for_each_safe(dst, prev, &mld->ctrl_dst, struct wpa_ctrl_dst,
+ list)
+ os_free(dst);
+#endif /* !CONFIG_CTRL_IFACE_UDP */
+
+ os_free(mld->ctrl_interface);
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
#ifndef CONFIG_CTRL_IFACE_UDP
static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
{
char *buf;
size_t len;
+ const char *ctrl_sock_iface;
+
+#ifdef CONFIG_IEEE80211BE
+ ctrl_sock_iface = hapd->ctrl_sock_iface;
+#else /* CONFIG_IEEE80211BE */
+ ctrl_sock_iface = hapd->conf->iface;
+#endif /* CONFIG_IEEE80211BE */
if (hapd->conf->ctrl_interface == NULL)
return NULL;
len = os_strlen(hapd->conf->ctrl_interface) +
- os_strlen(hapd->conf->iface) + 2;
+ os_strlen(ctrl_sock_iface) + 2;
+
buf = os_malloc(len);
if (buf == NULL)
return NULL;
os_snprintf(buf, len, "%s/%s",
- hapd->conf->ctrl_interface, hapd->conf->iface);
+ hapd->conf->ctrl_interface, ctrl_sock_iface);
buf[len - 1] = '\0';
return buf;
}
@@ -4818,6 +5207,7 @@
struct sockaddr_un addr;
int s = -1;
char *fname = NULL;
+ size_t iflen;
if (hapd->ctrl_sock > -1) {
wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
@@ -4872,8 +5262,13 @@
}
#endif /* ANDROID */
+#ifdef CONFIG_IEEE80211BE
+ iflen = os_strlen(hapd->ctrl_sock_iface);
+#else /* CONFIG_IEEE80211BE */
+ iflen = os_strlen(hapd->conf->iface);
+#endif /* CONFIG_IEEE80211BE */
if (os_strlen(hapd->conf->ctrl_interface) + 1 +
- os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
+ iflen >= sizeof(addr.sun_path))
goto fail;
s = socket(PF_UNIX, SOCK_DGRAM, 0);
diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h
index 3341a66..6ce209d 100644
--- a/hostapd/ctrl_iface.h
+++ b/hostapd/ctrl_iface.h
@@ -14,6 +14,8 @@
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface);
void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface);
+int hostapd_mld_ctrl_iface_init(struct hostapd_mld *mld);
+void hostapd_mld_ctrl_iface_deinit(struct hostapd_mld *mld);
#else /* CONFIG_NO_CTRL_IFACE */
static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
{
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 24f3986..93524cf 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -2333,6 +2333,15 @@
#rsn_override_pairwise_2
#rsn_override_mfp_2
#
+# The RSNXE is normally included if any of the extended RSN capabilities is
+# enabled/supported. When using RSN overriding, a separate RSNXOE is included
+# and it may be more interoperable to omit the RSNXE completely. This
+# configuration parameter can be used to do that.
+# 0 = Include the RSNXE if any extended RSN capability is enabled/supported
+# (default).
+# 1 = Do not include the RSNXE.
+#rsn_override_omit_rsnxe=0
+#
# Example configuration for WPA2-Personal/PMF-optional in RSNE and
# WPA3-Personal/PMF-required/MLO in override elements
#wpa_key_mgmt=WPA-PSK
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index eb8a383..57702d9 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -54,7 +54,11 @@
fprintf(stderr, "%s\n", hostapd_cli_version);
fprintf(stderr,
"\n"
- "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvBr] "
+ "usage: hostapd_cli [-p<path>] [-i<ifname>] "
+#ifdef CONFIG_IEEE80211BE
+ "[-l<link_id>] "
+#endif /* CONFIG_IEEE80211BE */
+ "[-hvBr] "
"[-a<path>] \\\n"
" [-P<pid file>] [-G<ping interval>] [command..]\n"
"\n"
@@ -74,7 +78,11 @@
" -B run a daemon in the background\n"
" -i<ifname> Interface to listen on (default: first "
"interface found in the\n"
- " socket path)\n\n");
+ " socket path)\n"
+#ifdef CONFIG_IEEE80211BE
+ " -l<link_id> Link ID of the interface in case of Multi-Link Operation\n"
+#endif /* CONFIG_IEEE80211BE */
+ "\n");
print_help(stderr, NULL);
}
@@ -2212,12 +2220,15 @@
int c;
int daemonize = 0;
int reconnect = 0;
+#ifdef CONFIG_IEEE80211BE
+ int link_id = -1;
+#endif /* CONFIG_IEEE80211BE */
if (os_program_init())
return -1;
for (;;) {
- c = getopt(argc, argv, "a:BhG:i:p:P:rs:v");
+ c = getopt(argc, argv, "a:BhG:i:l:p:P:rs:v");
if (c < 0)
break;
switch (c) {
@@ -2252,6 +2263,11 @@
case 's':
client_socket_dir = optarg;
break;
+#ifdef CONFIG_IEEE80211BE
+ case 'l':
+ link_id = atoi(optarg);
+ break;
+#endif /* CONFIG_IEEE80211BE */
default:
usage();
return -1;
@@ -2285,6 +2301,24 @@
closedir(dir);
}
}
+
+#ifdef CONFIG_IEEE80211BE
+ if (link_id >= 0 && ctrl_ifname) {
+ int ret;
+ char buf[300];
+
+ ret = os_snprintf(buf, sizeof(buf), "%s_%s%d",
+ ctrl_ifname, WPA_CTRL_IFACE_LINK_NAME,
+ link_id);
+ if (os_snprintf_error(sizeof(buf), ret))
+ return -1;
+
+ os_free(ctrl_ifname);
+ ctrl_ifname = os_strdup(buf);
+ link_id = -1;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
hostapd_cli_reconnect(ctrl_ifname);
if (ctrl_conn) {
if (warning_displayed)
diff --git a/hostapd/main.c b/hostapd/main.c
index 640a169..50b9f04 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -193,7 +193,6 @@
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);
@@ -280,7 +279,6 @@
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);
}
@@ -340,8 +338,14 @@
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);
+ if (hostapd_drv_link_add(hapd, hapd->mld_link_id,
+ hapd->own_addr)) {
+ wpa_printf(MSG_ERROR,
+ "MLD: Failed to add link %d in MLD %s",
+ hapd->mld_link_id, hapd->conf->iface);
+ return -1;
+ }
+ hostapd_mld_add_link(hapd);
}
#endif /* CONFIG_IEEE80211BE */
@@ -757,6 +761,7 @@
if (!interfaces->mld[i])
continue;
+ interfaces->mld_ctrl_iface_deinit(interfaces->mld[i]);
os_free(interfaces->mld[i]);
interfaces->mld[i] = NULL;
}
@@ -802,6 +807,10 @@
interfaces.global_iface_path = NULL;
interfaces.global_iface_name = NULL;
interfaces.global_ctrl_sock = -1;
+#ifdef CONFIG_IEEE80211BE
+ interfaces.mld_ctrl_iface_init = hostapd_mld_ctrl_iface_init;
+ interfaces.mld_ctrl_iface_deinit = hostapd_mld_ctrl_iface_deinit;
+#endif /* CONFIG_IEEE80211BE */
dl_list_init(&interfaces.global_ctrl_dst);
#ifdef CONFIG_ETH_P_OUI
dl_list_init(&interfaces.eth_p_oui);
diff --git a/hs20/client/Android.bp b/hs20/client/Android.bp
new file mode 100644
index 0000000..3c8383c
--- /dev/null
+++ b/hs20/client/Android.bp
@@ -0,0 +1,61 @@
+//
+// Copyright (C) 2024 The Android Open Source Project
+//
+// 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.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "external_wpa_supplicant_8_license",
+ ],
+}
+
+cc_binary {
+ name: "hs20-osu-client",
+ vendor: true,
+ srcs: [
+ ":hs20_client_srcs",
+ ],
+ shared_libs: [
+ "libc",
+ "libcrypto",
+ "libcurl",
+ "libcutils",
+ "liblog",
+ "libssl",
+ "libxml2",
+ ],
+ cflags: [
+ "-DCONFIG_CTRL_IFACE",
+ "-DCONFIG_CTRL_IFACE_UNIX",
+ "-DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"",
+ "-DCONFIG_DEBUG_FILE",
+ "-DEAP_TLS_OPENSSL",
+ "-Wno-unused-parameter",
+ "-DCONFIG_ANDROID_LOG",
+ "-DANDROID_LOG_NAME=\"hs20-osu-client\"",
+ ],
+ local_include_dirs: [
+ ".",
+ ],
+ include_dirs: [
+ "external/curl/include",
+ "external/libxml2/include",
+ "external/wpa_supplicant_8/src",
+ "external/wpa_supplicant_8/src/common",
+ "external/wpa_supplicant_8/src/utils",
+ ],
+ defaults: [
+ "wpa_supplicant_cflags_default",
+ ],
+}
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index a5a821b..c8fbb6a 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -493,6 +493,8 @@
#ifdef CONFIG_SAE
struct hostapd_ssid *ssid = &conf->ssid;
struct sae_password_entry *pw;
+ int *groups = conf->sae_groups;
+ int default_groups[] = { 19, 0, 0 };
if ((conf->sae_pwe == SAE_PWE_HUNT_AND_PECK &&
!hostapd_sae_pw_id_in_use(conf) &&
@@ -506,11 +508,18 @@
conf->rsn_override_key_mgmt_2))
return 0; /* PT not needed */
+ if (!groups) {
+ groups = default_groups;
+ if (wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt |
+ conf->rsn_override_key_mgmt |
+ conf->rsn_override_key_mgmt_2))
+ default_groups[1] = 20;
+ }
+
sae_deinit_pt(ssid->pt);
ssid->pt = NULL;
if (ssid->wpa_passphrase) {
- ssid->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
- ssid->ssid_len,
+ ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
(const u8 *) ssid->wpa_passphrase,
os_strlen(ssid->wpa_passphrase),
NULL);
@@ -520,8 +529,7 @@
for (pw = conf->sae_passwords; pw; pw = pw->next) {
sae_deinit_pt(pw->pt);
- pw->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
- ssid->ssid_len,
+ pw->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
(const u8 *) pw->password,
os_strlen(pw->password),
pw->identifier);
@@ -966,6 +974,11 @@
#ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(conf->own_ie_override);
+ wpabuf_free(conf->rsne_override);
+ wpabuf_free(conf->rsnoe_override);
+ wpabuf_free(conf->rsno2e_override);
+ wpabuf_free(conf->rsnxe_override);
+ wpabuf_free(conf->rsnxoe_override);
wpabuf_free(conf->sae_commit_override);
wpabuf_free(conf->rsne_override_eapol);
wpabuf_free(conf->rsnxe_override_eapol);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 1a4c912..55f3b64 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -396,6 +396,8 @@
int rsn_preauth;
char *rsn_preauth_interfaces;
+ int rsn_override_omit_rsnxe;
+
#ifdef CONFIG_IEEE80211R_AP
/* IEEE 802.11r - Fast BSS Transition */
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
@@ -694,6 +696,11 @@
u8 bss_load_test[5];
u8 bss_load_test_set;
struct wpabuf *own_ie_override;
+ struct wpabuf *rsne_override;
+ struct wpabuf *rsnoe_override;
+ struct wpabuf *rsno2e_override;
+ struct wpabuf *rsnxe_override;
+ struct wpabuf *rsnxoe_override;
int sae_reflection_attack;
int sae_commit_status;
int sae_pk_omit;
@@ -718,6 +725,7 @@
struct wpabuf *eapol_m1_elements;
struct wpabuf *eapol_m3_elements;
bool eapol_m3_no_encrypt;
+ bool eapol_key_reserved_random;
int test_assoc_comeback_type;
struct wpabuf *presp_elements;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index c473491..92dbc16 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -1250,3 +1250,14 @@
return hapd->driver->set_secure_ranging_ctx(hapd->drv_priv, ¶ms);
}
#endif /* CONFIG_PASN */
+
+
+struct hostapd_multi_hw_info *
+hostapd_get_multi_hw_info(struct hostapd_data *hapd,
+ unsigned int *num_multi_hws)
+{
+ if (!hapd->driver || !hapd->driver->get_multi_hw_info)
+ return NULL;
+
+ return hapd->driver->get_multi_hw_info(hapd->drv_priv, num_multi_hws);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index d7e79c8..6b7f02a 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -478,4 +478,8 @@
#endif /* CONFIG_IEEE80211BE */
+struct hostapd_multi_hw_info *
+hostapd_get_multi_hw_info(struct hostapd_data *hapd,
+ unsigned int *num_multi_hws);
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index f8ce810..2e3d904 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -514,6 +514,35 @@
}
+static u8 * hostapd_eid_max_cs_time(struct hostapd_data *hapd, u8 *eid)
+{
+#ifdef CONFIG_IEEE80211BE
+ u32 switch_time;
+
+ /* Add Max Channel Switch Time element only if this AP is affiliated
+ * with an AP MLD and channel switch is in process. */
+ if (!hapd->conf->mld_ap || !hapd->cs_freq_params.channel)
+ return eid;
+
+ /* Switch time is basically time between CSA count 1 and CSA count
+ * 0 (1 beacon interval) + time for interface restart + time to
+ * send a Beacon frame in the new channel (1 beacon interval).
+ *
+ * TODO: Use dynamic interface restart time. For now, assume 1 sec.
+ */
+ switch_time = USEC_TO_TU(1000 * 1000) + 2 * hapd->iconf->beacon_int;
+
+ *eid++ = WLAN_EID_EXTENSION;
+ *eid++ = 4;
+ *eid++ = WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME;
+ WPA_PUT_LE24(eid, switch_time);
+ eid += 3;
+#endif /* CONFIG_IEEE80211BE */
+
+ return eid;
+}
+
+
static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
{
u8 op_class, channel;
@@ -676,7 +705,6 @@
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;
@@ -698,7 +726,7 @@
#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 */
@@ -737,17 +765,21 @@
#ifdef CONFIG_IEEE80211BE
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ struct hostapd_data *ml_elem_ap =
+ params->mld_ap ? params->mld_ap : hapd;
+
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;
-
+ if (ml_elem_ap->conf->mld_ap) {
buflen += hostapd_eid_eht_ml_beacon_len(
ml_elem_ap, params->mld_info, !!params->mld_ap);
+
+ /* For Max Channel Switch Time element during channel
+ * switch */
+ buflen += 6;
}
}
#endif /* CONFIG_IEEE80211BE */
@@ -755,9 +787,7 @@
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_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);
@@ -778,13 +808,11 @@
epos = pos + 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;
- }
+ *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);
@@ -797,18 +825,13 @@
/* Power Constraint element */
pos = hostapd_eid_pwr_constraint(hapd, 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;
- }
+ /* CSA element */
+ 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);
@@ -824,18 +847,13 @@
pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
pos = hostapd_get_mde(hapd, pos, epos - 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;
- }
+ /* eCSA element */
+ 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);
@@ -877,12 +895,14 @@
pos = hostapd_eid_txpower_envelope(hapd, pos);
#endif /* CONFIG_IEEE80211AX */
- pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
+ pos = hostapd_eid_chsw_wrapper(hapd, pos);
- if (!params->is_ml_sta_info)
- pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP,
- true);
+ pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP, true);
pos = hostapd_eid_fils_indic(hapd, pos, 0);
+
+ /* Max Channel Switch Time element */
+ pos = hostapd_eid_max_cs_time(hapd, pos);
+
pos = hostapd_get_rsnxe(hapd, pos, epos - pos);
#ifdef CONFIG_IEEE80211AX
@@ -1039,7 +1059,6 @@
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;
@@ -1053,10 +1072,7 @@
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
@@ -1076,49 +1092,12 @@
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);
+ os_memcpy(link_info, &hapd->partner_links[mld_link_id],
+ sizeof(hapd->partner_links[mld_link_id]));
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);
+ "MLD: ML probe response includes link STA info for %d: %u bytes",
+ mld_link_id, link_info->resp_sta_profile_len);
}
if (mld_id != -1 && !params->mld_ap) {
@@ -1685,7 +1664,6 @@
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);
@@ -1766,7 +1744,6 @@
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;
@@ -1810,7 +1787,6 @@
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;
@@ -2188,7 +2164,7 @@
#ifdef NEED_AP_MLME
#define BEACON_HEAD_BUF_SIZE 256
-#define BEACON_TAIL_BUF_SIZE 512
+#define BEACON_TAIL_BUF_SIZE 1500
head = os_zalloc(BEACON_HEAD_BUF_SIZE);
tail_len = BEACON_TAIL_BUF_SIZE;
#ifdef CONFIG_WPS
@@ -2227,8 +2203,13 @@
* long based on the common info and number of per
* station profiles. For now use 256.
*/
- if (hapd->conf->mld_ap)
+ if (hapd->conf->mld_ap) {
tail_len += 256;
+
+ /* for Max Channel Switch Time element during channel
+ * switch */
+ tail_len += 6;
+ }
}
#endif /* CONFIG_IEEE80211BE */
@@ -2372,10 +2353,14 @@
tailpos = hostapd_eid_txpower_envelope(hapd, tailpos);
#endif /* CONFIG_IEEE80211AX */
- tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
+ tailpos = hostapd_eid_chsw_wrapper(hapd, tailpos);
tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON, true);
tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
+
+ /* Max Channel Switch Time element */
+ tailpos = hostapd_eid_max_cs_time(hapd, tailpos);
+
tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos);
tailpos = hostapd_eid_mbssid_config(hapd, tailpos,
params->mbssid_elem_count);
@@ -2775,12 +2760,438 @@
}
+#ifdef CONFIG_IEEE80211BE
+
+static int hostapd_get_probe_resp_tmpl(struct hostapd_data *hapd,
+ struct probe_resp_params *params,
+ bool is_ml_sta_info)
+{
+ os_memset(params, 0, sizeof(*params));
+ hostapd_gen_probe_resp(hapd, params);
+ if (!params->resp)
+ return -1;
+
+ /* The caller takes care of freeing params->resp. */
+ return 0;
+}
+
+
+static bool is_restricted_eid_in_sta_profile(u8 eid, bool tx_vap)
+{
+ switch (eid) {
+ case WLAN_EID_TIM:
+ case WLAN_EID_BSS_MAX_IDLE_PERIOD:
+ case WLAN_EID_MULTIPLE_BSSID:
+ case WLAN_EID_REDUCED_NEIGHBOR_REPORT:
+ case WLAN_EID_NEIGHBOR_REPORT:
+ return true;
+ case WLAN_EID_SSID:
+ /* SSID is not restricted for non-transmitted BSSID */
+ return tx_vap;
+ default:
+ return false;
+ }
+}
+
+
+static bool is_restricted_ext_eid_in_sta_profile(u8 ext_id)
+{
+ switch (ext_id) {
+ case WLAN_EID_EXT_MULTI_LINK:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+/* Create the link STA profiles based on inheritance from the reporting
+ * profile.
+ *
+ * NOTE: The same function is used for length calculation as well as filling
+ * data in the given buffer. This avoids risk of not updating the length
+ * function but filling function or vice versa.
+ */
+static size_t hostapd_add_sta_profile(struct ieee80211_mgmt *link_fdata,
+ size_t link_data_len,
+ struct ieee80211_mgmt *own_fdata,
+ size_t own_data_len,
+ u8 *sta_profile, bool tx_vap)
+{
+ const struct element *link_elem;
+ size_t sta_profile_len = 0;
+ const u8 *link_elem_data;
+ u8 link_ele_len;
+ u8 *link_data;
+ const struct element *own_elem;
+ u8 link_eid, own_eid, own_ele_len;
+ const u8 *own_elem_data;
+ u8 *own_data;
+ bool is_ext;
+ bool ie_found;
+ u8 non_inherit_ele_ext_list[256] = { 0 };
+ u8 non_inherit_ele_ext_list_len = 0;
+ u8 non_inherit_ele_list[256] = { 0 };
+ u8 non_inherit_ele_list_len = 0;
+ u8 num_link_elem_vendor_ies = 0, num_own_elem_vendor_ies = 0;
+ bool add_vendor_ies = false, is_identical_vendor_ies = true;
+ /* The bitmap of parsed EIDs. There are 256 EIDs and ext EIDs, so 32
+ * bytes to store the bitmaps. */
+ u8 parsed_eid_bmap[32] = { 0 }, parsed_ext_eid_bmap[32] = { 0 };
+ /* extra len used in the logic includes the element id and len */
+ u8 extra_len = 2;
+
+ /* Include len for capab info */
+ sta_profile_len += sizeof(le16);
+ if (sta_profile) {
+ os_memcpy(sta_profile, &link_fdata->u.probe_resp.capab_info,
+ sizeof(le16));
+ sta_profile += sizeof(le16);
+ }
+
+ own_data = own_fdata->u.probe_resp.variable;
+ link_data = link_fdata->u.probe_resp.variable;
+
+ /* The below logic takes the reporting BSS data and reported BSS data
+ * and performs intersection to build the STA profile of the reported
+ * BSS. Certain elements are not added to the STA profile as
+ * recommended in standard. Matching element information in the
+ * reporting BSS profile are ignored in the STA profile. Remaining
+ * elements pertaining to the STA profile are appended at the end. */
+ for_each_element(own_elem, own_data, own_data_len) {
+ is_ext = false;
+ ie_found = false;
+
+ /* Pick one of own elements and get its EID and length */
+ own_elem_data = own_elem->data;
+ own_ele_len = own_elem->datalen;
+
+ if (own_elem->id == WLAN_EID_EXTENSION) {
+ is_ext = true;
+ own_eid = *(own_elem_data);
+ if (is_restricted_ext_eid_in_sta_profile(own_eid))
+ continue;
+ } else {
+ own_eid = own_elem->id;
+ if (is_restricted_eid_in_sta_profile(own_eid, tx_vap))
+ continue;
+ }
+
+ for_each_element(link_elem, link_data, link_data_len) {
+ /* If the element type mismatches, do not consider
+ * this link element for comparison. */
+ if ((link_elem->id == WLAN_EID_EXTENSION &&
+ !is_ext) ||
+ (is_ext && link_elem->id != WLAN_EID_EXTENSION))
+ continue;
+
+ /* Comparison can be done so get the link element and
+ * its EID and length. */
+ link_elem_data = link_elem->data;
+ link_ele_len = link_elem->datalen;
+
+ if (link_elem->id == WLAN_EID_EXTENSION)
+ link_eid = *(link_elem_data);
+ else
+ link_eid = link_elem->id;
+
+ /* Ignore if EID does not match */
+ if (own_eid != link_eid)
+ continue;
+
+ ie_found = true;
+
+ /* Ignore if the contents is identical. */
+ if (own_ele_len == link_ele_len &&
+ os_memcmp(own_elem->data, link_elem->data,
+ own_ele_len) == 0) {
+ if (own_eid == WLAN_EID_VENDOR_SPECIFIC) {
+ is_identical_vendor_ies = true;
+ num_own_elem_vendor_ies++;
+ }
+ continue;
+ }
+
+ /* No need to include this non-matching Vendor Specific
+ * element explicitly at this point. */
+ if (own_eid == WLAN_EID_VENDOR_SPECIFIC) {
+ is_identical_vendor_ies = false;
+ continue;
+ }
+
+ /* This element is present in the reported profile
+ * as well as present in the reporting profile.
+ * However, there is a mismatch in the contents and
+ * hence, include this in the per STA profile. */
+ sta_profile_len += link_ele_len + extra_len;
+ if (sta_profile) {
+ os_memcpy(sta_profile,
+ link_elem->data - extra_len,
+ link_ele_len + extra_len);
+ sta_profile += link_ele_len + extra_len;
+ }
+
+ /* Update the parsed EIDs bitmap */
+ if (is_ext)
+ parsed_ext_eid_bmap[own_eid / 8] |=
+ BIT(own_eid % 8);
+ else
+ parsed_eid_bmap[own_eid / 8] |=
+ BIT(own_eid % 8);
+ break;
+ }
+
+ /* We found at least one Vendor Specific element in reporting
+ * link which is not same (or present) in the reported link. We
+ * need to include all Vendor Specific elements from the
+ * reported link. */
+ if (!is_identical_vendor_ies)
+ add_vendor_ies = true;
+
+ /* This is a unique element in the reporting profile which is
+ * not present in the reported profile. Update the
+ * non-inheritance list. */
+ if (!ie_found) {
+ u8 idx;
+
+ if (is_ext) {
+ idx = non_inherit_ele_ext_list_len++;
+ non_inherit_ele_ext_list[idx] = own_eid;
+ } else {
+ idx = non_inherit_ele_list_len++;
+ non_inherit_ele_list[idx] = own_eid;
+ }
+ }
+ }
+
+ /* Parse the remaining elements in the reported profile */
+ for_each_element(link_elem, link_data, link_data_len) {
+ link_elem_data = link_elem->data;
+ link_ele_len = link_elem->datalen;
+
+ /* No need to check this Vendor Specific element at this point.
+ * Just take the count and continue. */
+ if (link_elem->id == WLAN_EID_VENDOR_SPECIFIC) {
+ num_link_elem_vendor_ies++;
+ continue;
+ }
+
+ if (link_elem->id == WLAN_EID_EXTENSION) {
+ link_eid = *(link_elem_data);
+
+ if ((parsed_ext_eid_bmap[link_eid / 8] &
+ BIT(link_eid % 8)) ||
+ is_restricted_ext_eid_in_sta_profile(link_eid))
+ continue;
+ } else {
+ link_eid = link_elem->id;
+
+ if ((parsed_eid_bmap[link_eid / 8] &
+ BIT(link_eid % 8)) ||
+ is_restricted_eid_in_sta_profile(link_eid, tx_vap))
+ continue;
+ }
+
+ sta_profile_len += link_ele_len + extra_len;
+ if (sta_profile) {
+ os_memcpy(sta_profile, link_elem_data - extra_len,
+ link_ele_len + extra_len);
+ sta_profile += link_ele_len + extra_len;
+ }
+ }
+
+ /* Handle Vendor Specific elements
+ * Add all the Vendor Specific elements of the reported link if
+ * a. There is at least one non-matching Vendor Specific element, or
+ * b. The number of Vendor Specific elements in reporting and reported
+ * link is not same. */
+ if (add_vendor_ies ||
+ num_own_elem_vendor_ies != num_link_elem_vendor_ies) {
+ for_each_element(link_elem, link_data, link_data_len) {
+ link_elem_data = link_elem->data;
+ link_ele_len = link_elem->datalen;
+
+ if (link_elem->id != WLAN_EID_VENDOR_SPECIFIC)
+ continue;
+
+ sta_profile_len += link_ele_len + extra_len;
+ if (sta_profile) {
+ os_memcpy(sta_profile,
+ link_elem_data - extra_len,
+ link_ele_len + extra_len);
+ sta_profile += link_ele_len + extra_len;
+ }
+ }
+ }
+
+ /* Handle non-inheritance
+ * Non-Inheritance element:
+ * Element ID Ext: 1 octet
+ * Length: 1 octet
+ * Ext tag number: 1 octet
+ * Length of Elements ID list: 1 octet
+ * Elements ID list: variable
+ * Length of Elements ID Extension list: 1 octet
+ * Elements ID extensions list: variable
+ */
+ if (non_inherit_ele_list_len || non_inherit_ele_ext_list_len)
+ sta_profile_len += 3 + 2 + non_inherit_ele_list_len +
+ non_inherit_ele_ext_list_len;
+
+ if (sta_profile &&
+ (non_inherit_ele_list_len || non_inherit_ele_ext_list_len)) {
+ *sta_profile++ = WLAN_EID_EXTENSION;
+ *sta_profile++ = non_inherit_ele_list_len +
+ non_inherit_ele_ext_list_len + 3;
+ *sta_profile++ = WLAN_EID_EXT_NON_INHERITANCE;
+ *sta_profile++ = non_inherit_ele_list_len;
+ os_memcpy(sta_profile, non_inherit_ele_list,
+ non_inherit_ele_list_len);
+ sta_profile += non_inherit_ele_list_len;
+ *sta_profile++ = non_inherit_ele_ext_list_len;
+ os_memcpy(sta_profile, non_inherit_ele_ext_list,
+ non_inherit_ele_ext_list_len);
+ sta_profile += non_inherit_ele_ext_list_len;
+ }
+
+ return sta_profile_len;
+}
+
+
+static u8 * hostapd_gen_sta_profile(struct ieee80211_mgmt *link_data,
+ size_t link_data_len,
+ struct ieee80211_mgmt *own_data,
+ size_t own_data_len,
+ size_t *sta_profile_len, bool tx_vap)
+{
+ u8 *sta_profile;
+
+ /* Get the length first */
+ *sta_profile_len = hostapd_add_sta_profile(link_data, link_data_len,
+ own_data, own_data_len,
+ NULL, tx_vap);
+ if (!(*sta_profile_len) || *sta_profile_len > EHT_ML_MAX_STA_PROF_LEN)
+ return NULL;
+
+ sta_profile = os_zalloc(*sta_profile_len);
+ if (!sta_profile)
+ return NULL;
+
+ /* Now fill in the data */
+ hostapd_add_sta_profile(link_data, link_data_len, own_data,
+ own_data_len, sta_profile, tx_vap);
+
+ /* The caller takes care of freeing the returned sta_profile */
+ return sta_profile;
+}
+
+
+static void hostapd_gen_per_sta_profiles(struct hostapd_data *hapd)
+{
+ bool tx_vap = hapd == hostapd_mbssid_get_tx_bss(hapd);
+ size_t link_data_len, sta_profile_len;
+ size_t own_data_len;
+ struct probe_resp_params link_params;
+ struct probe_resp_params own_params;
+ struct ieee80211_mgmt *link_data;
+ struct ieee80211_mgmt *own_data;
+ struct mld_link_info *link_info;
+ struct hostapd_data *link_bss;
+ u8 link_id, *sta_profile;
+
+ if (!hapd->conf->mld_ap)
+ return;
+
+ wpa_printf(MSG_DEBUG, "MLD: Generating per STA profiles for MLD %s",
+ hapd->conf->iface);
+
+ wpa_printf(MSG_DEBUG, "MLD: Reporting link %d", hapd->mld_link_id);
+
+ /* Generate a Probe Response template for self */
+ if (hostapd_get_probe_resp_tmpl(hapd, &own_params, false)) {
+ wpa_printf(MSG_ERROR,
+ "MLD: Error in building per STA profiles");
+ return;
+ }
+
+ own_data = own_params.resp;
+ own_data_len = own_params.resp_len;
+
+ /* Consider the length of the variable fields */
+ own_data_len -= offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+
+ for_each_mld_link(link_bss, hapd) {
+ if (link_bss == hapd || !link_bss->started)
+ continue;
+
+ link_id = link_bss->mld_link_id;
+ if (link_id >= MAX_NUM_MLD_LINKS)
+ continue;
+
+ sta_profile = NULL;
+ sta_profile_len = 0;
+
+ /* Generate a Probe Response frame template for partner link */
+ if (hostapd_get_probe_resp_tmpl(link_bss, &link_params, true)) {
+ wpa_printf(MSG_ERROR,
+ "MLD: Could not get link STA probe response template for link %d",
+ link_id);
+ continue;
+ }
+
+ link_data = link_params.resp;
+ link_data_len = link_params.resp_len;
+
+ /* Consider length of the variable fields */
+ link_data_len -= offsetof(struct ieee80211_mgmt,
+ u.probe_resp.variable);
+
+ sta_profile = hostapd_gen_sta_profile(link_data, link_data_len,
+ own_data, own_data_len,
+ &sta_profile_len, tx_vap);
+ if (!sta_profile) {
+ wpa_printf(MSG_ERROR,
+ "MLD: Could not generate link STA profile for link %d",
+ link_id);
+ continue;
+ }
+
+ link_info = &hapd->partner_links[link_id];
+ link_info->valid = true;
+
+ os_free(link_info->resp_sta_profile);
+ link_info->resp_sta_profile_len = sta_profile_len;
+
+ link_info->resp_sta_profile = os_memdup(sta_profile,
+ sta_profile_len);
+ if (!link_info->resp_sta_profile)
+ link_info->resp_sta_profile_len = 0;
+
+ os_memcpy(link_info->local_addr, link_bss->own_addr, ETH_ALEN);
+
+ wpa_printf(MSG_DEBUG,
+ "MLD: Reported link STA info for %d: %u bytes",
+ link_id, link_info->resp_sta_profile_len);
+
+ os_free(sta_profile);
+ os_free(link_params.resp);
+ }
+
+ os_free(own_params.resp);
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
int ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct hostapd_iface *iface = hapd->iface;
int ret;
size_t i, j;
bool is_6g, hapd_mld = false;
+#ifdef CONFIG_IEEE80211BE
+ struct hostapd_data *link_bss;
+#endif /* CONFIG_IEEE80211BE */
ret = __ieee802_11_set_beacon(hapd);
if (ret != 0)
@@ -2821,6 +3232,15 @@
}
}
+#ifdef CONFIG_IEEE80211BE
+ if (!hapd_mld)
+ return 0;
+
+ /* Generate per STA profiles for each affiliated APs */
+ for_each_mld_link(link_bss, hapd)
+ hostapd_gen_per_sta_profiles(link_bss);
+#endif /* CONFIG_IEEE80211BE */
+
return 0;
}
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index d4d73de..b93a5d2 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -661,15 +661,18 @@
}
#endif /* CONFIG_P2P_MANAGER */
- if (os_strstr(txtaddr, " tx=0"))
- hostapd_drv_sta_remove(hapd, addr);
- else
- hostapd_drv_sta_deauth(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
- if (sta)
- ap_sta_deauthenticate(hapd, sta, reason);
- else if (addr[0] == 0xff)
- hostapd_free_stas(hapd);
+ if (os_strstr(txtaddr, " tx=0")) {
+ hostapd_drv_sta_remove(hapd, addr);
+ if (sta)
+ ap_free_sta(hapd, sta);
+ } else {
+ hostapd_drv_sta_deauth(hapd, addr, reason);
+ if (sta)
+ ap_sta_deauthenticate(hapd, sta, reason);
+ else if (addr[0] == 0xff)
+ hostapd_free_stas(hapd);
+ }
return 0;
}
@@ -723,15 +726,18 @@
}
#endif /* CONFIG_P2P_MANAGER */
- if (os_strstr(txtaddr, " tx=0"))
- hostapd_drv_sta_remove(hapd, addr);
- else
- hostapd_drv_sta_disassoc(hapd, addr, reason);
sta = ap_get_sta(hapd, addr);
- if (sta)
- ap_sta_disassociate(hapd, sta, reason);
- else if (addr[0] == 0xff)
- hostapd_free_stas(hapd);
+ if (os_strstr(txtaddr, " tx=0")) {
+ hostapd_drv_sta_remove(hapd, addr);
+ if (sta)
+ ap_free_sta(hapd, sta);
+ } else {
+ hostapd_drv_sta_disassoc(hapd, addr, reason);
+ if (sta)
+ ap_sta_disassociate(hapd, sta, reason);
+ else if (addr[0] == 0xff)
+ hostapd_free_stas(hapd);
+ }
return 0;
}
@@ -1137,8 +1143,9 @@
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->freq_params.he_enabled = !!os_strstr(pos, " he") ||
+ settings->freq_params.eht_enabled;
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
#undef SET_CSA_SETTING_EXT
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index af9dc16..0cac194 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -253,6 +253,13 @@
for (i = 0; i < mode->num_channels; i++) {
chan = &mode->channels[i];
+ if (!chan_in_current_hw_info(iface->current_hw_info, chan)) {
+ wpa_printf(MSG_DEBUG,
+ "DFS: channel %d (%d) is not under current hardware index",
+ chan->freq, chan->chan);
+ continue;
+ }
+
/* Skip HT40/VHT incompatible channels */
if (iface->conf->ieee80211n &&
iface->conf->secondary_channel &&
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 233984f..05adc41 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -73,6 +73,8 @@
p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
elems.fils_session,
sta->fils_hlp_resp);
+ if (!p)
+ return;
reply_res = hostapd_sta_assoc(hapd, sta->addr,
sta->fils_pending_assoc_is_reassoc,
@@ -248,6 +250,52 @@
#endif /* CONFIG_IEEE80211BE */
+#if defined(HOSTAPD) || defined(CONFIG_IEEE80211BE)
+static struct hostapd_data * hostapd_find_by_sta(struct hostapd_iface *iface,
+ const u8 *src, bool rsn,
+ struct sta_info **sta_ret)
+{
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+ unsigned int j;
+
+ if (sta_ret)
+ *sta_ret = NULL;
+
+ for (j = 0; j < iface->num_bss; j++) {
+ 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;
+}
+#endif /* HOSTAPD || CONFIG_IEEE80211BE */
+
+
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *req_ies, size_t req_ies_len,
const u8 *resp_ies, size_t resp_ies_len,
@@ -513,10 +561,8 @@
"Failed to initialize WPA state machine");
return -1;
}
- wpa_auth_set_rsn_override(sta->wpa_sm,
- elems.rsne_override != NULL);
- wpa_auth_set_rsn_override_2(sta->wpa_sm,
- elems.rsne_override_2 != NULL);
+ wpa_auth_set_rsn_selection(sta->wpa_sm, elems.rsn_selection,
+ elems.rsn_selection_len);
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta)) {
wpa_printf(MSG_DEBUG,
@@ -777,6 +823,9 @@
p = hostapd_eid_assoc_fils_session(sta->wpa_sm, p,
elems.fils_session,
sta->fils_hlp_resp);
+ if (!p)
+ goto fail;
+
wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)",
buf, p - buf);
}
@@ -1041,6 +1090,20 @@
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta = ap_get_sta(hapd, addr);
+#ifdef CONFIG_IEEE80211BE
+ struct hostapd_data *orig_hapd = hapd;
+
+ if (!sta && hapd->conf->mld_ap) {
+ hapd = hostapd_find_by_sta(hapd->iface, addr, true, &sta);
+ if (!hapd) {
+ wpa_printf(MSG_DEBUG,
+ "No partner link BSS found for STA " MACSTR
+ " - fallback to received context",
+ MAC2STR(addr));
+ hapd = orig_hapd;
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
if (!sta || !hapd->conf->disassoc_low_ack || sta->agreed_to_steer)
return;
@@ -1983,50 +2046,6 @@
}
-static struct hostapd_data * hostapd_find_by_sta(struct hostapd_iface *iface,
- const u8 *src, bool rsn,
- struct sta_info **sta_ret)
-{
- struct hostapd_data *hapd;
- struct sta_info *sta;
- unsigned int j;
-
- if (sta_ret)
- *sta_ret = NULL;
-
- for (j = 0; j < iface->num_bss; j++) {
- 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,
@@ -2416,6 +2435,88 @@
#endif /* CONFIG_IEEE80211AX */
+static void hostapd_iface_enable(struct hostapd_data *hapd)
+{
+ wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
+ if (hapd->disabled && hapd->started) {
+ hapd->disabled = 0;
+ /*
+ * Try to re-enable interface if the driver stopped it
+ * when the interface got disabled.
+ */
+ if (hapd->wpa_auth)
+ wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+ else
+ hostapd_reconfig_encryption(hapd);
+ hapd->reenable_beacon = 1;
+ ieee802_11_set_beacon(hapd);
+#ifdef NEED_AP_MLME
+ } else if (hapd->disabled && hapd->iface->cac_started) {
+ wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
+ hostapd_handle_dfs(hapd->iface);
+#endif /* NEED_AP_MLME */
+ }
+}
+
+
+static void hostapd_iface_disable(struct hostapd_data *hapd)
+{
+ hostapd_free_stas(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
+ hapd->disabled = 1;
+}
+
+
+#ifdef CONFIG_IEEE80211BE
+
+static void hostapd_mld_iface_enable(struct hostapd_data *hapd)
+{
+ struct hostapd_data *first_link, *link_bss;
+
+ first_link = hostapd_mld_is_first_bss(hapd) ? hapd :
+ hostapd_mld_get_first_bss(hapd);
+
+ /* Links have been removed. Re-add all links and enable them, but
+ * enable the first link BSS before doing that. */
+ if (hostapd_drv_link_add(first_link, first_link->mld_link_id,
+ first_link->own_addr)) {
+ wpa_printf(MSG_ERROR, "MLD: Failed to re-add link %d in MLD %s",
+ first_link->mld_link_id, first_link->conf->iface);
+ return;
+ }
+
+ hostapd_iface_enable(first_link);
+
+ /* Add other affiliated links */
+ for_each_mld_link(link_bss, first_link) {
+ if (link_bss == first_link)
+ continue;
+
+ if (hostapd_drv_link_add(link_bss, link_bss->mld_link_id,
+ link_bss->own_addr)) {
+ wpa_printf(MSG_ERROR,
+ "MLD: Failed to re-add link %d in MLD %s",
+ link_bss->mld_link_id,
+ link_bss->conf->iface);
+ continue;
+ }
+
+ hostapd_iface_enable(link_bss);
+ }
+}
+
+
+static void hostapd_mld_iface_disable(struct hostapd_data *hapd)
+{
+ struct hostapd_data *link_bss;
+
+ for_each_mld_link(link_bss, hapd)
+ hostapd_iface_disable(link_bss);
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -2693,30 +2794,22 @@
break;
#endif /* NEED_AP_MLME */
case EVENT_INTERFACE_ENABLED:
- wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
- if (hapd->disabled && hapd->started) {
- hapd->disabled = 0;
- /*
- * Try to re-enable interface if the driver stopped it
- * when the interface got disabled.
- */
- if (hapd->wpa_auth)
- wpa_auth_reconfig_group_keys(hapd->wpa_auth);
- else
- hostapd_reconfig_encryption(hapd);
- hapd->reenable_beacon = 1;
- ieee802_11_set_beacon(hapd);
-#ifdef NEED_AP_MLME
- } else if (hapd->disabled && hapd->iface->cac_started) {
- wpa_printf(MSG_DEBUG, "DFS: restarting pending CAC");
- hostapd_handle_dfs(hapd->iface);
-#endif /* NEED_AP_MLME */
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap) {
+ hostapd_mld_iface_enable(hapd);
+ break;
}
+#endif /* CONFIG_IEEE80211BE */
+ hostapd_iface_enable(hapd);
break;
case EVENT_INTERFACE_DISABLED:
- hostapd_free_stas(hapd);
- wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
- hapd->disabled = 1;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap) {
+ hostapd_mld_iface_disable(hapd);
+ break;
+ }
+#endif /* CONFIG_IEEE80211BE */
+ hostapd_iface_disable(hapd);
break;
#ifdef CONFIG_ACS
case EVENT_ACS_CHANNEL_SELECTED:
@@ -2769,6 +2862,13 @@
hostapd_event_color_change(hapd, true);
break;
#endif /* CONFIG_IEEE80211AX */
+#ifdef CONFIG_IEEE80211BE
+ case EVENT_MLD_INTERFACE_FREED:
+ wpa_printf(MSG_DEBUG, "MLD: Interface %s freed",
+ hapd->conf->iface);
+ hostapd_mld_interface_freed(hapd);
+ break;
+#endif /* CONFIG_IEEE80211BE */
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index a05de03..7d92489 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -400,8 +400,6 @@
#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)
{
@@ -440,6 +438,8 @@
hapd->eht_mld_link_removal_count = count;
hapd->eht_mld_bss_param_change++;
+ if (hapd->eht_mld_bss_param_change == 255)
+ hapd->eht_mld_bss_param_change = 0;
eloop_register_timeout(0, TU_TO_USEC(hapd->iconf->beacon_int),
hostapd_link_remove_timeout_handler,
@@ -620,9 +620,19 @@
static void hostapd_bss_link_deinit(struct hostapd_data *hapd)
{
#ifdef CONFIG_IEEE80211BE
+ int i;
+
if (!hapd->conf || !hapd->conf->mld_ap)
return;
+ /* Free per STA profiles */
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ os_free(hapd->partner_links[i].resp_sta_profile);
+ os_memset(&hapd->partner_links[i], 0,
+ sizeof(hapd->partner_links[i]));
+ }
+
+ /* Put all freeing logic above this */
if (!hapd->mld->num_links)
return;
@@ -702,6 +712,9 @@
ap_list_deinit(iface);
sta_track_deinit(iface);
airtime_policy_update_deinit(iface);
+ hostapd_free_multi_hw_info(iface->multi_hw_info);
+ iface->multi_hw_info = NULL;
+ iface->current_hw_info = NULL;
}
@@ -1440,7 +1453,6 @@
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);
@@ -1471,7 +1483,6 @@
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 */
}
@@ -1486,8 +1497,13 @@
MAC2STR(hapd->own_addr));
if (hostapd_drv_link_add(hapd, hapd->mld_link_id,
- hapd->own_addr))
+ hapd->own_addr)) {
+ wpa_printf(MSG_ERROR,
+ "MLD: Failed to add link %d in MLD %s",
+ hapd->mld_link_id, hapd->conf->iface);
return -1;
+ }
+ hostapd_mld_add_link(hapd);
}
#endif /* CONFIG_IEEE80211BE */
@@ -1808,12 +1824,36 @@
}
+static int hostapd_set_ctrl_sock_iface(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_IEEE80211BE
+ int ret;
+
+ if (hapd->conf->mld_ap) {
+ ret = os_snprintf(hapd->ctrl_sock_iface,
+ sizeof(hapd->ctrl_sock_iface), "%s_%s%d",
+ hapd->conf->iface, WPA_CTRL_IFACE_LINK_NAME,
+ hapd->mld_link_id);
+ if (os_snprintf_error(sizeof(hapd->ctrl_sock_iface), ret))
+ return -1;
+ } else {
+ os_strlcpy(hapd->ctrl_sock_iface, hapd->conf->iface,
+ sizeof(hapd->ctrl_sock_iface));
+ }
+#endif /* CONFIG_IEEE80211BE */
+ return 0;
+}
+
+
static int start_ctrl_iface_bss(struct hostapd_data *hapd)
{
if (!hapd->iface->interfaces ||
!hapd->iface->interfaces->ctrl_iface_init)
return 0;
+ if (hostapd_set_ctrl_sock_iface(hapd))
+ return -1;
+
if (hapd->iface->interfaces->ctrl_iface_init(hapd)) {
wpa_printf(MSG_ERROR,
"Failed to setup control interface for %s",
@@ -1834,6 +1874,10 @@
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *hapd = iface->bss[i];
+
+ if (hostapd_set_ctrl_sock_iface(hapd))
+ return -1;
+
if (iface->interfaces->ctrl_iface_init(hapd)) {
wpa_printf(MSG_ERROR,
"Failed to setup control interface for %s",
@@ -2492,6 +2536,12 @@
hostapd_hw_mode_txt(iface->conf->hw_mode),
iface->conf->channel, iface->freq);
+ if (hostapd_set_current_hw_info(iface, iface->freq)) {
+ wpa_printf(MSG_ERROR,
+ "Failed to set current hardware info");
+ goto fail;
+ }
+
#ifdef NEED_AP_MLME
/* Handle DFS only if it is not offloaded to the driver */
if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) {
@@ -3065,9 +3115,17 @@
os_strlcpy(mld->name, conf->iface, sizeof(conf->iface));
dl_list_init(&mld->links);
+ mld->ctrl_sock = -1;
+ if (hapd->conf->ctrl_interface)
+ mld->ctrl_interface = os_strdup(hapd->conf->ctrl_interface);
wpa_printf(MSG_DEBUG, "AP MLD %s created", mld->name);
+ /* Initialize MLD control interfaces early to allow external monitoring
+ * of link setup operations. */
+ if (interfaces->mld_ctrl_iface_init(mld))
+ goto fail;
+
hapd->mld = mld;
hostapd_mld_ref_inc(mld);
hostapd_bss_alloc_link_id(hapd);
@@ -3127,6 +3185,8 @@
if (!remove && !forced_remove)
continue;
+ interfaces->mld_ctrl_iface_deinit(mld);
+
wpa_printf(MSG_DEBUG, "AP MLD %s: Freed%s", mld->name,
forced_remove ? " (forced)" : "");
os_free(mld);
@@ -3387,8 +3447,10 @@
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->is_drv_shared(drv_priv,
+ iface->bss[0]->mld_link_id)) {
driver->hapd_deinit(drv_priv);
+ hostapd_mld_interface_freed(iface->bss[0]);
} else if (hostapd_if_link_remove(iface->bss[0],
WPA_IF_AP_BSS,
iface->bss[0]->conf->iface,
@@ -4501,6 +4563,42 @@
}
+int hostapd_force_channel_switch(struct hostapd_iface *iface,
+ struct csa_settings *settings)
+{
+ int ret = 0;
+
+ if (!settings->freq_params.channel) {
+ /* Check if the new channel is supported */
+ settings->freq_params.channel = hostapd_hw_get_channel(
+ iface->bss[0], settings->freq_params.freq);
+ if (!settings->freq_params.channel)
+ return -1;
+ }
+
+ ret = hostapd_disable_iface(iface);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "Failed to disable the interface");
+ return ret;
+ }
+
+ hostapd_chan_switch_config(iface->bss[0], &settings->freq_params);
+ ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
+ &settings->freq_params, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to set the new channel in config");
+ return ret;
+ }
+
+ ret = hostapd_enable_iface(iface);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "Failed to enable the interface");
+
+ return ret;
+}
+
+
void
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params)
@@ -4932,6 +5030,18 @@
return mld->fbss;
}
+
+void hostapd_mld_interface_freed(struct hostapd_data *hapd)
+{
+ struct hostapd_data *link_bss = NULL;
+
+ if (!hapd || !hapd->conf->mld_ap)
+ return;
+
+ for_each_mld_link(link_bss, hapd)
+ link_bss->drv_priv = NULL;
+}
+
#endif /* CONFIG_IEEE80211BE */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 85122d4..5d91d85 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -97,6 +97,8 @@
#ifdef CONFIG_IEEE80211BE
struct hostapd_mld **mld;
size_t mld_count;
+ int (*mld_ctrl_iface_init)(struct hostapd_mld *mld);
+ void (*mld_ctrl_iface_deinit)(struct hostapd_mld *mld);
#endif /* CONFIG_IEEE80211BE */
};
@@ -167,6 +169,21 @@
u8 msg[];
};
+struct mld_link_info {
+ u8 valid:1;
+ u8 nstr_bitmap_len:2;
+ u8 local_addr[ETH_ALEN];
+ u8 peer_addr[ETH_ALEN];
+
+ u8 nstr_bitmap[2];
+
+ u16 capability;
+
+ u16 status;
+ u16 resp_sta_profile_len;
+ u8 *resp_sta_profile;
+};
+
/**
* struct hostapd_data - hostapd per-BSS data structure
*/
@@ -476,6 +493,14 @@
struct hostapd_mld *mld;
struct dl_list link;
u8 mld_link_id;
+
+ /* Cached partner info for ML probe response */
+ struct mld_link_info partner_links[MAX_NUM_MLD_LINKS];
+
+ /* 5 characters for "_link", up to 2 characters for <link ID>, so in
+ * total, additional 7 characters required. */
+ char ctrl_sock_iface[IFNAMSIZ + 7 + 1];
+
#ifdef CONFIG_TESTING_OPTIONS
u8 eht_mld_link_removal_count;
#endif /* CONFIG_TESTING_OPTIONS */
@@ -529,6 +554,10 @@
struct hostapd_data *fbss;
struct dl_list links; /* List head of all affiliated links */
+
+ int ctrl_sock;
+ struct dl_list ctrl_dst;
+ char *ctrl_interface; /* Directory for UNIX domain sockets */
};
#define HOSTAPD_MLD_MAX_REF_COUNT 0xFF
@@ -713,6 +742,10 @@
bool is_no_ir;
bool is_ch_switch_dfs; /* Channel switch from ACS to DFS */
+
+ struct hostapd_multi_hw_info *multi_hw_info;
+ unsigned int num_multi_hws;
+ struct hostapd_multi_hw_info *current_hw_info;
};
/* hostapd.c */
@@ -755,6 +788,8 @@
struct hostapd_freq_params *freq_params);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
+int hostapd_force_channel_switch(struct hostapd_iface *iface,
+ struct csa_settings *settings);
void
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params);
@@ -833,6 +868,7 @@
#ifdef CONFIG_IEEE80211BE
bool hostapd_mld_is_first_bss(struct hostapd_data *hapd);
+void hostapd_mld_interface_freed(struct hostapd_data *hapd);
#define for_each_mld_link(partner, self) \
dl_list_for_each(partner, &self->mld->links, struct hostapd_data, link)
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index c455660..02d6759 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -76,12 +76,15 @@
{
struct hostapd_data *hapd = iface->bss[0];
int i, j;
+ unsigned int k;
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;
+ struct hostapd_multi_hw_info *multi_hw_info;
+ unsigned int num_multi_hws;
if (hostapd_drv_none(hapd))
return -1;
@@ -168,6 +171,25 @@
__func__);
}
+ multi_hw_info = hostapd_get_multi_hw_info(hapd, &num_multi_hws);
+ if (!multi_hw_info)
+ return 0;
+
+ hostapd_free_multi_hw_info(iface->multi_hw_info);
+ iface->multi_hw_info = multi_hw_info;
+ iface->num_multi_hws = num_multi_hws;
+
+ wpa_printf(MSG_DEBUG, "Multiple underlying hardwares info:");
+
+ for (k = 0; k < num_multi_hws; k++) {
+ struct hostapd_multi_hw_info *hw_info = &multi_hw_info[k];
+
+ wpa_printf(MSG_DEBUG,
+ " %d. hw_idx=%u, frequency range: %d-%d MHz",
+ k + 1, hw_info->hw_idx, hw_info->start_freq,
+ hw_info->end_freq);
+ }
+
return 0;
}
@@ -1391,3 +1413,34 @@
}
return 0;
}
+
+
+void hostapd_free_multi_hw_info(struct hostapd_multi_hw_info *multi_hw_info)
+{
+ os_free(multi_hw_info);
+}
+
+
+int hostapd_set_current_hw_info(struct hostapd_iface *iface, int oper_freq)
+{
+ struct hostapd_multi_hw_info *hw_info;
+ unsigned int i;
+
+ if (!iface->num_multi_hws)
+ return 0;
+
+ for (i = 0; i < iface->num_multi_hws; i++) {
+ hw_info = &iface->multi_hw_info[i];
+
+ if (hw_info->start_freq <= oper_freq &&
+ hw_info->end_freq >= oper_freq) {
+ iface->current_hw_info = hw_info;
+ wpa_printf(MSG_DEBUG,
+ "Mode: Selected underlying hardware: hw_idx=%u",
+ iface->current_hw_info->hw_idx);
+ return 0;
+ }
+ }
+
+ return -1;
+}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index c682c6d..73663d0 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -30,6 +30,8 @@
int hostapd_hw_skip_mode(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
int hostapd_determine_mode(struct hostapd_iface *iface);
+void hostapd_free_multi_hw_info(struct hostapd_multi_hw_info *multi_hw_info);
+int hostapd_set_current_hw_info(struct hostapd_iface *iface, int oper_freq);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -103,6 +105,16 @@
return 0;
}
+static inline
+void hostapd_free_multi_hw_info(struct hostapd_multi_hw_info *multi_hw_info)
+{
+}
+
+static inline int hostapd_set_current_hw_info(struct hostapd_iface *iface,
+ u32 oper_freq)
+{
+ return 0;
+}
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 1cd76ca..d4552f2 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1173,16 +1173,23 @@
static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
{
struct sae_data *sae = sta->sae;
- int i, *groups = hapd->conf->sae_groups;
- int default_groups[] = { 19, 0 };
+ struct hostapd_bss_config *conf = hapd->conf;
+ int i, *groups = conf->sae_groups;
+ int default_groups[] = { 19, 0, 0 };
if (sae->state != SAE_COMMITTED)
return;
wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
- if (!groups)
+ if (!groups) {
groups = default_groups;
+ if (wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt |
+ conf->rsn_override_key_mgmt |
+ conf->rsn_override_key_mgmt_2))
+ default_groups[1] = 20;
+ }
+
for (i = 0; groups[i] > 0; i++) {
if (sae->group == groups[i])
break;
@@ -1247,12 +1254,18 @@
static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
{
- int *groups = hapd->conf->sae_groups;
- int default_groups[] = { 19, 0 };
+ struct hostapd_bss_config *conf = hapd->conf;
+ int *groups = conf->sae_groups;
+ int default_groups[] = { 19, 0, 0 };
int i;
- if (!groups)
+ if (!groups) {
groups = default_groups;
+ if (wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt |
+ conf->rsn_override_key_mgmt |
+ conf->rsn_override_key_mgmt_2))
+ default_groups[1] = 20;
+ }
for (i = 0; groups[i] > 0; i++) {
if (groups[i] == group)
@@ -1309,14 +1322,20 @@
{
int resp = WLAN_STATUS_SUCCESS;
struct wpabuf *data = NULL;
- int *groups = hapd->conf->sae_groups;
- int default_groups[] = { 19, 0 };
+ struct hostapd_bss_config *conf = hapd->conf;
+ int *groups = conf->sae_groups;
+ int default_groups[] = { 19, 0, 0 };
const u8 *pos, *end;
int sta_removed = 0;
bool success_status;
- if (!groups)
+ if (!groups) {
groups = default_groups;
+ if (wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt |
+ conf->rsn_override_key_mgmt |
+ conf->rsn_override_key_mgmt_2))
+ default_groups[1] = 20;
+ }
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->conf->sae_reflection_attack && auth_transaction == 1) {
@@ -1609,12 +1628,12 @@
!data && end - pos >= 2)
data = wpabuf_alloc_copy(pos, 2);
- sae_sme_send_external_auth_status(hapd, sta, resp);
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");
+ sae_sme_send_external_auth_status(hapd, sta, resp);
if (sta->sae && sta->sae->tmp && sta->sae->tmp->pw_id &&
resp == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER &&
auth_transaction == 1) {
@@ -1935,6 +1954,8 @@
goto fail;
}
+ wpa_auth_set_rsn_selection(sta->wpa_sm, elems.rsn_selection,
+ elems.rsn_selection_len);
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
@@ -1945,9 +1966,6 @@
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
- wpa_auth_set_rsn_override(sta->wpa_sm, elems.rsne_override != NULL);
- wpa_auth_set_rsn_override_2(sta->wpa_sm, elems.rsne_override_2 != NULL);
-
if (!elems.fils_nonce) {
wpa_printf(MSG_DEBUG, "FILS: No FILS Nonce field");
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -2463,7 +2481,8 @@
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);
+ pasn_get_cipher(sta->pasn), sta->pasn->kdk_len,
+ sta->pasn->kek_len);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: FILS: Failed to derive PTK");
goto fail;
@@ -2832,7 +2851,7 @@
hapd_pasn_update_params(hapd, sta, mgmt, len);
if (handle_auth_pasn_1(sta->pasn, hapd->own_addr,
- sta->addr, mgmt, len) < 0)
+ sta->addr, mgmt, len, false) < 0)
ap_free_sta(hapd, sta);
} else if (trans_seq == 3) {
if (!sta->pasn) {
@@ -4134,10 +4153,8 @@
#endif /* CONFIG_IEEE80211BE */
wpa_auth_set_auth_alg(sta->wpa_sm, sta->auth_alg);
- wpa_auth_set_rsn_override(sta->wpa_sm,
- elems->rsne_override != NULL);
- wpa_auth_set_rsn_override_2(sta->wpa_sm,
- elems->rsne_override_2 != NULL);
+ wpa_auth_set_rsn_selection(sta->wpa_sm, elems->rsn_selection,
+ elems->rsn_selection_len);
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
wpa_ie, wpa_ie_len,
@@ -4998,7 +5015,8 @@
#endif /* CONFIG_IEEE80211AX */
p = hostapd_eid_ext_capab(hapd, p, false);
- p = hostapd_eid_bss_max_idle_period(hapd, p, sta->max_idle_period);
+ p = hostapd_eid_bss_max_idle_period(hapd, p,
+ sta ? sta->max_idle_period : 0);
if (sta && sta->qos_map_enabled)
p = hostapd_eid_qos_map_set(hapd, p);
@@ -7230,16 +7248,11 @@
}
-u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
+/* Wide Bandwidth Channel Switch subelement */
+static u8 * hostapd_eid_wb_channel_switch(struct hostapd_data *hapd, u8 *eid,
+ u8 chan1, u8 chan2)
{
- 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.eht_enabled))
- return eid;
+ u8 bw;
/* 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. */
@@ -7261,20 +7274,6 @@
return eid;
}
- freq1 = hapd->cs_freq_params.center_freq1 ?
- hapd->cs_freq_params.center_freq1 :
- hapd->cs_freq_params.freq;
- if (ieee80211_freq_to_chan(freq1, &chan1) !=
- HOSTAPD_MODE_IEEE80211A)
- return eid;
-
- if (hapd->cs_freq_params.center_freq2 &&
- ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
- &chan2) != HOSTAPD_MODE_IEEE80211A)
- return eid;
-
- *eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
- *eid++ = 5; /* Length of Channel Switch Wrapper */
*eid++ = WLAN_EID_WIDE_BW_CHSWITCH;
*eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
*eid++ = bw; /* New Channel Width */
@@ -7300,6 +7299,118 @@
}
+#ifdef CONFIG_IEEE80211BE
+/* Bandwidth Indication element that is also used as the Bandwidth Indication
+ * For Channel Switch subelement within a Channel Switch Wrapper element. */
+static u8 * hostapd_eid_bw_indication(struct hostapd_data *hapd, u8 *eid,
+ u8 chan1, u8 chan2)
+{
+ u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
+ struct ieee80211_bw_ind_element *bw_ind_elem;
+ size_t elen = 3;
+
+ if (hapd->cs_freq_params.bandwidth <= 160 && !punct_bitmap)
+ return eid;
+
+ if (punct_bitmap)
+ elen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
+
+ *eid++ = WLAN_EID_EXTENSION;
+ *eid++ = 1 + elen;
+ *eid++ = WLAN_EID_EXT_BANDWIDTH_INDICATION;
+
+ bw_ind_elem = (struct ieee80211_bw_ind_element *) eid;
+ os_memset(bw_ind_elem, 0, sizeof(struct ieee80211_bw_ind_element));
+
+ switch (hapd->cs_freq_params.bandwidth) {
+ case 320:
+ bw_ind_elem->bw_ind_info.control |= BW_IND_CHANNEL_WIDTH_320MHZ;
+ chan2 = chan1;
+ if (hapd->cs_freq_params.channel < chan1)
+ chan1 -= 16;
+ else
+ chan1 += 16;
+ break;
+ case 160:
+ bw_ind_elem->bw_ind_info.control |= BW_IND_CHANNEL_WIDTH_160MHZ;
+ chan2 = chan1;
+ if (hapd->cs_freq_params.channel < chan1)
+ chan1 -= 8;
+ else
+ chan1 += 8;
+ break;
+ case 80:
+ bw_ind_elem->bw_ind_info.control |= BW_IND_CHANNEL_WIDTH_80MHZ;
+ break;
+ case 40:
+ if (hapd->cs_freq_params.sec_channel_offset == 1)
+ bw_ind_elem->bw_ind_info.control |=
+ BW_IND_CHANNEL_WIDTH_40MHZ;
+ else
+ bw_ind_elem->bw_ind_info.control |=
+ BW_IND_CHANNEL_WIDTH_20MHZ;
+ break;
+ default:
+ bw_ind_elem->bw_ind_info.control |= BW_IND_CHANNEL_WIDTH_20MHZ;
+ break;
+ }
+
+ bw_ind_elem->bw_ind_info.ccfs0 = chan1;
+ bw_ind_elem->bw_ind_info.ccfs1 = chan2;
+
+ if (punct_bitmap) {
+ bw_ind_elem->bw_ind_params |=
+ BW_IND_PARAMETER_DISABLED_SUBCHAN_BITMAP_PRESENT;
+ bw_ind_elem->bw_ind_info.disabled_chan_bitmap =
+ host_to_le16(punct_bitmap);
+ }
+
+ return eid + elen;
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
+u8 * hostapd_eid_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 chan1 = 0, chan2 = 0;
+ u8 *eid_len_offset;
+ int freq1;
+
+ if (!hapd->cs_freq_params.channel ||
+ (!hapd->cs_freq_params.vht_enabled &&
+ !hapd->cs_freq_params.he_enabled &&
+ !hapd->cs_freq_params.eht_enabled))
+ return eid;
+
+ freq1 = hapd->cs_freq_params.center_freq1 ?
+ hapd->cs_freq_params.center_freq1 :
+ hapd->cs_freq_params.freq;
+ if (ieee80211_freq_to_chan(freq1, &chan1) !=
+ HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ if (hapd->cs_freq_params.center_freq2 &&
+ ieee80211_freq_to_chan(hapd->cs_freq_params.center_freq2,
+ &chan2) != HOSTAPD_MODE_IEEE80211A)
+ return eid;
+
+ *eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
+ eid_len_offset = eid++; /* Length of Channel Switch Wrapper element */
+
+ eid = hostapd_eid_wb_channel_switch(hapd, eid, chan1, chan2);
+
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
+ /* Bandwidth Indication For Channel Switch subelement */
+ eid = hostapd_eid_bw_indication(hapd, eid, chan1, chan2);
+ }
+#endif /* CONFIG_IEEE80211BE */
+
+ *eid_len_offset = (eid - eid_len_offset) - 1;
+ return eid;
+}
+
+
static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd,
size_t *current_len)
{
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index dd4995f..abf48ab 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -63,7 +63,7 @@
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
-u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
enum ieee80211_op_mode opmode);
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
index afb2e16..aea69ab 100644
--- a/src/ap/ieee802_11_eht.c
+++ b/src/ap/ieee802_11_eht.c
@@ -871,6 +871,8 @@
wpa_printf(MSG_DEBUG, "EHT: SAE scalar length is %zu", prime_len);
+ if (len - 2 < prime_len * (ec ? 3 : 2))
+ goto truncated;
/* scalar */
pos += prime_len;
@@ -882,6 +884,7 @@
}
if (pos - mgmt->u.auth.variable > (int) len) {
+ truncated:
wpa_printf(MSG_DEBUG,
"EHT: Too short SAE commit Authentication frame");
return NULL;
@@ -905,16 +908,38 @@
return pos;
/* send confirm integer */
+ if (len < 2)
+ goto truncated;
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.
+ * will be replaced with the MLD MAC address by the driver. However,
+ * there is at least a theoretical race condition in a case where the
+ * peer sends the SAE confirm message quickly enough for the driver
+ * translation mechanism to not be available to update the SAE confirm
+ * message addresses. Work around that by searching for the STA entry
+ * using the link address of the non-AP MLD if no match is found based
+ * on the MLD MAC address.
*/
sta = ap_get_sta(hapd, mgmt->sa);
if (!sta) {
wpa_printf(MSG_DEBUG, "SAE: No MLD STA for SAE confirm");
- return NULL;
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ int link_id = hapd->mld_link_id;
+
+ if (!sta->mld_info.mld_sta ||
+ sta->mld_info.links[link_id].valid ||
+ !ether_addr_equal(
+ mgmt->sa,
+ sta->mld_info.links[link_id].peer_addr))
+ continue;
+ wpa_printf(MSG_DEBUG,
+ "SAE: Found MLD STA for SAE confirm based on link address");
+ break;
+ }
+ if (!sta)
+ return NULL;
}
if (!sta->sae || sta->sae->state < SAE_COMMITTED || !sta->sae->tmp) {
@@ -929,9 +954,12 @@
wpa_printf(MSG_DEBUG, "SAE: confirm: kck_len=%zu",
sta->sae->tmp->kck_len);
+ if (len - 2 < sta->sae->tmp->kck_len)
+ goto truncated;
pos += sta->sae->tmp->kck_len;
if (pos - mgmt->u.auth.variable > (int) len) {
+ truncated:
wpa_printf(MSG_DEBUG,
"EHT: Too short SAE confirm Authentication frame");
return NULL;
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index f90f125..4c39e40 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -79,6 +79,51 @@
}
+static void set_ht_param(struct hostapd_data *hapd,
+ struct ieee80211_ht_operation *oper)
+{
+ int secondary_channel = hapd->iconf->secondary_channel;
+#ifdef CONFIG_IEEE80211BE
+ enum oper_chan_width chwidth = hostapd_get_oper_chwidth(hapd->iconf);
+ u16 bw = 0, punct_bitmap = hostapd_get_punct_bitmap(hapd);
+ u8 offset, chan_bit_pos;
+
+ switch (chwidth) {
+ case CONF_OPER_CHWIDTH_80MHZ:
+ bw = 80;
+ offset = 6;
+ break;
+ case CONF_OPER_CHWIDTH_160MHZ:
+ bw = 160;
+ offset = 14;
+ break;
+ case CONF_OPER_CHWIDTH_320MHZ:
+ bw = 320;
+ offset = 30;
+ break;
+ default:
+ goto no_update;
+ }
+
+ chan_bit_pos = (hapd->iconf->channel -
+ hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf) +
+ offset) / 4;
+ /* Check if secondary channel is punctured */
+ if (bw >= 80 && punct_bitmap && secondary_channel &&
+ (punct_bitmap & BIT(chan_bit_pos + secondary_channel)))
+ return; /* Do not indicate punctured secondary channel for HT */
+no_update:
+#endif /* CONFIG_IEEE80211BE */
+
+ if (secondary_channel == 1)
+ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
+ HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
+ if (secondary_channel == -1)
+ oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
+ HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
+}
+
+
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_ht_operation *oper;
@@ -96,12 +141,7 @@
oper->primary_chan = hapd->iconf->channel;
oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
- if (hapd->iconf->secondary_channel == 1)
- oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
- HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
- if (hapd->iconf->secondary_channel == -1)
- oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
- HT_INFO_HT_PARAM_STA_CHNL_WIDTH;
+ set_ht_param(hapd, oper);
pos += sizeof(*oper);
diff --git a/src/ap/nan_usd_ap.c b/src/ap/nan_usd_ap.c
index 52a967a..570abfc 100644
--- a/src/ap/nan_usd_ap.c
+++ b/src/ap/nan_usd_ap.c
@@ -158,7 +158,7 @@
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);
+ hapd->nan_de = nan_de_init(hapd->own_addr, false, true, &cb);
if (!hapd->nan_de)
return -1;
return 0;
@@ -192,7 +192,7 @@
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)
+ struct nan_publish_params *params, bool p2p)
{
int publish_id;
struct wpabuf *elems = NULL;
@@ -201,7 +201,7 @@
return -1;
publish_id = nan_de_publish(hapd->nan_de, service_name, srv_proto_type,
- ssi, elems, params);
+ ssi, elems, params, p2p);
wpabuf_free(elems);
return publish_id;
}
@@ -231,7 +231,7 @@
const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi,
- struct nan_subscribe_params *params)
+ struct nan_subscribe_params *params, bool p2p)
{
int subscribe_id;
struct wpabuf *elems = NULL;
@@ -240,7 +240,7 @@
return -1;
subscribe_id = nan_de_subscribe(hapd->nan_de, service_name,
- srv_proto_type, ssi, elems, params);
+ srv_proto_type, ssi, elems, params, p2p);
wpabuf_free(elems);
return subscribe_id;
}
diff --git a/src/ap/nan_usd_ap.h b/src/ap/nan_usd_ap.h
index 58ff5fc..0571643 100644
--- a/src/ap/nan_usd_ap.h
+++ b/src/ap/nan_usd_ap.h
@@ -21,7 +21,7 @@
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);
+ struct nan_publish_params *params, bool p2p);
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);
@@ -29,7 +29,7 @@
const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi,
- struct nan_subscribe_params *params);
+ struct nan_subscribe_params *params, bool p2p);
void hostapd_nan_usd_cancel_subscribe(struct hostapd_data *hapd,
int subscribe_id);
int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle,
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 13613db..aa7e156 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1625,6 +1625,7 @@
if (sta == NULL)
return;
+ sta->deauth_reason = reason;
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
hostapd_set_sta_flags(hapd, sta);
@@ -1654,7 +1655,6 @@
return;
}
- sta->deauth_reason = reason;
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
eloop_register_timeout(hapd->iface->drv_flags &
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 8462935..5b01c1e 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -81,20 +81,7 @@
u16 mld_capa;
} common_info;
- struct mld_link_info {
- u8 valid:1;
- u8 nstr_bitmap_len:2;
- u8 local_addr[ETH_ALEN];
- u8 peer_addr[ETH_ALEN];
-
- u8 nstr_bitmap[2];
-
- u16 capability;
-
- u16 status;
- u16 resp_sta_profile_len;
- u8 *resp_sta_profile;
- } links[MAX_NUM_MLD_LINKS];
+ struct mld_link_info links[MAX_NUM_MLD_LINKS];
};
struct sta_info {
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index bbf41d3..3af3404 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -112,10 +112,7 @@
int link_id;
#endif /* CONFIG_IEEE80211BE */
- if (!sm->wpa_auth)
- return;
-
- sm->wpa_auth->group->GKeyDoneStations--;
+ sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = false;
#ifdef CONFIG_IEEE80211BE
@@ -889,9 +886,6 @@
os_free(wpa_auth->wpa_ie);
- os_free(wpa_auth->rsne_override);
- os_free(wpa_auth->rsne_override_2);
- os_free(wpa_auth->rsnxe_override);
group = wpa_auth->group;
while (group) {
@@ -1053,6 +1047,7 @@
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
os_free(sm->rsnxe);
+ os_free(sm->rsn_selection);
#ifdef CONFIG_IEEE80211BE
for_each_sm_auth(sm, link_id) {
wpa_group_put(sm->mld_links[link_id].wpa_auth,
@@ -1893,7 +1888,8 @@
sm->EAPOLKeyReceived = true;
sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
- os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
+ if (msg == PAIRWISE_2)
+ os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
wpa_sm_step(sm);
out:
@@ -2071,6 +2067,11 @@
if (key_rsc)
os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (conf->eapol_key_reserved_random)
+ random_get_bytes(key->key_id, sizeof(key->key_id));
+#endif /* CONFIG_TESTING_OPTIONS */
+
if (kde && !encr) {
os_memcpy(key_data, kde, kde_len);
WPA_PUT_BE16(key_mic + mic_len, kde_len);
@@ -3926,6 +3927,34 @@
goto out;
}
#endif /* CONFIG_IEEE80211R_AP */
+
+ /* Verify RSN Selection element for RSN overriding */
+ if ((wpa_auth->conf.rsn_override_key_mgmt ||
+ wpa_auth->conf.rsn_override_key_mgmt_2) &&
+ ((rsn_is_snonce_cookie(sm->SNonce) && !kde.rsn_selection) ||
+ (!rsn_is_snonce_cookie(sm->SNonce) && kde.rsn_selection) ||
+ (sm->rsn_selection && !kde.rsn_selection) ||
+ (!sm->rsn_selection && kde.rsn_selection) ||
+ (sm->rsn_selection && kde.rsn_selection &&
+ (sm->rsn_selection_len != kde.rsn_selection_len ||
+ os_memcmp(sm->rsn_selection, kde.rsn_selection,
+ sm->rsn_selection_len) != 0)))) {
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm), LOGGER_INFO,
+ "RSN Selection element from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
+ wpa_printf(MSG_DEBUG,
+ "SNonce cookie for RSN overriding %sused",
+ rsn_is_snonce_cookie(sm->SNonce) ? "" : "not ");
+ wpa_hexdump(MSG_DEBUG, "RSN Selection in AssocReq",
+ sm->rsn_selection, sm->rsn_selection_len);
+ wpa_hexdump(MSG_DEBUG, "RSN Selection in EAPOL-Key msg 2/4",
+ kde.rsn_selection, kde.rsn_selection_len);
+ /* MLME-DEAUTHENTICATE.request */
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ goto out;
+
+ }
+
#ifdef CONFIG_P2P
if (kde.ip_addr_req && kde.ip_addr_req[0] &&
wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
@@ -4189,7 +4218,8 @@
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)
+ bool mgmt_frame_prot, bool beacon_prot,
+ bool rekey)
{
struct wpa_group *gsm = a->group;
u8 rsc[WPA_KEY_RSC_LEN];
@@ -4202,7 +4232,7 @@
info->gtk = gsm->GTK[gsm->GN - 1];
info->gtk_len = gsm->GTK_len;
- if (wpa_auth_get_seqnum(a, NULL, gsm->GN, rsc) < 0)
+ if (rekey || 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));
@@ -4214,7 +4244,7 @@
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)
+ if (rekey || 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));
@@ -4230,7 +4260,7 @@
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)
+ if (rekey || 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));
@@ -4238,12 +4268,13 @@
static void wpa_auth_get_ml_key_info(struct wpa_authenticator *wpa_auth,
- struct wpa_auth_ml_key_info *info)
+ struct wpa_auth_ml_key_info *info,
+ bool rekey)
{
if (!wpa_auth->cb->get_ml_key_info)
return;
- wpa_auth->cb->get_ml_key_info(wpa_auth->cb_ctx, info);
+ wpa_auth->cb->get_ml_key_info(wpa_auth->cb_ctx, info, rekey);
}
@@ -4300,6 +4331,7 @@
struct wpa_auth_ml_key_info ml_key_info;
unsigned int i, link_id;
u8 *start = pos;
+ bool rekey = sm->wpa_ptk_group_state == WPA_PTK_GROUP_REKEYNEGOTIATING;
/* First fetch the key information from all the authenticators */
os_memset(&ml_key_info, 0, sizeof(ml_key_info));
@@ -4319,7 +4351,7 @@
ml_key_info.links[i++].link_id = link_id;
}
- wpa_auth_get_ml_key_info(sm->wpa_auth, &ml_key_info);
+ wpa_auth_get_ml_key_info(sm->wpa_auth, &ml_key_info, rekey);
/* Add MLO GTK KDEs */
for (i = 0, link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
@@ -4458,34 +4490,47 @@
/* For the MAC Address KDE */
kde_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN;
- /* MLO Link KDE for each link */
+ /* MLO Link KDE and RSN Override 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, *ieo;
+ const u8 *ie;
wpa_auth = wpa_get_link_auth(sm->wpa_auth, link_id);
if (!wpa_auth)
continue;
+ /* MLO Link KDE */
kde_len += 2 + RSN_SELECTOR_LEN + 1 + ETH_ALEN;
+
ie = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
WLAN_EID_RSN);
- ieo = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
- sm->rsn_override_2 ?
- RSNE_OVERRIDE_2_IE_VENDOR_TYPE :
- RSNE_OVERRIDE_IE_VENDOR_TYPE);
- if ((sm->rsn_override || sm->rsn_override_2) && ieo)
- kde_len += 2 + ieo[1 - 4];
- else
+ if (ie)
kde_len += 2 + ie[1];
ie = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
WLAN_EID_RSNX);
- ieo = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
- RSNXE_OVERRIDE_IE_VENDOR_TYPE);
- if ((sm->rsn_override || sm->rsn_override_2) && ieo)
- kde_len += 2 + ieo[1] - 4;
- else if (ie)
+ if (ie)
+ kde_len += 2 + ie[1];
+
+ if (!rsn_is_snonce_cookie(sm->SNonce))
+ continue;
+
+ /* RSN Override Link KDE */
+ kde_len += 2 + RSN_SELECTOR_LEN + 1;
+
+ ie = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ if (ie)
+ kde_len += 2 + ie[1];
+
+ ie = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+ if (ie)
+ kde_len += 2 + ie[1];
+
+ ie = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+ if (ie)
kde_len += 2 + ie[1];
}
@@ -4511,8 +4556,9 @@
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
struct wpa_authenticator *wpa_auth;
- const u8 *rsne, *rsnxe, *rsneo, *rsnxeo;
- size_t rsne_len, rsnxe_len;
+ const u8 *rsne, *rsnxe, *rsnoe, *rsno2e, *rsnxoe;
+ size_t rsne_len, rsnxe_len, rsnoe_len, rsno2e_len, rsnxoe_len;
+ size_t kde_len;
wpa_auth = wpa_get_link_auth(sm->wpa_auth, link_id);
if (!wpa_auth)
@@ -4521,30 +4567,17 @@
rsne = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
WLAN_EID_RSN);
rsne_len = rsne ? 2 + rsne[1] : 0;
- rsneo = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
- sm->rsn_override_2 ?
- RSNE_OVERRIDE_2_IE_VENDOR_TYPE :
- RSNE_OVERRIDE_IE_VENDOR_TYPE);
- if ((sm->rsn_override || sm->rsn_override_2) && rsneo)
- rsne_len = 2 + rsneo[1] - 4;
- else
- rsneo = NULL;
rsnxe = get_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
WLAN_EID_RSNX);
rsnxe_len = rsnxe ? 2 + rsnxe[1] : 0;
- rsnxeo = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
- RSNXE_OVERRIDE_IE_VENDOR_TYPE);
- if ((sm->rsn_override || sm->rsn_override_2) && rsnxeo)
- rsnxe_len = 2 + rsnxeo[1] - 4;
- else
- rsnxeo = NULL;
wpa_printf(MSG_DEBUG,
"RSN: MLO Link: link=%u, len=%zu", link_id,
RSN_SELECTOR_LEN + 1 + ETH_ALEN +
rsne_len + rsnxe_len);
+ /* MLO Link KDE */
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = RSN_SELECTOR_LEN + 1 + ETH_ALEN +
rsne_len + rsnxe_len;
@@ -4564,31 +4597,71 @@
pos += ETH_ALEN;
if (rsne_len) {
- if (rsneo) {
- *pos++ = WLAN_EID_RSN;
- *pos++ = rsneo[1] - 4;
- os_memcpy(pos, &rsneo[2 + 4], rsneo[1] - 4);
- pos += rsneo[1] - 4;
- } else {
- os_memcpy(pos, rsne, rsne_len);
- pos += rsne_len;
- }
+ os_memcpy(pos, rsne, rsne_len);
+ pos += rsne_len;
}
if (rsnxe_len) {
- if (rsnxeo) {
- *pos++ = WLAN_EID_RSNX;
- *pos++ = rsnxeo[1] - 4;
- os_memcpy(pos, &rsnxeo[2 + 4], rsnxeo[1] - 4);
- pos += rsnxeo[1] - 4;
- } else {
- os_memcpy(pos, rsnxe, rsnxe_len);
- pos += rsnxe_len;
- }
+ os_memcpy(pos, rsnxe, rsnxe_len);
+ pos += rsnxe_len;
+ }
+
+ if (!rsn_is_snonce_cookie(sm->SNonce))
+ continue;
+
+ rsnoe = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ rsnoe_len = rsnoe ? 2 + rsnoe[1] : 0;
+
+ rsno2e = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+ rsno2e_len = rsno2e ? 2 + rsno2e[1] : 0;
+
+ rsnxoe = get_vendor_ie(wpa_auth->wpa_ie, wpa_auth->wpa_ie_len,
+ RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+ rsnxoe_len = rsnxoe ? 2 + rsnxoe[1] : 0;
+
+ wpa_printf(MSG_DEBUG,
+ "RSN: RSN Override Link KDE: link=%u, len=%zu",
+ link_id, RSN_SELECTOR_LEN + rsnoe_len + rsno2e_len +
+ rsnxoe_len);
+
+ /* RSN Override Link KDE */
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ kde_len = RSN_SELECTOR_LEN + 1 + rsnoe_len + rsno2e_len +
+ rsnxoe_len;
+ if (kde_len > 255) {
+ wpa_printf(MSG_ERROR,
+ "RSN: RSNOE/RSNO2E/RSNXOE too long (KDE length %zu) to fit in RSN Override Link KDE for link %u",
+ kde_len, link_id);
+ return NULL;
+ }
+ *pos++ = kde_len;
+
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_RSN_OVERRIDE_LINK);
+ pos += RSN_SELECTOR_LEN;
+
+ *pos++ = link_id;
+
+ if (rsnoe_len) {
+ os_memcpy(pos, rsnoe, rsnoe_len);
+ pos += rsnoe_len;
+ }
+
+ if (rsno2e_len) {
+ os_memcpy(pos, rsno2e, rsno2e_len);
+ pos += rsno2e_len;
+ }
+
+ if (rsnxoe_len) {
+ os_memcpy(pos, rsnxoe, rsnxoe_len);
+ pos += rsnxoe_len;
}
}
- wpa_printf(MSG_DEBUG, "RSN: MLO Link KDE len = %ld", pos - start);
+ wpa_printf(MSG_DEBUG,
+ "RSN: MLO Link KDEs and RSN Override Link KDEs len = %ld",
+ pos - start);
pos = wpa_auth_ml_group_kdes(sm, pos);
#endif /* CONFIG_IEEE80211BE */
@@ -4644,77 +4717,36 @@
wpa_ie = wpa_ie + wpa_ie[1] + 2;
wpa_ie_len = wpa_ie[1] + 2;
}
- if ((sm->rsn_override &&
- get_vendor_ie(wpa_ie, wpa_ie_len, RSNE_OVERRIDE_IE_VENDOR_TYPE)) ||
- (sm->rsn_override_2 &&
- get_vendor_ie(wpa_ie, wpa_ie_len,
- RSNE_OVERRIDE_2_IE_VENDOR_TYPE))) {
- const u8 *mde, *fte, *tie, *tie2 = NULL;
- const u8 *override_rsne = NULL, *override_rsnxe = NULL;
- const struct element *elem;
+ if ((conf->rsn_override_key_mgmt || conf->rsn_override_key_mgmt_2) &&
+ !rsn_is_snonce_cookie(sm->SNonce)) {
+ u8 *ie;
+ size_t ie_len;
+ u32 ids[] = {
+ RSNE_OVERRIDE_IE_VENDOR_TYPE,
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE,
+ RSNXE_OVERRIDE_IE_VENDOR_TYPE,
+ 0
+ };
+ int i;
wpa_printf(MSG_DEBUG,
- "RSN: Use RSNE/RSNXE override element contents");
- mde = get_ie(wpa_ie, wpa_ie_len, WLAN_EID_MOBILITY_DOMAIN);
- fte = get_ie(wpa_ie, wpa_ie_len, WLAN_EID_FAST_BSS_TRANSITION);
- tie = get_ie(wpa_ie, wpa_ie_len, WLAN_EID_TIMEOUT_INTERVAL);
- if (tie) {
- const u8 *next = tie + 2 + tie[1];
-
- tie2 = get_ie(next, wpa_ie + wpa_ie_len - next,
- WLAN_EID_TIMEOUT_INTERVAL);
- }
- for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC,
- wpa_ie, wpa_ie_len) {
- if (elem->datalen >= 4) {
- if (WPA_GET_BE32(elem->data) ==
- (sm->rsn_override_2 ?
- RSNE_OVERRIDE_2_IE_VENDOR_TYPE :
- RSNE_OVERRIDE_IE_VENDOR_TYPE))
- override_rsne = &elem->id;
- if (WPA_GET_BE32(elem->data) ==
- RSNXE_OVERRIDE_IE_VENDOR_TYPE)
- override_rsnxe = &elem->id;
- }
- }
+ "RSN: Remove RSNE/RSNXE override elements");
wpa_hexdump(MSG_DEBUG, "EAPOL-Key msg 3/4 IEs before edits",
wpa_ie, wpa_ie_len);
- wpa_ie_buf3 = os_malloc(wpa_ie_len);
+ wpa_ie_buf3 = os_memdup(wpa_ie, wpa_ie_len);
if (!wpa_ie_buf3)
goto done;
- pos = wpa_ie_buf3;
- if (override_rsne) {
- *pos++ = WLAN_EID_RSN;
- *pos++ = override_rsne[1] - 4;
- os_memcpy(pos, &override_rsne[2 + 4],
- override_rsne[1] - 4);
- pos += override_rsne[1] - 4;
- }
- if (mde) {
- os_memcpy(pos, mde, 2 + mde[1]);
- pos += 2 + mde[1];
- }
- if (fte) {
- os_memcpy(pos, fte, 2 + fte[1]);
- pos += 2 + fte[1];
- }
- if (tie) {
- os_memcpy(pos, tie, 2 + tie[1]);
- pos += 2 + tie[1];
- }
- if (tie2) {
- os_memcpy(pos, tie2, 2 + tie2[1]);
- pos += 2 + tie2[1];
- }
- if (override_rsnxe) {
- *pos++ = WLAN_EID_RSNX;
- *pos++ = override_rsnxe[1] - 4;
- os_memcpy(pos, &override_rsnxe[2 + 4],
- override_rsnxe[1] - 4);
- pos += override_rsnxe[1] - 4;
- }
wpa_ie = wpa_ie_buf3;
- wpa_ie_len = pos - wpa_ie_buf3;
+
+ for (i = 0; ids[i]; i++) {
+ ie = (u8 *) get_vendor_ie(wpa_ie, wpa_ie_len, ids[i]);
+ if (ie) {
+ ie_len = 2 + ie[1];
+ os_memmove(ie, ie + ie_len,
+ wpa_ie_len - (ie + ie_len - wpa_ie));
+ wpa_ie_len -= ie_len;
+ }
+ }
wpa_hexdump(MSG_DEBUG, "EAPOL-Key msg 3/4 IEs after edits",
wpa_ie, wpa_ie_len);
}
@@ -4957,6 +4989,10 @@
#endif /* CONFIG_DPP2 */
pos = wpa_auth_ml_kdes(sm, pos);
+ if (!pos) {
+ wpa_printf(MSG_ERROR, "RSN: Failed to add MLO KDEs");
+ goto done;
+ }
if (sm->ssid_protection) {
*pos++ = WLAN_EID_SSID;
@@ -5601,11 +5637,38 @@
static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
{
- if (ctx != NULL && ctx != sm->group)
+ struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+ struct wpa_group *group = sm->group;
+#ifdef CONFIG_IEEE80211BE
+ int link_id;
+
+ for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
+ if (!sm->mld_links[link_id].valid)
+ continue;
+ if (sm->mld_links[link_id].wpa_auth &&
+ sm->mld_links[link_id].wpa_auth->group == ctx) {
+ group = sm->mld_links[link_id].wpa_auth->group;
+ wpa_auth = sm->mld_links[link_id].wpa_auth;
+ break;
+ }
+ }
+#endif /* CONFIG_IEEE80211BE */
+
+ if (ctx && ctx != group)
return 0;
+#ifdef CONFIG_IEEE80211BE
+ /* For ML STA, run rekey on the association link and send G1 with keys
+ * for all links. This is based on assumption that MLD level
+ * Authenticator updates group keys on all affiliated links in one shot
+ * and not independently or concurrently for separate links. */
+ if (sm->mld_assoc_link_id >= 0 &&
+ sm->mld_assoc_link_id != wpa_auth->link_id)
+ return 0;
+#endif /* CONFIG_IEEE80211BE */
+
if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
- wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
LOGGER_DEBUG,
"Not in PTKINITDONE; skip Group Key update");
sm->GUpdateStationKeys = false;
@@ -5617,7 +5680,7 @@
* Since we clear the GKeyDoneStations before the loop, the
* station needs to be counted here anyway.
*/
- wpa_auth_logger(sm->wpa_auth, wpa_auth_get_spa(sm),
+ wpa_auth_logger(wpa_auth, wpa_auth_get_spa(sm),
LOGGER_DEBUG,
"GUpdateStationKeys was already set when marking station for GTK rekeying");
}
@@ -5627,6 +5690,11 @@
return 0;
sm->group->GKeyDoneStations++;
+#ifdef CONFIG_IEEE80211BE
+ for_each_sm_auth(sm, link_id)
+ sm->mld_links[link_id].wpa_auth->group->GKeyDoneStations++;
+#endif /* CONFIG_IEEE80211BE */
+
sm->GUpdateStationKeys = true;
wpa_sm_step(sm);
@@ -6939,17 +7007,27 @@
}
-void wpa_auth_set_rsn_override(struct wpa_state_machine *sm, bool val)
+void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie,
+ size_t len)
{
- if (sm)
- sm->rsn_override = val;
-}
-
-
-void wpa_auth_set_rsn_override_2(struct wpa_state_machine *sm, bool val)
-{
- if (sm)
- sm->rsn_override_2 = val;
+ if (!sm)
+ return;
+ os_free(sm->rsn_selection);
+ sm->rsn_selection = NULL;
+ sm->rsn_selection_len = 0;
+ sm->rsn_override = false;
+ sm->rsn_override_2 = false;
+ if (ie) {
+ if (len >= 1) {
+ if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE)
+ sm->rsn_override = true;
+ else if (ie[0] == RSN_SELECTION_RSNE_OVERRIDE_2)
+ sm->rsn_override_2 = true;
+ }
+ sm->rsn_selection = os_memdup(ie, len);
+ if (sm->rsn_selection)
+ sm->rsn_selection_len = len;
+ }
}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 86cb4e8..0b692ad 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -17,7 +17,7 @@
struct vlan_description;
struct mld_info;
-#define MAX_OWN_IE_OVERRIDE 256
+#define MAX_OWN_IE_OVERRIDE 257
#ifdef _MSC_VER
#pragma pack(push, 1)
@@ -230,6 +230,21 @@
double corrupt_gtk_rekey_mic_probability;
u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
size_t own_ie_override_len;
+ bool rsne_override_set;
+ u8 rsne_override[MAX_OWN_IE_OVERRIDE];
+ size_t rsne_override_len;
+ bool rsnoe_override_set;
+ u8 rsnoe_override[MAX_OWN_IE_OVERRIDE];
+ size_t rsnoe_override_len;
+ bool rsno2e_override_set;
+ u8 rsno2e_override[MAX_OWN_IE_OVERRIDE];
+ size_t rsno2e_override_len;
+ bool rsnxe_override_set;
+ u8 rsnxe_override[MAX_OWN_IE_OVERRIDE];
+ size_t rsnxe_override_len;
+ bool rsnxoe_override_set;
+ u8 rsnxoe_override[MAX_OWN_IE_OVERRIDE];
+ size_t rsnxoe_override_len;
u8 rsne_override_eapol[MAX_OWN_IE_OVERRIDE];
size_t rsne_override_eapol_len;
u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE];
@@ -253,6 +268,7 @@
struct wpabuf *eapol_m1_elements;
struct wpabuf *eapol_m3_elements;
bool eapol_m3_no_encrypt;
+ bool eapol_key_reserved_random;
#endif /* CONFIG_TESTING_OPTIONS */
unsigned int oci_freq_override_eapol_m3;
unsigned int oci_freq_override_eapol_g1;
@@ -303,6 +319,8 @@
#endif /* CONFIG_IEEE80211BE */
bool ssid_protection;
+
+ int rsn_override_omit_rsnxe;
};
typedef enum {
@@ -408,7 +426,8 @@
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);
+ int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info,
+ bool rekey);
#endif /* CONFIG_IEEE80211BE */
int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2);
};
@@ -613,8 +632,8 @@
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_rsn_override(struct wpa_state_machine *sm, bool val);
-void wpa_auth_set_rsn_override_2(struct wpa_state_machine *sm, bool val);
+void wpa_auth_set_rsn_selection(struct wpa_state_machine *sm, const u8 *ie,
+ size_t len);
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,
@@ -658,7 +677,8 @@
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);
+ bool mgmt_frame_prot, bool beacon_prot,
+ bool rekey);
void wpa_release_link_auth_ref(struct wpa_state_machine *sm,
int release_link_id);
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index e88644f..2323a59 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -132,6 +132,46 @@
wpabuf_head(conf->own_ie_override),
wconf->own_ie_override_len);
}
+ if (conf->rsne_override &&
+ wpabuf_len(conf->rsne_override) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsne_override_len = wpabuf_len(conf->rsne_override);
+ os_memcpy(wconf->rsne_override,
+ wpabuf_head(conf->rsne_override),
+ wconf->rsne_override_len);
+ wconf->rsne_override_set = true;
+ }
+ if (conf->rsnoe_override &&
+ wpabuf_len(conf->rsnoe_override) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnoe_override_len = wpabuf_len(conf->rsnoe_override);
+ os_memcpy(wconf->rsnoe_override,
+ wpabuf_head(conf->rsnoe_override),
+ wconf->rsnoe_override_len);
+ wconf->rsnoe_override_set = true;
+ }
+ if (conf->rsno2e_override &&
+ wpabuf_len(conf->rsno2e_override) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsno2e_override_len = wpabuf_len(conf->rsno2e_override);
+ os_memcpy(wconf->rsno2e_override,
+ wpabuf_head(conf->rsno2e_override),
+ wconf->rsno2e_override_len);
+ wconf->rsno2e_override_set = true;
+ }
+ if (conf->rsnxe_override &&
+ wpabuf_len(conf->rsnxe_override) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnxe_override_len = wpabuf_len(conf->rsnxe_override);
+ os_memcpy(wconf->rsnxe_override,
+ wpabuf_head(conf->rsnxe_override),
+ wconf->rsnxe_override_len);
+ wconf->rsnxe_override_set = true;
+ }
+ if (conf->rsnxoe_override &&
+ wpabuf_len(conf->rsnxoe_override) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->rsnxoe_override_len = wpabuf_len(conf->rsnxoe_override);
+ os_memcpy(wconf->rsnxoe_override,
+ wpabuf_head(conf->rsnxoe_override),
+ wconf->rsnxoe_override_len);
+ wconf->rsnxoe_override_set = true;
+ }
if (conf->rsne_override_eapol &&
wpabuf_len(conf->rsne_override_eapol) <= MAX_OWN_IE_OVERRIDE) {
wconf->rsne_override_eapol_set = 1;
@@ -199,6 +239,7 @@
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;
+ wconf->eapol_key_reserved_random = conf->eapol_key_reserved_random;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@@ -237,6 +278,8 @@
wconf->no_disconnect_on_group_keyerror =
conf->bss_max_idle && conf->ap_max_inactivity &&
conf->no_disconnect_on_group_keyerror;
+
+ wconf->rsn_override_omit_rsnxe = conf->rsn_override_omit_rsnxe;
}
@@ -1547,7 +1590,8 @@
#ifdef CONFIG_IEEE80211BE
static int hostapd_wpa_auth_get_ml_key_info(void *ctx,
- struct wpa_auth_ml_key_info *info)
+ struct wpa_auth_ml_key_info *info,
+ bool rekey)
{
struct hostapd_data *hapd = ctx;
unsigned int i;
@@ -1571,7 +1615,8 @@
wpa_auth_ml_get_key_info(hapd->wpa_auth,
&info->links[i],
info->mgmt_frame_prot,
- info->beacon_prot);
+ info->beacon_prot,
+ rekey);
continue;
}
@@ -1582,7 +1627,8 @@
wpa_auth_ml_get_key_info(bss->wpa_auth,
&info->links[i],
info->mgmt_frame_prot,
- info->beacon_prot);
+ info->beacon_prot,
+ rekey);
link_bss_found = true;
break;
}
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 29988c2..cb902e4 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -111,6 +111,8 @@
size_t wpa_ie_len;
u8 *rsnxe;
size_t rsnxe_len;
+ u8 *rsn_selection;
+ size_t rsn_selection_len;
enum {
WPA_VERSION_NO_WPA = 0 /* WPA not used */,
@@ -251,9 +253,6 @@
u8 *wpa_ie;
size_t wpa_ie_len;
- u8 *rsne_override; /* RSNE with overridden payload */
- u8 *rsne_override_2; /* RSNE with overridden (2) payload */
- u8 *rsnxe_override; /* RSNXE with overridden payload */
u8 addr[ETH_ALEN];
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index f4f9cc8..43d9c1d 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -547,15 +547,20 @@
size_t len)
{
u8 *pos = buf;
- u16 capab;
+ u32 capab, tmp;
size_t flen;
capab = rsnxe_capab(conf, conf->rsn_override_key_mgmt |
conf->rsn_override_key_mgmt_2);
- 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) */
@@ -565,10 +570,10 @@
WPA_PUT_BE32(pos, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
pos += 4;
- *pos++ = capab & 0x00ff;
- capab >>= 8;
- if (capab)
- *pos++ = capab;
+ while (capab) {
+ *pos++ = capab & 0xff;
+ capab >>= 8;
+ }
return pos - buf;
}
@@ -627,7 +632,7 @@
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
{
- u8 *pos, buf[256];
+ u8 *pos, buf[1500];
int res;
#ifdef CONFIG_TESTING_OPTIONS
@@ -653,17 +658,54 @@
pos = wpa_write_osen(&wpa_auth->conf, pos);
}
if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_auth->conf.rsne_override_set) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Forced own RSNE for testing",
+ wpa_auth->conf.rsne_override,
+ wpa_auth->conf.rsne_override_len);
+ if (sizeof(buf) - (pos - buf) <
+ wpa_auth->conf.rsne_override_len)
+ return -1;
+ os_memcpy(pos, wpa_auth->conf.rsne_override,
+ wpa_auth->conf.rsne_override_len);
+ pos += wpa_auth->conf.rsne_override_len;
+ goto rsnxe;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_rsn_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos, NULL);
if (res < 0)
return res;
pos += res;
- res = wpa_write_rsnxe(&wpa_auth->conf, pos,
- buf + sizeof(buf) - pos);
+#ifdef CONFIG_TESTING_OPTIONS
+ rsnxe:
+ if (wpa_auth->conf.rsnxe_override_set) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Forced own RSNXE for testing",
+ wpa_auth->conf.rsnxe_override,
+ wpa_auth->conf.rsnxe_override_len);
+ if (sizeof(buf) - (pos - buf) <
+ wpa_auth->conf.rsnxe_override_len)
+ return -1;
+ os_memcpy(pos, wpa_auth->conf.rsnxe_override,
+ wpa_auth->conf.rsnxe_override_len);
+ pos += wpa_auth->conf.rsnxe_override_len;
+ goto fte;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (wpa_auth->conf.rsn_override_omit_rsnxe)
+ res = 0;
+ else
+ res = wpa_write_rsnxe(&wpa_auth->conf, pos,
+ buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
+#ifdef CONFIG_TESTING_OPTIONS
+fte:
+#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
res = wpa_write_mdie(&wpa_auth->conf, pos,
@@ -682,30 +724,85 @@
}
if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
wpa_auth->conf.rsn_override_key_mgmt) {
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_auth->conf.rsnoe_override_set) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Forced own RSNOE for testing",
+ wpa_auth->conf.rsnoe_override,
+ wpa_auth->conf.rsnoe_override_len);
+ if (sizeof(buf) - (pos - buf) <
+ wpa_auth->conf.rsnoe_override_len)
+ return -1;
+ os_memcpy(pos, wpa_auth->conf.rsnoe_override,
+ wpa_auth->conf.rsnoe_override_len);
+ pos += wpa_auth->conf.rsnoe_override_len;
+ goto rsno2e;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_rsne_override(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
+#ifdef CONFIG_TESTING_OPTIONS
+rsno2e:
+#endif /* CONFIG_TESTING_OPTIONS */
if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
wpa_auth->conf.rsn_override_key_mgmt_2) {
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_auth->conf.rsno2e_override_set) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Forced own RSNO2E for testing",
+ wpa_auth->conf.rsno2e_override,
+ wpa_auth->conf.rsno2e_override_len);
+ if (sizeof(buf) - (pos - buf) <
+ wpa_auth->conf.rsno2e_override_len)
+ return -1;
+ os_memcpy(pos, wpa_auth->conf.rsno2e_override,
+ wpa_auth->conf.rsno2e_override_len);
+ pos += wpa_auth->conf.rsno2e_override_len;
+ goto rsnxoe;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_rsne_override_2(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
+#ifdef CONFIG_TESTING_OPTIONS
+rsnxoe:
+#endif /* CONFIG_TESTING_OPTIONS */
if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
(wpa_auth->conf.rsn_override_key_mgmt ||
wpa_auth->conf.rsn_override_key_mgmt_2)) {
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_auth->conf.rsnxoe_override_set) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Forced own RSNXOE for testing",
+ wpa_auth->conf.rsnxoe_override,
+ wpa_auth->conf.rsnxoe_override_len);
+ if (sizeof(buf) - (pos - buf) <
+ wpa_auth->conf.rsnxoe_override_len)
+ return -1;
+ os_memcpy(pos, wpa_auth->conf.rsnxoe_override,
+ wpa_auth->conf.rsnxoe_override_len);
+ pos += wpa_auth->conf.rsnxoe_override_len;
+ goto done;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_write_rsnxe_override(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
+#ifdef CONFIG_TESTING_OPTIONS
+done:
+#endif /* CONFIG_TESTING_OPTIONS */
+ wpa_hexdump(MSG_DEBUG, "RSN: Own IEs", buf, pos - buf);
os_free(wpa_auth->wpa_ie);
wpa_auth->wpa_ie = os_malloc(pos - buf);
if (wpa_auth->wpa_ie == NULL)
@@ -713,59 +810,6 @@
os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
wpa_auth->wpa_ie_len = pos - buf;
- if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
- wpa_auth->conf.rsn_override_key_mgmt) {
- res = wpa_write_rsne_override(&wpa_auth->conf, buf,
- sizeof(buf));
- if (res < 0)
- return res;
- os_free(wpa_auth->rsne_override);
- wpa_auth->rsne_override = os_malloc(res - 4);
- if (!wpa_auth->rsne_override)
- return -1;
- pos = wpa_auth->rsne_override;
- *pos++ = WLAN_EID_RSN;
- *pos++ = res - 2 - 4;
- os_memcpy(pos, &buf[2 + 4], res - 2 - 4);
- }
-
- if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
- wpa_auth->conf.rsn_override_key_mgmt_2) {
- res = wpa_write_rsne_override_2(&wpa_auth->conf, buf,
- sizeof(buf));
- if (res < 0)
- return res;
- os_free(wpa_auth->rsne_override_2);
- wpa_auth->rsne_override_2 = os_malloc(res - 4);
- if (!wpa_auth->rsne_override_2)
- return -1;
- pos = wpa_auth->rsne_override_2;
- *pos++ = WLAN_EID_RSN;
- *pos++ = res - 2 - 4;
- os_memcpy(pos, &buf[2 + 4], res - 2 - 4);
- }
-
- if ((wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
- (wpa_auth->conf.rsn_override_key_mgmt ||
- wpa_auth->conf.rsn_override_key_mgmt_2)) {
- res = wpa_write_rsnxe_override(&wpa_auth->conf, buf,
- sizeof(buf));
- if (res < 0)
- return res;
- os_free(wpa_auth->rsnxe_override);
- if (res == 0) {
- wpa_auth->rsnxe_override = NULL;
- return 0;
- }
- wpa_auth->rsnxe_override = os_malloc(res - 4);
- if (!wpa_auth->rsnxe_override)
- return -1;
- pos = wpa_auth->rsnxe_override;
- *pos++ = WLAN_EID_RSNX;
- *pos++ = res - 2 - 4;
- os_memcpy(pos, &buf[2 + 4], res - 2 - 4);
- }
-
return 0;
}
@@ -970,9 +1014,13 @@
return WPA_INVALID_GROUP;
}
- key_mgmt = data.key_mgmt & (wpa_auth->conf.wpa_key_mgmt |
- wpa_auth->conf.rsn_override_key_mgmt |
- wpa_auth->conf.rsn_override_key_mgmt_2);
+ if (sm->rsn_override_2)
+ key_mgmt = data.key_mgmt &
+ wpa_auth->conf.rsn_override_key_mgmt_2;
+ else if (sm->rsn_override)
+ key_mgmt = data.key_mgmt & wpa_auth->conf.rsn_override_key_mgmt;
+ else
+ key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
if (!key_mgmt) {
wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
MACSTR, data.key_mgmt, MAC2STR(sm->addr));
@@ -1041,11 +1089,14 @@
else
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
- if (version == WPA_PROTO_RSN)
+ if (version == WPA_PROTO_RSN && sm->rsn_override_2)
ciphers = data.pairwise_cipher &
- (wpa_auth->conf.rsn_pairwise |
- wpa_auth->conf.rsn_override_pairwise |
- wpa_auth->conf.rsn_override_pairwise_2);
+ wpa_auth->conf.rsn_override_pairwise_2;
+ else if (version == WPA_PROTO_RSN && sm->rsn_override)
+ ciphers = data.pairwise_cipher &
+ wpa_auth->conf.rsn_override_pairwise;
+ else if (version == WPA_PROTO_RSN)
+ ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
else
ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
if (!ciphers) {
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index a95ae36..5763c51 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -651,7 +651,7 @@
spa_addr, bssid,
dhss, sizeof(dhss),
&ptk, WPA_KEY_MGMT_PASN, WPA_CIPHER_CCMP,
- WPA_KDK_MAX_LEN);
+ WPA_KDK_MAX_LEN, 0);
if (ret)
return ret;
diff --git a/src/common/defs.h b/src/common/defs.h
index 48d5d3c..754c4e4 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -537,4 +537,9 @@
SAE_PWE_NOT_SET = 4,
};
+#define USEC_80211_TU 1024
+
+#define USEC_TO_TU(m) ((m) / USEC_80211_TU)
+#define TU_TO_USEC(m) ((m) * USEC_80211_TU)
+
#endif /* DEFS_H */
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 02c32dc..46f2551 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -1035,6 +1035,10 @@
json_value_sep(json);
json_add_string(json, "pkcs10", csr);
}
+#ifdef CONFIG_DPP3
+ json_value_sep(json);
+ json_add_int(json, "capabilities", DPP_ENROLLEE_CAPAB_SAE_PW_ID);
+#endif /* CONFIG_DPP3 */
if (extra_name && extra_value && extra_name[0] && extra_value[0]) {
json_value_sep(json);
wpabuf_printf(json, "\"%s\":%s", extra_name, extra_value);
@@ -1139,8 +1143,18 @@
return 0;
if (dpp_akm_psk(conf->akm) && !conf->passphrase && !conf->psk_set)
return 0;
+ if (dpp_akm_psk(conf->akm) && conf->passphrase) {
+ size_t len = os_strlen(conf->passphrase);
+
+ if (len > 63 || len < 8)
+ return 0;
+ }
if (dpp_akm_sae(conf->akm) && !conf->passphrase)
return 0;
+#ifdef CONFIG_DPP3
+ if (conf->idpass && (!conf->passphrase || !dpp_akm_sae(conf->akm)))
+ return 0;
+#endif /* CONFIG_DPP3 */
return 1;
}
@@ -1150,6 +1164,9 @@
if (!conf)
return;
str_clear_free(conf->passphrase);
+#ifdef CONFIG_DPP3
+ os_free(conf->idpass);
+#endif /* CONFIG_DPP3 */
os_free(conf->group_id);
os_free(conf->csrattrs);
os_free(conf->extra_name);
@@ -1228,14 +1245,28 @@
end = os_strchr(pos, ' ');
pass_len = end ? (size_t) (end - pos) : os_strlen(pos);
pass_len /= 2;
- if (pass_len > 63 || pass_len < 8)
- goto fail;
conf->passphrase = os_zalloc(pass_len + 1);
if (!conf->passphrase ||
hexstr2bin(pos, (u8 *) conf->passphrase, pass_len) < 0)
goto fail;
}
+#ifdef CONFIG_DPP3
+ pos = os_strstr(cmd, " idpass=");
+ if (pos) {
+ size_t idpass_len;
+
+ pos += 8;
+ end = os_strchr(pos, ' ');
+ idpass_len = end ? (size_t) (end - pos) : os_strlen(pos);
+ idpass_len /= 2;
+ conf->idpass = os_zalloc(idpass_len + 1);
+ if (!conf->idpass ||
+ hexstr2bin(pos, (u8 *) conf->idpass, idpass_len) < 0)
+ goto fail;
+ }
+#endif /* CONFIG_DPP3 */
+
pos = os_strstr(cmd, " psk=");
if (pos) {
pos += 5;
@@ -1595,6 +1626,13 @@
if (conf->passphrase && os_strlen(conf->passphrase) < 64) {
json_add_string_escape(buf, "pass", conf->passphrase,
os_strlen(conf->passphrase));
+#ifdef CONFIG_DPP3
+ if (conf->idpass) {
+ json_value_sep(buf);
+ json_add_string_escape(buf, "idpass", conf->idpass,
+ os_strlen(conf->idpass));
+ }
+#endif /* CONFIG_DPP3 */
} else if (conf->psk_set) {
char psk[2 * sizeof(conf->psk) + 1];
@@ -1917,6 +1955,16 @@
const char *akm_str;
size_t len = 1000;
+
+#ifdef CONFIG_DPP3
+ if (conf->idpass &&
+ !(auth->enrollee_capabilities & DPP_ENROLLEE_CAPAB_SAE_PW_ID)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Enrollee does not support SAE Password Identifier - cannot generate config object");
+ return NULL;
+ }
+#endif /* CONFIG_DPP3 */
+
if (conf->extra_name && conf->extra_value)
len += 10 + os_strlen(conf->extra_name) +
os_strlen(conf->extra_value);
@@ -2540,6 +2588,18 @@
cont:
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+ token = json_get_member(root, "capabilities");
+ if (token && token->type == JSON_NUMBER) {
+ wpa_printf(MSG_DEBUG, "DPP: capabilities = 0x%x",
+ token->number);
+ wpa_msg(auth->msg_ctx, MSG_INFO,
+ DPP_EVENT_ENROLLEE_CAPABILITY "%d",
+ token->number);
+ auth->enrollee_capabilities = token->number;
+ }
+#endif /* CONFIG_DPP3 */
+
resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, netrole,
cert_req);
@@ -2563,13 +2623,25 @@
if (pass && pass->type == JSON_STRING) {
size_t len = os_strlen(pass->string);
+#ifdef CONFIG_DPP3
+ struct json_token *saepi = json_get_member(cred, "idpass");
+#endif /* CONFIG_DPP3 */
wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase",
pass->string, len);
- if (len < 8 || len > 63)
+ if (dpp_akm_psk(conf->akm) && (len < 8 || len > 63)) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Unexpected pass length %zu for a config object that includes PSK",
+ len);
return -1;
+ }
os_strlcpy(conf->passphrase, pass->string,
sizeof(conf->passphrase));
+#ifdef CONFIG_DPP3
+ if (saepi && saepi->type == JSON_STRING)
+ os_strlcpy(conf->password_id, saepi->string,
+ sizeof(conf->password_id));
+#endif /* CONFIG_DPP3 */
} else if (psk_hex && psk_hex->type == JSON_STRING) {
if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
wpa_printf(MSG_DEBUG,
diff --git a/src/common/dpp.h b/src/common/dpp.h
index 86f8478..f9af506 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -134,6 +134,9 @@
#define DPP_MAX_SHARED_SECRET_LEN 66
#define DPP_CP_LEN 64
+/* DPP Configuration Request - Enrollee Capabilities */
+#define DPP_ENROLLEE_CAPAB_SAE_PW_ID BIT(0)
+
struct dpp_curve_params {
const char *name;
size_t hash_len;
@@ -260,6 +263,7 @@
/* For legacy configuration */
char *passphrase;
+ char *idpass;
u8 psk[32];
int psk_set;
@@ -359,6 +363,9 @@
u8 ssid_len;
int ssid_charset;
char passphrase[64];
+#ifdef CONFIG_DPP3
+ char password_id[64];
+#endif /* CONFIG_DPP3 */
u8 psk[PMK_LEN];
int psk_set;
enum dpp_akm akm;
@@ -396,6 +403,7 @@
char *e_name;
char *e_mud_url;
int *e_band_support;
+ unsigned int enrollee_capabilities;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 2c47bf8..bffb440 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -1033,3 +1033,18 @@
return false;
}
+
+
+bool chan_in_current_hw_info(struct hostapd_multi_hw_info *current_hw_info,
+ struct hostapd_channel_data *chan)
+{
+ /* Assuming that if current_hw_info is not set full
+ * iface->current_mode->channels[] can be used to scan for channels,
+ * hence we return true.
+ */
+ if (!current_hw_info)
+ return true;
+
+ return current_hw_info->start_freq <= chan->freq &&
+ current_hw_info->end_freq >= chan->freq;
+}
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index e791c33..80e33ad 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -58,5 +58,7 @@
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);
+bool chan_in_current_hw_info(struct hostapd_multi_hw_info *current_hw_info,
+ struct hostapd_channel_data *chan);
#endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 10f9c4a..c9b2d37 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -148,6 +148,20 @@
elems->rsne_override_2 = pos;
elems->rsne_override_2_len = elen;
break;
+ case WFA_RSN_SELECTION_OUI_TYPE:
+ if (elen < 4 + 1) {
+ wpa_printf(MSG_DEBUG,
+ "Too short RSN Selection element ignored");
+ return -1;
+ }
+ elems->rsn_selection = pos + 4;
+ elems->rsn_selection_len = elen - 4;
+ break;
+ case P2P2_OUI_TYPE:
+ /* Wi-Fi Alliance - P2P2 IE */
+ elems->p2p2_ie = pos;
+ elems->p2p2_ie_len = elen;
+ break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
@@ -407,6 +421,10 @@
elems->mbssid_known_bss = pos;
elems->mbssid_known_bss_len = elen;
break;
+ case WLAN_EID_EXT_PASN_ENCRYPTED_DATA:
+ elems->pasn_encrypted_data = pos;
+ elems->pasn_encrypted_data_len = elen;
+ break;
default:
if (show_errors) {
wpa_printf(MSG_MSGDUMP,
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 17e0822..62090ce 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -65,6 +65,8 @@
const u8 *vendor_ht_cap;
const u8 *vendor_vht;
const u8 *p2p;
+ const u8 *p2p2_ie;
+ const u8 *pasn_encrypted_data;
const u8 *wfd;
const u8 *link_id;
const u8 *interworking;
@@ -118,6 +120,7 @@
const u8 *mbssid;
const u8 *rsne_override;
const u8 *rsne_override_2;
+ const u8 *rsn_selection;
u8 ssid_len;
u8 supp_rates_len;
@@ -138,6 +141,8 @@
u8 vendor_ht_cap_len;
u8 vendor_vht_len;
u8 p2p_len;
+ u8 p2p2_ie_len;
+ u8 pasn_encrypted_data_len;
u8 wfd_len;
u8 interworking_len;
u8 qos_map_set_len;
@@ -183,6 +188,7 @@
u8 mbssid_len;
size_t rsne_override_len;
size_t rsne_override_2_len;
+ size_t rsn_selection_len;
struct mb_ies_info mb_ies;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 4cc6e41..7ce7591 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -504,6 +504,7 @@
#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_MAX_CHANNEL_SWITCH_TIME 52
#define WLAN_EID_EXT_OCV_OCI 54
#define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55
#define WLAN_EID_EXT_NON_INHERITANCE 56
@@ -524,6 +525,8 @@
#define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
#define WLAN_EID_EXT_QOS_CHARACTERISTICS 113
#define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
+#define WLAN_EID_EXT_BANDWIDTH_INDICATION 135
+#define WLAN_EID_EXT_PASN_ENCRYPTED_DATA 140
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -1431,6 +1434,7 @@
#define WPS_IE_VENDOR_TYPE 0x0050f204
#define OUI_WFA 0x506f9a
#define P2P_IE_VENDOR_TYPE 0x506f9a09
+#define P2P2_IE_VENDOR_TYPE 0x506f9a28
#define WFD_IE_VENDOR_TYPE 0x506f9a0a
#define WFD_OUI_TYPE 10
#define HS20_IE_VENDOR_TYPE 0x506f9a10
@@ -1455,9 +1459,11 @@
#define WFA_RSNE_OVERRIDE_OUI_TYPE 0x29
#define WFA_RSNE_OVERRIDE_2_OUI_TYPE 0x2a
#define WFA_RSNXE_OVERRIDE_OUI_TYPE 0x2b
+#define WFA_RSN_SELECTION_OUI_TYPE 0x2c
#define RSNE_OVERRIDE_IE_VENDOR_TYPE 0x506f9a29
#define RSNE_OVERRIDE_2_IE_VENDOR_TYPE 0x506f9a2a
#define RSNXE_OVERRIDE_IE_VENDOR_TYPE 0x506f9a2b
+#define RSN_SELECTION_IE_VENDOR_TYPE 0x506f9a2c
#define MULTI_AP_SUB_ELEM_TYPE 0x06
#define MULTI_AP_PROFILE_SUB_ELEM_TYPE 0x07
@@ -1722,6 +1728,7 @@
/* Wi-Fi Direct (P2P) */
#define P2P_OUI_TYPE 9
+#define P2P2_OUI_TYPE 0x28
enum p2p_attr_id {
P2P_ATTR_STATUS = 0,
@@ -1752,6 +1759,13 @@
P2P_ATTR_SESSION_ID = 26,
P2P_ATTR_FEATURE_CAPABILITY = 27,
P2P_ATTR_PERSISTENT_GROUP = 28,
+ P2P_ATTR_CAPABILITY_EXTENSION = 29,
+ P2P_ATTR_WLAN_AP_INFORMATION = 30,
+ P2P_ATTR_DEVICE_IDENTITY_KEY = 31,
+ P2P_ATTR_DEVICE_IDENTITY_RESOLUTION = 32,
+ P2P_ATTR_PAIRING_AND_BOOTSTRAPPING = 33,
+ P2P_ATTR_PASSWORD = 34,
+ P2P_ATTR_ACTION_FRAME_WRAPPER = 35,
P2P_ATTR_VENDOR_SPECIFIC = 221
};
@@ -1776,6 +1790,31 @@
#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
#define P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION BIT(7)
+/* P2P Capability Extension attribute - Capability info */
+#define P2P_PCEA_LEN_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define P2P_PCEA_6GHZ BIT(4)
+#define P2P_PCEA_REG_INFO BIT(5)
+#define P2P_PCEA_DFS_OWNER BIT(6)
+#define P2P_PCEA_CLI_REQ_CS BIT(7)
+#define P2P_PCEA_PAIRING_CAPABLE BIT(8)
+#define P2P_PCEA_PAIRING_SETUP_ENABLED BIT(9)
+#define P2P_PCEA_PMK_CACHING BIT(10)
+#define P2P_PCEA_PASN_TYPE BIT(11)
+#define P2P_PCEA_TWT_POWER_MGMT BIT(12)
+
+/* P2P Pairing Bootstrapping Method attribute - Bootstrapping Method */
+#define P2P_PBMA_OPPORTUNISTIC BIT(0)
+#define P2P_PBMA_PIN_CODE_DISPLAY BIT(1)
+#define P2P_PBMA_PASSPHRASE_DISPLAY BIT(2)
+#define P2P_PBMA_QR_DISPLAY BIT(3)
+#define P2P_PBMA_NFC_TAG BIT(4)
+#define P2P_PBMA_PIN_CODE_KEYPAD BIT(5)
+#define P2P_PBMA_PASSPHRASE_KEYPAD BIT(6)
+#define P2P_PBMA_QR_SCAN BIT(7)
+#define P2P_PBMA_NFC_READER BIT(8)
+#define P2P_PBMA_SERVICE_MANAGED BIT(14)
+#define P2P_PBMA_HANDSHAKE_SKIP BIT(15)
+
/* P2PS Coordination Protocol Transport Bitmap */
#define P2PS_FEATURE_CAPAB_UDP_TRANSPORT BIT(0)
#define P2PS_FEATURE_CAPAB_MAC_TRANSPORT BIT(1)
@@ -1807,6 +1846,7 @@
P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
P2P_SC_FAIL_REJECTED_BY_USER = 11,
P2P_SC_SUCCESS_DEFERRED = 12,
+ P2P_SC_COMEBACK = 13,
};
enum p2p_role_indication {
@@ -2904,6 +2944,33 @@
EHT_ML_SUB_ELEM_FRAGMENT = 254,
};
+/* IEEE P802.11be/D7.0, 9.4.2.329 (Bandwidth Indication element) defines the
+ * Bandwidth Indication Information field to have the same definition as the
+ * EHT Operation Information field in the EHT Operation element.
+ */
+struct ieee80211_bw_ind_info {
+ u8 control; /* B0..B2: Channel Width */
+ u8 ccfs0;
+ u8 ccfs1;
+ le16 disabled_chan_bitmap; /* 0 or 2 octets */
+} STRUCT_PACKED;
+
+/* Control subfield: Channel Width subfield; see Table 9-417e (Channel width,
+ * CCFS0, and CCFS1 subfields) in IEEE P802.11be/D7.0. */
+#define BW_IND_CHANNEL_WIDTH_20MHZ EHT_OPER_CHANNEL_WIDTH_20MHZ
+#define BW_IND_CHANNEL_WIDTH_40MHZ EHT_OPER_CHANNEL_WIDTH_40MHZ
+#define BW_IND_CHANNEL_WIDTH_80MHZ EHT_OPER_CHANNEL_WIDTH_80MHZ
+#define BW_IND_CHANNEL_WIDTH_160MHZ EHT_OPER_CHANNEL_WIDTH_160MHZ
+#define BW_IND_CHANNEL_WIDTH_320MHZ EHT_OPER_CHANNEL_WIDTH_320MHZ
+
+/* IEEE P802.11be/D7.0, 9.4.2.329 (Bandwidth Indication element) */
+struct ieee80211_bw_ind_element {
+ u8 bw_ind_params; /* Bandwidth Indication Parameters */
+ struct ieee80211_bw_ind_info bw_ind_info; /* 3 or 5 octets */
+} STRUCT_PACKED;
+
+#define BW_IND_PARAMETER_DISABLED_SUBCHAN_BITMAP_PRESENT BIT(1)
+
/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
#define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
diff --git a/src/common/nan_de.c b/src/common/nan_de.c
index 12fad31..acde4f3 100644
--- a/src/common/nan_de.c
+++ b/src/common/nan_de.c
@@ -58,10 +58,12 @@
struct os_reltime next_publish_state;
struct os_reltime next_publish_chan;
unsigned int next_publish_duration;
+ bool is_p2p;
};
struct nan_de {
u8 nmi[ETH_ALEN];
+ bool offload;
bool ap;
struct nan_callbacks cb;
@@ -77,7 +79,7 @@
};
-struct nan_de * nan_de_init(const u8 *nmi, bool ap,
+struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap,
const struct nan_callbacks *cb)
{
struct nan_de *de;
@@ -87,6 +89,7 @@
return NULL;
os_memcpy(de->nmi, nmi, ETH_ALEN);
+ de->offload = offload;
de->ap = ap;
os_memcpy(&de->cb, cb, sizeof(*cb));
@@ -590,7 +593,7 @@
if (srv_next >= 0 && (next == -1 || srv_next < next))
next = srv_next;
- if (srv_next == 0 && !started &&
+ if (srv_next == 0 && !started && !de->offload &&
de->listen_freq == 0 && de->ext_listen_freq == 0 &&
de->tx_wait_end_freq == 0 &&
nan_de_next_multicast(de, srv, &now) == 0) {
@@ -598,7 +601,7 @@
nan_de_tx_multicast(de, srv, 0);
}
- if (!started && de->cb.listen &&
+ if (!started && !de->offload && de->cb.listen &&
de->listen_freq == 0 && de->ext_listen_freq == 0 &&
de->tx_wait_end_freq == 0 &&
((srv->type == NAN_DE_PUBLISH &&
@@ -774,6 +777,34 @@
}
+static void nan_de_process_elem_container(struct nan_de *de, const u8 *buf,
+ size_t len, const u8 *peer_addr,
+ unsigned int freq, bool p2p)
+{
+ const u8 *elem;
+ u16 elem_len;
+
+ elem = nan_de_get_attr(buf, len, NAN_ATTR_ELEM_CONTAINER, 0);
+ if (!elem)
+ return;
+
+ elem++;
+ elem_len = WPA_GET_LE16(elem);
+ elem += 2;
+ /* Skip the attribute if there is not enough froom for an element. */
+ if (elem_len < 1 + 2)
+ return;
+
+ /* Skip Map ID */
+ elem++;
+ elem_len--;
+
+ if (p2p && de->cb.process_p2p_usd_elems)
+ de->cb.process_p2p_usd_elems(de->cb.ctx, elem, elem_len,
+ peer_addr, freq);
+}
+
+
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,
@@ -787,13 +818,13 @@
nan_de_run_timer(de);
}
- if (srv->subscribe.active && req_instance_id == 0) {
+ if (!de->offload && 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) {
+ if (!de->offload && !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. */
@@ -873,6 +904,9 @@
return;
}
+ if (de->offload)
+ goto offload;
+
/* Reply with a solicited Publish message */
/* Service Descriptor attribute */
sda_len = NAN_SERVICE_ID_LEN + 1 + 1 + 1;
@@ -939,6 +973,7 @@
nan_de_pause_state(srv, peer_addr, instance_id);
+offload:
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);
@@ -1094,6 +1129,8 @@
wpa_hexdump(MSG_MSGDUMP, "NAN: ssi",
ssi, ssi_len);
}
+ nan_de_process_elem_container(de, buf, len, peer_addr,
+ freq, srv->is_p2p);
}
switch (type) {
@@ -1196,10 +1233,23 @@
}
+const u8 * nan_de_get_service_id(struct nan_de *de, int id)
+{
+ struct nan_de_service *srv;
+
+ if (id < 1 || id > NAN_DE_MAX_SERVICE)
+ return NULL;
+ srv = de->service[id - 1];
+ if (!srv)
+ return NULL;
+ return srv->service_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)
+ struct nan_publish_params *params, bool p2p)
{
int publish_id;
struct nan_de_service *srv;
@@ -1261,6 +1311,7 @@
wpa_printf(MSG_DEBUG, "NAN: Assigned new publish handle %d for %s",
publish_id, service_name);
srv->id = publish_id;
+ srv->is_p2p = p2p;
nan_de_add_srv(de, srv);
nan_de_run_timer(de);
return publish_id;
@@ -1312,7 +1363,7 @@
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)
+ struct nan_subscribe_params *params, bool p2p)
{
int subscribe_id;
struct nan_de_service *srv;
@@ -1337,6 +1388,17 @@
if (nan_de_derive_service_id(srv) < 0)
goto fail;
os_memcpy(&srv->subscribe, 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->subscribe.freq_list = NULL;
+
srv->srv_proto_type = srv_proto_type;
if (ssi) {
srv->ssi = wpabuf_dup(ssi);
@@ -1352,6 +1414,7 @@
wpa_printf(MSG_DEBUG, "NAN: Assigned new subscribe handle %d for %s",
subscribe_id, service_name);
srv->id = subscribe_id;
+ srv->is_p2p = p2p;
nan_de_add_srv(de, srv);
nan_de_run_timer(de);
return subscribe_id;
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index 6223506..f369a57 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -53,9 +53,13 @@
void (*receive)(void *ctx, int id, int peer_instance_id,
const u8 *ssi, size_t ssi_len,
const u8 *peer_addr);
+
+ void (*process_p2p_usd_elems)(void *ctx, const u8 *buf,
+ u16 buf_len, const u8 *peer_addr,
+ unsigned int freq);
};
-struct nan_de * nan_de_init(const u8 *nmi, bool ap,
+struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap,
const struct nan_callbacks *cb);
void nan_de_flush(struct nan_de *de);
void nan_de_deinit(struct nan_de *de);
@@ -68,6 +72,7 @@
void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq,
const u8 *buf, size_t len);
+const u8 * nan_de_get_service_id(struct nan_de *de, int id);
struct nan_publish_params {
/* configuration_parameters */
@@ -105,7 +110,7 @@
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);
+ struct nan_publish_params *params, bool p2p);
void nan_de_cancel_publish(struct nan_de *de, int publish_id);
@@ -124,6 +129,9 @@
/* Selected frequency */
unsigned int freq;
+ /* Multi-channel frequencies (publishChannelList) */
+ const int *freq_list;
+
/* Query period in ms; 0 = use default */
unsigned int query_period;
};
@@ -132,7 +140,7 @@
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);
+ struct nan_subscribe_params *params, bool p2p);
void nan_de_cancel_subscribe(struct nan_de *de, int subscribe_id);
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 5dab120..ddf1966 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -230,7 +230,8 @@
*
* @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
* supported by the driver. enum qca_wlan_vendor_features defines
- * the possible features.
+ * the possible features that are encoded in
+ * QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS.
*
* @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: Event used by driver,
* which supports DFS offloading, to indicate a channel availability check
@@ -1132,6 +1133,39 @@
* Uses the attributes defined in
* enum qca_wlan_vendor_attr_tdls_disc_rsp_ext.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH: This vendor subcommand is
+ * used to configure and indicate the audio transport switch in both
+ * command and event paths. This is used when two or more audio transports
+ * (e.g., WLAN and Bluetooth) are available between peers.
+ *
+ * If the driver needs to perform operations like scan, connection,
+ * roaming, RoC, etc. and AP concurrency policy is set to either
+ * QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO or
+ * QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING, the driver sends
+ * audio transport switch event to userspace. Userspace application upon
+ * receiving the event, can try to switch to the requested audio transport.
+ * The userspace uses this command to send the status of transport
+ * switching (either confirm or reject) to the driver using this
+ * subcommand. The driver continues with the pending operation either upon
+ * receiving the command from userspace or after waiting for a timeout from
+ * sending the event to userspace. The driver can request userspace to
+ * switch to WLAN upon availability of WLAN audio transport once after the
+ * concurrent operations are completed.
+ *
+ * Userspace can also request audio transport switch from non-WLAN to WLAN
+ * using this subcommand to the driver. The driver can accept or reject
+ * depending on other concurrent operations in progress. The driver returns
+ * success if it can allow audio transport when it receives the command or
+ * appropriate kernel error code otherwise. Userspace indicates the audio
+ * transport switch from WLAN to non-WLAN using this subcommand and the
+ * driver can do other concurrent operations without needing to send any
+ * event to userspace. This subcommand is used by userspace only when the
+ * driver advertises support for
+ * QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN.
+ *
+ * The attributes used with this command are defined in enum
+ * qca_wlan_vendor_attr_audio_transport_switch.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY: This vendor subcommand is used to
* configure, retrieve, and report per-link transmit latency statistics.
*
@@ -1237,6 +1271,33 @@
*
* The attributes used with this command are defined in
* enum qca_wlan_vendor_attr_usd.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT: This is an extension to
+ * %NL80211_CMD_CONNECT command. Userspace can use this to indicate
+ * additional information to be considered for the subsequent
+ * (re)association request attempts with %NL80211_CMD_CONNECT. The
+ * additional information sent with this command is applicable for the
+ * entire duration of the connection established with %NL80211_CMD_CONNECT,
+ * including the roams triggered by the driver internally due to other
+ * vendor interfaces, driver internal logic, and BTM requests from the
+ * connected AP.
+ *
+ * The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_connect_ext.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_P2P_MODE: Vendor subcommand to configure
+ * Wi-Fi Direct mode. This command sets the configuration through
+ * the attributes defined in the enum qca_wlan_vendor_attr_set_p2p_mode.
+ * It is applicable for P2P Group Owner only. This command is used before
+ * starting the GO.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_CHAN_USAGE_REQ: Vendor subcommand to request
+ * transmission of a channel usage request. It carries channel usage
+ * information for BSSs that are not infrastructure BSSs or an off channel
+ * TDLS direct link.
+ *
+ * The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_chan_usage_req.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -1452,7 +1513,7 @@
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_AUDIO_TRANSPORT_SWITCH = 232,
QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY = 233,
/* 234 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SDWF_PHY_OPS = 235,
@@ -1470,6 +1531,9 @@
QCA_NL80211_VENDOR_SUBCMD_ASYNC_STATS_POLICY = 247,
QCA_NL80211_VENDOR_SUBCMD_CLASSIFIED_FLOW_REPORT = 248,
QCA_NL80211_VENDOR_SUBCMD_USD = 249,
+ QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT = 250,
+ QCA_NL80211_VENDOR_SUBCMD_SET_P2P_MODE = 251,
+ QCA_NL80211_VENDOR_SUBCMD_CHAN_USAGE_REQ = 252,
};
/* Compatibility defines for previously used subcmd names.
@@ -1496,7 +1560,11 @@
*/
QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
- /* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
+ /* Feature flags contained in a byte array. The feature flags are
+ * identified by their bit index (see &enum qca_wlan_vendor_features)
+ * with the first byte being the least significant one and the last one
+ * being the most significant one. Used by
+ * QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES. */
QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
QCA_WLAN_VENDOR_ATTR_TEST = 8,
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
@@ -2193,31 +2261,15 @@
* in AP mode supports TWT responder mode in HT and VHT modes.
*
* @QCA_WLAN_VENDOR_FEATURE_RSN_OVERRIDE_STA: Flag indicates that the device
- * supports RSNE/RSNXE overriding in STA mode.
+ * supports RSNE/RSNXE overriding in STA mode. Supplicant should enable
+ * RSN overriding elements use only when the driver indicates this feature
+ * flag. For BSS selection offload to the driver case, the driver shall
+ * strip/modify the RSN Selection element indicated in connect request
+ * elements or add that element if none was provided based on the BSS
+ * selected by the driver.
*
- * For SME offload to the driver case:
- * - Supplicant should enable RSNO element use only when the driver
- * indicates this feature flag.
- * - The driver should enable RSNO element use with the supplicant selected
- * BSS only when the supplicant sends an RSNO element with an empty
- * payload in the connect request elements buffer in NL80211_CMD_CONNECT.
- *
- * For BSS selection offload to the driver case:
- * - Supplicant should enable RSNO element use only when the driver
- * indicates this feature flag.
- * - Supplicant should always send RSNO elements in the connect request
- * elements buffer in NL80211_CMD_CONNECT irrespective of whether RSNO
- * elements are supported by the BSS that the supplicant selected
- * - The driver should enable RSNO element use only when the supplicant
- * sends an RSNO element with an empty payload in connect request
- * elements in NL80211_CMD_CONNECT.
- * - The driver should remove RSNO elements from the connect request
- * elements while preparing the (Re)Association Request frame elements
- * if the driver selects a different BSS which is not advertising RSNO
- * elements.
- *
- * If both SME and BSS selection offload to the driver, BSS selection
- * offload to the driver case rules shall be applied.
+ * @QCA_WLAN_VENDOR_FEATURE_NAN_USD_OFFLOAD: Flag indicates that the driver
+ * supports Unsynchronized Service Discovery to be offloaded to it.
*
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
@@ -2248,6 +2300,7 @@
QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN = 23,
QCA_WLAN_VENDOR_FEATURE_HT_VHT_TWT_RESPONDER = 24,
QCA_WLAN_VENDOR_FEATURE_RSN_OVERRIDE_STA = 25,
+ QCA_WLAN_VENDOR_FEATURE_NAN_USD_OFFLOAD = 26,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -2667,6 +2720,9 @@
* 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.
+ * @QCA_WLAN_VENDOR_ATTR_SCAN_SKIP_CHANNEL_RECENCY_PERIOD: Optional (u32). Skip
+ * scanning channels which are scanned recently within configured time
+ * (in ms).
*/
enum qca_wlan_vendor_attr_scan {
QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0,
@@ -2685,6 +2741,7 @@
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_SKIP_CHANNEL_RECENCY_PERIOD = 16,
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SCAN_MAX =
QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1
@@ -3686,6 +3743,17 @@
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_FOLLOW_AP_PREFERENCE_FOR_CNDS_SELECT = 121,
+ /* 16-bit unsigned value to configure P2P GO beacon interval in TUs.
+ * This attribute is used to update the P2P GO beacon interval
+ * dynamically.
+ *
+ * Updating the beacon interval while the GO continues operating the BSS
+ * will likely interoperability issues and is not recommended to be
+ * used. All the values should be multiples of the minimum used value to
+ * minimize risk of issues.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_P2P_GO_BEACON_INTERVAL = 122,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -7457,6 +7525,10 @@
* for External ACS
*/
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_AFC_CAPABILITY = 15,
+ /* Link ID attibute (u8) is used to identify a specific link affiliated
+ * to an AP MLD.
+ */
+ QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LINK_ID = 16,
/* keep last */
QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_LAST,
@@ -10398,6 +10470,26 @@
*/
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_SCS_TRAFFIC_SUPPORT = 73,
+ /* 8-bit unsigned value to disable or not disable the channel switch
+ * initiation in P2P GO mode.
+ * 0 - Not-disable, 1 - Disable
+ *
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISABLE_CHAN_SWITCH_INITIATION = 74,
+
+ /* 8-bit unsigned value. This indicates number of random PMKIDs to be
+ * added in the RSNE of the (Re)Association request frames. This is
+ * exclusively used for the scenarios where the device is used as a test
+ * bed device with special functionality and not recommended for
+ * production. Default value is zero. If the user space configures a
+ * non-zero value, that remains in use until the driver is unloaded or
+ * the user space resets the value to zero.
+ *
+ * This attribute is used for testing purposes.
+ */
+ QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RSNE_ADD_RANDOM_PMKIDS = 75,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX =
@@ -10695,7 +10787,8 @@
* TWT (Target Wake Time) setup request. These attributes are sent as part of
* %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP and
* %QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION. Also used by
- * attributes through %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT.
+ * attributes through %QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT and
+ * %QCA_NL80211_VENDOR_SUBCMD_CHAN_USAGE_REQ.
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST: Flag attribute.
* Disable (flag attribute not present) - Individual TWT
@@ -12451,6 +12544,12 @@
*/
QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_IS_ML = 3,
+ /*
+ * This is u8 attribute used to identify a specific link affiliated
+ * to an AP MLD.
+ */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_LINK_ID = 4,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_MAX =
@@ -18047,4 +18146,238 @@
QCA_WLAN_VENDOR_ATTR_USD_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_audio_transport_switch_type - Represents the possible transport
+ * switch types.
+ *
+ * @QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN: Request to route audio data
+ * via non-WLAN transport (e.g., Bluetooth).
+ *
+ * @QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN: Request to route audio data via
+ * WLAN transport.
+ */
+enum qca_wlan_audio_transport_switch_type {
+ QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN = 0,
+ QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN = 1,
+};
+
+/**
+ * enum qca_wlan_audio_transport_switch_status - Represents the status of audio
+ * transport switch request.
+ *
+ * @QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED: Request to switch transport
+ * has been rejected. For example, when transport switch is requested from WLAN
+ * to non-WLAN transport, user space modules and peers would evaluate the switch
+ * request and may not be ready for switch and hence switch to non-WLAN
+ * transport gets rejected.
+ *
+ * @QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED: Request to switch
+ * transport has been completed. This is sent only in the command path. For
+ * example, when the driver had requested for audio transport switch and
+ * userspace modules as well as peers are ready for the switch, userspace module
+ * switches the transport and sends the subcommand with status completed to the
+ * driver.
+ */
+enum qca_wlan_audio_transport_switch_status {
+ QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED = 0,
+ QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED = 1,
+};
+
+/**
+ * enum qca_wlan_audio_transport_switch_reason - Represents the reason of audio
+ * transport switch request.
+ *
+ * @QCA_WLAN_AUDIO_TRANSPORT_SWITCH_REASON_TERMINATING: Requester transport is
+ * terminating. After this indication, requester module may not be available to
+ * process further request on its transport. For example, to handle a high
+ * priority concurrent interface, WLAN transport needs to terminate and hence
+ * indicates switch to a non-WLAN transport with reason terminating. User space
+ * modules switch to non-WLAN immediately without waiting for further
+ * confirmation.
+ */
+enum qca_wlan_audio_transport_switch_reason {
+ QCA_WLAN_AUDIO_TRANSPORT_SWITCH_REASON_TERMINATING = 0,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_audio_transport_switch - Attributes used by
+ * %QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH vendor command.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE: u8 attribute. Indicates
+ * the transport switch type from one of the values in enum
+ * qca_wlan_audio_transport_switch_type. This is mandatory attribute in both
+ * command and event path. This attribute is included in both requests and
+ * responses.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS: u8 attribute. Indicates
+ * the transport switch status from one of the values in enum
+ * qca_wlan_audio_transport_switch_status. This is optional attribute and used
+ * in both command and event path. This attribute must not be included in
+ * requests.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_REASON: u8 attribute. Indicates
+ * the transport switch reason from one of the values in enum
+ * qca_wlan_audio_transport_switch_reason. This is optional attribute and used
+ * in both command and event path.
+ */
+enum qca_wlan_vendor_attr_audio_transport_switch {
+ QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE = 1,
+ QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS = 2,
+ QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_REASON = 3,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX =
+ QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_AFTER_LAST - 1,
+};
+
+
+/**
+ * enum qca_wlan_connect_ext_features - Feature flags for
+ * %QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_FEATURES
+ *
+ * @QCA_CONNECT_EXT_FEATURE_RSNO: Flag attribute. This indicates supplicant
+ * support for RSN overriding. The driver shall enable RSN overriding in the
+ * (re)association attempts only if this flag is indicated. This functionality
+ * is available only when the driver indicates support for
+ * @QCA_WLAN_VENDOR_FEATURE_RSN_OVERRIDE_STA.
+ *
+ * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits.
+ */
+enum qca_wlan_connect_ext_features {
+ QCA_CONNECT_EXT_FEATURE_RSNO = 0,
+ NUM_QCA_CONNECT_EXT_FEATURES /* keep last */
+};
+
+/* enum qca_wlan_vendor_attr_connect_ext: Attributes used by vendor command
+ * %QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_FEATURES: Feature flags contained in a byte
+ * array. The feature flags are identified by their bit index (see &enum
+ * qca_wlan_connect_ext_features) with the first byte being the least
+ * significant one and the last one being the most significant one.
+ */
+enum qca_wlan_vendor_attr_connect_ext {
+ QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_FEATURES = 1,
+
+ QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_MAX =
+ QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_p2p_mode - Defines the values used with
+ * %QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_CONFIG.
+ *
+ * @QCA_P2P_MODE_WFD_R1: Wi-Fi Direct R1 only.
+ * @QCA_P2P_MODE_WFD_R2: Wi-Fi Direct R2 only.
+ * @QCA_P2P_MODE_WFD_PCC: P2P Connection Compatibility Mode which supports both
+ * Wi-Fi Direct R1 and R2.
+ */
+enum qca_wlan_vendor_p2p_mode {
+ QCA_P2P_MODE_WFD_R1 = 0,
+ QCA_P2P_MODE_WFD_R2 = 1,
+ QCA_P2P_MODE_WFD_PCC = 2,
+};
+
+/* enum qca_wlan_vendor_attr_set_p2p_mode: Attributes used by vendor command
+ * %QCA_NL80211_VENDOR_SUBCMD_SET_P2P_MODE.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_CONFIG: u8 attribute. Sets the P2P device
+ * mode. The values used are defined in enum qca_wlan_vendor_p2p_mode.
+ * This configuration is valid until the interface is brought up next time after
+ * this configuration and the driver shall use this configuration only when the
+ * interface is brought up in NL80211_IFTYPE_P2P_GO mode.
+ * When this parameter has not been set, the interface is brought up with
+ * Wi-Fi Direct R1 only configuration by default.
+ */
+enum qca_wlan_vendor_attr_set_p2p_mode {
+ QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_CONFIG = 1,
+
+ QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_MAX =
+ QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_chan_usage_req_chan_list: Attributes used inside
+ * nested attributes %QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST_CHAN: u8 attribute. Indicates
+ * the channel number of the channel list entry.
+ * @QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST_OP_CLASS: u8 attribute.
+ * Indicates the operating class of the channel list entry.
+ */
+enum qca_wlan_vendor_attr_chan_usage_req_chan_list {
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST_CHAN = 1,
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST_OP_CLASS = 2,
+
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST_MAX =
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_chan_usage_req_mode: Defines the values used
+ * with %QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_MODE.
+ *
+ * @QCA_CHAN_USAGE_MODE_UNAVAILABILITY_INDICATION: Mode set by STA to indicate
+ * the AP about its unavailability during a peer-to-peer TWT agreement.
+ *
+ * @QCA_CHAN_USAGE_MODE_CHANNEL_SWITCH_REQ: Mode set by the STA that is in a
+ * channel-usage-aidable BSS to request a channel switch. Other Channel Usage
+ * elements are not required. Optional HT/VHT/HE Capabilities are present.
+ */
+enum qca_wlan_vendor_attr_chan_usage_req_mode {
+ QCA_CHAN_USAGE_MODE_UNAVAILABILITY_INDICATION = 3,
+ QCA_CHAN_USAGE_MODE_CHANNEL_SWITCH_REQ = 4,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_chan_usage_req: Attributes used by vendor command
+ * %QCA_NL80211_VENDOR_SUBCMD_CHAN_USAGE_REQ.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_MODE: Required u8 attribute. Identifies
+ * the usage of the channel list entry provided in the channel usage request.
+ * Channel switch request and unavailability channel usage modes are
+ * configured on a STA/P2P Client.
+ * See enum qca_wlan_vendor_attr_chan_usage_req_mode for attribute values.
+ * See IEEE P802.11-REVme/D7.0, 9.4.2.84, Table 9-268 for more information.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST: Required array of nested
+ * attributes containing channel usage parameters.
+ * Required when channel usage mode is Channel-usage-aidable BSS channel
+ * switch request.
+ * See enum qca_wlan_vendor_attr_req_chan_list for nested attributes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_UNAVAILABILITY_CONFIG_PARAMS: Nested
+ * attribute representing the parameters configured for unavailability
+ * indication. Required when channel usage mode is unavailability indication.
+ *
+ * Below attributes from enum qca_wlan_vendor_attr_twt_setup are used inside
+ * this nested attribute:
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE,
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE,
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER,
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE,
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP,
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION,
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION,
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA.
+ */
+enum qca_wlan_vendor_attr_chan_usage_req {
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_MODE = 1,
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_CHAN_LIST = 2,
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_UNAVAILABILITY_CONFIG_PARAMS = 3,
+
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_MAX =
+ QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 8eb4a1d..a8c7c41 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1456,15 +1456,18 @@
* @akmp: Negotiated AKM
* @cipher: Negotiated pairwise cipher
* @kdk_len: the length in octets that should be derived for HTLK. Can be zero.
+ * @kek_len: The length in octets that should be derived for KEK. Can be zero.
* Returns: 0 on success, -1 on failure
*/
int pasn_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
const u8 *spa, const u8 *bssid,
const u8 *dhss, size_t dhss_len,
struct wpa_ptk *ptk, int akmp, int cipher,
- size_t kdk_len)
+ size_t kdk_len, size_t kek_len)
{
- u8 tmp[WPA_KCK_MAX_LEN + WPA_TK_MAX_LEN + WPA_KDK_MAX_LEN];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN +
+ WPA_KDK_MAX_LEN];
+ const u8 *pos;
u8 *data;
size_t data_len, ptk_len;
int ret = -1;
@@ -1499,7 +1502,7 @@
ptk->kck_len = WPA_PASN_KCK_LEN;
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk->kdk_len = kdk_len;
- ptk->kek_len = 0;
+ ptk->kek_len = kek_len;
ptk->kek2_len = 0;
ptk->kck2_len = 0;
@@ -1510,7 +1513,7 @@
goto err;
}
- ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len;
+ ptk_len = ptk->kck_len + ptk->tk_len + ptk->kdk_len + ptk->kek_len;
if (ptk_len > sizeof(tmp))
goto err;
@@ -1538,13 +1541,21 @@
os_memcpy(ptk->kck, tmp, WPA_PASN_KCK_LEN);
wpa_hexdump_key(MSG_DEBUG, "PASN: KCK:", ptk->kck, WPA_PASN_KCK_LEN);
+ pos = &tmp[WPA_PASN_KCK_LEN];
- os_memcpy(ptk->tk, tmp + WPA_PASN_KCK_LEN, ptk->tk_len);
+ if (kek_len) {
+ os_memcpy(ptk->kek, pos, kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "PASN: KEK:",
+ ptk->kek, ptk->kek_len);
+ pos += kek_len;
+ }
+
+ os_memcpy(ptk->tk, pos, ptk->tk_len);
wpa_hexdump_key(MSG_DEBUG, "PASN: TK:", ptk->tk, ptk->tk_len);
+ pos += ptk->tk_len;
if (kdk_len) {
- os_memcpy(ptk->kdk, tmp + WPA_PASN_KCK_LEN + ptk->tk_len,
- ptk->kdk_len);
+ os_memcpy(ptk->kdk, pos, ptk->kdk_len);
wpa_hexdump_key(MSG_DEBUG, "PASN: KDK:",
ptk->kdk, ptk->kdk_len);
}
@@ -3448,7 +3459,7 @@
const u8 *p;
size_t left;
u8 link_id;
- char title[50];
+ char title[100];
int ret;
if (len == 0)
@@ -3629,6 +3640,57 @@
return 0;
}
+ if (left >= 1 && selector == WFA_KEY_DATA_RSN_OVERRIDE_LINK) {
+ link_id = p[0];
+ if (link_id >= MAX_NUM_MLD_LINKS)
+ return 2;
+
+ ie->rsn_override_link[link_id] = p;
+ ie->rsn_override_link_len[link_id] = left;
+ ret = os_snprintf(title, sizeof(title),
+ "RSN: Link ID %u - RSN Override Link KDE in EAPOL-Key",
+ link_id);
+ if (!os_snprintf_error(sizeof(title), ret))
+ wpa_hexdump(MSG_DEBUG, title, pos, dlen);
+ return 0;
+ }
+
+ if (selector == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
+ ie->rsne_override = pos;
+ ie->rsne_override_len = dlen;
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: RSNE Override element in EAPOL-Key",
+ ie->rsne_override, ie->rsne_override_len);
+ return 0;
+ }
+
+ if (selector == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
+ ie->rsne_override_2 = pos;
+ ie->rsne_override_2_len = dlen;
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: RSNE Override 2 element in EAPOL-Key",
+ ie->rsne_override_2, ie->rsne_override_2_len);
+ return 0;
+ }
+
+ if (selector == RSNXE_OVERRIDE_IE_VENDOR_TYPE) {
+ ie->rsnxe_override = pos;
+ ie->rsnxe_override_len = dlen;
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: RSNXE Override element in EAPOL-Key",
+ ie->rsnxe_override, ie->rsnxe_override_len);
+ return 0;
+ }
+
+ if (selector == RSN_SELECTION_IE_VENDOR_TYPE) {
+ ie->rsn_selection = p;
+ ie->rsn_selection_len = left;
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: RSN Selection element in EAPOL-Key",
+ ie->rsn_selection, ie->rsn_selection_len);
+ return 0;
+ }
+
return 2;
}
@@ -4268,3 +4330,24 @@
}
#endif /* CONFIG_PASN */
+
+
+void rsn_set_snonce_cookie(u8 *snonce)
+{
+ u8 *pos;
+
+ pos = snonce + WPA_NONCE_LEN - 6;
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ WPA_PUT_BE24(pos, 0x000029);
+}
+
+
+bool rsn_is_snonce_cookie(const u8 *snonce)
+{
+ const u8 *pos;
+
+ pos = snonce + WPA_NONCE_LEN - 6;
+ return WPA_GET_BE24(pos) == OUI_WFA &&
+ WPA_GET_BE24(pos + 3) == 0x000029;
+}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 1e31368..e608d3c 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -144,6 +144,7 @@
#define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5)
#define WFA_KEY_DATA_TRANSITION_DISABLE RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x20)
#define WFA_KEY_DATA_DPP RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x21)
+#define WFA_KEY_DATA_RSN_OVERRIDE_LINK RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x2d)
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
@@ -643,6 +644,14 @@
#define WPA_PASN_PUBKEY_COMPRESSED_1 0x03
#define WPA_PASN_PUBKEY_UNCOMPRESSED 0x04
+/* WPA3 specification - RSN Selection element */
+enum rsn_selection_variant {
+ RSN_SELECTION_RSNE = 0,
+ RSN_SELECTION_RSNE_OVERRIDE = 1,
+ RSN_SELECTION_RSNE_OVERRIDE_2 = 2,
+};
+
+
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
int key_mgmt, bool reassoc_resp);
void wpa_ft_parse_ies_free(struct wpa_ft_ies *parse);
@@ -704,6 +713,14 @@
u16 aid;
const u8 *wmm;
size_t wmm_len;
+ const u8 *rsn_selection;
+ size_t rsn_selection_len;
+ const u8 *rsne_override;
+ size_t rsne_override_len;
+ const u8 *rsne_override_2;
+ size_t rsne_override_2_len;
+ const u8 *rsnxe_override;
+ size_t rsnxe_override_len;
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];
@@ -716,6 +733,8 @@
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];
+ const u8 *rsn_override_link[MAX_NUM_MLD_LINKS];
+ size_t rsn_override_link_len[MAX_NUM_MLD_LINKS];
};
int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie);
@@ -751,7 +770,7 @@
const u8 *spa, const u8 *bssid,
const u8 *dhss, size_t dhss_len,
struct wpa_ptk *ptk, int akmp, int cipher,
- size_t kdk_len);
+ size_t kdk_len, size_t kek_len);
u8 pasn_mic_len(int akmp, int cipher);
@@ -787,4 +806,7 @@
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);
+void rsn_set_snonce_cookie(u8 *snonce);
+bool rsn_is_snonce_cookie(const u8 *snonce);
+
#endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index f614250..2ea8ab3 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -13,6 +13,8 @@
extern "C" {
#endif
+#define WPA_CTRL_IFACE_LINK_NAME "link"
+
/* wpa_supplicant control interface - fixed message prefixes */
/** Interactive request for identity/password/pin */
@@ -204,6 +206,7 @@
#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
#define DPP_EVENT_CONFOBJ_SSID_CHARSET "DPP-CONFOBJ-SSID-CHARSET "
#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
+#define DPP_EVENT_CONFOBJ_IDPASS "DPP-CONFOBJ-IDPASS "
#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR "
#define DPP_EVENT_C_SIGN_KEY "DPP-C-SIGN-KEY "
@@ -225,6 +228,7 @@
#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED "
#define DPP_EVENT_MUD_URL "DPP-MUD-URL "
#define DPP_EVENT_BAND_SUPPORT "DPP-BAND-SUPPORT "
+#define DPP_EVENT_ENROLLEE_CAPABILITY "DPP-ENROLLEE-CAPABILITY "
#define DPP_EVENT_CSR "DPP-CSR "
#define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX "
#define DPP_EVENT_CONF_NEEDED "DPP-CONF-NEEDED "
@@ -304,6 +308,10 @@
#define P2P_EVENT_P2PS_PROVISION_START "P2PS-PROV-START "
#define P2P_EVENT_P2PS_PROVISION_DONE "P2PS-PROV-DONE "
+#define P2P_EVENT_BOOTSTRAP_REQUEST "P2P-BOOTSTRAP-REQUEST "
+#define P2P_EVENT_BOOTSTRAP_SUCCESS "P2P-BOOTSTRAP-SUCCESS "
+#define P2P_EVENT_BOOTSTRAP_FAILURE "P2P-BOOTSTRAP-FAILURE "
+
#define INTERWORKING_AP "INTERWORKING-AP "
#define INTERWORKING_EXCLUDED "INTERWORKING-BLACKLISTED "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index f5d734d..d849933 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -1290,8 +1290,9 @@
#endif /* OPENSSL_NO_ENGINE */
-#ifdef ANDROID
-/* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
+// Imported from system/security/keystore-engine. This method
+// is not used by the mainline supplicant.
+#if defined(ANDROID) && !defined(MAINLINE_SUPPLICANT)
EVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
#endif /* ANDROID */
@@ -1299,7 +1300,7 @@
const char *pin, const char *key_id,
const char *cert_id, const char *ca_cert_id)
{
-#if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
+#if defined(ANDROID) && !defined(MAINLINE_SUPPLICANT) && defined(OPENSSL_IS_BORINGSSL)
#if !defined(OPENSSL_NO_ENGINE)
#error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
#endif
@@ -1307,6 +1308,7 @@
return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
conn->engine = NULL;
conn->private_key = EVP_PKEY_from_keystore(key_id);
+
if (!conn->private_key) {
wpa_printf(MSG_ERROR,
"ENGINE: cannot load private key with id '%s' [%s]",
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 8be4012..765ea59 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -22,11 +22,15 @@
#include "common/defs.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_common.h"
+#include "common/nan.h"
#ifdef CONFIG_MACSEC
#include "pae/ieee802_1x_kay.h"
#endif /* CONFIG_MACSEC */
#include "utils/list.h"
+struct nan_subscribe_params;
+struct nan_publish_params;
+
#define HOSTAPD_CHAN_DISABLED 0x00000001
#define HOSTAPD_CHAN_NO_IR 0x00000002
#define HOSTAPD_CHAN_RADAR 0x00000008
@@ -317,6 +321,27 @@
};
+/**
+ * struct hostapd_multi_hw_info: Supported multiple underlying hardware info
+ */
+struct hostapd_multi_hw_info {
+ /**
+ * hw_idx - Hardware index
+ */
+ u8 hw_idx;
+
+ /**
+ * start_freq - Frequency range start in MHz
+ */
+ int start_freq;
+
+ /**
+ * end_freq - Frequency range end in MHz
+ */
+ int end_freq;
+};
+
+
#define IEEE80211_CAP_ESS 0x0001
#define IEEE80211_CAP_IBSS 0x0002
#define IEEE80211_CAP_PRIVACY 0x0010
@@ -1370,6 +1395,12 @@
* mld_params - MLD association parameters
*/
struct wpa_driver_mld_params mld_params;
+
+
+ /**
+ * rsn_overriding - wpa_supplicant RSN overriding support
+ */
+ bool rsn_overriding;
};
enum hide_ssid {
@@ -2339,6 +2370,8 @@
#define WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER 0x0000000000200000ULL
/** Driver supports RSN override elements */
#define WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA 0x0000000000400000ULL
+/** Driver supports NAN offload */
+#define WPA_DRIVER_FLAGS2_NAN_OFFLOAD 0x0000000000800000ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -5206,15 +5239,19 @@
/**
* 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
+ * @link_id: Link ID to match
+ * Returns: true if it is being used or else false.
*
* 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.
+ * NOTE: @link_id will be used only when there is only one BSS
+ * present and if that single link is active. In that case, the
+ * link ID is matched with the active link_id to decide whether the
+ * driver interface is being used by other partner BSS(s).
*/
- bool (*is_drv_shared)(void *priv, void *bss_ctx);
+ bool (*is_drv_shared)(void *priv, int link_id);
/**
* link_sta_remove - Remove a link STA from an MLD STA
@@ -5225,11 +5262,94 @@
*/
int (*link_sta_remove)(void *priv, u8 link_id, const u8 *addr);
+ /**
+ * nan_flush - Flush all NAN offload services
+ * @priv: Private driver interface data
+ * Returns: 0 on success, negative value on failure
+ */
+ int (*nan_flush)(void *priv);
+
+ /**
+ * nan_publish - NAN offload for Publish()
+ * @priv: Private driver interface data
+ * @src: Source P2P device addr
+ * @publish_id: Publish instance to add
+ * @service_name: Service name
+ * @service_id: Service ID (6 octet value derived from service name)
+ * @srv_proto_type: Service protocol type
+ * @ssi: Service specific information or %NULL
+ * @elems: Information elements for Element Container attribute or %NULL
+ * @params: Configuration parameters
+ * Returns: 0 on success, negative value on failure
+ */
+ int (*nan_publish)(void *priv, const u8 *src, int publish_id,
+ const char *service_name, const u8 *service_id,
+ enum nan_service_protocol_type srv_proto_type,
+ const struct wpabuf *ssi, const struct wpabuf *elems,
+ struct nan_publish_params *params);
+
+ /**
+ * nan_cancel_publish - NAN offload for CancelPublish()
+ * @priv: Private driver interface data
+ * @publish_id: Publish instance to cancel
+ * Returns: 0 on success, negative value on failure
+ */
+ int (*nan_cancel_publish)(void *priv, int publish_id);
+
+ /**
+ * nan_update_publish - NAN offload for UpdatePublish()
+ * @priv: Private driver interface data
+ * @ssi: Service specific information or %NULL
+ * Returns: 0 on success, negative value on failure
+ */
+ int (*nan_update_publish)(void *priv, int publish_id,
+ const struct wpabuf *ssi);
+
+ /**
+ * nan_subscribe - NAN offload for Subscribe()
+ * @priv: Private driver interface data
+ * @src: Source P2P device addr
+ * @subscribe_id: Subscribe instance to add
+ * @service_name: Service name
+ * @service_id: Service ID (6 octet value derived from service name)
+ * @srv_proto_type: Service protocol type
+ * @ssi: Service specific information or %NULL
+ * @elems: Information elements for Element Container attribute or %NULL
+ * @params: Configuration parameters
+ * Returns: 0 on success, negative value on failure
+ */
+ int (*nan_subscribe)(void *priv, const u8 *src, int subscribe_id,
+ const char *service_name, const u8 *service_id,
+ enum nan_service_protocol_type srv_proto_type,
+ const struct wpabuf *ssi,
+ const struct wpabuf *elems,
+ struct nan_subscribe_params *params);
+
+ /**
+ * nan_cancel_subscribe - NAN offload for CancelSubscribe()
+ * @priv: Private driver interface data
+ * @subscribe_id: Subscribe instance to cancel
+ * Returns: 0 on success, negative value on failure
+ */
+ int (*nan_cancel_subscribe)(void *priv, int subscribe_id);
+
#ifdef CONFIG_TESTING_OPTIONS
int (*register_frame)(void *priv, u16 type,
const u8 *match, size_t match_len,
bool multicast);
#endif /* CONFIG_TESTING_OPTIONS */
+
+ /**
+ * get_multi_hw_info - Get multiple underlying hardware information
+ * (hardware IDx and supported frequency range)
+ * @priv: Private driver interface data
+ * @num_multi_hws: Variable for returning the number of returned
+ * hardware info data
+ * Returns: Pointer to allocated multiple hardware data on success
+ * or %NULL on failure. Caller is responsible for freeing this.
+ */
+ struct hostapd_multi_hw_info *
+ (*get_multi_hw_info)(void *priv, unsigned int *num_multi_hws);
};
/**
@@ -5857,6 +5977,11 @@
* EVENT_LINK_RECONFIG - Notification that AP links removed
*/
EVENT_LINK_RECONFIG,
+
+ /**
+ * EVENT_MLD_INTERFACE_FREED - Notification of AP MLD interface removal
+ */
+ EVENT_MLD_INTERFACE_FREED,
};
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 9bc5a73..9589183 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -100,6 +100,7 @@
E2S(LINK_CH_SWITCH_STARTED);
E2S(TID_LINK_MAP);
E2S(LINK_RECONFIG);
+ E2S(MLD_INTERFACE_FREED);
}
return "UNKNOWN";
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index c867154..fad47a2 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -19,6 +19,7 @@
#include <netlink/route/link.h>
#include <netlink/route/link/macsec.h>
#include <linux/if_macsec.h>
+#include <linux/version.h>
#include <inttypes.h>
#include "utils/common.h"
@@ -32,7 +33,8 @@
#define UNUSED_SCI 0xffffffffffffffff
-#if LIBNL_VER_NUM >= LIBNL_VER(3, 6)
+#if (LIBNL_VER_NUM >= LIBNL_VER(3, 6) && \
+ LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
#define LIBNL_HAS_OFFLOAD
#endif
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index b2b909e..5890ac6 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -30,6 +30,8 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_common.h"
+#include "common/nan.h"
+#include "common/nan_de.h"
#include "crypto/sha256.h"
#include "crypto/sha384.h"
#include "netlink.h"
@@ -3089,7 +3091,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct i802_link *link = nl80211_get_link(bss, link_id);
- if (!link->beacon_set)
+ if (!link || !link->beacon_set)
return 0;
wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
@@ -3157,9 +3159,6 @@
bss->ifname, bss->brname, strerror(errno));
}
- if (drv->rtnl_sk)
- nl_socket_free(drv->rtnl_sk);
-
if (bss->added_bridge) {
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
0) < 0)
@@ -3179,6 +3178,9 @@
nl80211_remove_links(bss);
}
+ if (drv->rtnl_sk)
+ nl_socket_free(drv->rtnl_sk);
+
if (drv->eapol_sock >= 0) {
eloop_unregister_read_sock(drv->eapol_sock);
close(drv->eapol_sock);
@@ -3195,7 +3197,7 @@
eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
rfkill_deinit(drv->rfkill);
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, bss->ctx);
if (!drv->start_iface_up)
(void) i802_set_iface_flags(bss, 0);
@@ -4272,6 +4274,22 @@
}
+u8 nl80211_get_link_id_from_link(struct i802_bss *bss, struct i802_link *link)
+{
+ u8 link_id;
+
+ if (link == bss->flink)
+ return 0;
+
+ for_each_link(bss->valid_links, link_id) {
+ if (&bss->links[link_id] == link)
+ return link_id;
+ }
+
+ return 0;
+}
+
+
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);
@@ -5930,13 +5948,15 @@
}
-static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
+static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr,
+ bool is_bridge)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct ndmsg nhdr = {
.ndm_state = NUD_PERMANENT,
- .ndm_ifindex = bss->ifindex,
+ .ndm_ifindex = is_bridge ? bss->br_ifindex : bss->ifindex,
.ndm_family = AF_BRIDGE,
+ .ndm_type = is_bridge ? NTF_SELF : 0,
};
struct nl_msg *msg;
int err;
@@ -5953,11 +5973,61 @@
err = nl_wait_for_ack(drv->rtnl_sk);
if (err < 0) {
wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
- MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
- bss->ifindex, nl_geterror(err));
+ MACSTR " ifindex=%d ifname %s failed: %s",
+ MAC2STR(addr),
+ is_bridge ? bss->br_ifindex : bss->ifindex,
+ is_bridge ? bss->brname : bss->ifname,
+ nl_geterror(err));
} else {
- wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for "
- MACSTR, MAC2STR(addr));
+ wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry "
+ MACSTR " from %s",
+ MAC2STR(addr),
+ is_bridge ? bss->brname : bss->ifname);
+ }
+
+errout:
+ nlmsg_free(msg);
+}
+
+
+static void rtnl_neigh_add_fdb_entry(struct i802_bss *bss, const u8 *addr,
+ bool is_bridge)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct ndmsg nhdr = {
+ .ndm_state = NUD_PERMANENT,
+ .ndm_ifindex = is_bridge ? bss->br_ifindex : bss->ifindex,
+ .ndm_family = AF_BRIDGE,
+ /* TODO: remove this check if this flag needs to be used,
+ * for other interfaces type.
+ */
+ .ndm_flags = is_bridge ? NTF_SELF : 0,
+ };
+ struct nl_msg *msg;
+ int err;
+
+ msg = nlmsg_alloc_simple(RTM_NEWNEIGH, NLM_F_CREATE);
+ if (!msg)
+ return;
+
+ 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 = nl_wait_for_ack(drv->rtnl_sk);
+ if (err < 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry addition for "
+ MACSTR " ifindex=%d ifname %s failed: %s",
+ MAC2STR(addr),
+ is_bridge ? bss->br_ifindex : bss->ifindex,
+ is_bridge ? bss->brname : bss->ifname,
+ nl_geterror(err));
+ } else {
+ wpa_printf(MSG_DEBUG, "nl80211: added bridge FDB entry " MACSTR
+ " to %s",
+ MAC2STR(addr),
+ is_bridge ? bss->brname : bss->ifname);
}
errout:
@@ -5992,7 +6062,7 @@
bss->ifname, MAC2STR(addr), ret, strerror(-ret));
if (drv->rtnl_sk)
- rtnl_neigh_delete_fdb_entry(bss, addr);
+ rtnl_neigh_delete_fdb_entry(bss, addr, false);
if (ret == -ENOENT)
return 0;
@@ -7151,6 +7221,60 @@
}
+#ifdef CONFIG_DRIVER_NL80211_QCA
+static void connect_ext_feature_set(u8 *features,
+ enum qca_wlan_connect_ext_features idx)
+{
+ u8 *idx_byte = &features[idx / 8];
+
+ *idx_byte |= BIT(idx % 8);
+}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
+static int nl80211_connect_ext(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ struct nl_msg *msg;
+ struct nlattr *attr;
+ u8 features[(NUM_QCA_CONNECT_EXT_FEATURES + 7) / 8] = {};
+
+ if (!drv->connect_ext_vendor_cmd_avail)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Connect_ext (ifindex=%d)",
+ drv->ifindex);
+
+ 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_CONNECT_EXT))
+ goto fail;
+
+ attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!attr)
+ goto fail;
+
+ if (params->rsn_overriding) {
+ wpa_printf(MSG_DEBUG, "- RSN overriding");
+ connect_ext_feature_set(features, QCA_CONNECT_EXT_FEATURE_RSNO);
+ }
+
+ if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_CONNECT_EXT_FEATURES,
+ sizeof(features), features))
+ goto fail;
+
+ nla_nest_end(msg, attr);
+
+ return send_and_recv_cmd(drv, msg);
+fail:
+ nlmsg_free(msg);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+ return -1;
+}
+
+
static int wpa_driver_nl80211_try_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params,
@@ -7172,6 +7296,7 @@
}
#endif /* CONFIG_DRIVER_NL80211_QCA */
+ nl80211_connect_ext(drv, params);
wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
if (!msg)
@@ -8508,6 +8633,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
char name[IFNAMSIZ + 1];
union wpa_event_data event;
+ bool add_br = false;
int ret;
ret = os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
@@ -8529,10 +8655,9 @@
bss->addr, 1, NULL, NULL, 0) <
0)
return -1;
- if (bridge_ifname &&
- linux_br_add_if(drv->global->ioctl_sock,
- bridge_ifname, name) < 0)
- return -1;
+
+ if (bridge_ifname)
+ add_br = true;
os_memset(&event, 0, sizeof(event));
event.wds_sta_interface.sta_addr = addr;
@@ -8546,6 +8671,12 @@
wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
"interface %s up", name);
}
+
+ if (add_br &&
+ linux_br_add_if(drv->global->ioctl_sock,
+ bridge_ifname, name) < 0)
+ return -1;
+
return i802_set_sta_vlan(priv, addr, name, 0,
NL80211_DRV_LINK_ID_NA);
} else {
@@ -9532,13 +9663,14 @@
}
-static int nl80211_remove_link(struct i802_bss *bss, int link_id)
+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;
+ u8 link_addr[ETH_ALEN];
wpa_printf(MSG_DEBUG, "nl80211: Remove link (ifindex=%d link_id=%u)",
bss->ifindex, link_id);
@@ -9553,6 +9685,7 @@
wpa_driver_nl80211_del_beacon(bss, link_id);
+ os_memcpy(link_addr, link->addr, ETH_ALEN);
/* First remove the link locally */
bss->valid_links &= ~BIT(link_id);
os_memset(link->addr, 0, ETH_ALEN);
@@ -9590,6 +9723,9 @@
"nl80211: remove link (%d) failed. ret=%d (%s)",
link_id, ret, strerror(-ret));
+ if (drv->rtnl_sk)
+ rtnl_neigh_delete_fdb_entry(bss, link_addr, true);
+
return ret;
}
@@ -10342,6 +10478,8 @@
int err;
union wpa_event_data data;
struct survey_results *survey_results;
+ void *ctx = (bss->scan_link && bss->scan_link->ctx) ?
+ bss->scan_link->ctx : bss->ctx;
os_memset(&data, 0, sizeof(data));
survey_results = &data.survey_results;
@@ -10364,7 +10502,7 @@
if (err)
wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
else
- wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
+ wpa_supplicant_event(ctx, EVENT_SURVEY, &data);
clean_survey_results(survey_results);
return err;
@@ -10837,6 +10975,7 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret;
if (type != WPA_IF_AP_BSS ||
!nl80211_link_valid(bss->valid_links, link_id))
@@ -10856,18 +10995,25 @@
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);
+ ret = wpa_driver_nl80211_if_remove(bss, type, ifname);
+ if (ret)
+ return ret;
+
+ /* Notify that the MLD interface is removed */
+ wpa_supplicant_event(bss->ctx, EVENT_MLD_INTERFACE_FREED, NULL);
}
return 0;
}
-static bool nl80211_is_drv_shared(void *priv, void *bss_ctx)
+static bool nl80211_is_drv_shared(void *priv, int link_id)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- unsigned int num_bss = 0;
+ unsigned int num_bss = 0, num_links = 0;
+ bool self = false;
+ u8 i;
/* 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
@@ -10882,13 +11028,23 @@
/* This is the only BSS present */
bss = priv;
- /* If only one/no link is there no one is sharing */
- if (bss->valid_links <= 1)
+ for_each_link(bss->valid_links, i) {
+ num_links++;
+ if (i == link_id)
+ self = true;
+ }
+
+ /* More than one links means some one is still sharing */
+ if (num_links > 1)
+ return true;
+
+ /* Even if only one link is there, it should match the given
+ * link ID to assert that no one else is sharing. */
+ if (num_links == 1 && self)
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)))
+ /* No links are active means no one is sharing */
+ if (num_links == 0)
return false;
return true;
@@ -12623,7 +12779,7 @@
}
-static int add_acs_freq_list(struct nl_msg *msg, const int *freq_list)
+static int add_freq_list(struct nl_msg *msg, int attr, const int *freq_list)
{
int i, len, ret;
u32 *freqs;
@@ -12636,8 +12792,7 @@
return -1;
for (i = 0; i < len; i++)
freqs[i] = freq_list[i];
- ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
- sizeof(u32) * len, freqs);
+ ret = nla_put(msg, attr, sizeof(u32) * len, freqs);
os_free(freqs);
return ret;
}
@@ -12672,7 +12827,8 @@
nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
params->ch_width) ||
add_acs_ch_list(msg, params->freq_list) ||
- add_acs_freq_list(msg, params->freq_list) ||
+ add_freq_list(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
+ params->freq_list) ||
(params->edmg_enabled &&
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED)) ||
(params->link_id != NL80211_DRV_LINK_ID_NA &&
@@ -13559,6 +13715,315 @@
#endif /* CONFIG_PASN */
+#ifdef CONFIG_NAN_USD
+
+static int nl80211_nan_flush(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: NAN USD flush");
+
+ 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_USD))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!container ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
+ QCA_WLAN_VENDOR_USD_OP_TYPE_FLUSH))
+ goto fail;
+
+ nla_nest_end(msg, container);
+
+ ret = send_and_recv_cmd(drv, msg);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to send NAN USD flush");
+ goto fail;
+ }
+ return 0;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_nan_publish(void *priv, const u8 *src, int publish_id,
+ const char *service_name, const u8 *service_id,
+ enum nan_service_protocol_type srv_proto_type,
+ const struct wpabuf *ssi,
+ const struct wpabuf *elems,
+ struct nan_publish_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container, *attr;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Start NAN USD publish: default freq=%u, ttl=%u",
+ params->freq, params->ttl);
+ wpa_hexdump_buf(MSG_MSGDUMP, "nl80211: USD elements", elems);
+
+ 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_USD))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!container)
+ goto fail;
+
+ if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
+ QCA_WLAN_VENDOR_USD_OP_TYPE_PUBLISH) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SRC_ADDR, ETH_ALEN, src) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID, publish_id) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SERVICE_ID,
+ NAN_SERVICE_ID_LEN, service_id) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_SERVICE_PROTOCOL_TYPE,
+ srv_proto_type) ||
+ nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_USD_TTL, params->ttl) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_ELEMENT_CONTAINER,
+ wpabuf_len(elems), wpabuf_head(elems)) ||
+ (ssi && nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SSI,
+ wpabuf_len(ssi), wpabuf_head(ssi))))
+ goto fail;
+
+ attr = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG);
+ if (!attr)
+ goto fail;
+ if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_DEFAULT_FREQ,
+ params->freq) ||
+ add_freq_list(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_FREQ_LIST,
+ params->freq_list))
+ nla_nest_end(msg, attr);
+
+ nla_nest_end(msg, container);
+ ret = send_and_recv_cmd(drv, msg);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to send NAN USD publish");
+ goto fail;
+ }
+ return 0;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_nan_cancel_publish(void *priv, int publish_id)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: NAN USD cancel publish");
+
+ 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_USD))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!container)
+ goto fail;
+
+ if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
+ QCA_WLAN_VENDOR_USD_OP_TYPE_CANCEL_PUBLISH) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID,
+ publish_id))
+ goto fail;
+
+ nla_nest_end(msg, container);
+
+ ret = send_and_recv_cmd(drv, msg);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to send NAN USD cancel publish");
+ goto fail;
+ }
+ return 0;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_nan_update_publish(void *priv, int publish_id,
+ const struct wpabuf *ssi)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: NAN USD update publish: id=%d",
+ publish_id);
+
+ 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_USD))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!container)
+ goto fail;
+
+ if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
+ QCA_WLAN_VENDOR_USD_OP_TYPE_UPDATE_PUBLISH) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID,
+ publish_id) ||
+ (ssi && nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SSI,
+ wpabuf_len(ssi), wpabuf_head(ssi))))
+ goto fail;
+
+ nla_nest_end(msg, container);
+ ret = send_and_recv_cmd(drv, msg);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to send NAN USD update publish");
+ goto fail;
+ }
+ return 0;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_nan_subscribe(void *priv, const u8 *src, int subscribe_id,
+ const char *service_name, const u8 *service_id,
+ enum nan_service_protocol_type srv_proto_type,
+ const struct wpabuf *ssi,
+ const struct wpabuf *elems,
+ struct nan_subscribe_params *params)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container, *attr;
+ int ret;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Start NAN USD subscribe: freq=%u, ttl=%u",
+ params->freq, params->ttl);
+ wpa_hexdump_buf(MSG_MSGDUMP, "nl80211: USD elements", elems);
+
+ 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_USD))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!container)
+ goto fail;
+
+ if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
+ QCA_WLAN_VENDOR_USD_OP_TYPE_SUBSCRIBE) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SRC_ADDR, ETH_ALEN, src) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID,
+ subscribe_id) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SERVICE_ID,
+ NAN_SERVICE_ID_LEN, service_id) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_SERVICE_PROTOCOL_TYPE,
+ srv_proto_type) ||
+ nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_USD_TTL, params->ttl) ||
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_ELEMENT_CONTAINER,
+ wpabuf_len(elems), wpabuf_head(elems)) ||
+ (ssi && nla_put(msg, QCA_WLAN_VENDOR_ATTR_USD_SSI,
+ wpabuf_len(ssi), wpabuf_head(ssi))))
+ goto fail;
+
+ attr = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG);
+ if (!attr ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_DEFAULT_FREQ,
+ params->freq) ||
+ add_freq_list(msg, QCA_WLAN_VENDOR_ATTR_USD_CHAN_CONFIG_FREQ_LIST,
+ params->freq_list))
+ goto fail;
+ nla_nest_end(msg, attr);
+
+ nla_nest_end(msg, container);
+ ret = send_and_recv_cmd(drv, msg);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to send NAN USD subscribe");
+ goto fail;
+ }
+ return 0;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+
+static int nl80211_nan_cancel_subscribe(void *priv, int subscribe_id)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "nl80211: NAN USD cancel subscribe");
+
+ 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_USD))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!container ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_OP_TYPE,
+ QCA_WLAN_VENDOR_USD_OP_TYPE_CANCEL_SUBSCRIBE) ||
+ nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_USD_INSTANCE_ID,
+ subscribe_id))
+ goto fail;
+
+ nla_nest_end(msg, container);
+
+ ret = send_and_recv_cmd(drv, msg);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to send NAN USD cancel subscribe");
+ goto fail;
+ }
+ return 0;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+
+#endif /* CONFIG_NAN_USD */
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -14091,6 +14556,10 @@
wpa_printf(MSG_DEBUG, "nl80211: MLD: valid_links=0x%04x on %s",
bss->valid_links, bss->ifname);
+
+ if (drv->rtnl_sk)
+ rtnl_neigh_add_fdb_entry(bss, addr, true);
+
return 0;
}
@@ -14170,6 +14639,15 @@
#endif /* CONFIG_TESTING_OPTIONS */
+static struct hostapd_multi_hw_info *
+wpa_driver_get_multi_hw_info(void *priv, unsigned int *num_multi_hws)
+{
+ struct i802_bss *bss = priv;
+
+ return nl80211_get_multi_hw_info(bss, num_multi_hws);
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -14306,6 +14784,14 @@
.send_pasn_resp = nl80211_send_pasn_resp,
.set_secure_ranging_ctx = nl80211_set_secure_ranging_ctx,
#endif /* CONFIG_PASN */
+#ifdef CONFIG_NAN_USD
+ .nan_flush = nl80211_nan_flush,
+ .nan_publish = nl80211_nan_publish,
+ .nan_cancel_publish = nl80211_nan_cancel_publish,
+ .nan_update_publish = nl80211_nan_update_publish,
+ .nan_subscribe = nl80211_nan_subscribe,
+ .nan_cancel_subscribe = nl80211_nan_cancel_subscribe,
+#endif /* CONFIG_NAN_USD */
#endif /* CONFIG_DRIVER_NL80211_QCA */
.do_acs = nl80211_do_acs,
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
@@ -14328,4 +14814,5 @@
.register_frame = testing_nl80211_register_frame,
.radio_disable = testing_nl80211_radio_disable,
#endif /* CONFIG_TESTING_OPTIONS */
+ .get_multi_hw_info = wpa_driver_get_multi_hw_info,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index d2c1ffa..bf1bf4e 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -67,7 +67,7 @@
u16 valid_links;
struct i802_link links[MAX_NUM_MLD_LINKS];
- struct i802_link *flink;
+ struct i802_link *flink, *scan_link;
int ifindex;
int br_ifindex;
@@ -200,6 +200,7 @@
unsigned int secure_ranging_ctx_vendor_cmd_avail:1;
unsigned int puncturing:1;
unsigned int qca_ap_allowed_freqs:1;
+ unsigned int connect_ext_vendor_cmd_avail:1;
u32 ignore_next_local_disconnect;
u32 ignore_next_local_deauth;
@@ -370,6 +371,8 @@
void nl80211_restore_ap_mode(struct i802_bss *bss);
struct i802_link * nl80211_get_link(struct i802_bss *bss, s8 link_id);
+u8 nl80211_get_link_id_from_link(struct i802_bss *bss, struct i802_link *link);
+int nl80211_remove_link(struct i802_bss *bss, int link_id);
static inline bool nl80211_link_valid(u16 links, s8 link_id)
{
@@ -427,5 +430,7 @@
int wpa_driver_nl80211_vendor_scan(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int nl80211_set_default_scan_ies(void *priv, const u8 *ies, size_t ies_len);
+struct hostapd_multi_hw_info *
+nl80211_get_multi_hw_info(struct i802_bss *bss, unsigned int *num_multi_hws);
#endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index ebf69dc..58fb71d 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1119,6 +1119,9 @@
case QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT:
drv->secure_ranging_ctx_vendor_cmd_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT:
+ drv->connect_ext_vendor_cmd_avail = 1;
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
@@ -1457,6 +1460,8 @@
"The driver supports RSN overriding in STA mode");
drv->capa.flags2 |= WPA_DRIVER_FLAGS2_RSN_OVERRIDE_STA;
}
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_NAN_USD_OFFLOAD, &info))
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_NAN_OFFLOAD;
os_free(info.flags);
}
@@ -2745,3 +2750,132 @@
return NULL;
}
+
+
+static int phy_multi_hw_info_parse(struct hostapd_multi_hw_info *hw_info,
+ struct nlattr *radio_attr)
+{
+ struct nlattr *tb_freq[NL80211_WIPHY_RADIO_FREQ_ATTR_MAX + 1];
+ int start_freq, end_freq;
+
+ switch (nla_type(radio_attr)) {
+ case NL80211_WIPHY_RADIO_ATTR_INDEX:
+ hw_info->hw_idx = nla_get_u32(radio_attr);
+ return NL_OK;
+ case NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE:
+ if (nla_parse_nested(tb_freq, NL80211_WIPHY_RADIO_FREQ_ATTR_MAX,
+ radio_attr, NULL) ||
+ !tb_freq[NL80211_WIPHY_RADIO_FREQ_ATTR_START] ||
+ !tb_freq[NL80211_WIPHY_RADIO_FREQ_ATTR_END])
+ return NL_STOP;
+
+ start_freq = nla_get_u32(
+ tb_freq[NL80211_WIPHY_RADIO_FREQ_ATTR_START]);
+ end_freq = nla_get_u32(
+ tb_freq[NL80211_WIPHY_RADIO_FREQ_ATTR_END]);
+
+ /* Convert to MHz and store */
+ hw_info->start_freq = start_freq / 1000;
+ hw_info->end_freq = end_freq / 1000;
+ return NL_OK;
+ default:
+ return NL_OK;
+ }
+}
+
+
+struct phy_multi_hw_info_arg {
+ bool failed;
+ unsigned int *num_multi_hws;
+ struct hostapd_multi_hw_info *multi_hws;
+};
+
+
+static int phy_multi_hw_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct phy_multi_hw_info_arg *multi_hw_info = arg;
+ struct hostapd_multi_hw_info *multi_hws, hw_info;
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct nlattr *nl_hw, *radio_attr;
+ int rem_hw, rem_radio_prop, res;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_WIPHY_RADIOS])
+ return NL_SKIP;
+
+ *multi_hw_info->num_multi_hws = 0;
+
+ nla_for_each_nested(nl_hw, tb_msg[NL80211_ATTR_WIPHY_RADIOS], rem_hw) {
+ os_memset(&hw_info, 0, sizeof(hw_info));
+
+ nla_for_each_nested(radio_attr, nl_hw, rem_radio_prop) {
+ res = phy_multi_hw_info_parse(&hw_info, radio_attr);
+ if (res != NL_OK)
+ goto out;
+ }
+
+ if (hw_info.start_freq == 0 || hw_info.end_freq == 0)
+ goto out;
+
+ multi_hws = os_realloc_array(multi_hw_info->multi_hws,
+ *multi_hw_info->num_multi_hws + 1,
+ sizeof(*multi_hws));
+ if (!multi_hws)
+ goto out;
+
+ multi_hw_info->multi_hws = multi_hws;
+ os_memcpy(&multi_hws[*(multi_hw_info->num_multi_hws)],
+ &hw_info, sizeof(struct hostapd_multi_hw_info));
+ *(multi_hw_info->num_multi_hws) += 1;
+ }
+
+ return NL_OK;
+out:
+ multi_hw_info->failed = true;
+ return NL_STOP;
+}
+
+
+struct hostapd_multi_hw_info *
+nl80211_get_multi_hw_info(struct i802_bss *bss, unsigned int *num_multi_hws)
+{
+ u32 feat;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ int nl_flags = 0;
+ struct nl_msg *msg;
+ struct phy_multi_hw_info_arg result = {
+ .failed = false,
+ .num_multi_hws = num_multi_hws,
+ .multi_hws = NULL,
+ };
+
+ *num_multi_hws = 0;
+
+ if (!drv->has_capability || !(drv->capa.flags2 & WPA_DRIVER_FLAGS2_MLO))
+ return NULL;
+
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ nl_flags = NLM_F_DUMP;
+ if (!(msg = nl80211_cmd_msg(bss, nl_flags, NL80211_CMD_GET_WIPHY)) ||
+ nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+ nlmsg_free(msg);
+ return NULL;
+ }
+
+ if (send_and_recv_resp(drv, msg, phy_multi_hw_info_handler,
+ &result) == 0) {
+ if (result.failed) {
+ os_free(result.multi_hws);
+ *num_multi_hws = 0;
+ return NULL;
+ }
+
+ return result.multi_hws;
+ }
+
+ return NULL;
+}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index ba6aa9c..c6b8e72 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -185,6 +185,7 @@
C2S(NL80211_CMD_REMOVE_LINK_STA)
C2S(NL80211_CMD_SET_HW_TIMESTAMP)
C2S(NL80211_CMD_LINKS_REMOVED)
+ C2S(NL80211_CMD_SET_TID_TO_LINK_MAPPING)
C2S(__NL80211_CMD_AFTER_LAST)
}
#undef C2S
@@ -1204,9 +1205,6 @@
int chan_offset = 0;
int ifidx;
- wpa_printf(MSG_DEBUG, "nl80211: Channel switch%s event",
- finished ? "" : " started");
-
if (!freq)
return;
@@ -1218,6 +1216,9 @@
return;
}
+ wpa_printf(MSG_DEBUG, "nl80211: Channel switch%s event for %s",
+ finished ? "" : " started", bss->ifname);
+
if (type) {
enum nl80211_channel_type ch_type = nla_get_u32(type);
@@ -1260,10 +1261,13 @@
if (cf2)
data.ch_switch.cf2 = nla_get_u32(cf2);
- if (link)
+ if (link) {
data.ch_switch.link_id = nla_get_u8(link);
- else
+ wpa_printf(MSG_DEBUG, "nl80211: Link ID: %d",
+ data.ch_switch.link_id);
+ } else {
data.ch_switch.link_id = NL80211_DRV_LINK_ID_NA;
+ }
if (finished) {
if (data.ch_switch.link_id != NL80211_DRV_LINK_ID_NA) {
@@ -1300,6 +1304,14 @@
return;
}
+ if (link && is_ap_interface(drv->nlmode) &&
+ !nl80211_link_valid(bss->valid_links, data.ch_switch.link_id)) {
+ wpa_printf(MSG_WARNING,
+ "nl80211: Unknown link ID (%d) for channel switch (%s), ignoring",
+ data.ch_switch.link_id, bss->ifname);
+ return;
+ }
+
drv->assoc_freq = data.ch_switch.freq;
wpa_supplicant_event(bss->ctx, finished ?
@@ -1965,9 +1977,10 @@
}
-static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
+static void send_scan_event(struct i802_bss *bss, int aborted,
struct nlattr *tb[], int external_scan)
{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
union wpa_event_data event;
struct nlattr *nl;
int rem;
@@ -1975,6 +1988,8 @@
#define MAX_REPORT_FREQS 110
int freqs[MAX_REPORT_FREQS];
int num_freqs = 0;
+ struct i802_link *mld_link;
+ void *ctx = bss->ctx;
if (!external_scan && drv->scan_for_auth) {
drv->scan_for_auth = 0;
@@ -2038,13 +2053,30 @@
ETH_ALEN);
}
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
+ /* Need to pass to the correct link ctx during AP MLD operation */
+ if (is_ap_interface(drv->nlmode)) {
+ mld_link = bss->scan_link;
+ if (!mld_link) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Scan event on unknown link");
+ } else if (mld_link->ctx) {
+ u8 link_id = nl80211_get_link_id_from_link(bss,
+ mld_link);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Scan event for link_id %d",
+ link_id);
+ ctx = mld_link->ctx;
+ }
+ }
+
+ wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, &event);
}
-static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr *tb[])
+static void nl80211_cqm_event(struct i802_bss *bss, struct nlattr *tb[])
{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
@@ -2079,7 +2111,7 @@
wpa_printf(MSG_DEBUG, "nl80211: Packet loss event for " MACSTR
" (num_packets %u)",
MAC2STR(ed.low_ack.addr), ed.low_ack.num_packets);
- wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
+ wpa_supplicant_event(bss->ctx, EVENT_STATION_LOW_ACK, &ed);
return;
}
@@ -2411,10 +2443,33 @@
}
-static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
+static void nl80211_stop_ap(struct i802_bss *bss, struct nlattr **tb)
{
- wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
+ struct i802_link *mld_link = NULL;
+ void *ctx = bss->ctx;
+ int link_id = -1;
+
+ if (tb[NL80211_ATTR_MLO_LINK_ID]) {
+ link_id = nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]);
+ if (!nl80211_link_valid(bss->valid_links, link_id)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Ignoring STOP_AP event for invalid link ID %d (valid: 0x%04x)",
+ link_id, bss->valid_links);
+ return;
+ }
+
+ mld_link = nl80211_get_link(bss, link_id);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: STOP_AP event on link %d", link_id);
+ ctx = mld_link->ctx;
+
+ /* The driver would have already deleted the link and this call
+ * will return an error. Ignore that since nl80211_remove_link()
+ * is called here only to update the bss->links[] state. */
+ nl80211_remove_link(bss, link_id);
+ }
+
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
}
@@ -3054,7 +3109,7 @@
drv->scan_state = SCAN_ABORTED;
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
- drv->ctx);
+ drv->first_bss->ctx);
drv->vendor_scan_cookie = 0;
drv->last_scan_cmd = 0;
}
@@ -3893,7 +3948,7 @@
switch (cmd) {
case NL80211_CMD_TRIGGER_SCAN:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
+ wpa_dbg(bss->ctx, MSG_DEBUG, "nl80211: Scan trigger");
drv->scan_state = SCAN_STARTED;
if (drv->scan_for_auth) {
/*
@@ -3905,40 +3960,40 @@
wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth");
break;
}
- wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
+ wpa_supplicant_event(bss->ctx, EVENT_SCAN_STARTED, NULL);
break;
case NL80211_CMD_START_SCHED_SCAN:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
+ wpa_dbg(bss->ctx, MSG_DEBUG, "nl80211: Sched scan started");
drv->scan_state = SCHED_SCAN_STARTED;
break;
case NL80211_CMD_SCHED_SCAN_STOPPED:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
+ wpa_dbg(bss->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
drv->scan_state = SCHED_SCAN_STOPPED;
- wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
+ wpa_supplicant_event(bss->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
break;
case NL80211_CMD_NEW_SCAN_RESULTS:
- wpa_dbg(drv->ctx, MSG_DEBUG,
+ wpa_dbg(bss->ctx, MSG_DEBUG,
"nl80211: New scan results available");
if (drv->last_scan_cmd != NL80211_CMD_VENDOR)
drv->scan_state = SCAN_COMPLETED;
drv->scan_complete_events = 1;
if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
- drv, drv->ctx);
+ drv, bss->ctx);
drv->last_scan_cmd = 0;
} else {
external_scan_event = 1;
}
- send_scan_event(drv, 0, tb, external_scan_event);
+ send_scan_event(bss, 0, tb, external_scan_event);
break;
case NL80211_CMD_SCHED_SCAN_RESULTS:
- wpa_dbg(drv->ctx, MSG_DEBUG,
+ wpa_dbg(bss->ctx, MSG_DEBUG,
"nl80211: New sched scan results available");
drv->scan_state = SCHED_SCAN_RESULTS;
- send_scan_event(drv, 0, tb, 0);
+ send_scan_event(bss, 0, tb, 0);
break;
case NL80211_CMD_SCAN_ABORTED:
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
+ wpa_dbg(bss->ctx, MSG_DEBUG, "nl80211: Scan aborted");
if (drv->last_scan_cmd != NL80211_CMD_VENDOR)
drv->scan_state = SCAN_ABORTED;
if (drv->last_scan_cmd == NL80211_CMD_TRIGGER_SCAN) {
@@ -3947,12 +4002,12 @@
* order not to make wpa_supplicant stop its scanning.
*/
eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
- drv, drv->ctx);
+ drv, bss->ctx);
drv->last_scan_cmd = 0;
} else {
external_scan_event = 1;
}
- send_scan_event(drv, 1, tb, external_scan_event);
+ send_scan_event(bss, 1, tb, external_scan_event);
break;
case NL80211_CMD_AUTHENTICATE:
case NL80211_CMD_ASSOCIATE:
@@ -4030,7 +4085,7 @@
mlme_event_remain_on_channel(drv, 1, tb);
break;
case NL80211_CMD_NOTIFY_CQM:
- nl80211_cqm_event(drv, tb);
+ nl80211_cqm_event(bss, tb);
break;
case NL80211_CMD_REG_CHANGE:
case NL80211_CMD_WIPHY_REG_CHANGE:
@@ -4067,7 +4122,7 @@
nl80211_radar_event(drv, tb);
break;
case NL80211_CMD_STOP_AP:
- nl80211_stop_ap(drv, tb);
+ nl80211_stop_ap(bss, tb);
break;
case NL80211_CMD_VENDOR:
nl80211_vendor_event(drv, tb);
@@ -4201,7 +4256,16 @@
wdev_id == bss->wdev_id)) {
processed = true;
do_process_drv_event(bss, gnlh->cmd, tb);
- if (!wiphy_idx_set)
+ /* There are two types of events that may need
+ * to be delivered to multiple interfaces:
+ * 1. Events for a wiphy, as it can have
+ * multiple interfaces.
+ * 2. "Global" events, like
+ * NL80211_CMD_REG_CHANGE.
+ *
+ * Terminate early only if the event is directed
+ * to a specific interface or wdev. */
+ if (ifidx != -1 || wdev_id_set)
return NL_SKIP;
/* The driver instance could have been removed,
* e.g., due to NL80211_CMD_RADAR_DETECT event,
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index b055e68..d0ed7ad 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -153,6 +153,7 @@
void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ struct i802_bss *bss;
wpa_printf(MSG_DEBUG, "nl80211: Scan timeout - try to abort it");
#ifdef CONFIG_DRIVER_NL80211_QCA
@@ -160,14 +161,27 @@
nl80211_abort_vendor_scan(drv, drv->vendor_scan_cookie) == 0)
return;
#endif /* CONFIG_DRIVER_NL80211_QCA */
- if (!drv->vendor_scan_cookie &&
- nl80211_abort_scan(drv->first_bss) == 0)
+
+ for (bss = drv->first_bss; bss; bss = bss->next) {
+ if (bss->scan_link)
+ break;
+ }
+
+ if (!bss) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed to find scan BSS");
return;
+ }
+
+ if (!drv->vendor_scan_cookie &&
+ nl80211_abort_scan(bss) == 0) {
+ bss->scan_link = NULL;
+ return;
+ }
wpa_printf(MSG_DEBUG, "nl80211: Failed to abort scan");
if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED)
- nl80211_restore_ap_mode(drv->first_bss);
+ nl80211_restore_ap_mode(bss);
wpa_printf(MSG_DEBUG, "nl80211: Try to get scan results");
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
@@ -347,7 +361,7 @@
int ret = -1, timeout;
struct nl_msg *msg = NULL;
- wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
+ wpa_dbg(bss->ctx, MSG_DEBUG, "nl80211: scan request");
drv->scan_for_auth = 0;
if (TEST_FAIL())
@@ -402,6 +416,40 @@
wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
"(%s)", ret, strerror(-ret));
if (drv->hostapd && is_ap_interface(drv->nlmode)) {
+#ifdef CONFIG_IEEE80211BE
+ /* For multi link BSS, retry scan if any other links
+ * are busy scanning. */
+ if (ret == -EBUSY &&
+ nl80211_link_valid(bss->valid_links,
+ params->link_id)) {
+ struct i802_bss *link_bss;
+ u8 link_id;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Scan trigger on multi link BSS failed (requested link=%d on interface %s)",
+ params->link_id, bss->ifname);
+
+ for (link_bss = drv->first_bss; link_bss;
+ link_bss = link_bss->next) {
+ if (link_bss->scan_link)
+ break;
+ }
+
+ if (!link_bss) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: BSS information already running scan not available");
+ goto fail;
+ }
+
+ link_id = nl80211_get_link_id_from_link(
+ link_bss, link_bss->scan_link);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Scan already running on interface %s link %d",
+ link_bss->ifname, link_id);
+ goto fail;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
/*
* mac80211 does not allow scan requests in AP mode, so
* try to do this in station mode.
@@ -435,11 +483,20 @@
}
wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
"seconds", ret, timeout);
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, bss->ctx);
eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
- drv, drv->ctx);
+ drv, bss->ctx);
drv->last_scan_cmd = NL80211_CMD_TRIGGER_SCAN;
+ bss->scan_link = bss->flink;
+ if (is_ap_interface(drv->nlmode) &&
+ nl80211_link_valid(bss->valid_links, params->link_id)) {
+ wpa_dbg(bss->ctx, MSG_DEBUG,
+ "nl80211: Scan requested for link %d",
+ params->link_id);
+ bss->scan_link = nl80211_get_link(bss, params->link_id);
+ }
+
fail:
nlmsg_free(msg);
return ret;
@@ -1294,9 +1351,9 @@
wpa_printf(MSG_DEBUG,
"nl80211: Vendor scan requested (ret=%d) - scan timeout 30 seconds, scan cookie:0x%llx",
ret, (long long unsigned int) cookie);
- eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, bss->ctx);
eloop_register_timeout(30, 0, wpa_driver_nl80211_scan_timeout,
- drv, drv->ctx);
+ drv, bss->ctx);
drv->last_scan_cmd = NL80211_CMD_VENDOR;
fail:
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index dced2c4..f97f5ad 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -11,7 +11,7 @@
* Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
* Copyright 2008 Colin McCabe <colin@cozybit.com>
* Copyright 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2023 Intel Corporation
+ * Copyright (C) 2018-2024 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
@@ -72,7 +72,7 @@
* For drivers supporting TDLS with external setup (WIPHY_FLAG_SUPPORTS_TDLS
* and WIPHY_FLAG_TDLS_EXTERNAL_SETUP), the station lifetime is as follows:
* - a setup station entry is added, not yet authorized, without any rate
- * or capability information, this just exists to avoid race conditions
+ * or capability information; this just exists to avoid race conditions
* - when the TDLS setup is done, a single NL80211_CMD_SET_STATION is valid
* to add rate and capability information to the station and at the same
* time mark it authorized.
@@ -87,7 +87,7 @@
* DOC: Frame transmission/registration support
*
* Frame transmission and registration support exists to allow userspace
- * management entities such as wpa_supplicant react to management frames
+ * management entities such as wpa_supplicant to react to management frames
* that are not being handled by the kernel. This includes, for example,
* certain classes of action frames that cannot be handled in the kernel
* for various reasons.
@@ -113,7 +113,7 @@
*
* Frame transmission allows userspace to send for example the required
* responses to action frames. It is subject to some sanity checking,
- * but many frames can be transmitted. When a frame was transmitted, its
+ * but many frames can be transmitted. When a frame is transmitted, its
* status is indicated to the sending socket.
*
* For more technical details, see the corresponding command descriptions
@@ -123,7 +123,7 @@
/**
* DOC: Virtual interface / concurrency capabilities
*
- * Some devices are able to operate with virtual MACs, they can have
+ * Some devices are able to operate with virtual MACs; they can have
* more than one virtual interface. The capability handling for this
* is a bit complex though, as there may be a number of restrictions
* on the types of concurrency that are supported.
@@ -135,7 +135,7 @@
* Once concurrency is desired, more attributes must be observed:
* To start with, since some interface types are purely managed in
* software, like the AP-VLAN type in mac80211 for example, there's
- * an additional list of these, they can be added at any time and
+ * an additional list of these; they can be added at any time and
* are only restricted by some semantic restrictions (e.g. AP-VLAN
* cannot be added without a corresponding AP interface). This list
* is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute.
@@ -164,7 +164,7 @@
* Packet coalesce feature helps to reduce number of received interrupts
* to host by buffering these packets in firmware/hardware for some
* predefined time. Received interrupt will be generated when one of the
- * following events occur.
+ * following events occurs.
* a) Expiration of hardware timer whose expiration time is set to maximum
* coalescing delay of matching coalesce rule.
* b) Coalescing buffer in hardware reaches its limit.
@@ -174,7 +174,7 @@
* rule.
* a) Maximum coalescing delay
* b) List of packet patterns which needs to be matched
- * c) Condition for coalescence. pattern 'match' or 'no match'
+ * c) Condition for coalescence: pattern 'match' or 'no match'
* Multiple such rules can be created.
*/
@@ -213,7 +213,7 @@
/**
* DOC: FILS shared key authentication offload
*
- * FILS shared key authentication offload can be advertized by drivers by
+ * FILS shared key authentication offload can be advertised by drivers by
* setting @NL80211_EXT_FEATURE_FILS_SK_OFFLOAD flag. The drivers that support
* FILS shared key authentication offload should be able to construct the
* authentication and association frames for FILS shared key authentication and
@@ -239,7 +239,7 @@
* The PMKSA can be maintained in userspace persistently so that it can be used
* later after reboots or wifi turn off/on also.
*
- * %NL80211_ATTR_FILS_CACHE_ID is the cache identifier advertized by a FILS
+ * %NL80211_ATTR_FILS_CACHE_ID is the cache identifier advertised by a FILS
* capable AP supporting PMK caching. It specifies the scope within which the
* PMKSAs are cached in an ESS. %NL80211_CMD_SET_PMKSA and
* %NL80211_CMD_DEL_PMKSA are enhanced to allow support for PMKSA caching based
@@ -290,12 +290,12 @@
* If the configuration needs to be applied for specific peer then the MAC
* address of the peer needs to be passed in %NL80211_ATTR_MAC, otherwise the
* configuration will be applied for all the connected peers in the vif except
- * any peers that have peer specific configuration for the TID by default; if
- * the %NL80211_TID_CONFIG_ATTR_OVERRIDE flag is set, peer specific values
+ * any peers that have peer-specific configuration for the TID by default; if
+ * the %NL80211_TID_CONFIG_ATTR_OVERRIDE flag is set, peer-specific values
* will be overwritten.
*
- * All this configuration is valid only for STA's current connection
- * i.e. the configuration will be reset to default when the STA connects back
+ * All this configuration is valid only for STA's current connection,
+ * i.e., the configuration will be reset to default when the STA connects back
* after disconnection/roaming, and this configuration will be cleared when
* the interface goes down.
*/
@@ -413,8 +413,8 @@
* are like for %NL80211_CMD_SET_BEACON, and additionally parameters that
* do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL,
* %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID,
- * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
- * %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
+ * %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ * %NL80211_ATTR_CIPHER_SUITE_GROUP, %NL80211_ATTR_WPA_VERSIONS,
* %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
* %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT,
* %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS.
@@ -438,23 +438,19 @@
* %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
- * frame).
+ * frame). %NL80211_ATTR_MLO_LINK_ID can be used optionally to remove
+ * stations connected and using at least that link as one of its links.
*
* @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
- * destination %NL80211_ATTR_MAC on the interface identified by
- * %NL80211_ATTR_IFINDEX.
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to
- * destination %NL80211_ATTR_MAC on the interface identified by
- * %NL80211_ATTR_IFINDEX.
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by
* %NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP.
* @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
* %NL80211_ATTR_MAC.
- * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
- * interface identified by %NL80211_ATTR_IFINDEX.
- * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
- * or, if no MAC address given, all mesh paths, on the interface identified
- * by %NL80211_ATTR_IFINDEX.
* @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
* %NL80211_ATTR_IFINDEX.
*
@@ -475,15 +471,15 @@
* after being queried by the kernel. CRDA replies by sending a regulatory
* domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
* current alpha2 if it found a match. It also provides
- * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
- * regulatory rule is a nested set of attributes given by
- * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and
- * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
- * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
- * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
+ * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
+ * regulatory rule is a nested set of attributes given by
+ * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and
+ * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
* @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
- * to the specified ISO/IEC 3166-1 alpha2 country code. The core will
- * store this as a valid request and then query userspace for it.
+ * to the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * store this as a valid request and then query userspace for it.
*
* @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the
* interface identified by %NL80211_ATTR_IFINDEX
@@ -521,7 +517,7 @@
* %NL80211_ATTR_SCHED_SCAN_PLANS. If %NL80211_ATTR_SCHED_SCAN_PLANS is
* not specified and only %NL80211_ATTR_SCHED_SCAN_INTERVAL is specified,
* scheduled scan will run in an infinite loop with the specified interval.
- * These attributes are mutually exculsive,
+ * These attributes are mutually exclusive,
* i.e. NL80211_ATTR_SCHED_SCAN_INTERVAL must not be passed if
* NL80211_ATTR_SCHED_SCAN_PLANS is defined.
* If for some reason scheduled scan is aborted by the driver, all scan
@@ -552,7 +548,7 @@
* %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface
* is brought down while a scheduled scan was running.
*
- * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
+ * @NL80211_CMD_GET_SURVEY: get survey results, e.g. channel occupation
* or noise level
* @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
* NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
@@ -563,40 +559,41 @@
* using %NL80211_ATTR_SSID, %NL80211_ATTR_FILS_CACHE_ID,
* %NL80211_ATTR_PMKID, and %NL80211_ATTR_PMK in case of FILS
* authentication where %NL80211_ATTR_FILS_CACHE_ID is the identifier
- * advertized by a FILS capable AP identifying the scope of PMKSA in an
+ * advertised by a FILS capable AP identifying the scope of PMKSA in an
* ESS.
* @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
* (for the BSSID) and %NL80211_ATTR_PMKID or using %NL80211_ATTR_SSID,
* %NL80211_ATTR_FILS_CACHE_ID, and %NL80211_ATTR_PMKID in case of FILS
- * authentication.
+ * authentication. Additionally in case of SAE offload and OWE offloads
+ * PMKSA entry can be deleted using %NL80211_ATTR_SSID.
* @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
*
* @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
- * has been changed and provides details of the request information
- * that caused the change such as who initiated the regulatory request
- * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
- * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
- * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
- * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
- * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
- * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
- * to (%NL80211_ATTR_REG_ALPHA2).
+ * has been changed and provides details of the request information
+ * that caused the change such as who initiated the regulatory request
+ * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
+ * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
+ * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
+ * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
+ * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
+ * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
+ * to (%NL80211_ATTR_REG_ALPHA2).
* @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon
- * has been found while world roaming thus enabling active scan or
- * any mode of operation that initiates TX (beacons) on a channel
- * where we would not have been able to do either before. As an example
- * if you are world roaming (regulatory domain set to world or if your
- * driver is using a custom world roaming regulatory domain) and while
- * doing a passive scan on the 5 GHz band you find an AP there (if not
- * on a DFS channel) you will now be able to actively scan for that AP
- * or use AP mode on your card on that same channel. Note that this will
- * never be used for channels 1-11 on the 2 GHz band as they are always
- * enabled world wide. This beacon hint is only sent if your device had
- * either disabled active scanning or beaconing on a channel. We send to
- * userspace the wiphy on which we removed a restriction from
- * (%NL80211_ATTR_WIPHY) and the channel on which this occurred
- * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
- * the beacon hint was processed.
+ * has been found while world roaming thus enabling active scan or
+ * any mode of operation that initiates TX (beacons) on a channel
+ * where we would not have been able to do either before. As an example
+ * if you are world roaming (regulatory domain set to world or if your
+ * driver is using a custom world roaming regulatory domain) and while
+ * doing a passive scan on the 5 GHz band you find an AP there (if not
+ * on a DFS channel) you will now be able to actively scan for that AP
+ * or use AP mode on your card on that same channel. Note that this will
+ * never be used for channels 1-11 on the 2 GHz band as they are always
+ * enabled world wide. This beacon hint is only sent if your device had
+ * either disabled active scanning or beaconing on a channel. We send to
+ * userspace the wiphy on which we removed a restriction from
+ * (%NL80211_ATTR_WIPHY) and the channel on which this occurred
+ * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
+ * the beacon hint was processed.
*
* @NL80211_CMD_AUTHENTICATE: authentication request and notification.
* This command is used both as a command (request to authenticate) and
@@ -607,7 +604,7 @@
* BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
* the SSID (mainly for association, but is included in authentication
* request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ +
- * %NL80211_ATTR_WIPHY_FREQ_OFFSET is used to specify the frequence of the
+ * %NL80211_ATTR_WIPHY_FREQ_OFFSET is used to specify the frequency of the
* channel in MHz. %NL80211_ATTR_AUTH_TYPE is used to specify the
* authentication type. %NL80211_ATTR_IE is used to define IEs
* (VendorSpecificInfo, but also including RSN IE and FT IEs) to be added
@@ -816,7 +813,7 @@
* reached.
* @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
* and the attributes determining channel width) the given interface
- * (identifed by %NL80211_ATTR_IFINDEX) shall operate on.
+ * (identified by %NL80211_ATTR_IFINDEX) shall operate on.
* In case multiple channels are supported by the device, the mechanism
* with which it switches channels is implementation-defined.
* When a monitor interface is given, it can only switch channel while
@@ -888,7 +885,7 @@
* inform userspace of the new replay counter.
*
* @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
- * of PMKSA caching dandidates.
+ * of PMKSA caching candidates.
*
* @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
* In addition, this can be used as an event to request userspace to take
@@ -924,7 +921,7 @@
*
* @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
* by sending a null data frame to it and reporting when the frame is
- * acknowleged. This is used to allow timing out inactive clients. Uses
+ * acknowledged. This is used to allow timing out inactive clients. Uses
* %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
* direct reply with an %NL80211_ATTR_COOKIE that is later used to match
* up the event with the request. The event includes the same data and
@@ -1118,7 +1115,7 @@
* current configuration is not changed. If it is present but
* set to zero, the configuration is changed to don't-care
* (i.e. the device can decide what to do).
- * @NL80211_CMD_NAN_FUNC_MATCH: Notification sent when a match is reported.
+ * @NL80211_CMD_NAN_MATCH: Notification sent when a match is reported.
* This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and
* %NL80211_ATTR_COOKIE.
*
@@ -1135,11 +1132,15 @@
* @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously
* configured PMK for the authenticator address identified by
* %NL80211_ATTR_MAC.
- * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates an 802.1X FT roam was
- * completed successfully. Drivers that support 4 way handshake offload
- * should send this event after indicating 802.1X FT assocation with
- * %NL80211_CMD_ROAM. If the 4 way handshake failed %NL80211_CMD_DISCONNECT
- * should be indicated instead.
+ * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates port is authorized and
+ * open for regular data traffic. For STA/P2P-client, this event is sent
+ * with AP MAC address and for AP/P2P-GO, the event carries the STA/P2P-
+ * client MAC address.
+ * Drivers that support 4 way handshake offload should send this event for
+ * STA/P2P-client after successful 4-way HS or after 802.1X FT following
+ * NL80211_CMD_CONNECT or NL80211_CMD_ROAM. Drivers using AP/P2P-GO 4-way
+ * handshake offload should send this event on successful completion of
+ * 4-way handshake with the peer (STA/P2P-client).
* @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request
* and RX notification. This command is used both as a request to transmit
* a control port frame and as a notification that a control port frame
@@ -1323,6 +1324,11 @@
* Multi-Link reconfiguration. %NL80211_ATTR_MLO_LINKS is used to provide
* information about the removed STA MLD setup links.
*
+ * @NL80211_CMD_SET_TID_TO_LINK_MAPPING: Set the TID to Link Mapping for a
+ * non-AP MLD station. The %NL80211_ATTR_MLO_TTLM_DLINK and
+ * %NL80211_ATTR_MLO_TTLM_ULINK attributes are used to specify the
+ * TID to Link mapping for downlink/uplink traffic.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -1578,6 +1584,8 @@
NL80211_CMD_LINKS_REMOVED,
+ NL80211_CMD_SET_TID_TO_LINK_MAPPING,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1702,21 +1710,21 @@
* (see &enum nl80211_plink_action).
* @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
* @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
- * info given for %NL80211_CMD_GET_MPATH, nested attribute described at
+ * info given for %NL80211_CMD_GET_MPATH, nested attribute described at
* &enum nl80211_mpath_info.
*
* @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
* &enum nl80211_mntr_flags.
*
* @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
- * current regulatory domain should be set to or is already set to.
- * For example, 'CR', for Costa Rica. This attribute is used by the kernel
- * to query the CRDA to retrieve one regulatory domain. This attribute can
- * also be used by userspace to query the kernel for the currently set
- * regulatory domain. We chose an alpha2 as that is also used by the
- * IEEE-802.11 country information element to identify a country.
- * Users can also simply ask the wireless core to set regulatory domain
- * to a specific alpha2.
+ * current regulatory domain should be set to or is already set to.
+ * For example, 'CR', for Costa Rica. This attribute is used by the kernel
+ * to query the CRDA to retrieve one regulatory domain. This attribute can
+ * also be used by userspace to query the kernel for the currently set
+ * regulatory domain. We chose an alpha2 as that is also used by the
+ * IEEE-802.11 country information element to identify a country.
+ * Users can also simply ask the wireless core to set regulatory domain
+ * to a specific alpha2.
* @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
* rules.
*
@@ -1759,9 +1767,9 @@
* @NL80211_ATTR_BSS: scan result BSS
*
* @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
- * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
+ * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
* @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently
- * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*)
+ * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*)
*
* @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies
* an array of command numbers (i.e. a mapping index to command number)
@@ -1780,15 +1788,15 @@
* a u32
*
* @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change
- * due to considerations from a beacon hint. This attribute reflects
- * the state of the channel _before_ the beacon hint processing. This
- * attributes consists of a nested attribute containing
- * NL80211_FREQUENCY_ATTR_*
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _before_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
* @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change
- * due to considerations from a beacon hint. This attribute reflects
- * the state of the channel _after_ the beacon hint processing. This
- * attributes consists of a nested attribute containing
- * NL80211_FREQUENCY_ATTR_*
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _after_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
*
* @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported
* cipher suites
@@ -1835,7 +1843,7 @@
* using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is
* to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER
* flag. When used with %NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, pre-auth
- * frames are not forwared over the control port.
+ * frames are not forwarded over the control port.
*
* @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
* We recommend using nested, driver-specific attributes within this.
@@ -1849,12 +1857,6 @@
* that protected APs should be used. This is also used with NEW_BEACON to
* indicate that the BSS is to use protection.
*
- * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON
- * to indicate which unicast key ciphers will be used with the connection
- * (an array of u32).
- * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
- * indicate which group key cipher will be used with the connection (a
- * u32).
* @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
* indicate which WPA version(s) the AP we want to associate with is using
* (a u32 with flags from &enum nl80211_wpa_versions).
@@ -1885,6 +1887,7 @@
* with %NL80211_KEY_* sub-attributes
*
* @NL80211_ATTR_PID: Process ID of a network namespace.
+ * @NL80211_ATTR_NETNS_FD: File descriptor of a network namespace.
*
* @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for
* dumps. This number increases whenever the object list being
@@ -1939,6 +1942,7 @@
*
* @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
* acknowledged by the recipient.
+ * @NL80211_ATTR_ACK_SIGNAL: Station's ack signal strength (s32)
*
* @NL80211_ATTR_PS_STATE: powersave state, using &enum nl80211_ps_state values.
*
@@ -1972,10 +1976,10 @@
* bit. Depending on which antennas are selected in the bitmap, 802.11n
* drivers can derive which chainmasks to use (if all antennas belonging to
* a particular chain are disabled this chain should be disabled) and if
- * a chain has diversity antennas wether diversity should be used or not.
+ * a chain has diversity antennas whether diversity should be used or not.
* HT capabilities (STBC, TX Beamforming, Antenna selection) can be
* derived from the available chains after applying the antenna mask.
- * Non-802.11n drivers can derive wether to use diversity or not.
+ * Non-802.11n drivers can derive whether to use diversity or not.
* Drivers may reject configurations or RX/TX mask combinations they cannot
* support by returning -EINVAL.
*
@@ -2048,6 +2052,10 @@
* @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
* interface combinations. In each nested item, it contains attributes
* defined in &enum nl80211_if_combination_attrs.
+ * If the wiphy uses multiple radios (@NL80211_ATTR_WIPHY_RADIOS is set),
+ * this attribute contains the interface combinations of the first radio.
+ * See @NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS for the global wiphy
+ * combinations for the sum of all radios.
* @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like
* %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that
* are managed in software: interfaces of these types aren't subject to
@@ -2136,6 +2144,9 @@
* @NL80211_ATTR_DISABLE_HE: Force HE capable interfaces to disable
* this feature during association. This is a flag attribute.
* Currently only supported in mac80211 drivers.
+ * @NL80211_ATTR_DISABLE_EHT: Force EHT capable interfaces to disable
+ * this feature during association. This is a flag attribute.
+ * Currently only supported in mac80211 drivers.
* @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the
* ATTR_HT_CAPABILITY to which attention should be paid.
* Currently, only mac80211 NICs support this feature.
@@ -2145,6 +2156,12 @@
* All values are treated as suggestions and may be ignored
* by the driver as required. The actual values may be seen in
* the station debugfs ht_caps file.
+ * @NL80211_ATTR_VHT_CAPABILITY_MASK: Specify which bits of the
+ * ATTR_VHT_CAPABILITY to which attention should be paid.
+ * Currently, only mac80211 NICs support this feature.
+ * All values are treated as suggestions and may be ignored
+ * by the driver as required. The actual values may be seen in
+ * the station debugfs vht_caps file.
*
* @NL80211_ATTR_DFS_REGION: region for regulatory rules which this country
* abides to when initiating radiation on DFS channels. A country maps
@@ -2403,7 +2420,7 @@
* scheduled scan is started. Or the delay before a WoWLAN
* net-detect scan is started, counting from the moment the
* system is suspended. This value is a u32, in seconds.
-
+ *
* @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
* is operating in an indoor environment.
*
@@ -2545,7 +2562,7 @@
* from successful FILS authentication and is used with
* %NL80211_CMD_CONNECT.
*
- * @NL80211_ATTR_FILS_CACHE_ID: A 2-octet identifier advertized by a FILS AP
+ * @NL80211_ATTR_FILS_CACHE_ID: A 2-octet identifier advertised by a FILS AP
* identifying the scope of PMKSAs. This is used with
* @NL80211_CMD_SET_PMKSA and @NL80211_CMD_DEL_PMKSA.
*
@@ -2826,6 +2843,31 @@
* @NL80211_ATTR_MLO_LINK_DISABLED: Flag attribute indicating that the link is
* disabled.
*
+ * @NL80211_ATTR_BSS_DUMP_INCLUDE_USE_DATA: Include BSS usage data, i.e.
+ * include BSSes that can only be used in restricted scenarios and/or
+ * cannot be used at all.
+ *
+ * @NL80211_ATTR_MLO_TTLM_DLINK: Binary attribute specifying the downlink TID to
+ * link mapping. The length is 8 * sizeof(u16). For each TID the link
+ * mapping is as defined in section 9.4.2.314 (TID-To-Link Mapping element)
+ * in Draft P802.11be_D4.0.
+ * @NL80211_ATTR_MLO_TTLM_ULINK: Binary attribute specifying the uplink TID to
+ * link mapping. The length is 8 * sizeof(u16). For each TID the link
+ * mapping is as defined in section 9.4.2.314 (TID-To-Link Mapping element)
+ * in Draft P802.11be_D4.0.
+ *
+ * @NL80211_ATTR_ASSOC_SPP_AMSDU: flag attribute used with
+ * %NL80211_CMD_ASSOCIATE indicating the SPP A-MSDUs
+ * are used on this connection
+ *
+ * @NL80211_ATTR_WIPHY_RADIOS: Nested attribute describing physical radios
+ * belonging to this wiphy. See &enum nl80211_wiphy_radio_attrs.
+ *
+ * @NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS: Nested attribute listing the
+ * supported interface combinations for all radios combined. In each
+ * nested item, it contains attributes defined in
+ * &enum nl80211_if_combination_attrs.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3364,6 +3406,16 @@
NL80211_ATTR_MLO_LINK_DISABLED,
+ NL80211_ATTR_BSS_DUMP_INCLUDE_USE_DATA,
+
+ NL80211_ATTR_MLO_TTLM_DLINK,
+ NL80211_ATTR_MLO_TTLM_ULINK,
+
+ NL80211_ATTR_ASSOC_SPP_AMSDU,
+
+ NL80211_ATTR_WIPHY_RADIOS,
+ NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3504,6 +3556,7 @@
* @NL80211_STA_FLAG_ASSOCIATED: station is associated; used with drivers
* that support %NL80211_FEATURE_FULL_AP_CLIENT_STATE to transition a
* previously added station into associated state
+ * @NL80211_STA_FLAG_SPP_AMSDU: station supports SPP A-MSDUs
* @NL80211_STA_FLAG_MAX: highest station flag number currently defined
* @__NL80211_STA_FLAG_AFTER_LAST: internal use
*/
@@ -3516,6 +3569,7 @@
NL80211_STA_FLAG_AUTHENTICATED,
NL80211_STA_FLAG_TDLS_PEER,
NL80211_STA_FLAG_ASSOCIATED,
+ NL80211_STA_FLAG_SPP_AMSDU,
/* keep last */
__NL80211_STA_FLAG_AFTER_LAST,
@@ -3526,7 +3580,7 @@
* enum nl80211_sta_p2p_ps_status - station support of P2P PS
*
* @NL80211_P2P_PS_UNSUPPORTED: station doesn't support P2P PS mechanism
- * @@NL80211_P2P_PS_SUPPORTED: station supports P2P PS mechanism
+ * @NL80211_P2P_PS_SUPPORTED: station supports P2P PS mechanism
* @NUM_NL80211_P2P_PS_STATUS: number of values
*/
enum nl80211_sta_p2p_ps_status {
@@ -3564,9 +3618,9 @@
/**
* enum nl80211_he_ltf - HE long training field
- * @NL80211_RATE_INFO_HE_1xLTF: 3.2 usec
- * @NL80211_RATE_INFO_HE_2xLTF: 6.4 usec
- * @NL80211_RATE_INFO_HE_4xLTF: 12.8 usec
+ * @NL80211_RATE_INFO_HE_1XLTF: 3.2 usec
+ * @NL80211_RATE_INFO_HE_2XLTF: 6.4 usec
+ * @NL80211_RATE_INFO_HE_4XLTF: 12.8 usec
*/
enum nl80211_he_ltf {
NL80211_RATE_INFO_HE_1XLTF,
@@ -3681,7 +3735,7 @@
* @NL80211_RATE_INFO_HE_GI: HE guard interval identifier
* (u8, see &enum nl80211_he_gi)
* @NL80211_RATE_INFO_HE_DCM: HE DCM value (u8, 0/1)
- * @NL80211_RATE_INFO_RU_ALLOC: HE RU allocation, if not present then
+ * @NL80211_RATE_INFO_HE_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)
@@ -3784,7 +3838,7 @@
* (u64, to this station)
* @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
* @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
- * containing info as possible, see &enum nl80211_rate_info
+ * containing info as possible, see &enum nl80211_rate_info
* @NL80211_STA_INFO_RX_PACKETS: total received packet (MSDUs and MMPDUs)
* (u32, from this station)
* @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (MSDUs and MMPDUs)
@@ -3813,8 +3867,8 @@
* Contains a nested array of signal strength attributes (u8, dBm)
* @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average
* Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
- * @NL80211_STA_EXPECTED_THROUGHPUT: expected throughput considering also the
- * 802.11 header (u32, kbps)
+ * @NL80211_STA_INFO_EXPECTED_THROUGHPUT: expected throughput considering also
+ * the 802.11 header (u32, kbps)
* @NL80211_STA_INFO_RX_DROP_MISC: RX packets dropped for unspecified reasons
* (u64)
* @NL80211_STA_INFO_BEACON_RX: number of beacons received from this peer (u64)
@@ -4000,7 +4054,7 @@
* @NL80211_MPATH_INFO_METRIC: metric (cost) of this mesh path
* @NL80211_MPATH_INFO_EXPTIME: expiration time for the path, in msec from now
* @NL80211_MPATH_INFO_FLAGS: mesh path flags, enumerated in
- * &enum nl80211_mpath_flags;
+ * &enum nl80211_mpath_flags;
* @NL80211_MPATH_INFO_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
* @NL80211_MPATH_INFO_DISCOVERY_RETRIES: mesh path discovery retries
* @NL80211_MPATH_INFO_HOP_COUNT: hop count to destination
@@ -4140,7 +4194,7 @@
* @NL80211_WMMR_CW_MAX: Maximum contention window slot.
* @NL80211_WMMR_AIFSN: Arbitration Inter Frame Space.
* @NL80211_WMMR_TXOP: Maximum allowed tx operation time.
- * @nl80211_WMMR_MAX: highest possible wmm rule.
+ * @NL80211_WMMR_MAX: highest possible wmm rule.
* @__NL80211_WMMR_LAST: Internal use.
*/
enum nl80211_wmm_rule {
@@ -4162,15 +4216,16 @@
* @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
* regulatory domain.
* @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation
- * are permitted on this channel, this includes sending probe
- * requests, or modes of operation that require beaconing.
+ * are permitted on this channel, this includes sending probe
+ * requests, or modes of operation that require beaconing.
+ * @__NL80211_FREQUENCY_ATTR_NO_IBSS: obsolete, same as _NO_IR
* @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
* on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
* (100 * dBm).
* @NL80211_FREQUENCY_ATTR_DFS_STATE: current state for DFS
* (enum nl80211_dfs_state)
- * @NL80211_FREQUENCY_ATTR_DFS_TIME: time in miliseconds for how long
+ * @NL80211_FREQUENCY_ATTR_DFS_TIME: time in milliseconds for how long
* this channel is in this DFS state.
* @NL80211_FREQUENCY_ATTR_NO_HT40_MINUS: HT40- isn't possible with this
* channel as the control channel
@@ -4226,6 +4281,19 @@
* 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_DFS_CONCURRENT: Operation on this channel is
+ * allowed for peer-to-peer or adhoc communication under the control
+ * of a DFS master which operates on the same channel (FCC-594280 D01
+ * Section B.3). Should be used together with %NL80211_RRF_DFS only.
+ * @NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT: Client connection to VLP AP
+ * not allowed using this channel
+ * @NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT: Client connection to AFC AP
+ * not allowed using this channel
+ * @NL80211_FREQUENCY_ATTR_CAN_MONITOR: This channel can be used in monitor
+ * mode despite other (regulatory) restrictions, even if the channel is
+ * otherwise completely disabled.
+ * @NL80211_FREQUENCY_ATTR_ALLOW_6GHZ_VLP_AP: This channel can be used for a
+ * very low power (VLP) AP, despite being NO_IR.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -4265,6 +4333,11 @@
NL80211_FREQUENCY_ATTR_NO_320MHZ,
NL80211_FREQUENCY_ATTR_NO_EHT,
NL80211_FREQUENCY_ATTR_PSD,
+ NL80211_FREQUENCY_ATTR_DFS_CONCURRENT,
+ NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT,
+ NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT,
+ NL80211_FREQUENCY_ATTR_CAN_MONITOR,
+ NL80211_FREQUENCY_ATTR_ALLOW_6GHZ_VLP_AP,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -4277,6 +4350,10 @@
#define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR
#define NL80211_FREQUENCY_ATTR_GO_CONCURRENT \
NL80211_FREQUENCY_ATTR_IR_CONCURRENT
+#define NL80211_FREQUENCY_ATTR_NO_UHB_VLP_CLIENT \
+ NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT
+#define NL80211_FREQUENCY_ATTR_NO_UHB_AFC_CLIENT \
+ NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT
/**
* enum nl80211_bitrate_attr - bitrate attributes
@@ -4299,16 +4376,16 @@
};
/**
- * enum nl80211_initiator - Indicates the initiator of a reg domain request
+ * enum nl80211_reg_initiator - Indicates the initiator of a reg domain request
* @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world
- * regulatory domain.
+ * regulatory domain.
* @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the
- * regulatory domain.
+ * regulatory domain.
* @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the
- * wireless core it thinks its knows the regulatory domain we should be in.
+ * wireless core it thinks its knows the regulatory domain we should be in.
* @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an
- * 802.11 country information element with regulatory information it
- * thinks we should consider. cfg80211 only processes the country
+ * 802.11 country information element with regulatory information it
+ * thinks we should consider. cfg80211 only processes the country
* code from the IE, and relies on the regulatory domain information
* structure passed by userspace (CRDA) from our wireless-regdb.
* If a channel is enabled but the country code indicates it should
@@ -4327,11 +4404,11 @@
* to a specific country. When this is set you can count on the
* ISO / IEC 3166 alpha2 country code being valid.
* @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory
- * domain.
+ * domain.
* @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom
- * driver specific world regulatory domain. These do not apply system-wide
- * and are only applicable to the individual devices which have requested
- * them to be applied.
+ * driver specific world regulatory domain. These do not apply system-wide
+ * and are only applicable to the individual devices which have requested
+ * them to be applied.
* @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product
* of an intersection between two regulatory domains -- the previously
* set regulatory domain on the system and the last accepted regulatory
@@ -4348,21 +4425,21 @@
* enum nl80211_reg_rule_attr - regulatory rule attributes
* @__NL80211_REG_RULE_ATTR_INVALID: attribute number 0 is reserved
* @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
- * considerations for a given frequency range. These are the
- * &enum nl80211_reg_rule_flags.
+ * considerations for a given frequency range. These are the
+ * &enum nl80211_reg_rule_flags.
* @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
- * rule in KHz. This is not a center of frequency but an actual regulatory
- * band edge.
+ * rule in KHz. This is not a center of frequency but an actual regulatory
+ * band edge.
* @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
- * in KHz. This is not a center a frequency but an actual regulatory
- * band edge.
+ * in KHz. This is not a center a frequency but an actual regulatory
+ * band edge.
* @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
* frequency range, in KHz.
* @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
- * for a given frequency range. The value is in mBi (100 * dBi).
- * If you don't have one then don't send this.
+ * for a given frequency range. The value is in mBi (100 * dBi).
+ * If you don't have one then don't send this.
* @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
- * a given frequency range. The value is in mBm (100 * dBm).
+ * 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).
@@ -4414,14 +4491,7 @@
* value as specified by &struct nl80211_bss_select_rssi_adjust.
* @NL80211_SCHED_SCAN_MATCH_ATTR_BSSID: BSSID to be used for matching
* (this cannot be used together with SSID).
- * @NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI: Nested attribute that carries the
- * band specific minimum rssi thresholds for the bands defined in
- * enum nl80211_band. The minimum rssi threshold value(s32) specific to a
- * band shall be encapsulated in attribute with type value equals to one
- * of the NL80211_BAND_* defined in enum nl80211_band. For example, the
- * minimum rssi threshold value for 2.4GHZ band shall be encapsulated
- * within an attribute of type NL80211_BAND_2GHZ. And one or more of such
- * attributes will be nested within this attribute.
+ * @NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI: Obsolete
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
* attribute number currently defined
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -4434,7 +4504,7 @@
NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
NL80211_SCHED_SCAN_MATCH_ATTR_BSSID,
- NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI,
+ NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI, /* obsolete */
/* keep last */
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -4456,8 +4526,9 @@
* @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
* @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
* @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed,
- * this includes probe requests or modes of operation that require
- * beaconing.
+ * this includes probe requests or modes of operation that require
+ * beaconing.
+ * @__NL80211_RRF_NO_IBSS: obsolete, same as NO_IR
* @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
* base on contiguous rules and wider channels will be allowed to cross
* multiple contiguous/overlapping frequency ranges.
@@ -4470,6 +4541,14 @@
* @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
+ * @NL80211_RRF_DFS_CONCURRENT: Operation on this channel is allowed for
+ * peer-to-peer or adhoc communication under the control of a DFS master
+ * which operates on the same channel (FCC-594280 D01 Section B.3).
+ * Should be used together with %NL80211_RRF_DFS only.
+ * @NL80211_RRF_NO_6GHZ_VLP_CLIENT: Client connection to VLP AP not allowed
+ * @NL80211_RRF_NO_6GHZ_AFC_CLIENT: Client connection to AFC AP not allowed
+ * @NL80211_RRF_ALLOW_6GHZ_VLP_AP: Very low power (VLP) AP can be permitted
+ * despite NO_IR configuration.
*/
enum nl80211_reg_rule_flags {
NL80211_RRF_NO_OFDM = 1<<0,
@@ -4491,6 +4570,10 @@
NL80211_RRF_NO_320MHZ = 1<<18,
NL80211_RRF_NO_EHT = 1<<19,
NL80211_RRF_PSD = 1<<20,
+ NL80211_RRF_DFS_CONCURRENT = 1<<21,
+ NL80211_RRF_NO_6GHZ_VLP_CLIENT = 1<<22,
+ NL80211_RRF_NO_6GHZ_AFC_CLIENT = 1<<23,
+ NL80211_RRF_ALLOW_6GHZ_VLP_AP = 1<<24,
};
#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR
@@ -4499,6 +4582,8 @@
#define NL80211_RRF_NO_HT40 (NL80211_RRF_NO_HT40MINUS |\
NL80211_RRF_NO_HT40PLUS)
#define NL80211_RRF_GO_CONCURRENT NL80211_RRF_IR_CONCURRENT
+#define NL80211_RRF_NO_UHB_VLP_CLIENT NL80211_RRF_NO_6GHZ_VLP_CLIENT
+#define NL80211_RRF_NO_UHB_AFC_CLIENT NL80211_RRF_NO_6GHZ_AFC_CLIENT
/* For backport compatibility with older userspace */
#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
@@ -4645,8 +4730,8 @@
* alternate between Active and Doze states, but may not wake up
* for neighbor's beacons.
*
- * @__NL80211_MESH_POWER_AFTER_LAST - internal use
- * @NL80211_MESH_POWER_MAX - highest possible power save level
+ * @__NL80211_MESH_POWER_AFTER_LAST: internal use
+ * @NL80211_MESH_POWER_MAX: highest possible power save level
*/
enum nl80211_mesh_power_mode {
@@ -5028,6 +5113,36 @@
};
/**
+ * enum nl80211_bss_use_for - bitmap indicating possible BSS use
+ * @NL80211_BSS_USE_FOR_NORMAL: Use this BSS for normal "connection",
+ * including IBSS/MBSS depending on the type.
+ * @NL80211_BSS_USE_FOR_MLD_LINK: This BSS can be used as a link in an
+ * MLO connection. Note that for an MLO connection, all links including
+ * the assoc link must have this flag set, and the assoc link must
+ * additionally have %NL80211_BSS_USE_FOR_NORMAL set.
+ */
+enum nl80211_bss_use_for {
+ NL80211_BSS_USE_FOR_NORMAL = 1 << 0,
+ NL80211_BSS_USE_FOR_MLD_LINK = 1 << 1,
+};
+
+/**
+ * enum nl80211_bss_cannot_use_reasons - reason(s) connection to a
+ * BSS isn't possible
+ * @NL80211_BSS_CANNOT_USE_NSTR_NONPRIMARY: NSTR nonprimary links aren't
+ * supported by the device, and this BSS entry represents one.
+ * @NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH: STA is not supporting
+ * the AP power type (SP, VLP, AP) that the AP uses.
+ */
+enum nl80211_bss_cannot_use_reasons {
+ NL80211_BSS_CANNOT_USE_NSTR_NONPRIMARY = 1 << 0,
+ NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH = 1 << 1,
+};
+
+#define NL80211_BSS_CANNOT_USE_UHB_PWR_MISMATCH \
+ NL80211_BSS_CANNOT_USE_6GHZ_PWR_MISMATCH
+
+/**
* enum nl80211_bss - netlink attributes for a BSS
*
* @__NL80211_BSS_INVALID: invalid
@@ -5079,6 +5194,14 @@
* @NL80211_BSS_FREQUENCY_OFFSET: frequency offset in KHz
* @NL80211_BSS_MLO_LINK_ID: MLO link ID of the BSS (u8).
* @NL80211_BSS_MLD_ADDR: MLD address of this BSS if connected to it.
+ * @NL80211_BSS_USE_FOR: u32 bitmap attribute indicating what the BSS can be
+ * used for, see &enum nl80211_bss_use_for.
+ * @NL80211_BSS_CANNOT_USE_REASONS: Indicates the reason that this BSS cannot
+ * be used for all or some of the possible uses by the device reporting it,
+ * even though its presence was detected.
+ * This is a u64 attribute containing a bitmap of values from
+ * &enum nl80211_cannot_use_reasons, note that the attribute may be missing
+ * if no reasons are specified.
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
@@ -5106,6 +5229,8 @@
NL80211_BSS_FREQUENCY_OFFSET,
NL80211_BSS_MLO_LINK_ID,
NL80211_BSS_MLD_ADDR,
+ NL80211_BSS_USE_FOR,
+ NL80211_BSS_CANNOT_USE_REASONS,
/* keep last */
__NL80211_BSS_AFTER_LAST,
@@ -5454,7 +5579,7 @@
* (%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE).
* @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but
* per peer instead.
- * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribue, if set indicates
+ * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribute, if set indicates
* that the new configuration overrides all previous peer
* configurations, otherwise previous peer specific configurations
* should be left untouched.
@@ -5626,7 +5751,7 @@
* "TCP connection wakeup" for more details. This is a nested attribute
* containing the exact information for establishing and keeping alive
* the TCP connection.
- * @NL80211_WOWLAN_TRIG_TCP_WAKEUP_MATCH: For wakeup reporting only, the
+ * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH: For wakeup reporting only, the
* wakeup packet was received on the TCP connection
* @NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST: For wakeup reporting only, the
* TCP connection was lost or failed to be established
@@ -5655,6 +5780,8 @@
* %NL80211_ATTR_SCAN_FREQUENCIES contains more than one
* frequency, it means that the match occurred in more than one
* channel.
+ * @NL80211_WOWLAN_TRIG_UNPROTECTED_DEAUTH_DISASSOC: For wakeup reporting only.
+ * Wake up happened due to unprotected deauth or disassoc frame in MFP.
* @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
* @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
*
@@ -5682,6 +5809,7 @@
NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS,
NL80211_WOWLAN_TRIG_NET_DETECT,
NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS,
+ NL80211_WOWLAN_TRIG_UNPROTECTED_DEAUTH_DISASSOC,
/* keep last */
NUM_NL80211_WOWLAN_TRIG,
@@ -5837,7 +5965,7 @@
/**
* enum nl80211_coalesce_condition - coalesce rule conditions
- * @NL80211_COALESCE_CONDITION_MATCH: coalaesce Rx packets when patterns
+ * @NL80211_COALESCE_CONDITION_MATCH: coalesce Rx packets when patterns
* in a rule are matched.
* @NL80211_COALESCE_CONDITION_NO_MATCH: coalesce Rx packets when patterns
* in a rule are not matched.
@@ -5936,7 +6064,7 @@
* enum nl80211_plink_state - state of a mesh peer link finite state machine
*
* @NL80211_PLINK_LISTEN: initial state, considered the implicit
- * state of non existent mesh peer links
+ * state of non-existent mesh peer links
* @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to
* this mesh peer
* @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received
@@ -5972,7 +6100,7 @@
* @NL80211_PLINK_ACTION_BLOCK: block traffic from this mesh peer
* @NUM_NL80211_PLINK_ACTIONS: number of possible actions
*/
-enum plink_actions {
+enum nl80211_plink_action {
NL80211_PLINK_ACTION_NO_ACTION,
NL80211_PLINK_ACTION_OPEN,
NL80211_PLINK_ACTION_BLOCK,
@@ -6229,7 +6357,7 @@
* request to use RRM (see %NL80211_ATTR_USE_RRM) with
* %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set
* the ASSOC_REQ_USE_RRM flag in the association request even if
- * NL80211_FEATURE_QUIET is not advertized.
+ * NL80211_FEATURE_QUIET is not advertised.
* @NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER: This device supports MU-MIMO air
* sniffer which means that it can be configured to hear packets from
* certain groups which can be configured by the
@@ -6241,13 +6369,15 @@
* the BSS that the interface that requested the scan is connected to
* (if available).
* @NL80211_EXT_FEATURE_BSS_PARENT_TSF: Per BSS, this driver reports the
- * time the last beacon/probe was received. The time is the TSF of the
- * BSS that the interface that requested the scan is connected to
- * (if available).
+ * time the last beacon/probe was received. For a non-MLO connection, the
+ * time is the TSF of the BSS that the interface that requested the scan is
+ * connected to (if available). For an MLO connection, the time is the TSF
+ * of the BSS corresponding with link ID specified in the scan request (if
+ * specified).
* @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of
* channel dwell time.
* @NL80211_EXT_FEATURE_BEACON_RATE_LEGACY: Driver supports beacon rate
- * configuration (AP/mesh), supporting a legacy (non HT/VHT) rate.
+ * configuration (AP/mesh), supporting a legacy (non-HT/VHT) rate.
* @NL80211_EXT_FEATURE_BEACON_RATE_HT: Driver supports beacon rate
* configuration (AP/mesh) with HT rates.
* @NL80211_EXT_FEATURE_BEACON_RATE_VHT: Driver supports beacon rate
@@ -6297,6 +6427,7 @@
* receiving control port frames over nl80211 instead of the netdevice.
* @NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT: This driver/device supports
* (average) ACK signal strength reporting.
+ * @NL80211_EXT_FEATURE_DATA_ACK_SIGNAL_SUPPORT: Backward-compatible ID
* @NL80211_EXT_FEATURE_TXQS: Driver supports FQ-CoDel-enabled intermediate
* TXQs.
* @NL80211_EXT_FEATURE_SCAN_RANDOM_SN: Driver/device supports randomizing the
@@ -6321,8 +6452,7 @@
* @NL80211_EXT_FEATURE_AP_PMKSA_CACHING: Driver/device supports PMKSA caching
* (set/del PMKSA operations) in AP mode.
*
- * @NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD: Driver supports
- * filtering of sched scan results using band specific RSSI thresholds.
+ * @NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD: Obsolete
*
* @NL80211_EXT_FEATURE_STA_TX_PWR: This driver supports controlling tx power
* to a station.
@@ -6426,6 +6556,16 @@
* @NL80211_EXT_FEATURE_OWE_OFFLOAD_AP: Driver/Device wants to do OWE DH IE
* handling in AP mode.
*
+ * @NL80211_EXT_FEATURE_DFS_CONCURRENT: The device supports peer-to-peer or
+ * ad hoc operation on DFS channels under the control of a concurrent
+ * DFS master on the same channel as described in FCC-594280 D01
+ * (Section B.3). This, for example, allows P2P GO and P2P clients to
+ * operate on DFS channels as long as there's a concurrent BSS connection.
+ *
+ * @NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT: The driver has support for SPP
+ * (signaling and payload protected) A-MSDUs and this shall be advertised
+ * in the RSNXE.
+ *
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@@ -6467,7 +6607,7 @@
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
NL80211_EXT_FEATURE_AP_PMKSA_CACHING,
- NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD,
+ NL80211_EXT_FEATURE_SCHED_SCAN_BAND_SPECIFIC_RSSI_THOLD, /* obsolete */
NL80211_EXT_FEATURE_EXT_KEY_ID,
NL80211_EXT_FEATURE_STA_TX_PWR,
NL80211_EXT_FEATURE_SAE_OFFLOAD,
@@ -6499,6 +6639,8 @@
NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA,
NL80211_EXT_FEATURE_OWE_OFFLOAD,
NL80211_EXT_FEATURE_OWE_OFFLOAD_AP,
+ NL80211_EXT_FEATURE_DFS_CONCURRENT,
+ NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -6583,7 +6725,7 @@
* request parameters IE in the probe request
* @NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP: accept broadcast probe responses
* @NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE: send probe request frames at
- * rate of at least 5.5M. In case non OCE AP is discovered in the channel,
+ * rate of at least 5.5M. In case non-OCE AP is discovered in the channel,
* only the first probe req in the channel will be sent in high rate.
* @NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION: allow probe request
* tx deferral (dot11FILSProbeDelay shall be set to 15ms)
@@ -6619,7 +6761,7 @@
* 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
+ * 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.
@@ -6669,6 +6811,8 @@
* @NL80211_SMPS_STATIC: static SMPS (use a single antenna)
* @NL80211_SMPS_DYNAMIC: dynamic smps (start with a single antenna and
* turn on other antennas after CTS/RTS).
+ * @__NL80211_SMPS_AFTER_LAST: internal
+ * @NL80211_SMPS_MAX: highest used enumeration
*/
enum nl80211_smps_mode {
NL80211_SMPS_OFF,
@@ -6890,6 +7034,8 @@
* @NL80211_NAN_FUNC_PUBLISH: function is publish
* @NL80211_NAN_FUNC_SUBSCRIBE: function is subscribe
* @NL80211_NAN_FUNC_FOLLOW_UP: function is follow-up
+ * @__NL80211_NAN_FUNC_TYPE_AFTER_LAST: internal use
+ * @NL80211_NAN_FUNC_MAX_TYPE: internal use
*/
enum nl80211_nan_function_type {
NL80211_NAN_FUNC_PUBLISH,
@@ -6951,7 +7097,7 @@
* The instance ID for the follow up Service Discovery Frame. This is u8.
* @NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID: relevant if the function's type
* is follow up. This is a u8.
- * The requestor instance ID for the follow up Service Discovery Frame.
+ * The requester instance ID for the follow up Service Discovery Frame.
* @NL80211_NAN_FUNC_FOLLOW_UP_DEST: the MAC address of the recipient of the
* follow up Service Discovery Frame. This is a binary attribute.
* @NL80211_NAN_FUNC_CLOSE_RANGE: is this function limited for devices in a
@@ -7050,7 +7196,7 @@
};
/**
- * nl80211_external_auth_action - Action to perform with external
+ * enum nl80211_external_auth_action - Action to perform with external
* authentication request. Used by NL80211_ATTR_EXTERNAL_AUTH_ACTION.
* @NL80211_EXTERNAL_AUTH_START: Start the authentication.
* @NL80211_EXTERNAL_AUTH_ABORT: Abort the ongoing authentication.
@@ -7068,7 +7214,7 @@
* @NL80211_FTM_RESP_ATTR_LCI: The content of Measurement Report Element
* (9.4.2.22 in 802.11-2016) with type 8 - LCI (9.4.2.22.10),
* i.e. starting with the measurement token
- * @NL80211_FTM_RESP_ATTR_CIVIC: The content of Measurement Report Element
+ * @NL80211_FTM_RESP_ATTR_CIVICLOC: The content of Measurement Report Element
* (9.4.2.22 in 802.11-2016) with type 11 - Civic (Section 9.4.2.22.13),
* i.e. starting with the measurement token
* @__NL80211_FTM_RESP_ATTR_LAST: Internal
@@ -7341,7 +7487,7 @@
* @NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED: flag attribute indicating if
* trigger based ranging measurement is supported
* @NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED: flag attribute indicating
- * if non trigger based ranging measurement is supported
+ * if non-trigger-based ranging measurement is supported
*
* @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal
* @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number
@@ -7395,7 +7541,7 @@
* if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
* %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
* ranging will be used.
- * @NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED: request non trigger based
+ * @NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED: request non-trigger-based
* ranging measurement (flag)
* This attribute and %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED are
* mutually exclusive.
@@ -7473,7 +7619,7 @@
* @NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS: number of FTM Request frames
* transmitted (u32, optional)
* @NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES: number of FTM Request frames
- * that were acknowleged (u32, optional)
+ * that were acknowledged (u32, optional)
* @NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME: retry time received from the
* busy peer (u32, seconds)
* @NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP: actual number of bursts exponent
@@ -7711,6 +7857,7 @@
*
* @NL80211_SAR_TYPE_POWER: power limitation specified in 0.25dBm unit
*
+ * @NUM_NL80211_SAR_TYPE: internal
*/
enum nl80211_sar_type {
NL80211_SAR_TYPE_POWER,
@@ -7724,6 +7871,8 @@
/**
* enum nl80211_sar_attrs - Attributes for SAR spec
*
+ * @__NL80211_SAR_ATTR_INVALID: Invalid
+ *
* @NL80211_SAR_ATTR_TYPE: the SAR type as defined in &enum nl80211_sar_type.
*
* @NL80211_SAR_ATTR_SPECS: Nested array of SAR power
@@ -7755,6 +7904,8 @@
/**
* enum nl80211_sar_specs_attrs - Attributes for SAR power limit specs
*
+ * @__NL80211_SAR_ATTR_SPECS_INVALID: Invalid
+ *
* @NL80211_SAR_ATTR_SPECS_POWER: Required (s32)value to specify the actual
* power limit value in units of 0.25 dBm if type is
* NL80211_SAR_TYPE_POWER. (i.e., a value of 44 represents 11 dBm).
@@ -7869,4 +8020,54 @@
NL80211_AP_SETTINGS_SA_QUERY_OFFLOAD_SUPPORT = 1 << 1,
};
+/**
+ * enum nl80211_wiphy_radio_attrs - wiphy radio attributes
+ *
+ * @__NL80211_WIPHY_RADIO_ATTR_INVALID: Invalid
+ *
+ * @NL80211_WIPHY_RADIO_ATTR_INDEX: Index of this radio (u32)
+ * @NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE: Frequency range supported by this
+ * radio. Attribute may be present multiple times.
+ * @NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION: Supported interface
+ * combination for this radio. Attribute may be present multiple times
+ * and contains attributes defined in &enum nl80211_if_combination_attrs.
+ *
+ * @__NL80211_WIPHY_RADIO_ATTR_LAST: Internal
+ * @NL80211_WIPHY_RADIO_ATTR_MAX: Highest attribute
+ */
+enum nl80211_wiphy_radio_attrs {
+ __NL80211_WIPHY_RADIO_ATTR_INVALID,
+
+ NL80211_WIPHY_RADIO_ATTR_INDEX,
+ NL80211_WIPHY_RADIO_ATTR_FREQ_RANGE,
+ NL80211_WIPHY_RADIO_ATTR_INTERFACE_COMBINATION,
+
+ /* keep last */
+ __NL80211_WIPHY_RADIO_ATTR_LAST,
+ NL80211_WIPHY_RADIO_ATTR_MAX = __NL80211_WIPHY_RADIO_ATTR_LAST - 1,
+};
+
+/**
+ * enum nl80211_wiphy_radio_freq_range - wiphy radio frequency range
+ *
+ * @__NL80211_WIPHY_RADIO_FREQ_ATTR_INVALID: Invalid
+ *
+ * @NL80211_WIPHY_RADIO_FREQ_ATTR_START: Frequency range start (u32).
+ * The unit is kHz.
+ * @NL80211_WIPHY_RADIO_FREQ_ATTR_END: Frequency range end (u32).
+ * The unit is kHz.
+ *
+ * @__NL80211_WIPHY_RADIO_FREQ_ATTR_LAST: Internal
+ * @NL80211_WIPHY_RADIO_FREQ_ATTR_MAX: Highest attribute
+ */
+enum nl80211_wiphy_radio_freq_range {
+ __NL80211_WIPHY_RADIO_FREQ_ATTR_INVALID,
+
+ NL80211_WIPHY_RADIO_FREQ_ATTR_START,
+ NL80211_WIPHY_RADIO_FREQ_ATTR_END,
+
+ __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST,
+ NL80211_WIPHY_RADIO_FREQ_ATTR_MAX = __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST - 1,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/src/fst/fst_session.c b/src/fst/fst_session.c
index 49886ff..f8de9a1 100644
--- a/src/fst/fst_session.c
+++ b/src/fst/fst_session.c
@@ -18,11 +18,6 @@
#include "fst/fst_ctrl_defs.h"
#endif /* CONFIG_FST_TEST */
-#define US_80211_TU 1024
-
-#define US_TO_TU(m) ((m) * / US_80211_TU)
-#define TU_TO_US(m) ((m) * US_80211_TU)
-
#define FST_LLT_SWITCH_IMMEDIATELY 0
#define fst_printf_session(s, level, format, ...) \
@@ -182,7 +177,8 @@
static void fst_session_stt_arm(struct fst_session *s)
{
/* Action frames sometimes get delayed. Use relaxed timeout (2*) */
- eloop_register_timeout(0, 2 * TU_TO_US(FST_DEFAULT_SESSION_TIMEOUT_TU),
+ eloop_register_timeout(0,
+ 2 * TU_TO_USEC(FST_DEFAULT_SESSION_TIMEOUT_TU),
fst_session_timeout_handler, NULL, s);
s->stt_armed = true;
}
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index df7cb7f..f3742ea 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -14,9 +14,13 @@
#include "common/defs.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/wpa_common.h"
#include "common/wpa_ctrl.h"
+#include "common/sae.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
#include "crypto/crypto.h"
+#include "pasn/pasn_common.h"
#include "wps/wps_i.h"
#include "p2p_i.h"
#include "p2p.h"
@@ -957,6 +961,7 @@
dev->info.wps_vendor_ext[i] = NULL;
}
+ os_free(dev->bootstrap_params);
wpabuf_free(dev->info.wfd_subelems);
wpabuf_free(dev->info.vendor_elems);
wpabuf_free(dev->go_neg_conf);
@@ -1602,7 +1607,8 @@
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id)
+ int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id,
+ bool p2p2, u16 bootstrap, const char *password)
{
struct p2p_device *dev;
@@ -1686,6 +1692,10 @@
dev->wps_method = wps_method;
dev->oob_pw_id = oob_pw_id;
+ dev->p2p2 = p2p2;
+ dev->req_bootstrap_method = bootstrap;
+ if (password && os_strlen(password) < sizeof(dev->password))
+ os_strlcpy(dev->password, password, sizeof(dev->password));
dev->status = P2P_SC_SUCCESS;
if (p2p->p2p_scan_running) {
@@ -1704,7 +1714,8 @@
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- unsigned int pref_freq, u16 oob_pw_id)
+ unsigned int pref_freq, u16 oob_pw_id, u16 bootstrap,
+ const char *password)
{
struct p2p_device *dev;
@@ -1738,6 +1749,10 @@
dev->flags &= ~P2P_DEV_USER_REJECTED;
dev->go_neg_req_sent = 0;
dev->go_state = UNKNOWN_GO;
+ dev->req_bootstrap_method = bootstrap;
+
+ if (password && os_strlen(password) < sizeof(dev->password))
+ os_strlcpy(dev->password, password, sizeof(dev->password));
p2p_set_dev_persistent(dev, persistent_group);
p2p->go_intent = go_intent;
os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
@@ -1916,26 +1931,25 @@
switch (data[0]) {
case P2P_GO_NEG_REQ:
- p2p_process_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq);
+ p2p_handle_go_neg_req(p2p, sa, data + 1, len - 1, rx_freq);
break;
case P2P_GO_NEG_RESP:
- p2p_process_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq);
+ p2p_handle_go_neg_resp(p2p, sa, data + 1, len - 1, rx_freq);
break;
case P2P_GO_NEG_CONF:
- p2p_process_go_neg_conf(p2p, sa, data + 1, len - 1);
+ p2p_handle_go_neg_conf(p2p, sa, data + 1, len - 1, false);
break;
case P2P_INVITATION_REQ:
- p2p_process_invitation_req(p2p, sa, data + 1, len - 1,
- rx_freq);
+ p2p_handle_invitation_req(p2p, sa, data + 1, len - 1, rx_freq);
break;
case P2P_INVITATION_RESP:
p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
break;
case P2P_PROV_DISC_REQ:
- p2p_process_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
+ p2p_handle_prov_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
break;
case P2P_PROV_DISC_RESP:
- p2p_process_prov_disc_resp(p2p, sa, data + 1, len - 1);
+ p2p_handle_prov_disc_resp(p2p, sa, data + 1, len - 1, rx_freq);
break;
case P2P_DEV_DISC_REQ:
p2p_process_dev_disc_req(p2p, sa, data + 1, len - 1, rx_freq);
@@ -2984,6 +2998,52 @@
}
+static void p2p_pairing_info_deinit(struct p2p_data *p2p)
+{
+#ifdef CONFIG_PASN
+ pasn_initiator_pmksa_cache_deinit(p2p->initiator_pmksa);
+ pasn_responder_pmksa_cache_deinit(p2p->responder_pmksa);
+#endif /* CONFIG_PASN */
+ os_free(p2p->pairing_info);
+}
+
+
+static int p2p_pairing_info_init(struct p2p_data *p2p)
+{
+ struct p2p_pairing_info *pairing_info;
+
+ if (p2p->cfg->pairing_config.dik_len > DEVICE_IDENTITY_KEY_MAX_LEN)
+ return -1;
+
+ pairing_info = os_zalloc(sizeof(struct p2p_pairing_info));
+ if (!pairing_info)
+ return -1;
+
+ pairing_info->enable_pairing_setup =
+ p2p->cfg->pairing_config.enable_pairing_setup;
+ pairing_info->enable_pairing_cache =
+ p2p->cfg->pairing_config.enable_pairing_cache;
+ pairing_info->supported_bootstrap =
+ p2p->cfg->pairing_config.bootstrap_methods;
+
+ pairing_info->dev_ik.cipher_version =
+ p2p->cfg->pairing_config.dik_cipher;
+ pairing_info->dev_ik.dik_len = p2p->cfg->pairing_config.dik_len;
+ os_memcpy(pairing_info->dev_ik.dik_data,
+ p2p->cfg->pairing_config.dik_data,
+ p2p->cfg->pairing_config.dik_len);
+
+ p2p_pairing_info_deinit(p2p);
+ p2p->pairing_info = pairing_info;
+#ifdef CONFIG_PASN
+ p2p->initiator_pmksa = pasn_initiator_pmksa_cache_init();
+ p2p->responder_pmksa = pasn_responder_pmksa_cache_init();
+#endif /* CONFIG_PASN */
+
+ return 0;
+}
+
+
struct p2p_data * p2p_init(const struct p2p_config *cfg)
{
struct p2p_data *p2p;
@@ -3039,6 +3099,10 @@
p2p->go_timeout = 100;
p2p->client_timeout = 20;
p2p->num_p2p_sd_queries = 0;
+ /* Default comeback after one second */
+ if (!p2p->cfg->comeback_after)
+ p2p->cfg->comeback_after = 977; /* TUs */
+ p2p_pairing_info_init(p2p);
p2p_dbg(p2p, "initialized");
p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
@@ -3082,6 +3146,7 @@
p2p_remove_wps_vendor_extensions(p2p);
os_free(p2p->no_go_freq.range);
p2p_service_flush_asp(p2p);
+ p2p_pairing_info_deinit(p2p);
os_free(p2p);
}
@@ -3415,7 +3480,7 @@
if (!ether_addr_equal(p2p->pending_pd_devaddr,
dev->info.p2p_device_addr))
continue;
- if (!dev->req_config_methods)
+ if (!dev->req_config_methods && !dev->req_bootstrap_method)
continue;
p2p_dbg(p2p, "Send pending Provision Discovery Request to "
@@ -4933,8 +4998,13 @@
u8 *iface_addr)
{
struct p2p_device *dev = p2p_get_device(p2p, dev_addr);
- if (dev == NULL || is_zero_ether_addr(dev->interface_addr))
+
+ if (!dev || is_zero_ether_addr(dev->interface_addr)) {
+ p2p_dbg(p2p,
+ "P2P: Failed to get interface address from device addr "
+ MACSTR, MAC2STR(dev_addr));
return -1;
+ }
os_memcpy(iface_addr, dev->interface_addr, ETH_ALEN);
return 0;
}
@@ -4944,8 +5014,13 @@
u8 *dev_addr)
{
struct p2p_device *dev = p2p_get_device_interface(p2p, iface_addr);
- if (dev == NULL)
+
+ if (!dev) {
+ p2p_dbg(p2p,
+ "P2P: Failed to get device address from interface address "
+ MACSTR, MAC2STR(iface_addr));
return -1;
+ }
os_memcpy(dev_addr, dev->info.p2p_device_addr, ETH_ALEN);
return 0;
}
@@ -5704,3 +5779,184 @@
{
p2p->allow_6ghz = value;
}
+
+
+static int p2p_derive_nonce_tag(struct p2p_data *p2p)
+{
+ u8 dira_nonce[DEVICE_IDENTITY_NONCE_LEN];
+ u8 dira_tag[DEVICE_MAX_HASH_LEN];
+ u8 data[DIR_STR_LEN + DEVICE_IDENTITY_NONCE_LEN + ETH_ALEN];
+ struct p2p_id_key *dev_ik;
+
+ dev_ik = &p2p->pairing_info->dev_ik;
+
+ if (dev_ik->cipher_version != DIRA_CIPHER_VERSION_128) {
+ wpa_printf(MSG_INFO,
+ "P2P: Unsupported DIRA Cipher version = %d",
+ dev_ik->cipher_version);
+ return -1;
+ }
+
+ if (dev_ik->dik_len != DEVICE_IDENTITY_KEY_LEN) {
+ wpa_printf(MSG_INFO, "P2P: Invalid DIK length = %zu",
+ dev_ik->dik_len);
+ return -1;
+ }
+
+ os_memset(data, 0, sizeof(data));
+
+ if (os_get_random(dira_nonce, DEVICE_IDENTITY_NONCE_LEN) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: Failed to generate DIRA nonce");
+ return -1;
+ }
+
+ /* Tag = Truncate-64(HMAC-SHA-256(DevIK,
+ * "DIR" || P2P Device Address || Nonce))
+ */
+ os_memcpy(data, "DIR", DIR_STR_LEN);
+ os_memcpy(&data[DIR_STR_LEN], p2p->cfg->dev_addr, ETH_ALEN);
+ os_memcpy(&data[DIR_STR_LEN + ETH_ALEN], dira_nonce,
+ DEVICE_IDENTITY_NONCE_LEN);
+
+ if (hmac_sha256(dev_ik->dik_data, dev_ik->dik_len, data, sizeof(data),
+ dira_tag) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: Could not derive DIRA tag");
+ return -1;
+ }
+
+ dev_ik->dira_nonce_len = DEVICE_IDENTITY_NONCE_LEN;
+ os_memcpy(dev_ik->dira_nonce, dira_nonce, DEVICE_IDENTITY_NONCE_LEN);
+ dev_ik->dira_tag_len = DEVICE_IDENTITY_TAG_LEN;
+ os_memcpy(dev_ik->dira_tag, dira_tag, DEVICE_IDENTITY_TAG_LEN);
+
+ wpa_hexdump_key(MSG_DEBUG, "P2P: DIK", dev_ik->dik_data,
+ dev_ik->dik_len);
+ wpa_hexdump_key(MSG_DEBUG, "P2P: DIRA-NONCE", dev_ik->dira_nonce,
+ dev_ik->dira_nonce_len);
+ wpa_hexdump_key(MSG_DEBUG, "P2P: DIRA-TAG", dev_ik->dira_tag,
+ dev_ik->dira_tag_len);
+ return 0;
+}
+
+
+struct wpabuf * p2p_usd_elems(struct p2p_data *p2p)
+{
+ struct wpabuf *buf;
+ u8 *len;
+ u8 group_capab;
+
+ buf = wpabuf_alloc(1000);
+ if (!buf)
+ return NULL;
+
+ len = p2p_buf_add_ie_hdr(buf);
+
+ /* P2P Capability attribute */
+ group_capab = 0;
+ if (p2p->num_groups) {
+ group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
+ if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) &&
+ (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) &&
+ p2p->cross_connect)
+ group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
+ }
+ if (p2p->cfg->p2p_intra_bss)
+ group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
+ p2p_buf_add_capability(buf, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+ group_capab);
+
+ /* P2P Device Info attribute */
+ p2p_buf_add_device_info(buf, p2p, NULL);
+
+ p2p_buf_update_ie_hdr(buf, len);
+
+ len = p2p_buf_add_p2p2_ie_hdr(buf);
+
+ /* P2P Capability Extension attribute */
+ p2p_buf_add_pcea(buf, p2p);
+
+ /* P2P Pairing Bootstrapping Method attribute */
+ p2p_buf_add_pbma(buf, p2p->cfg->pairing_config.bootstrap_methods, NULL,
+ 0, 0);
+
+ /* P2P Device Identity Resolution attribute */
+ if (p2p->pairing_info &&
+ p2p->cfg->pairing_config.pairing_capable &&
+ p2p->cfg->pairing_config.enable_pairing_cache &&
+ p2p->cfg->pairing_config.enable_pairing_verification &&
+ p2p_derive_nonce_tag(p2p) == 0)
+ p2p_buf_add_dira(buf, p2p);
+
+ p2p_buf_update_ie_hdr(buf, len);
+
+ return buf;
+}
+
+
+void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
+ const u8 *peer_addr, unsigned int freq)
+{
+ struct p2p_device *dev;
+ struct p2p_message msg;
+ const u8 *p2p_dev_addr;
+
+ os_memset(&msg, 0, sizeof(msg));
+ if (p2p_parse_ies(ies, ies_len, &msg)) {
+ p2p_dbg(p2p, "Failed to parse P2P IE for a device entry");
+ p2p_parse_free(&msg);
+ return;
+ }
+ if (msg.p2p_device_addr)
+ p2p_dev_addr = msg.p2p_device_addr;
+ else
+ p2p_dev_addr = peer_addr;
+
+ dev = p2p_create_device(p2p, p2p_dev_addr);
+ if (!dev) {
+ p2p_parse_free(&msg);
+ p2p_dbg(p2p, "Failed to add a peer P2P Device");
+ return;
+ }
+
+ dev->p2p2 = true;
+ /* Reset info from old IEs */
+ dev->info.reg_info = 0;
+ os_memset(&dev->info.pairing_config, 0,
+ sizeof(struct p2p_pairing_config));
+
+ os_get_reltime(&dev->last_seen);
+ dev->listen_freq = freq;
+ dev->oper_freq = freq;
+
+ if (msg.capability) {
+ /*
+ * P2P Client Discoverability bit is reserved in all frames
+ * that use this function, so do not change its value here.
+ */
+ dev->info.dev_capab &= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+ dev->info.dev_capab |= msg.capability[0] &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+ dev->info.group_capab = msg.capability[1];
+ }
+
+ if (msg.pcea_info && msg.pcea_info_len >= 2)
+ p2p_process_pcea(p2p, &msg, dev);
+
+ if (msg.pbma_info && msg.pbma_info_len == 2)
+ dev->info.pairing_config.bootstrap_methods =
+ WPA_GET_LE16(msg.pbma_info);
+
+ if (!ether_addr_equal(peer_addr, p2p_dev_addr))
+ os_memcpy(dev->interface_addr, peer_addr, ETH_ALEN);
+
+ p2p_dbg(p2p, "Updated device entry based on USD frame: " MACSTR
+ " dev_capab=0x%x group_capab=0x%x listen_freq=%d",
+ MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab,
+ dev->info.group_capab, dev->listen_freq);
+
+ p2p->cfg->dev_found(p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
+ &dev->info, !(dev->flags & P2P_DEV_REPORTED_ONCE));
+
+ p2p_parse_free(&msg);
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 7784128..5b5c7dd 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -12,6 +12,16 @@
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
+#define DEVICE_IDENTITY_KEY_MAX_LEN 64
+#define DEVICE_IDENTITY_KEY_LEN 16
+#define DEVICE_IDENTITY_TAG_LEN 8
+#define DEVICE_IDENTITY_NONCE_LEN 8
+#define DEVICE_MAX_HASH_LEN 32
+#define DIR_STR_LEN 3
+
+/* DIRA Cipher versions */
+#define DIRA_CIPHER_VERSION_128 0
+
struct weighted_pcl;
/* P2P ASP Setup Capability */
@@ -321,6 +331,50 @@
#define P2P_MAX_WPS_VENDOR_EXT 10
/**
+ * struct p2p_pairing_config - P2P pairing configuration
+ */
+struct p2p_pairing_config {
+ /**
+ * Pairing capable
+ */
+ bool pairing_capable;
+
+ /**
+ * Enable P2P pairing setup
+ */
+ bool enable_pairing_setup;
+
+ /**
+ * Enable pairing cache to allow verification
+ */
+ bool enable_pairing_cache;
+
+ /**
+ * Enable P2P pairing verification with cached NIK/NPK
+ */
+ bool enable_pairing_verification;
+
+ /**
+ * P2P bootstrapping methods supported
+ */
+ u16 bootstrap_methods;
+
+ /**
+ * Bitmap of supported PASN types
+ */
+ u8 pasn_type;
+
+ /* Cipher version type */
+ int dik_cipher;
+
+ /* Buffer to hold the DevIK */
+ u8 dik_data[DEVICE_IDENTITY_KEY_MAX_LEN];
+
+ /* Length of DevIK in octets */
+ size_t dik_len;
+};
+
+/**
* struct p2p_peer_info - P2P peer information
*/
struct p2p_peer_info {
@@ -411,6 +465,21 @@
* p2ps_instance - P2PS Application Service Info
*/
struct wpabuf *p2ps_instance;
+
+ /**
+ * pcea_cap_info - Capability info in PCEA
+ */
+ u16 pcea_cap_info;
+
+ /**
+ * The regulatory info encoding for operation in 6 GHz band
+ */
+ u8 reg_info;
+
+ /**
+ * p2p_pairing_config - P2P pairing configuration
+ */
+ struct p2p_pairing_config pairing_config;
};
enum p2p_prov_disc_status {
@@ -595,6 +664,33 @@
unsigned int passphrase_len;
/**
+ * p2p_pairing_config - P2P pairing configuration
+ */
+ struct p2p_pairing_config pairing_config;
+
+ /**
+ * reg_info - Regulatory info encoding for operation in 6 GHz band
+ */
+ u8 reg_info;
+
+ /**
+ * dfs_owner - Enable P2P GO to act as DFS Owner
+ */
+ bool dfs_owner;
+
+ /**
+ * twt_power_mgmt - Enable TWT based power management for P2P
+ */
+ bool twt_power_mgmt;
+
+ /**
+ * comeback_after - Bootstrap request unauthorized for peer
+ *
+ * Ask to come back after this many TUs.
+ */
+ u16 comeback_after;
+
+ /**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
@@ -1089,7 +1185,8 @@
* When P2PS provisioning completes (successfully or not) we must
* transmit all of the results to the upper layers.
*/
- void (*p2ps_prov_complete)(void *ctx, u8 status, const u8 *dev,
+ void (*p2ps_prov_complete)(void *ctx, enum p2p_status_code status,
+ const u8 *dev,
const u8 *adv_mac, const u8 *ses_mac,
const u8 *grp_mac, u32 adv_id, u32 ses_id,
u8 conncap, int passwd_id,
@@ -1141,6 +1238,44 @@
int (*get_pref_freq_list)(void *ctx, int go,
unsigned int *len,
struct weighted_pcl *freq_list);
+
+ /**
+ * register_bootstrap_comeback - Register timeout to initiate bootstrap
+ * comeback request
+ * @ctx: Callback context from cb_ctx
+ * @addr: P2P Device Address to which comeback request is to be sent
+ * @comeback_after: Time in TUs after which comeback request is sent
+ *
+ * This function can be used to send comeback request after given
+ * timeout.
+ */
+ void (*register_bootstrap_comeback)(void *ctx, const u8 *addr,
+ u16 comeback_after);
+
+ /**
+ * bootstrap_req_rx - Indicate bootstrap request from a P2P peer
+ * @ctx: Callback context from cb_ctx
+ * @addr: P2P device address from which bootstrap request was received
+ * @bootstrap_method: Bootstrapping method request by the peer device
+ *
+ * This function can be used to notify that bootstrap request is
+ * received from a P2P peer.
+ */
+ void (*bootstrap_req_rx)(void *ctx, const u8 *addr,
+ u16 bootstrap_method);
+
+ /**
+ * bootstrap_completed - Indicate bootstrapping completed with P2P peer
+ * @ctx: Callback context from cb_ctx
+ * @addr: P2P device address with which bootstrapping is completed
+ * @status: P2P Status Code of bootstrapping handshake
+ * @freq: Frequency in which bootstrapping is done
+ *
+ * This function can be used to notify the status of bootstrapping
+ * handshake.
+ */
+ void (*bootstrap_completed)(void *ctx, const u8 *addr,
+ enum p2p_status_code status, int freq);
};
@@ -1324,6 +1459,10 @@
* formation
* @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
* force_freq == 0)
+ * @oob_pw_id: OOB password identifier
+ * @p2p2: Device supports P2P2 features
+ * @bootstrap: Bootstrapping method requested for P2P2 provision discovery
+ * @password: P2P2 pairing password or %NULL for opportunistic method
* Returns: 0 on success, -1 on failure
*/
int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
@@ -1331,7 +1470,8 @@
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id);
+ int pd_before_go_neg, unsigned int pref_freq, u16 oob_pw_id,
+ bool p2p2, u16 bootstrap, const char *password);
/**
* p2p_authorize - Authorize P2P group formation (GO negotiation)
@@ -1349,6 +1489,9 @@
* @force_ssid_len: Length of $force_ssid buffer
* @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
* force_freq == 0)
+ * @oob_pw_id: OOB password identifier
+ * @bootstrap: Bootstrapping method requested for P2P2 provision discovery
+ * @password: P2P2 pairing password or %NULL for opportunistic method
* Returns: 0 on success, -1 on failure
*
* This is like p2p_connect(), but the actual group negotiation is not
@@ -1359,7 +1502,8 @@
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
const u8 *force_ssid, size_t force_ssid_len,
- unsigned int pref_freq, u16 oob_pw_id);
+ unsigned int pref_freq, u16 oob_pw_id, u16 bootstrap,
+ const char *password);
/**
* p2p_reject - Reject peer device (explicitly block connection attempts)
@@ -2435,5 +2579,8 @@
void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value);
int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size);
int p2p_channel_to_freq(int op_class, int channel);
+struct wpabuf * p2p_usd_elems(struct p2p_data *p2p);
+void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
+ const u8 *peer_addr, unsigned int freq);
#endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index e4f40fe..ddadd34 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -55,11 +55,24 @@
void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len)
{
- /* Update P2P IE Length */
+ /* Update P2P/P2P2 IE Length */
*len = (u8 *) wpabuf_put(buf, 0) - len - 1;
}
+u8 * p2p_buf_add_p2p2_ie_hdr(struct wpabuf *buf)
+{
+ u8 *len;
+
+ /* P2P2 IE header */
+ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+ len = wpabuf_put(buf, 1); /* IE length to be filled */
+ wpabuf_put_be32(buf, P2P2_IE_VENDOR_TYPE);
+ wpa_printf(MSG_DEBUG, "P2P: * P2P2 IE header");
+ return len;
+}
+
+
void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab)
{
/* P2P Capability */
@@ -709,6 +722,111 @@
}
+void p2p_buf_add_pcea(struct wpabuf *buf, struct p2p_data *p2p)
+{
+ u8 *len;
+ u16 capability_info = 0;
+
+ /* P2P Capability Extension */
+ wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY_EXTENSION);
+ /* Length to be filled */
+ len = wpabuf_put(buf, 2);
+
+ if (!p2p->cfg->p2p_6ghz_disable)
+ capability_info |= P2P_PCEA_6GHZ;
+
+ if (p2p->cfg->reg_info)
+ capability_info |= P2P_PCEA_REG_INFO;
+
+ if (p2p->cfg->dfs_owner)
+ capability_info |= P2P_PCEA_DFS_OWNER;
+
+ if (p2p->cfg->pairing_config.pairing_capable)
+ capability_info |= P2P_PCEA_PAIRING_CAPABLE;
+
+ if (p2p->cfg->pairing_config.enable_pairing_setup)
+ capability_info |= P2P_PCEA_PAIRING_SETUP_ENABLED;
+
+ if (p2p->cfg->pairing_config.enable_pairing_cache)
+ capability_info |= P2P_PCEA_PMK_CACHING;
+
+ if (p2p->cfg->pairing_config.pasn_type)
+ capability_info |= P2P_PCEA_PASN_TYPE;
+
+ if (p2p->cfg->twt_power_mgmt)
+ capability_info |= P2P_PCEA_TWT_POWER_MGMT;
+
+ /* Field length is (n-1), n in octets */
+ capability_info |= (2 - 1) & P2P_PCEA_LEN_MASK;
+ wpabuf_put_le16(buf, capability_info);
+
+ if (capability_info & P2P_PCEA_REG_INFO)
+ wpabuf_put_u8(buf, p2p->cfg->reg_info);
+
+ if (capability_info & P2P_PCEA_PASN_TYPE)
+ wpabuf_put_u8(buf, p2p->cfg->pairing_config.pasn_type);
+
+ /* Update attribute length */
+ WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+
+ wpa_printf(MSG_DEBUG, "P2P: * Capability Extension info=0x%x",
+ capability_info);
+}
+
+
+void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie,
+ size_t cookie_len, int comeback_after)
+{
+ u8 *len;
+
+ /* P2P Pairing and Bootstrapping methods */
+ wpabuf_put_u8(buf, P2P_ATTR_PAIRING_AND_BOOTSTRAPPING);
+ /* Length to be filled */
+ len = wpabuf_put(buf, 2);
+
+ if (cookie && cookie_len) {
+ if (comeback_after)
+ wpabuf_put_le16(buf, comeback_after);
+ wpabuf_put_u8(buf, cookie_len);
+ wpabuf_put_data(buf, cookie, cookie_len);
+ }
+ wpabuf_put_le16(buf, bootstrap);
+
+ /* Update attribute length */
+ WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+
+ wpa_printf(MSG_DEBUG, "P2P: * Bootstrapping method=0x%x",
+ bootstrap);
+}
+
+
+void p2p_buf_add_dira(struct wpabuf *buf, struct p2p_data *p2p)
+{
+ u8 *len;
+ struct p2p_id_key *dev_ik;
+
+ if (!p2p->cfg->pairing_config.pairing_capable ||
+ !p2p->cfg->pairing_config.enable_pairing_cache ||
+ !p2p->cfg->pairing_config.enable_pairing_verification)
+ return;
+
+ dev_ik = &p2p->pairing_info->dev_ik;
+ /* P2P DIRA */
+ wpabuf_put_u8(buf, P2P_ATTR_DEVICE_IDENTITY_RESOLUTION);
+ /* Length to be filled */
+ len = wpabuf_put(buf, 2);
+
+ wpabuf_put_u8(buf, dev_ik->cipher_version);
+ wpabuf_put_data(buf, dev_ik->dira_nonce, dev_ik->dira_nonce_len);
+ wpabuf_put_data(buf, dev_ik->dira_tag, dev_ik->dira_tag_len);
+
+ /* Update attribute length */
+ WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+
+ wpa_printf(MSG_DEBUG, "P2P: * DIRA");
+}
+
+
static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
const char *val)
{
@@ -839,3 +957,37 @@
return 0;
}
+
+
+struct wpabuf * p2p_encaps_ie(const struct wpabuf *subelems, u32 ie_type)
+{
+ struct wpabuf *ie;
+ const u8 *pos, *end;
+ size_t len;
+
+ if (!subelems)
+ return NULL;
+
+ len = wpabuf_len(subelems) + 1000;
+
+ ie = wpabuf_alloc(len);
+ if (!ie)
+ return NULL;
+
+ pos = wpabuf_head(subelems);
+ end = pos + wpabuf_len(subelems);
+
+ while (end > pos) {
+ size_t frag_len = end - pos;
+
+ if (frag_len > 251)
+ frag_len = 251;
+ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(ie, 4 + frag_len);
+ wpabuf_put_be32(ie, ie_type);
+ wpabuf_put_data(ie, pos, frag_len);
+ pos += frag_len;
+ }
+
+ return ie;
+}
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 30901b3..ac6bbf7 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -135,11 +135,11 @@
}
-static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
- struct p2p_device *peer)
+struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
+ struct p2p_device *peer)
{
struct wpabuf *buf;
- u8 *len;
+ struct wpabuf *subelems;
u8 group_capab;
size_t extra = 0;
u16 pw_id;
@@ -159,7 +159,12 @@
p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token);
- len = p2p_buf_add_ie_hdr(buf);
+ subelems = wpabuf_alloc(500);
+ if (!subelems) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
group_capab = 0;
if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
@@ -170,17 +175,20 @@
group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
if (p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
- p2p_buf_add_capability(buf, p2p->dev_capab &
+ p2p_buf_add_capability(subelems, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
- p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | peer->tie_breaker);
- p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
- p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
+ p2p_buf_add_go_intent(subelems,
+ (p2p->go_intent << 1) | peer->tie_breaker);
+ p2p_buf_add_config_timeout(subelems, p2p->go_timeout,
+ p2p->client_timeout);
+ p2p_buf_add_listen_channel(subelems, p2p->cfg->country,
+ p2p->cfg->reg_class,
p2p->cfg->channel);
if (p2p->ext_listen_interval)
- p2p_buf_add_ext_listen_timing(buf, p2p->ext_listen_period,
+ p2p_buf_add_ext_listen_timing(subelems, p2p->ext_listen_period,
p2p->ext_listen_interval);
- p2p_buf_add_intended_addr(buf, p2p->intended_addr);
+ p2p_buf_add_intended_addr(subelems, p2p->intended_addr);
is_6ghz_capab = is_p2p_6ghz_capable(p2p) &&
p2p_is_peer_6ghz_capab(p2p, peer->info.p2p_device_addr);
if (p2p->num_pref_freq) {
@@ -191,16 +199,15 @@
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,
+ p2p_buf_add_channel_list(subelems, p2p->cfg->country,
&pref_chanlist, is_6ghz_capab);
} else {
- p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ p2p_buf_add_channel_list(subelems, 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_buf_add_device_info(subelems, p2p, peer);
+ p2p_buf_add_operating_channel(subelems, p2p->cfg->country,
p2p->op_reg_class, p2p->op_channel);
- p2p_buf_update_ie_hdr(buf, len);
p2p_buf_add_pref_channel_list(buf, p2p->pref_freq_list,
p2p->num_pref_freq);
@@ -209,8 +216,9 @@
pw_id = p2p_wps_method_pw_id(peer->wps_method);
if (peer->oob_pw_id)
pw_id = peer->oob_pw_id;
- if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+ if (!peer->p2p2 && p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request");
+ wpabuf_free(subelems);
wpabuf_free(buf);
return NULL;
}
@@ -223,6 +231,8 @@
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ])
wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]);
+ buf = wpabuf_concat(buf, p2p_encaps_ie(subelems, P2P_IE_VENDOR_TYPE));
+ wpabuf_free(subelems);
return buf;
}
@@ -244,6 +254,8 @@
config_method = WPS_CONFIG_PUSHBUTTON;
else if (dev->wps_method == WPS_P2PS)
config_method = WPS_CONFIG_P2PS;
+ else if (dev->p2p2 && dev->req_bootstrap_method)
+ config_method = WPS_NOT_READY;
else
return -1;
return p2p_prov_disc_req(p2p, dev->info.p2p_device_addr,
@@ -291,7 +303,7 @@
u8 tie_breaker)
{
struct wpabuf *buf;
- u8 *len;
+ struct wpabuf *subelems;
u8 group_capab;
size_t extra = 0;
u16 pw_id;
@@ -314,8 +326,13 @@
p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_RESP, dialog_token);
- len = p2p_buf_add_ie_hdr(buf);
- p2p_buf_add_status(buf, status);
+ subelems = wpabuf_alloc(500);
+ if (!subelems) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ p2p_buf_add_status(subelems, status);
group_capab = 0;
if (peer && peer->go_state == LOCAL_GO) {
if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
@@ -329,24 +346,26 @@
if (p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
}
- p2p_buf_add_capability(buf, p2p->dev_capab &
+ p2p_buf_add_capability(subelems, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
- p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
- p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
+ p2p_buf_add_go_intent(subelems, (p2p->go_intent << 1) | tie_breaker);
+ p2p_buf_add_config_timeout(subelems, p2p->go_timeout,
+ p2p->client_timeout);
if (p2p->override_pref_op_class) {
p2p_dbg(p2p, "Override operating channel preference");
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p_buf_add_operating_channel(subelems, p2p->cfg->country,
p2p->override_pref_op_class,
p2p->override_pref_channel);
} else if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
p2p_dbg(p2p, "Omit Operating Channel attribute");
} else {
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p_buf_add_operating_channel(subelems, p2p->cfg->country,
p2p->op_reg_class,
p2p->op_channel);
}
- p2p_buf_add_intended_addr(buf, p2p->intended_addr);
+ p2p_buf_add_intended_addr(subelems, p2p->intended_addr);
+
if (p2p->num_pref_freq) {
bool go = (peer && peer->go_state == LOCAL_GO) ||
p2p->go_intent == 15;
@@ -360,12 +379,12 @@
p2p->allow_6ghz);
}
if (status || peer == NULL) {
- p2p_buf_add_channel_list(buf, p2p->cfg->country,
+ p2p_buf_add_channel_list(subelems, p2p->cfg->country,
&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_buf_add_channel_list(subelems, p2p->cfg->country,
&pref_chanlist, is_6ghz_capab);
} else {
struct p2p_channels res;
@@ -374,22 +393,22 @@
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,
- is_6ghz_capab);
+ p2p_buf_add_channel_list(subelems, p2p->cfg->country, &res,
+ is_6ghz_capab);
}
- p2p_buf_add_device_info(buf, p2p, peer);
+ p2p_buf_add_device_info(subelems, p2p, peer);
if (peer && peer->go_state == LOCAL_GO) {
- p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
+ p2p_buf_add_group_id(subelems, p2p->cfg->dev_addr, p2p->ssid,
p2p->ssid_len);
}
- p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
pw_id = p2p_wps_method_pw_id(peer ? peer->wps_method : WPS_NOT_READY);
if (peer && peer->oob_pw_id)
pw_id = peer->oob_pw_id;
- if (p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
+ if (peer && !peer->p2p2 && p2p_build_wps_ie(p2p, buf, pw_id, 0) < 0) {
p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response");
+ wpabuf_free(subelems);
wpabuf_free(buf);
return NULL;
}
@@ -402,6 +421,8 @@
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP])
wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]);
+ buf = wpabuf_concat(buf, p2p_encaps_ie(subelems, P2P_IE_VENDOR_TYPE));
+ wpabuf_free(subelems);
return buf;
}
@@ -799,21 +820,21 @@
}
-void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq)
+struct wpabuf * p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq,
+ bool p2p2)
{
struct p2p_device *dev = NULL;
struct wpabuf *resp;
struct p2p_message msg;
u8 status = P2P_SC_FAIL_INVALID_PARAMS;
int tie_breaker = 0;
- int freq;
p2p_dbg(p2p, "Received GO Negotiation Request from " MACSTR "(freq=%d)",
MAC2STR(sa), rx_freq);
if (p2p_parse(data, len, &msg))
- return;
+ return NULL;
if (!msg.capability) {
p2p_dbg(p2p, "Mandatory Capability attribute missing from GO Negotiation Request");
@@ -888,7 +909,7 @@
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_go_neg_failed(p2p, *msg.status);
p2p_parse_free(&msg);
- return;
+ return NULL;
}
goto fail;
}
@@ -920,7 +941,7 @@
p2p_dbg(p2p, "User has rejected this peer");
status = P2P_SC_FAIL_REJECTED_BY_USER;
} else if (dev == NULL ||
- (dev->wps_method == WPS_NOT_READY &&
+ (dev->wps_method == WPS_NOT_READY && !p2p2 &&
(p2p->authorized_oob_dev_pw_id == 0 ||
p2p->authorized_oob_dev_pw_id !=
msg.dev_password_id))) {
@@ -966,7 +987,7 @@
os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) {
p2p_dbg(p2p, "Do not reply since peer has higher address and GO Neg Request already sent");
p2p_parse_free(&msg);
- return;
+ return NULL;
}
if (dev->go_neg_req_sent &&
@@ -974,7 +995,7 @@
p2p_dbg(p2p,
"Do not reply since peer is waiting for us to start a new GO Negotiation and GO Neg Request already sent");
p2p_parse_free(&msg);
- return;
+ return NULL;
}
go = p2p_go_det(p2p->go_intent, *msg.go_intent);
@@ -991,6 +1012,9 @@
goto fail;
}
+ if (p2p2)
+ goto skip;
+
switch (msg.dev_password_id) {
case DEV_PW_REGISTRAR_SPECIFIED:
p2p_dbg(p2p, "PIN from peer Display");
@@ -1058,6 +1082,7 @@
goto fail;
}
+skip:
if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
goto fail;
@@ -1097,18 +1122,8 @@
!tie_breaker);
p2p_parse_free(&msg);
if (resp == NULL)
- return;
- p2p_dbg(p2p, "Sending GO Negotiation Response");
- if (rx_freq > 0)
- freq = rx_freq;
- else
- freq = p2p_channel_to_freq(p2p->cfg->reg_class,
- p2p->cfg->channel);
- if (freq < 0) {
- p2p_dbg(p2p, "Unknown regulatory class/channel");
- wpabuf_free(resp);
- return;
- }
+ return NULL;
+
if (status == P2P_SC_SUCCESS) {
p2p->pending_action_state = P2P_PENDING_GO_NEG_RESPONSE;
dev->flags |= P2P_DEV_WAIT_GO_NEG_CONFIRM;
@@ -1126,6 +1141,33 @@
} else
p2p->pending_action_state =
P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
+ return resp;
+}
+
+
+void p2p_handle_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq)
+{
+ int freq;
+ struct wpabuf *resp;
+
+ resp = p2p_process_go_neg_req(p2p, sa, data, len, rx_freq, false);
+ if (!resp)
+ return;
+
+ p2p_dbg(p2p, "Sending GO Negotiation Response");
+
+ if (rx_freq > 0)
+ freq = rx_freq;
+ else
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
+ wpabuf_free(resp);
+ return;
+ }
+
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
wpabuf_head(resp), wpabuf_len(resp), 100) < 0) {
@@ -1142,7 +1184,7 @@
const u8 *resp_chan, int go)
{
struct wpabuf *buf;
- u8 *len;
+ struct wpabuf *subelems;
struct p2p_channels res;
u8 group_capab;
size_t extra = 0;
@@ -1164,8 +1206,13 @@
p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_CONF, dialog_token);
- len = p2p_buf_add_ie_hdr(buf);
- p2p_buf_add_status(buf, status);
+ subelems = wpabuf_alloc(500);
+ if (!subelems) {
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ p2p_buf_add_status(subelems, status);
group_capab = 0;
if (peer->go_state == LOCAL_GO) {
if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
@@ -1179,25 +1226,26 @@
if (p2p->cfg->p2p_intra_bss)
group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
}
- p2p_buf_add_capability(buf, p2p->dev_capab &
+ p2p_buf_add_capability(subelems, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
if (go || resp_chan == NULL)
- p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p_buf_add_operating_channel(subelems, p2p->cfg->country,
p2p->op_reg_class,
p2p->op_channel);
else
- p2p_buf_add_operating_channel(buf, (const char *) resp_chan,
+ p2p_buf_add_operating_channel(subelems,
+ (const char *) resp_chan,
resp_chan[3], resp_chan[4]);
p2p_channels_intersect(&p2p->channels, &peer->channels, &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);
+ p2p_buf_add_channel_list(subelems, p2p->cfg->country, &res,
+ is_6ghz_capab);
if (go) {
- p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, p2p->ssid,
+ p2p_buf_add_group_id(subelems, p2p->cfg->dev_addr, p2p->ssid,
p2p->ssid_len);
}
- p2p_buf_update_ie_hdr(buf, len);
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
@@ -1207,36 +1255,40 @@
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF])
wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]);
+ buf = wpabuf_concat(buf, p2p_encaps_ie(subelems, P2P_IE_VENDOR_TYPE));
+ wpabuf_free(subelems);
return buf;
}
-void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq)
+struct wpabuf * p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len,
+ int rx_freq, bool p2p2)
{
struct p2p_device *dev;
int go = -1;
struct p2p_message msg;
u8 status = P2P_SC_SUCCESS;
int freq;
+ struct wpabuf *conf = NULL;
p2p_dbg(p2p, "Received GO Negotiation Response from " MACSTR
" (freq=%d)", MAC2STR(sa), rx_freq);
dev = p2p_get_device(p2p, sa);
- if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
+ if (dev == NULL || (!p2p2 && dev->wps_method == WPS_NOT_READY) ||
dev != p2p->go_neg_peer) {
p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
- return;
+ return NULL;
}
if (p2p_parse(data, len, &msg))
- return;
+ return NULL;
if (!(dev->flags & P2P_DEV_WAIT_GO_NEG_RESPONSE)) {
p2p_dbg(p2p, "Was not expecting GO Negotiation Response - ignore");
p2p_parse_free(&msg);
- return;
+ return NULL;
}
dev->flags &= ~P2P_DEV_WAIT_GO_NEG_RESPONSE;
p2p_update_peer_6ghz_capab(dev, &msg);
@@ -1245,7 +1297,7 @@
p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
msg.dialog_token, dev->dialog_token);
p2p_parse_free(&msg);
- return;
+ return NULL;
}
if (!msg.status) {
@@ -1274,7 +1326,7 @@
}
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
p2p_parse_free(&msg);
- return;
+ return NULL;
}
if (!msg.capability) {
@@ -1375,6 +1427,9 @@
} else
dev->oper_freq = 0;
+ if (p2p2)
+ goto skip;
+
switch (msg.dev_password_id) {
case DEV_PW_REGISTRAR_SPECIFIED:
p2p_dbg(p2p, "PIN from peer Display");
@@ -1430,6 +1485,7 @@
goto fail;
}
+skip:
if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
goto fail;
@@ -1454,8 +1510,10 @@
go);
p2p_parse_free(&msg);
if (dev->go_neg_conf == NULL)
- return;
- p2p_dbg(p2p, "Sending GO Negotiation Confirm");
+ return NULL;
+
+ conf = wpabuf_dup(dev->go_neg_conf);
+
if (status == P2P_SC_SUCCESS) {
p2p->pending_action_state = P2P_PENDING_GO_NEG_CONFIRM;
dev->go_state = go ? LOCAL_GO : REMOTE_GO;
@@ -1469,7 +1527,39 @@
dev->go_neg_conf_freq = freq;
dev->go_neg_conf_sent = 0;
- if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
+ if (status != P2P_SC_SUCCESS) {
+ p2p_dbg(p2p, "GO Negotiation failed");
+ dev->status = status;
+ }
+
+ return conf;
+}
+
+
+void p2p_handle_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq)
+{
+ int freq;
+ struct p2p_device *dev;
+ struct wpabuf *conf;
+
+ conf = p2p_process_go_neg_resp(p2p, sa, data, len, rx_freq, false);
+ if (!conf)
+ return;
+ wpabuf_free(conf);
+
+ dev = p2p_get_device(p2p, sa);
+ if (!dev)
+ return;
+
+ p2p_dbg(p2p, "Sending GO Negotiation Confirm");
+ if (rx_freq > 0)
+ freq = rx_freq;
+ else
+ freq = dev->listen_freq;
+
+ if (dev->go_neg_conf &&
+ p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, sa,
wpabuf_head(dev->go_neg_conf),
wpabuf_len(dev->go_neg_conf), 50) < 0) {
p2p_dbg(p2p, "Failed to send Action frame");
@@ -1477,15 +1567,14 @@
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
} else
dev->go_neg_conf_sent++;
- if (status != P2P_SC_SUCCESS) {
- p2p_dbg(p2p, "GO Negotiation failed");
- p2p_go_neg_failed(p2p, status);
- }
+
+ if (dev->status != P2P_SC_SUCCESS)
+ p2p_go_neg_failed(p2p, dev->status);
}
-void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len)
+void p2p_handle_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, bool p2p2)
{
struct p2p_device *dev;
struct p2p_message msg;
@@ -1493,7 +1582,7 @@
p2p_dbg(p2p, "Received GO Negotiation Confirm from " MACSTR,
MAC2STR(sa));
dev = p2p_get_device(p2p, sa);
- if (dev == NULL || dev->wps_method == WPS_NOT_READY ||
+ if (dev == NULL || (!p2p2 && dev->wps_method == WPS_NOT_READY) ||
dev != p2p->go_neg_peer) {
p2p_dbg(p2p, "Not ready for GO negotiation with " MACSTR,
MAC2STR(sa));
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 5239ee4..808bb96 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -38,6 +38,26 @@
};
/**
+ * struct bootstrap_params - P2P Device bootstrap request parameters
+ */
+struct p2p_bootstrap_params {
+ /* Bootstrap method */
+ u16 bootstrap_method;
+
+ /* Status code */
+ enum p2p_status_code status;
+
+ /* Cookie for comeback */
+ u8 cookie[50];
+
+ /* Cookie length */
+ size_t cookie_len;
+
+ /* Comeback time in TUs after which receiver is requested to retry */
+ int comeback_after;
+};
+
+/**
* struct p2p_device - P2P Device data (internal to P2P module)
*/
struct p2p_device {
@@ -151,6 +171,18 @@
int sd_pending_bcast_queries;
bool support_6ghz;
+
+ /* Supports P2P2 */
+ bool p2p2;
+
+ /* Requested bootstrap method */
+ u16 req_bootstrap_method;
+
+ /* Bootstrap parameters received from peer */
+ struct p2p_bootstrap_params *bootstrap_params;
+
+ /* Password for P2P2 GO negotiation */
+ char password[100];
};
struct p2p_sd_query {
@@ -161,6 +193,39 @@
struct wpabuf *tlvs;
};
+/* P2P Device Identity Key parameters */
+struct p2p_id_key {
+ /* AKMP used for DevIK derviation */
+ int akmp;
+ /* Cipher version type */
+ int cipher_version;
+ /* Buffer to hold the DevIK */
+ u8 dik_data[DEVICE_IDENTITY_KEY_MAX_LEN];
+ /* Length of DevIK */
+ size_t dik_len;
+ /* Nonce used in DIRA attribute */
+ u8 dira_nonce[DEVICE_IDENTITY_NONCE_LEN];
+ /* Length of nonce */
+ size_t dira_nonce_len;
+ /* Tag computed for nonce using NIK */
+ u8 dira_tag[DEVICE_IDENTITY_TAG_LEN];
+ /* Length of tag in octets */
+ size_t dira_tag_len;
+};
+
+struct p2p_pairing_info {
+ /* P2P device own address */
+ u8 own_addr[ETH_ALEN];
+ /* device capability to enable pairing setup */
+ bool enable_pairing_setup;
+ /* device capability to enable pairing cache */
+ bool enable_pairing_cache;
+ /* device supported bootstrapping */
+ u16 supported_bootstrap;
+ /* P2P Device Identity Key info */
+ struct p2p_id_key dev_ik;
+};
+
/**
* struct p2p_data - P2P module data (internal to P2P module)
*/
@@ -565,6 +630,13 @@
bool p2p_6ghz_capable;
bool include_6ghz;
bool allow_6ghz;
+
+ struct p2p_pairing_info *pairing_info;
+
+ /* Pairing initiator PMKSA cache */
+ struct rsn_pmksa_cache *initiator_pmksa;
+ /* Pairing responder PMKSA cache */
+ struct rsn_pmksa_cache *responder_pmksa;
};
/**
@@ -572,6 +644,7 @@
*/
struct p2p_message {
struct wpabuf *p2p_attributes;
+ struct wpabuf *p2p2_attributes;
struct wpabuf *wps_attributes;
struct wpabuf *wfd_subelems;
@@ -670,6 +743,21 @@
const u8 *pref_freq_list;
size_t pref_freq_list_len;
+
+ const u8 *pcea_info;
+ size_t pcea_info_len;
+
+ const u8 *pbma_info;
+ size_t pbma_info_len;
+
+ const u8 *action_frame_wrapper;
+ size_t action_frame_wrapper_len;
+
+ const u8 *dira;
+ size_t dira_len;
+
+ const u8 *wlan_ap_info;
+ size_t wlan_ap_info_len;
};
@@ -759,6 +847,7 @@
void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype,
u8 dialog_token);
u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf);
+u8 * p2p_buf_add_p2p2_ie_hdr(struct wpabuf *buf);
void p2p_buf_add_status(struct wpabuf *buf, u8 status);
void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
struct p2p_device *peer);
@@ -799,11 +888,16 @@
const u8 *mask);
void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
const u8 *ssid, size_t ssid_len);
+void p2p_buf_add_pcea(struct wpabuf *buf, struct p2p_data *p2p);
+void p2p_buf_add_pbma(struct wpabuf *buf, u16 bootstrap, const u8 *cookie,
+ size_t cookie_len, int comeback_after);
+void p2p_buf_add_dira(struct wpabuf *buf, struct p2p_data *p2p);
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 struct weighted_pcl *pref_freq_list,
unsigned int size);
+struct wpabuf * p2p_encaps_ie(const struct wpabuf *subelems, u32 ie_type);
/* p2p_sd.c */
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
@@ -820,15 +914,23 @@
int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev);
/* p2p_go_neg.c */
+struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
+ struct p2p_device *peer);
int p2p_peer_channels_check(struct p2p_data *p2p, struct p2p_channels *own,
struct p2p_device *dev,
const u8 *channel_list, size_t channel_list_len);
-void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq);
-void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq);
-void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len);
+void p2p_handle_go_neg_req(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq);
+void p2p_handle_go_neg_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, int rx_freq);
+void p2p_handle_go_neg_conf(struct p2p_data *p2p, const u8 *sa, const u8 *data,
+ size_t len, bool p2p2);
+struct wpabuf * p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq,
+ bool p2p2);
+struct wpabuf * p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len,
+ int rx_freq, bool p2p2);
int p2p_connect_send(struct p2p_data *p2p, struct p2p_device *dev);
u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method);
void p2p_reselect_channel(struct p2p_data *p2p,
@@ -837,18 +939,25 @@
struct p2p_device *dev, struct p2p_message *msg);
/* p2p_pd.c */
-void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
+void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq);
+void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len, int rx_freq);
-void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len);
int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
int join, int force_freq);
void p2p_reset_pending_pd(struct p2p_data *p2p);
void p2ps_prov_free(struct p2p_data *p2p);
+void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg,
+ struct p2p_device *dev);
/* p2p_invitation.c */
-void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq);
+void p2p_handle_invitation_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq);
+void p2p_handle_invitation_resp(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len);
+struct wpabuf * p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len,
+ int rx_freq);
void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len);
int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 70a7f6f..3fd66c2 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -181,14 +181,14 @@
}
-void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq)
+struct wpabuf * p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len,
+ int rx_freq)
{
struct p2p_device *dev;
struct p2p_message msg;
struct wpabuf *resp = NULL;
u8 status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE;
- int freq;
int go = 0;
u8 group_bssid[ETH_ALEN], *bssid;
int op_freq = 0;
@@ -202,7 +202,7 @@
MAC2STR(sa), rx_freq);
if (p2p_parse(data, len, &msg))
- return;
+ return NULL;
dev = p2p_get_device(p2p, sa);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
@@ -388,19 +388,6 @@
resp = p2p_build_invitation_resp(p2p, dev, msg.dialog_token, status,
bssid, reg_class, channel, channels);
- if (resp == NULL)
- goto out;
-
- if (rx_freq > 0)
- freq = rx_freq;
- else
- freq = p2p_channel_to_freq(p2p->cfg->reg_class,
- p2p->cfg->channel);
- if (freq < 0) {
- p2p_dbg(p2p, "Unknown regulatory class/channel");
- goto out;
- }
-
/*
* Store copy of invitation data to be used when processing TX status
* callback for the Acton frame.
@@ -424,6 +411,28 @@
}
p2p->inv_status = status;
p2p->inv_op_freq = op_freq;
+ p2p_parse_free(&msg);
+ return resp;
+}
+
+
+void p2p_handle_invitation_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq)
+{
+ int freq;
+ struct wpabuf *resp;
+
+ resp = p2p_process_invitation_req(p2p, sa, data, len, rx_freq);
+ if (!resp)
+ return;
+
+ if (rx_freq > 0)
+ freq = rx_freq;
+ else
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ if (freq < 0)
+ p2p_dbg(p2p, "Unknown regulatory class/channel");
p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE;
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
@@ -432,9 +441,7 @@
p2p_dbg(p2p, "Failed to send Action frame");
}
-out:
wpabuf_free(resp);
- p2p_parse_free(&msg);
}
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index 07d6ca0..cd3332d 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -417,6 +417,60 @@
msg->persistent_ssid_len));
break;
}
+ case P2P_ATTR_CAPABILITY_EXTENSION:
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG, "P2P: Too short PCEA (length %d)",
+ len);
+ return -1;
+ }
+ msg->pcea_info = data;
+ msg->pcea_info_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * PCEA (length=%u)", len);
+ break;
+ case P2P_ATTR_PAIRING_AND_BOOTSTRAPPING:
+ if (len < 1) {
+ wpa_printf(MSG_DEBUG, "P2P: Too short PBMA (length %d)",
+ len);
+ return -1;
+ }
+ msg->pbma_info = data;
+ msg->pbma_info_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * PBMA (length=%u)", len);
+ break;
+ case P2P_ATTR_ACTION_FRAME_WRAPPER:
+ if (len < 2) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short Action Frame Wrapper attribute (length %d)",
+ len);
+ return -1;
+ }
+ msg->action_frame_wrapper = data;
+ msg->action_frame_wrapper_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * Action frame wrapper (length=%u)",
+ len);
+ break;
+ case P2P_ATTR_DEVICE_IDENTITY_RESOLUTION:
+ if (len < 1) {
+ wpa_printf(MSG_DEBUG, "P2P: Too short DIRA (length %d)",
+ len);
+ return -1;
+ }
+ msg->dira = data;
+ msg->dira_len = len;
+ wpa_printf(MSG_DEBUG, "P2P: * DIRA (length=%u)", len);
+ break;
+ case P2P_ATTR_WLAN_AP_INFORMATION:
+ /* One or more AP Info fields (each being 12 octets) is required
+ * to be included. */
+ if (len < 12) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Too short WLAN AP info (length %d)",
+ len);
+ return -1;
+ }
+ msg->wlan_ap_info = data;
+ msg->wlan_ap_info_len = len;
+ break;
default:
wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
"(length %d)", id, len);
@@ -573,6 +627,18 @@
return -1;
}
+ msg->p2p2_attributes = ieee802_11_vendor_ie_concat(data, len,
+ P2P2_IE_VENDOR_TYPE);
+ if (msg->p2p2_attributes &&
+ p2p_parse_p2p_ie(msg->p2p2_attributes, msg)) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P2 IE data");
+ if (msg->p2p2_attributes)
+ wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P2 IE data",
+ msg->p2p2_attributes);
+ p2p_parse_free(msg);
+ return -1;
+ }
+
#ifdef CONFIG_WIFI_DISPLAY
if (elems.wfd) {
msg->wfd_subelems = ieee802_11_vendor_ie_concat(
@@ -647,6 +713,8 @@
{
wpabuf_free(msg->p2p_attributes);
msg->p2p_attributes = NULL;
+ wpabuf_free(msg->p2p2_attributes);
+ msg->p2p2_attributes = NULL;
wpabuf_free(msg->wps_attributes);
msg->wps_attributes = NULL;
#ifdef CONFIG_WIFI_DISPLAY
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 542521e..fb20313 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -181,6 +181,64 @@
}
+static struct wpabuf * p2p_build_prov_disc_bootstrap_req(struct p2p_data *p2p,
+ struct p2p_device *dev)
+{
+ struct wpabuf *buf;
+ u8 *len;
+ size_t cookie_len = 0;
+ const u8 *cookie = NULL;
+ u8 dialog_token = dev->dialog_token;
+ u8 group_capab;
+
+ buf = wpabuf_alloc(1000);
+ if (!buf)
+ return NULL;
+
+ p2p_dbg(p2p, "P2P2: Building bootstrapping PD Request");
+ p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
+
+ len = p2p_buf_add_ie_hdr(buf);
+
+ group_capab = 0;
+
+ if (p2p->num_groups) {
+ group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
+ if ((p2p->dev_capab & P2P_DEV_CAPAB_CONCURRENT_OPER) &&
+ (p2p->dev_capab & P2P_DEV_CAPAB_INFRA_MANAGED) &&
+ p2p->cross_connect)
+ group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
+ }
+ if (p2p->cfg->p2p_intra_bss)
+ group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
+
+ p2p_buf_add_capability(buf, p2p->dev_capab &
+ ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
+ group_capab);
+ p2p_buf_add_device_info(buf, p2p, NULL);
+
+ if (dev->bootstrap_params) {
+ cookie = dev->bootstrap_params->cookie;
+ cookie_len = dev->bootstrap_params->cookie_len;
+
+ if (dev->bootstrap_params->status == P2P_SC_COMEBACK)
+ p2p_buf_add_status(buf, dev->bootstrap_params->status);
+ }
+
+ p2p_buf_update_ie_hdr(buf, len);
+
+ len = p2p_buf_add_p2p2_ie_hdr(buf);
+
+ p2p_buf_add_pcea(buf, p2p);
+ p2p_buf_add_pbma(buf, dev->req_bootstrap_method, cookie, cookie_len, 0);
+
+ p2p_buf_update_ie_hdr(buf, len);
+
+ wpa_printf(MSG_DEBUG, "P2P2: Added PCEA and PBMA in PD Request");
+ return buf;
+}
+
+
static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
struct p2p_device *dev,
int join)
@@ -249,6 +307,42 @@
}
+static struct wpabuf *
+p2p_build_prov_disc_bootstrap_resp(struct p2p_data *p2p, struct p2p_device *dev,
+ u8 dialog_token, enum p2p_status_code status)
+{
+ struct wpabuf *buf;
+ u8 *cookie = NULL;
+ size_t cookie_len = 0;
+ int comeback_after = 0;
+ u8 *len;
+
+ buf = wpabuf_alloc(1000);
+ if (!buf)
+ return NULL;
+
+ p2p_dbg(p2p, "P2P2: Building boostrapping PD Response");
+ if (status == P2P_SC_COMEBACK && dev->bootstrap_params) {
+ cookie = dev->bootstrap_params->cookie;
+ cookie_len = dev->bootstrap_params->cookie_len;
+ comeback_after = dev->bootstrap_params->comeback_after;
+ }
+
+ p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
+
+ len = p2p_buf_add_p2p2_ie_hdr(buf);
+
+ p2p_buf_add_status(buf, status);
+ p2p_buf_add_pcea(buf, p2p);
+ p2p_buf_add_pbma(buf, dev->req_bootstrap_method, cookie, cookie_len,
+ comeback_after);
+
+ p2p_buf_update_ie_hdr(buf, len);
+
+ return buf;
+}
+
+
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
struct p2p_device *dev,
u8 dialog_token,
@@ -563,10 +657,232 @@
}
-void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len, int rx_freq)
+void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg,
+ struct p2p_device *dev)
{
- struct p2p_message msg;
+ const u8 *pos, *end;
+ u8 cap_info_len;
+
+ if (!p2p || !dev || !msg || !msg->pcea_info)
+ return;
+
+ pos = msg->pcea_info;
+ end = pos + msg->pcea_info_len;
+ dev->info.pcea_cap_info = WPA_GET_LE16(pos);
+ cap_info_len = dev->info.pcea_cap_info & P2P_PCEA_LEN_MASK;
+
+ /* Field length is (n-1), n in octets */
+ if (end - pos < cap_info_len + 1)
+ return;
+ pos += cap_info_len + 1;
+
+ if (dev->info.pcea_cap_info & P2P_PCEA_6GHZ)
+ dev->support_6ghz = true;
+
+ if (dev->info.pcea_cap_info & P2P_PCEA_REG_INFO) {
+ if (end - pos < 1) {
+ p2p_dbg(p2p, "Truncated PCEA");
+ return;
+ }
+ dev->info.reg_info = *pos++;
+ }
+
+ if (dev->info.pcea_cap_info & P2P_PCEA_PASN_TYPE) {
+ if (end - pos < 1) {
+ p2p_dbg(p2p, "Truncated PCEA");
+ return;
+ }
+ dev->info.pairing_config.pasn_type = *pos++;
+ }
+
+ if (dev->info.pcea_cap_info & P2P_PCEA_PAIRING_CAPABLE)
+ dev->info.pairing_config.pairing_capable = true;
+
+ if (dev->info.pcea_cap_info & P2P_PCEA_PAIRING_SETUP_ENABLED)
+ dev->info.pairing_config.enable_pairing_setup = true;
+
+ if (dev->info.pcea_cap_info & P2P_PCEA_PMK_CACHING) {
+ dev->info.pairing_config.enable_pairing_cache = true;
+ dev->info.pairing_config.enable_pairing_verification = true;
+ }
+}
+
+
+static void p2p_process_prov_disc_bootstrap_req(struct p2p_data *p2p,
+ struct p2p_message *msg,
+ const u8 *sa, const u8 *data,
+ size_t len, int rx_freq)
+{
+ struct p2p_device *dev;
+ int freq;
+ struct wpabuf *resp;
+ u16 bootstrap;
+ size_t cookie_len = 0;
+ const u8 *pos, *cookie;
+ enum p2p_status_code status = P2P_SC_FAIL_INVALID_PARAMS;
+
+ p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
+ " with bootstrapping Attribute (freq=%d)",
+ MAC2STR(sa), rx_freq);
+
+ dev = p2p_get_device(p2p, sa);
+ if (!dev) {
+ p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
+ MACSTR, MAC2STR(sa));
+
+ if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data, len, 0)) {
+ p2p_dbg(p2p,
+ "Provision Discovery Request add device failed "
+ MACSTR, MAC2STR(sa));
+ return;
+ }
+
+ dev = p2p_get_device(p2p, sa);
+ if (!dev) {
+ p2p_dbg(p2p,
+ "Provision Discovery device not found "
+ MACSTR, MAC2STR(sa));
+ return;
+ }
+ }
+ dev->p2p2 = true;
+
+ if (p2p->send_action_in_progress) {
+ p2p_dbg(p2p, "Dropping retry frame as response TX pending");
+ return;
+ }
+
+ p2p_update_peer_6ghz_capab(dev, msg);
+
+ if (msg->pcea_info && msg->pcea_info_len >= 2)
+ p2p_process_pcea(p2p, msg, dev);
+
+ pos = msg->pbma_info;
+
+ if (msg->pbma_info_len > 2 && msg->status &&
+ *msg->status == P2P_SC_COMEBACK) {
+ /* PBMA comeback request */
+ cookie_len = *pos++;
+ if (msg->pbma_info_len < 1 + cookie_len) {
+ p2p_dbg(p2p, "Truncated PBMA");
+ return;
+ }
+ cookie = pos;
+
+ if (!dev->bootstrap_params ||
+ dev->bootstrap_params->cookie_len != cookie_len ||
+ os_memcmp(cookie, dev->bootstrap_params->cookie,
+ cookie_len) != 0) {
+ status = P2P_SC_FAIL_REJECTED_BY_USER;
+ goto out;
+ }
+
+ bootstrap = dev->bootstrap_params->bootstrap_method;
+
+ if (!dev->req_bootstrap_method) {
+ status = P2P_SC_COMEBACK;
+ if (p2p->cfg->bootstrap_req_rx)
+ p2p->cfg->bootstrap_req_rx(p2p->cfg->cb_ctx,
+ sa, bootstrap);
+ goto out;
+ }
+ } else {
+ /* PBMA request */
+ bootstrap = WPA_GET_LE16(pos);
+
+ os_free(dev->bootstrap_params);
+ dev->bootstrap_params = NULL;
+
+ if (!dev->req_bootstrap_method) {
+ dev->bootstrap_params =
+ os_zalloc(sizeof(struct p2p_bootstrap_params));
+ if (!dev->bootstrap_params)
+ return;
+ dev->bootstrap_params->bootstrap_method = bootstrap;
+ dev->bootstrap_params->cookie_len = 4;
+ if (os_get_random(dev->bootstrap_params->cookie,
+ dev->bootstrap_params->cookie_len) <
+ 0) {
+ os_free(dev->bootstrap_params);
+ dev->bootstrap_params = NULL;
+ return;
+ }
+ dev->bootstrap_params->comeback_after =
+ p2p->cfg->comeback_after;
+ status = P2P_SC_COMEBACK;
+ if (p2p->cfg->bootstrap_req_rx)
+ p2p->cfg->bootstrap_req_rx(p2p->cfg->cb_ctx,
+ sa, bootstrap);
+ goto out;
+ }
+ }
+
+ if (bootstrap == P2P_PBMA_PIN_CODE_DISPLAY &&
+ dev->req_bootstrap_method == P2P_PBMA_PIN_CODE_KEYPAD)
+ status = P2P_SC_SUCCESS;
+ else if (bootstrap == P2P_PBMA_PIN_CODE_KEYPAD &&
+ dev->req_bootstrap_method == P2P_PBMA_PIN_CODE_DISPLAY)
+ status = P2P_SC_SUCCESS;
+ else if (bootstrap == P2P_PBMA_PASSPHRASE_DISPLAY &&
+ dev->req_bootstrap_method == P2P_PBMA_PASSPHRASE_KEYPAD)
+ status = P2P_SC_SUCCESS;
+ else if (bootstrap == P2P_PBMA_PASSPHRASE_KEYPAD &&
+ dev->req_bootstrap_method == P2P_PBMA_PASSPHRASE_DISPLAY)
+ status = P2P_SC_SUCCESS;
+ else if (bootstrap == P2P_PBMA_NFC_TAG &&
+ dev->req_bootstrap_method == P2P_PBMA_NFC_READER)
+ status = P2P_SC_SUCCESS;
+ else if (bootstrap == P2P_PBMA_NFC_READER &&
+ dev->req_bootstrap_method == P2P_PBMA_NFC_TAG)
+ status = P2P_SC_SUCCESS;
+ else if (bootstrap == P2P_PBMA_QR_DISPLAY &&
+ dev->req_bootstrap_method == P2P_PBMA_QR_SCAN)
+ status = P2P_SC_SUCCESS;
+ else if (bootstrap == P2P_PBMA_QR_SCAN &&
+ dev->req_bootstrap_method == P2P_PBMA_QR_DISPLAY)
+ status = P2P_SC_SUCCESS;
+ else if (bootstrap == P2P_PBMA_OPPORTUNISTIC &&
+ dev->req_bootstrap_method == P2P_PBMA_OPPORTUNISTIC)
+ status = P2P_SC_SUCCESS;
+ else
+ status = P2P_SC_FAIL_INVALID_PARAMS;
+
+ wpa_printf(MSG_ERROR, "Bootstrap received %d", bootstrap);
+
+out:
+ /* Send PD Bootstrapping Response for the PD Request */
+ resp = p2p_build_prov_disc_bootstrap_resp(p2p, dev, msg->dialog_token,
+ status);
+ if (!resp)
+ return;
+
+ p2p_dbg(p2p, "Sending Provision Discovery Bootstrap Response");
+ if (rx_freq > 0)
+ freq = rx_freq;
+ else
+ freq = p2p_channel_to_freq(p2p->cfg->reg_class,
+ p2p->cfg->channel);
+ if (freq < 0) {
+ p2p_dbg(p2p, "Unknown operating class/channel");
+ wpabuf_free(resp);
+ return;
+ }
+ p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
+ if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
+ p2p->cfg->dev_addr, wpabuf_head(resp),
+ wpabuf_len(resp), 50) < 0)
+ p2p_dbg(p2p, "Failed to send Action frame");
+ else
+ p2p->send_action_in_progress = 1;
+
+ wpabuf_free(resp);
+}
+
+
+static void p2p_process_prov_disc_req(struct p2p_data *p2p,
+ struct p2p_message *msg, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq)
+{
struct p2p_device *dev;
int freq;
enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
@@ -587,21 +903,17 @@
u8 remote_conncap;
u16 method;
- if (p2p_parse(data, len, &msg))
- return;
-
p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
" with config methods 0x%x (freq=%d)",
- MAC2STR(sa), msg.wps_config_methods, rx_freq);
- group_mac = msg.intended_addr;
+ MAC2STR(sa), msg->wps_config_methods, rx_freq);
+ group_mac = msg->intended_addr;
dev = p2p_get_device(p2p, sa);
if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
MACSTR, MAC2STR(sa));
- if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
- 0)) {
+ if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data, len, 0)) {
p2p_dbg(p2p, "Provision Discovery Request add device failed "
MACSTR, MAC2STR(sa));
goto out;
@@ -614,29 +926,29 @@
MACSTR, MAC2STR(sa));
goto out;
}
- } else if (msg.wfd_subelems) {
+ } else if (msg->wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
- dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
}
- p2p_update_peer_6ghz_capab(dev, &msg);
+ p2p_update_peer_6ghz_capab(dev, msg);
- if (!msg.adv_id) {
+ if (!msg->adv_id) {
allowed_config_methods |= WPS_CONFIG_PUSHBUTTON;
- if (!(msg.wps_config_methods & allowed_config_methods)) {
+ if (!(msg->wps_config_methods & allowed_config_methods)) {
p2p_dbg(p2p,
"Unsupported Config Methods in Provision Discovery Request");
goto out;
}
/* Legacy (non-P2PS) - Unknown groups allowed for P2PS */
- if (msg.group_id) {
+ if (msg->group_id) {
size_t i;
for (i = 0; i < p2p->num_groups; i++) {
if (p2p_group_is_group_id_match(
p2p->groups[i],
- msg.group_id, msg.group_id_len))
+ msg->group_id, msg->group_id_len))
break;
}
if (i == p2p->num_groups) {
@@ -652,29 +964,29 @@
* Set adv_id here, so in case of an error, a P2PS PD Response
* will be sent.
*/
- adv_id = WPA_GET_LE32(msg.adv_id);
- if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) {
+ adv_id = WPA_GET_LE32(msg->adv_id);
+ if (p2ps_validate_pd_req(p2p, msg, sa) < 0) {
reject = P2P_SC_FAIL_INVALID_PARAMS;
goto out;
}
- req_fcap = (struct p2ps_feature_capab *) msg.feature_cap;
+ req_fcap = (struct p2ps_feature_capab *) msg->feature_cap;
- os_memcpy(session_mac, msg.session_mac, ETH_ALEN);
- os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+ os_memcpy(session_mac, msg->session_mac, ETH_ALEN);
+ os_memcpy(adv_mac, msg->adv_mac, ETH_ALEN);
- session_id = WPA_GET_LE32(msg.session_id);
+ session_id = WPA_GET_LE32(msg->session_id);
- if (msg.conn_cap)
- conncap = *msg.conn_cap;
+ if (msg->conn_cap)
+ conncap = *msg->conn_cap;
/*
* We need to verify a P2PS config methog in an initial PD
* request or in a follow-on PD request with the status
* SUCCESS_DEFERRED.
*/
- if ((!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) &&
- !(msg.wps_config_methods & allowed_config_methods)) {
+ if ((!msg->status || *msg->status == P2P_SC_SUCCESS_DEFERRED) &&
+ !(msg->wps_config_methods & allowed_config_methods)) {
p2p_dbg(p2p,
"Unsupported Config Methods in Provision Discovery Request");
goto out;
@@ -690,18 +1002,18 @@
P2P_DEV_PD_PEER_KEYPAD |
P2P_DEV_PD_PEER_P2PS);
- if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
+ if (msg->wps_config_methods & WPS_CONFIG_DISPLAY) {
p2p_dbg(p2p, "Peer " MACSTR
" requested us to show a PIN on display", MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
passwd_id = DEV_PW_USER_SPECIFIED;
- } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
+ } else if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
p2p_dbg(p2p, "Peer " MACSTR
" requested us to write its PIN using keypad",
MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
- } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
+ } else if (msg->wps_config_methods & WPS_CONFIG_P2PS) {
p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN",
MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_P2PS;
@@ -712,8 +1024,8 @@
if (p2p->cfg->remove_stale_groups) {
p2p->cfg->remove_stale_groups(
p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
- msg.persistent_dev,
- msg.persistent_ssid, msg.persistent_ssid_len);
+ msg->persistent_dev,
+ msg->persistent_ssid, msg->persistent_ssid_len);
}
reject = P2P_SC_SUCCESS;
@@ -722,15 +1034,15 @@
* End of a legacy P2P PD Request processing, from this point continue
* with P2PS one.
*/
- if (!msg.adv_id)
+ if (!msg->adv_id)
goto out;
remote_conncap = conncap;
- if (!msg.status) {
+ if (!msg->status) {
unsigned int forced_freq, pref_freq;
- if (!ether_addr_equal(p2p->cfg->dev_addr, msg.adv_mac)) {
+ 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;
@@ -767,12 +1079,12 @@
"Incompatible P2PS feature capability CPT bitmask");
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
} else if (p2ps_adv->config_methods &&
- !(msg.wps_config_methods &
+ !(msg->wps_config_methods &
p2ps_adv->config_methods)) {
p2p_dbg(p2p,
"Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)",
p2ps_adv->config_methods,
- msg.wps_config_methods);
+ msg->wps_config_methods);
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
} else if (!p2ps_adv->state) {
p2p_dbg(p2p, "P2PS state unavailable");
@@ -782,24 +1094,24 @@
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
}
- if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
+ if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
p2p_dbg(p2p, "Keypad - always defer");
auto_accept = 0;
}
if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
- msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
- msg.channel_list && msg.channel_list_len &&
+ msg->persistent_dev) && conncap != P2PS_SETUP_NEW &&
+ msg->channel_list && msg->channel_list_len &&
p2p_peer_channels_check(p2p, &p2p->channels, dev,
- msg.channel_list,
- msg.channel_list_len) < 0) {
+ msg->channel_list,
+ msg->channel_list_len) < 0) {
p2p_dbg(p2p,
"No common channels - force deferred flow");
auto_accept = 0;
}
if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) ||
- msg.persistent_dev) && msg.operating_channel) {
+ msg->persistent_dev) && msg->operating_channel) {
struct p2p_channels intersect;
/*
@@ -810,15 +1122,15 @@
*/
if (dev->channels.reg_classes == 0 ||
!p2p_channels_includes(&dev->channels,
- msg.operating_channel[3],
- msg.operating_channel[4])) {
+ msg->operating_channel[3],
+ msg->operating_channel[4])) {
struct p2p_channels *ch = &dev->channels;
os_memset(ch, 0, sizeof(*ch));
ch->reg_class[0].reg_class =
- msg.operating_channel[3];
+ msg->operating_channel[3];
ch->reg_class[0].channel[0] =
- msg.operating_channel[4];
+ msg->operating_channel[4];
ch->reg_class[0].channels = 1;
ch->reg_classes = 1;
}
@@ -837,7 +1149,7 @@
struct p2ps_provision *tmp;
if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
- msg.wps_config_methods,
+ msg->wps_config_methods,
session_mac, adv_mac) < 0) {
reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
goto out;
@@ -859,7 +1171,7 @@
}
}
- if (!msg.status && !auto_accept &&
+ if (!msg->status && !auto_accept &&
(!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) {
struct p2ps_provision *tmp;
@@ -869,7 +1181,7 @@
}
if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id,
- msg.wps_config_methods,
+ msg->wps_config_methods,
session_mac, adv_mac) < 0) {
reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
goto out;
@@ -880,26 +1192,26 @@
}
/* Not a P2PS Follow-on PD */
- if (!msg.status)
+ if (!msg->status)
goto out;
- if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) {
- reject = *msg.status;
+ if (*msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED) {
+ reject = *msg->status;
goto out;
}
- if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
+ if (*msg->status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov)
goto out;
if (p2p->p2ps_prov->adv_id != adv_id ||
- !ether_addr_equal(p2p->p2ps_prov->adv_mac, msg.adv_mac)) {
+ !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 ||
- !ether_addr_equal(p2p->p2ps_prov->session_mac, msg.session_mac)) {
+ !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;
}
@@ -930,7 +1242,7 @@
else if (method & WPS_CONFIG_KEYPAD)
method = WPS_CONFIG_DISPLAY;
- if (!conncap || !(msg.wps_config_methods & method)) {
+ if (!conncap || !(msg->wps_config_methods & method)) {
/*
* Reject this "Deferred Accept*
* if incompatible conncap or method
@@ -941,11 +1253,11 @@
"Incompatible P2PS feature capability CPT bitmask");
reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS;
} else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) ||
- msg.persistent_dev) && conncap != P2PS_SETUP_NEW &&
- msg.channel_list && msg.channel_list_len &&
+ msg->persistent_dev) && conncap != P2PS_SETUP_NEW &&
+ msg->channel_list && msg->channel_list_len &&
p2p_peer_channels_check(p2p, &p2p->channels, dev,
- msg.channel_list,
- msg.channel_list_len) < 0) {
+ msg->channel_list,
+ msg->channel_list_len) < 0) {
p2p_dbg(p2p,
"No common channels in Follow-On Provision Discovery Request");
reject = P2P_SC_FAIL_NO_COMMON_CHANNELS;
@@ -957,10 +1269,10 @@
if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) {
u8 tmp;
- if (msg.operating_channel)
+ if (msg->operating_channel)
dev->oper_freq =
- p2p_channel_to_freq(msg.operating_channel[3],
- msg.operating_channel[4]);
+ p2p_channel_to_freq(msg->operating_channel[3],
+ msg->operating_channel[4]);
if ((conncap & P2PS_SETUP_GROUP_OWNER) &&
p2p_go_select_channel(p2p, dev, &tmp) < 0)
@@ -973,7 +1285,7 @@
out:
if (reject == P2P_SC_SUCCESS ||
reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
- config_methods = msg.wps_config_methods;
+ config_methods = msg->wps_config_methods;
else
config_methods = 0;
@@ -981,18 +1293,18 @@
* Send PD Response for an initial PD Request or for follow-on
* PD Request with P2P_SC_SUCCESS_DEFERRED status.
*/
- if (!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) {
- resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token,
+ if (!msg->status || *msg->status == P2P_SC_SUCCESS_DEFERRED) {
+ resp = p2p_build_prov_disc_resp(p2p, dev, msg->dialog_token,
reject, config_methods, adv_id,
- msg.group_id, msg.group_id_len,
- msg.persistent_ssid,
- msg.persistent_ssid_len,
+ msg->group_id,
+ msg->group_id_len,
+ msg->persistent_ssid,
+ msg->persistent_ssid_len,
(const u8 *) &resp_fcap,
sizeof(resp_fcap));
- if (!resp) {
- p2p_parse_free(&msg);
+ if (!resp)
return;
- }
+
p2p_dbg(p2p, "Sending Provision Discovery Response");
if (rx_freq > 0)
freq = rx_freq;
@@ -1002,7 +1314,6 @@
if (freq < 0) {
p2p_dbg(p2p, "Unknown regulatory class/channel");
wpabuf_free(resp);
- p2p_parse_free(&msg);
return;
}
p2p->pending_action_state = P2P_PENDING_PD_RESPONSE;
@@ -1017,10 +1328,8 @@
wpabuf_free(resp);
}
- if (!dev) {
- p2p_parse_free(&msg);
+ if (!dev)
return;
- }
freq = 0;
if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) {
@@ -1032,17 +1341,17 @@
if (!p2p->cfg->p2ps_prov_complete) {
/* Don't emit anything */
- } else if (msg.status && *msg.status != P2P_SC_SUCCESS &&
- *msg.status != P2P_SC_SUCCESS_DEFERRED) {
- reject = *msg.status;
+ } else if (msg->status && *msg->status != P2P_SC_SUCCESS &&
+ *msg->status != P2P_SC_SUCCESS_DEFERRED) {
+ reject = *msg->status;
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject,
sa, adv_mac, session_mac,
NULL, adv_id, session_id,
- 0, 0, msg.persistent_ssid,
- msg.persistent_ssid_len,
+ 0, 0, msg->persistent_ssid,
+ msg->persistent_ssid_len,
0, 0, NULL, NULL, 0, freq,
NULL, 0);
- } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
+ } else if (msg->status && *msg->status == P2P_SC_SUCCESS_DEFERRED &&
p2p->p2ps_prov) {
p2p->p2ps_prov->status = reject;
p2p->p2ps_prov->conncap = conncap;
@@ -1052,77 +1361,77 @@
sa, adv_mac, session_mac,
NULL, adv_id,
session_id, conncap, 0,
- msg.persistent_ssid,
- msg.persistent_ssid_len, 0,
- 0, NULL, NULL, 0, freq,
+ msg->persistent_ssid,
+ msg->persistent_ssid_len,
+ 0, 0, NULL, NULL, 0, freq,
NULL, 0);
else
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx,
- *msg.status,
+ *msg->status,
sa, adv_mac, session_mac,
group_mac, adv_id,
session_id, conncap,
passwd_id,
- msg.persistent_ssid,
- msg.persistent_ssid_len, 0,
- 0, NULL,
+ msg->persistent_ssid,
+ msg->persistent_ssid_len,
+ 0, 0, NULL,
(const u8 *) &resp_fcap,
sizeof(resp_fcap), freq,
NULL, 0);
- } else if (msg.status && p2p->p2ps_prov) {
+ } else if (msg->status && p2p->p2ps_prov) {
p2p->p2ps_prov->status = P2P_SC_SUCCESS;
- p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa,
+ p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg->status, sa,
adv_mac, session_mac, group_mac,
adv_id, session_id, conncap,
passwd_id,
- msg.persistent_ssid,
- msg.persistent_ssid_len,
+ msg->persistent_ssid,
+ msg->persistent_ssid_len,
0, 0, NULL,
(const u8 *) &resp_fcap,
sizeof(resp_fcap), freq, NULL, 0);
- } else if (msg.status) {
+ } else if (msg->status) {
} else if (auto_accept && reject == P2P_SC_SUCCESS) {
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
sa, adv_mac, session_mac,
group_mac, adv_id, session_id,
conncap, passwd_id,
- msg.persistent_ssid,
- msg.persistent_ssid_len,
+ msg->persistent_ssid,
+ msg->persistent_ssid_len,
0, 0, NULL,
(const u8 *) &resp_fcap,
sizeof(resp_fcap), freq,
- msg.group_id ?
- msg.group_id + ETH_ALEN : NULL,
- msg.group_id ?
- msg.group_id_len - ETH_ALEN : 0);
+ msg->group_id ?
+ msg->group_id + ETH_ALEN : NULL,
+ msg->group_id ?
+ msg->group_id_len - ETH_ALEN : 0);
} else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
- (!msg.session_info || !msg.session_info_len)) {
- p2p->p2ps_prov->method = msg.wps_config_methods;
+ (!msg->session_info || !msg->session_info_len)) {
+ p2p->p2ps_prov->method = msg->wps_config_methods;
p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS,
sa, adv_mac, session_mac,
group_mac, adv_id, session_id,
conncap, passwd_id,
- msg.persistent_ssid,
- msg.persistent_ssid_len,
+ msg->persistent_ssid,
+ msg->persistent_ssid_len,
0, 1, NULL,
(const u8 *) &resp_fcap,
sizeof(resp_fcap), freq, NULL, 0);
} else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
- size_t buf_len = msg.session_info_len;
+ size_t buf_len = msg->session_info_len;
char *buf = os_malloc(2 * buf_len + 1);
if (buf) {
- p2p->p2ps_prov->method = msg.wps_config_methods;
+ p2p->p2ps_prov->method = msg->wps_config_methods;
- utf8_escape((char *) msg.session_info, buf_len,
+ utf8_escape((char *) msg->session_info, buf_len,
buf, 2 * buf_len + 1);
p2p->cfg->p2ps_prov_complete(
p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa,
adv_mac, session_mac, group_mac, adv_id,
session_id, conncap, passwd_id,
- msg.persistent_ssid, msg.persistent_ssid_len,
+ msg->persistent_ssid, msg->persistent_ssid_len,
0, 1, buf,
(const u8 *) &resp_fcap, sizeof(resp_fcap),
freq, NULL, 0);
@@ -1150,29 +1459,30 @@
* seeker: KEYPAD, response status: SUCCESS
*/
if (p2p->cfg->prov_disc_req &&
- ((reject == P2P_SC_SUCCESS && !msg.adv_id) ||
- (!msg.status &&
+ ((reject == P2P_SC_SUCCESS && !msg->adv_id) ||
+ (!msg->status &&
(reject == P2P_SC_SUCCESS ||
reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) &&
passwd_id == DEV_PW_USER_SPECIFIED) ||
- (!msg.status &&
+ (!msg->status &&
reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE &&
passwd_id == DEV_PW_REGISTRAR_SPECIFIED) ||
(reject == P2P_SC_SUCCESS &&
- msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED &&
+ msg->status && *msg->status == P2P_SC_SUCCESS_DEFERRED &&
passwd_id == DEV_PW_REGISTRAR_SPECIFIED))) {
const u8 *dev_addr = sa;
- if (msg.p2p_device_addr)
- dev_addr = msg.p2p_device_addr;
+ if (msg->p2p_device_addr)
+ dev_addr = msg->p2p_device_addr;
p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
- msg.wps_config_methods,
- dev_addr, msg.pri_dev_type,
- msg.device_name, msg.config_methods,
- msg.capability ? msg.capability[0] : 0,
- msg.capability ? msg.capability[1] :
+ msg->wps_config_methods,
+ dev_addr, msg->pri_dev_type,
+ msg->device_name, msg->config_methods,
+ msg->capability ? msg->capability[0] :
0,
- msg.group_id, msg.group_id_len);
+ msg->capability ? msg->capability[1] :
+ 0,
+ msg->group_id, msg->group_id_len);
}
if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE)
@@ -1197,10 +1507,28 @@
break;
}
- if (msg.intended_addr)
- os_memcpy(dev->interface_addr, msg.intended_addr,
+ if (msg->intended_addr)
+ os_memcpy(dev->interface_addr, msg->intended_addr,
ETH_ALEN);
}
+}
+
+
+void p2p_handle_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq)
+{
+ struct p2p_message msg;
+
+ if (p2p_parse(data, len, &msg))
+ return;
+
+ if (msg.pcea_info && msg.pbma_info)
+ p2p_process_prov_disc_bootstrap_req(p2p, &msg, sa, data + 1,
+ len - 1, rx_freq);
+ else
+ p2p_process_prov_disc_req(p2p, &msg, sa, data + 1, len - 1,
+ rx_freq);
+
p2p_parse_free(&msg);
}
@@ -1303,13 +1631,102 @@
}
-void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
- const u8 *data, size_t len)
+static void p2p_process_prov_disc_bootstrap_resp(struct p2p_data *p2p,
+ struct p2p_message *msg,
+ const u8 *sa, const u8 *data,
+ size_t len, int rx_freq)
{
- struct p2p_message msg;
+ struct p2p_device *dev;
+ enum p2p_status_code status = P2P_SC_SUCCESS;
+ size_t cookie_len = 0;
+ const u8 *pos, *cookie;
+ u16 comeback_after;
+
+ /* Parse the P2P status present */
+ if (msg->status)
+ status = *msg->status;
+
+ p2p_dbg(p2p, "Received Provision Discovery Bootstrap Response from "
+ MACSTR, MAC2STR(sa));
+
+ dev = p2p_get_device(p2p, sa);
+ if (!dev || !dev->req_bootstrap_method) {
+ p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
+ " with no pending request", MAC2STR(sa));
+ return;
+ }
+
+ 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);
+ return;
+ }
+
+ if (p2p->pending_action_state == P2P_PENDING_PD) {
+ os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+ p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+ }
+
+ os_free(dev->bootstrap_params);
+ dev->bootstrap_params = NULL;
+
+ /* If the response is from the peer to whom a user initiated request
+ * was sent earlier, we reset that state information here. */
+ if (p2p->user_initiated_pd &&
+ ether_addr_equal(p2p->pending_pd_devaddr, sa))
+ p2p_reset_pending_pd(p2p);
+
+ if (status == P2P_SC_COMEBACK) {
+ /* PBMA comeback response */
+ pos = msg->pbma_info;
+ if (msg->pbma_info_len < 2 + 1)
+ return;
+ comeback_after = WPA_GET_LE16(pos);
+ pos += 2;
+ cookie_len = *pos++;
+ if (msg->pbma_info_len < 2 + 1 + cookie_len) {
+ p2p_dbg(p2p, "Truncated PBMA");
+ return;
+ }
+ cookie = pos;
+
+ dev->bootstrap_params =
+ os_zalloc(sizeof(struct p2p_bootstrap_params));
+ if (!dev->bootstrap_params)
+ return;
+ dev->bootstrap_params->cookie_len = cookie_len;
+ os_memcpy(dev->bootstrap_params->cookie, cookie, cookie_len);
+ dev->bootstrap_params->comeback_after = comeback_after;
+ dev->bootstrap_params->bootstrap_method =
+ dev->req_bootstrap_method;
+ dev->bootstrap_params->status = status;
+
+ p2p->cfg->register_bootstrap_comeback(p2p->cfg->cb_ctx, sa,
+ comeback_after);
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ return;
+ }
+
+ p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+ if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG)
+ dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+
+ if (p2p->cfg->bootstrap_completed)
+ p2p->cfg->bootstrap_completed(p2p->cfg->cb_ctx, sa, status,
+ rx_freq);
+}
+
+
+static void p2p_process_prov_disc_resp(struct p2p_data *p2p,
+ struct p2p_message *msg, const u8 *sa,
+ const u8 *data, size_t len)
+{
struct p2p_device *dev;
u16 report_config_methods = 0, req_config_methods;
- u8 status = P2P_SC_SUCCESS;
+ enum p2p_status_code status = P2P_SC_SUCCESS;
u32 adv_id = 0;
u8 conncap = P2PS_SETUP_NEW;
u8 adv_mac[ETH_ALEN];
@@ -1317,30 +1734,25 @@
int passwd_id = DEV_PW_DEFAULT;
int p2ps_seeker;
- if (p2p_parse(data, len, &msg))
+ if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, msg))
return;
- if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, &msg)) {
- p2p_parse_free(&msg);
- return;
- }
-
/* Parse the P2PS members present */
- if (msg.status)
- status = *msg.status;
+ if (msg->status)
+ status = *msg->status;
- group_mac = msg.intended_addr;
+ group_mac = msg->intended_addr;
- if (msg.adv_mac)
- os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN);
+ if (msg->adv_mac)
+ os_memcpy(adv_mac, msg->adv_mac, ETH_ALEN);
else
os_memset(adv_mac, 0, ETH_ALEN);
- if (msg.adv_id)
- adv_id = WPA_GET_LE32(msg.adv_id);
+ if (msg->adv_id)
+ adv_id = WPA_GET_LE32(msg->adv_id);
- if (msg.conn_cap) {
- conncap = *msg.conn_cap;
+ if (msg->conn_cap) {
+ conncap = *msg->conn_cap;
/* Switch bits to local relative */
switch (conncap) {
@@ -1355,25 +1767,23 @@
p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
" with config methods 0x%x",
- MAC2STR(sa), msg.wps_config_methods);
+ MAC2STR(sa), msg->wps_config_methods);
dev = p2p_get_device(p2p, sa);
if (dev == NULL || !dev->req_config_methods) {
p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
" with no pending request", MAC2STR(sa));
- p2p_parse_free(&msg);
return;
- } else if (msg.wfd_subelems) {
+ } else if (msg->wfd_subelems) {
wpabuf_free(dev->info.wfd_subelems);
- dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
}
- p2p_update_peer_6ghz_capab(dev, &msg);
+ p2p_update_peer_6ghz_capab(dev, msg);
- if (dev->dialog_token != msg.dialog_token) {
+ 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);
- p2p_parse_free(&msg);
+ msg->dialog_token, dev->dialog_token);
return;
}
@@ -1398,14 +1808,13 @@
ether_addr_equal(p2p->pending_pd_devaddr, sa))
p2p_reset_pending_pd(p2p);
- if (msg.wps_config_methods != req_config_methods) {
+ if (msg->wps_config_methods != req_config_methods) {
p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
- msg.wps_config_methods, req_config_methods);
+ msg->wps_config_methods, req_config_methods);
if (p2p->cfg->prov_disc_fail)
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
P2P_PROV_DISC_REJECTED,
adv_id, adv_mac, NULL);
- p2p_parse_free(&msg);
p2ps_prov_free(p2p);
goto out;
}
@@ -1419,13 +1828,13 @@
" accepted to show a PIN on display", MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
passwd_id = DEV_PW_REGISTRAR_SPECIFIED;
- } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
+ } else if (msg->wps_config_methods & WPS_CONFIG_KEYPAD) {
p2p_dbg(p2p, "Peer " MACSTR
" accepted to write our PIN using keypad",
MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
passwd_id = DEV_PW_USER_SPECIFIED;
- } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) {
+ } else if (msg->wps_config_methods & WPS_CONFIG_P2PS) {
p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN",
MAC2STR(sa));
dev->flags |= P2P_DEV_PD_PEER_P2PS;
@@ -1444,23 +1853,23 @@
* fails the flow would continue, although it would probably
* fail. Same is true for the operating channel.
*/
- if (msg.channel_list && msg.channel_list_len &&
+ if (msg->channel_list && msg->channel_list_len &&
p2p_peer_channels_check(p2p, &p2p->channels, dev,
- msg.channel_list,
- msg.channel_list_len) < 0)
+ msg->channel_list,
+ msg->channel_list_len) < 0)
p2p_dbg(p2p, "P2PS PD Response - no common channels");
- if (msg.operating_channel) {
+ if (msg->operating_channel) {
if (p2p_channels_includes(&p2p->channels,
- msg.operating_channel[3],
- msg.operating_channel[4]) &&
+ msg->operating_channel[3],
+ msg->operating_channel[4]) &&
p2p_channels_includes(&dev->channels,
- msg.operating_channel[3],
- msg.operating_channel[4])) {
+ msg->operating_channel[3],
+ msg->operating_channel[4])) {
dev->oper_freq =
p2p_channel_to_freq(
- msg.operating_channel[3],
- msg.operating_channel[4]);
+ msg->operating_channel[3],
+ msg->operating_channel[4]);
} else {
p2p_dbg(p2p,
"P2PS PD Response - invalid operating channel");
@@ -1492,11 +1901,12 @@
p2p->cfg->cb_ctx, status, sa, adv_mac,
p2p->p2ps_prov->session_mac,
group_mac, adv_id, p2p->p2ps_prov->session_id,
- conncap, passwd_id, msg.persistent_ssid,
- msg.persistent_ssid_len, 1, 0, NULL,
- msg.feature_cap, msg.feature_cap_len, freq,
- msg.group_id ? msg.group_id + ETH_ALEN : NULL,
- msg.group_id ? msg.group_id_len - ETH_ALEN : 0);
+ conncap, passwd_id, msg->persistent_ssid,
+ msg->persistent_ssid_len, 1, 0, NULL,
+ msg->feature_cap, msg->feature_cap_len, freq,
+ msg->group_id ? msg->group_id + ETH_ALEN : NULL,
+ msg->group_id ? msg->group_id_len - ETH_ALEN :
+ 0);
}
p2ps_prov_free(p2p);
} else if (status != P2P_SC_SUCCESS &&
@@ -1518,16 +1928,15 @@
NULL, NULL, 0);
}
- if (msg.session_info && msg.session_info_len) {
- size_t info_len = msg.session_info_len;
+ if (msg->session_info && msg->session_info_len) {
+ size_t info_len = msg->session_info_len;
char *deferred_sess_resp = os_malloc(2 * info_len + 1);
if (!deferred_sess_resp) {
- p2p_parse_free(&msg);
p2ps_prov_free(p2p);
goto out;
}
- utf8_escape((char *) msg.session_info, info_len,
+ utf8_escape((char *) msg->session_info, info_len,
deferred_sess_resp, 2 * info_len + 1);
if (p2p->cfg->prov_disc_fail)
@@ -1549,17 +1958,14 @@
p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
P2P_PROV_DISC_REJECTED,
adv_id, adv_mac, NULL);
- p2p_parse_free(&msg);
p2ps_prov_free(p2p);
goto out;
}
/* Store the provisioning info */
- dev->wps_prov_info = msg.wps_config_methods;
- if (msg.intended_addr)
- os_memcpy(dev->interface_addr, msg.intended_addr, ETH_ALEN);
-
- p2p_parse_free(&msg);
+ dev->wps_prov_info = msg->wps_config_methods;
+ if (msg->intended_addr)
+ os_memcpy(dev->interface_addr, msg->intended_addr, ETH_ALEN);
out:
dev->req_config_methods = 0;
@@ -1603,6 +2009,24 @@
}
+void p2p_handle_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
+ const u8 *data, size_t len, int rx_freq)
+{
+ struct p2p_message msg;
+
+ if (p2p_parse(data, len, &msg))
+ return;
+
+ if (msg.pcea_info && msg.pbma_info)
+ p2p_process_prov_disc_bootstrap_resp(p2p, &msg, sa, data + 1,
+ len - 1, rx_freq);
+ else
+ p2p_process_prov_disc_resp(p2p, &msg, sa, data + 1, len - 1);
+
+ p2p_parse_free(&msg);
+}
+
+
int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
int join, int force_freq)
{
@@ -1632,7 +2056,7 @@
/* TODO: use device discoverability request through GO */
}
- if (p2p->p2ps_prov) {
+ if (!dev->p2p2 && p2p->p2ps_prov) {
if (p2p->p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED) {
if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY)
dev->req_config_methods = WPS_CONFIG_KEYPAD;
@@ -1662,7 +2086,11 @@
return -1;
}
- req = p2p_build_prov_disc_req(p2p, dev, join);
+ if (dev->p2p2)
+ req = p2p_build_prov_disc_bootstrap_req(p2p, dev);
+ else
+ req = p2p_build_prov_disc_req(p2p, dev, join);
+
if (req == NULL)
return -1;
@@ -1701,13 +2129,22 @@
return -1;
}
+ if (dev->p2p2 && dev->req_bootstrap_method) {
+ p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
+ " (bootstrap methods 0x%x)",
+ MAC2STR(peer_addr), dev->req_bootstrap_method);
+ goto out;
+ }
+
p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
" (config methods 0x%x)",
MAC2STR(peer_addr), config_methods);
+
if (config_methods == 0 && !p2ps_prov) {
os_free(p2ps_prov);
return -1;
}
+ dev->req_config_methods = config_methods;
if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED &&
p2p->p2ps_prov) {
@@ -1715,12 +2152,12 @@
p2ps_prov->method = p2p->p2ps_prov->method;
}
+out:
/* Reset provisioning info */
dev->wps_prov_info = 0;
p2ps_prov_free(p2p);
p2p->p2ps_prov = p2ps_prov;
- dev->req_config_methods = config_methods;
if (join)
dev->flags |= P2P_DEV_PD_FOR_JOIN;
else
@@ -1729,8 +2166,7 @@
if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
p2p->state != P2P_LISTEN_ONLY) {
p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
- MACSTR " (config methods 0x%x)",
- MAC2STR(peer_addr), config_methods);
+ MACSTR, MAC2STR(peer_addr));
return 0;
}
diff --git a/src/pasn/pasn_common.c b/src/pasn/pasn_common.c
index e2c6681..25e44a1 100644
--- a/src/pasn/pasn_common.c
+++ b/src/pasn/pasn_common.c
@@ -28,6 +28,9 @@
void pasn_data_deinit(struct pasn_data *pasn)
{
+ if (!pasn)
+ return;
+ os_free(pasn->rsnxe_ie);
bin_clear_free(pasn, sizeof(struct pasn_data));
}
@@ -157,7 +160,7 @@
{
if (!pasn || !rsnxe_ie)
return;
- pasn->rsnxe_ie = rsnxe_ie;
+ pasn->rsnxe_ie = os_memdup(rsnxe_ie, 2 + rsnxe_ie[1]);
}
@@ -192,6 +195,14 @@
}
+void pasn_set_noauth(struct pasn_data *pasn, bool noauth)
+{
+ if (!pasn)
+ return;
+ pasn->noauth = noauth;
+}
+
+
int pasn_get_akmp(struct pasn_data *pasn)
{
if (!pasn)
diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h
index 36710c2..7b7c737 100644
--- a/src/pasn/pasn_common.h
+++ b/src/pasn/pasn_common.h
@@ -54,7 +54,7 @@
int wpa_key_mgmt;
int rsn_pairwise;
u16 rsnxe_capab;
- const u8 *rsnxe_ie;
+ u8 *rsnxe_ie;
bool custom_pmkid_valid;
u8 custom_pmkid[PMKID_LEN];
@@ -66,6 +66,7 @@
size_t extra_ies_len;
/* External modules do not access below variables */
+ size_t kek_len;
u16 group;
bool secure_ltf;
int freq;
@@ -174,7 +175,8 @@
/* 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);
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ bool reject);
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);
@@ -205,8 +207,20 @@
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);
+struct rsn_pmksa_cache * pasn_initiator_pmksa_cache_init(void);
+void pasn_initiator_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
+int pasn_initiator_pmksa_cache_add(struct rsn_pmksa_cache *pmksa,
+ const u8 *own_addr, const u8 *bssid, u8 *pmk,
+ size_t pmk_len, u8 *pmkid);
+int pasn_initiator_pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+ const u8 *bssid, u8 *pmkid, u8 *pmk,
+ size_t *pmk_len);
+void pasn_initiator_pmksa_cache_remove(struct rsn_pmksa_cache *pmksa,
+ const u8 *bssid);
+void pasn_initiator_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa);
/* Responder */
+void pasn_set_noauth(struct pasn_data *pasn, bool noauth);
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);
@@ -215,6 +229,17 @@
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);
+struct rsn_pmksa_cache * pasn_responder_pmksa_cache_init(void);
+void pasn_responder_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
+int pasn_responder_pmksa_cache_add(struct rsn_pmksa_cache *pmksa,
+ const u8 *own_addr, const u8 *bssid, u8 *pmk,
+ size_t pmk_len, u8 *pmkid);
+int pasn_responder_pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+ const u8 *bssid, u8 *pmkid, u8 *pmk,
+ size_t *pmk_len);
+void pasn_responder_pmksa_cache_remove(struct rsn_pmksa_cache *pmksa,
+ const u8 *bssid);
+void pasn_responder_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa);
int pasn_get_akmp(struct pasn_data *pasn);
int pasn_get_cipher(struct pasn_data *pasn);
diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c
index d273067..ce1055b 100644
--- a/src/pasn/pasn_initiator.c
+++ b/src/pasn/pasn_initiator.c
@@ -26,6 +26,65 @@
#include "pasn_common.h"
+struct rsn_pmksa_cache * pasn_initiator_pmksa_cache_init(void)
+{
+ return pmksa_cache_init(NULL, NULL, NULL, NULL, NULL);
+}
+
+
+void pasn_initiator_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+ return pmksa_cache_deinit(pmksa);
+}
+
+
+int pasn_initiator_pmksa_cache_add(struct rsn_pmksa_cache *pmksa,
+ const u8 *own_addr, const u8 *bssid, u8 *pmk,
+ size_t pmk_len, u8 *pmkid)
+{
+ if (pmksa_cache_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, bssid,
+ own_addr, NULL, WPA_KEY_MGMT_SAE, 0))
+ return 0;
+ return -1;
+}
+
+
+void pasn_initiator_pmksa_cache_remove(struct rsn_pmksa_cache *pmksa,
+ const u8 *bssid)
+{
+ struct rsn_pmksa_cache_entry *entry;
+
+ entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL, 0);
+ if (!entry)
+ return;
+
+ pmksa_cache_remove(pmksa, entry);
+}
+
+
+int pasn_initiator_pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+ const u8 *bssid, u8 *pmkid, u8 *pmk,
+ size_t *pmk_len)
+{
+ struct rsn_pmksa_cache_entry *entry;
+
+ entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL, 0);
+ if (entry) {
+ os_memcpy(pmkid, entry->pmkid, PMKID_LEN);
+ os_memcpy(pmk, entry->pmk, entry->pmk_len);
+ *pmk_len = entry->pmk_len;
+ return 0;
+ }
+ return -1;
+}
+
+
+void pasn_initiator_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa)
+{
+ return pmksa_cache_flush(pmksa, NULL, NULL, 0, false);
+}
+
+
void pasn_set_initiator_pmksa(struct pasn_data *pasn,
struct rsn_pmksa_cache *pmksa)
{
@@ -587,7 +646,10 @@
if (wpa_pasn_add_wrapped_data(buf, wrapped_data_buf) < 0)
goto fail;
- wpa_pasn_add_rsnxe(buf, pasn->rsnxe_capab);
+ if (pasn->rsnxe_ie)
+ wpabuf_put_data(buf, pasn->rsnxe_ie, 2 + pasn->rsnxe_ie[1]);
+ else
+ wpa_pasn_add_rsnxe(buf, pasn->rsnxe_capab);
wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
@@ -747,6 +809,7 @@
pasn->derive_kdk = false;
pasn->rsn_ie = NULL;
pasn->rsn_ie_len = 0;
+ os_free(pasn->rsnxe_ie);
pasn->rsnxe_ie = NULL;
pasn->custom_pmkid_valid = false;
@@ -1233,7 +1296,7 @@
pasn->own_addr, pasn->peer_addr,
wpabuf_head(secret), wpabuf_len(secret),
&pasn->ptk, pasn->akmp, pasn->cipher,
- pasn->kdk_len);
+ pasn->kdk_len, pasn->kek_len);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
goto fail;
diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c
index b991364..e344898 100644
--- a/src/pasn/pasn_responder.c
+++ b/src/pasn/pasn_responder.c
@@ -26,6 +26,65 @@
#include "pasn_common.h"
+struct rsn_pmksa_cache * pasn_responder_pmksa_cache_init(void)
+{
+ return pmksa_cache_auth_init(NULL, NULL);
+}
+
+
+void pasn_responder_pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+ return pmksa_cache_auth_deinit(pmksa);
+}
+
+
+int pasn_responder_pmksa_cache_add(struct rsn_pmksa_cache *pmksa,
+ const u8 *own_addr, const u8 *bssid, u8 *pmk,
+ size_t pmk_len, u8 *pmkid)
+{
+ if (pmksa_cache_auth_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, own_addr,
+ bssid, 0, NULL, WPA_KEY_MGMT_SAE))
+ return 0;
+ return -1;
+}
+
+
+int pasn_responder_pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+ const u8 *bssid, u8 *pmkid, u8 *pmk,
+ size_t *pmk_len)
+{
+ struct rsn_pmksa_cache_entry *entry;
+
+ entry = pmksa_cache_auth_get(pmksa, bssid, NULL);
+ if (entry) {
+ os_memcpy(pmkid, entry->pmkid, PMKID_LEN);
+ os_memcpy(pmk, entry->pmk, entry->pmk_len);
+ *pmk_len = entry->pmk_len;
+ return 0;
+ }
+ return -1;
+}
+
+
+void pasn_responder_pmksa_cache_remove(struct rsn_pmksa_cache *pmksa,
+ const u8 *bssid)
+{
+ struct rsn_pmksa_cache_entry *entry;
+
+ entry = pmksa_cache_auth_get(pmksa, bssid, NULL);
+ if (!entry)
+ return;
+
+ pmksa_cache_free_entry(pmksa, entry);
+}
+
+
+void pasn_responder_pmksa_cache_flush(struct rsn_pmksa_cache *pmksa)
+{
+ return pmksa_cache_auth_flush(pmksa);
+}
+
+
void pasn_set_responder_pmksa(struct pasn_data *pasn,
struct rsn_pmksa_cache *pmksa)
{
@@ -349,7 +408,7 @@
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);
+ pasn->cipher, pasn->kdk_len, pasn->kek_len);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed to derive PTK");
return -1;
@@ -414,7 +473,7 @@
"PASN: comeback: STA=" MACSTR, MAC2STR(peer_addr));
ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
- wpabuf_len(buf), 0, 0, 0);
+ wpabuf_len(buf), 0, pasn->freq, 0);
if (ret)
wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2");
@@ -579,7 +638,7 @@
MAC2STR(peer_addr));
ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
- wpabuf_len(buf), 0, 0, 0);
+ wpabuf_len(buf), 0, pasn->freq, 0);
if (ret)
wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
@@ -597,7 +656,8 @@
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)
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ bool reject)
{
struct ieee802_11_elems elems;
struct wpa_ie_data rsn_data;
@@ -616,6 +676,12 @@
if (!groups)
groups = default_groups;
+ if (reject) {
+ wpa_printf(MSG_DEBUG, "PASN: Received Rejection");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto send_resp;
+ }
+
if (ieee802_11_parse_elems(mgmt->u.auth.variable,
len - offsetof(struct ieee80211_mgmt,
u.auth.variable),
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 935a1aa..d145da0 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -532,7 +532,7 @@
size_t mic_len, hdrlen, rlen, extra_len = 0;
struct wpa_eapol_key *reply;
u8 *rbuf, *key_mic;
- u8 *rsn_ie_buf = NULL;
+ u8 *rsn_ie_buf = NULL, *buf2 = NULL;
u16 key_info;
#ifdef CONFIG_TESTING_OPTIONS
size_t pad_len = 0;
@@ -582,6 +582,37 @@
}
#endif /* CONFIG_IEEE80211R */
+ if (sm->rsn_override != RSN_OVERRIDE_NOT_USED) {
+ u8 *pos;
+
+ buf2 = os_malloc(wpa_ie_len + 2 + 4 + 1);
+ if (!buf2) {
+ os_free(rsn_ie_buf);
+ return -1;
+ }
+ os_memcpy(buf2, wpa_ie, wpa_ie_len);
+ pos = buf2 + wpa_ie_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 + 1;
+ WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
+ pos += 4;
+ if (sm->rsn_override == RSN_OVERRIDE_RSNE) {
+ *pos++ = RSN_SELECTION_RSNE;
+ } else if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE) {
+ *pos++ = RSN_SELECTION_RSNE_OVERRIDE;
+ } else if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE_2) {
+ *pos++ = RSN_SELECTION_RSNE_OVERRIDE_2;
+ } else {
+ os_free(rsn_ie_buf);
+ os_free(buf2);
+ return -1;
+ }
+
+ wpa_ie = buf2;
+ wpa_ie_len += 2 + 4 + 1;
+
+ }
+
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
#ifdef CONFIG_TESTING_OPTIONS
@@ -602,6 +633,7 @@
&rlen, (void *) &reply);
if (rbuf == NULL) {
os_free(rsn_ie_buf);
+ os_free(buf2);
return -1;
}
@@ -634,6 +666,7 @@
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);
+ os_free(buf2);
#ifdef CONFIG_TESTING_OPTIONS
if (sm->test_eapol_m2_elems) {
os_memcpy(key_mic + mic_len + 2 + wpa_ie_len,
@@ -991,6 +1024,8 @@
"WPA: Failed to get random data for SNonce");
goto failed;
}
+ if (wpa_sm_rsn_overriding_supported(sm))
+ rsn_set_snonce_cookie(sm->snonce);
sm->renew_snonce = 0;
wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
sm->snonce, WPA_NONCE_LEN);
@@ -2194,6 +2229,68 @@
return -1;
}
+ if (sm->proto == WPA_PROTO_RSN && wpa_sm_rsn_overriding_supported(sm)) {
+ if ((sm->ap_rsne_override && !ie->rsne_override) ||
+ (!sm->ap_rsne_override && ie->rsne_override) ||
+ (sm->ap_rsne_override && ie->rsne_override &&
+ (sm->ap_rsne_override_len != ie->rsne_override_len ||
+ os_memcmp(sm->ap_rsne_override, ie->rsne_override,
+ sm->ap_rsne_override_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: RSNE Override element mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
+ wpa_hexdump(MSG_INFO,
+ "RSNE Override element in Beacon/ProbeResp",
+ sm->ap_rsne_override,
+ sm->ap_rsne_override_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNE Override element in EAPOL-Key msg 3/4",
+ ie->rsne_override, ie->rsne_override_len);
+ wpa_sm_deauthenticate(sm,
+ WLAN_REASON_IE_IN_4WAY_DIFFERS);
+ return -1;
+ }
+
+ if ((sm->ap_rsne_override_2 && !ie->rsne_override_2) ||
+ (!sm->ap_rsne_override_2 && ie->rsne_override_2) ||
+ (sm->ap_rsne_override_2 && ie->rsne_override_2 &&
+ (sm->ap_rsne_override_2_len != ie->rsne_override_2_len ||
+ os_memcmp(sm->ap_rsne_override_2, ie->rsne_override_2,
+ sm->ap_rsne_override_2_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: RSNE Override 2 element mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
+ wpa_hexdump(MSG_INFO,
+ "RSNE Override 2 element in Beacon/ProbeResp",
+ sm->ap_rsne_override_2,
+ sm->ap_rsne_override_2_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNE Override 2 element in EAPOL-Key msg 3/4",
+ ie->rsne_override_2, ie->rsne_override_2_len);
+ wpa_sm_deauthenticate(sm,
+ WLAN_REASON_IE_IN_4WAY_DIFFERS);
+ return -1;
+ }
+
+ if ((sm->ap_rsnxe_override && !ie->rsnxe_override) ||
+ (!sm->ap_rsnxe_override && ie->rsnxe_override) ||
+ (sm->ap_rsnxe_override && ie->rsnxe_override &&
+ (sm->ap_rsnxe_override_len != ie->rsnxe_override_len ||
+ os_memcmp(sm->ap_rsnxe_override, ie->rsnxe_override,
+ sm->ap_rsnxe_override_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: RSNXE Override element mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
+ wpa_hexdump(MSG_INFO,
+ "RSNXE Override element in Beacon/ProbeResp",
+ sm->ap_rsnxe_override,
+ sm->ap_rsnxe_override_len);
+ wpa_hexdump(MSG_INFO,
+ "RSNXE Override element in EAPOL-Key msg 3/4",
+ ie->rsnxe_override, ie->rsnxe_override_len);
+ wpa_sm_deauthenticate(sm,
+ WLAN_REASON_IE_IN_4WAY_DIFFERS);
+ return -1;
+ }
+ }
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt) &&
wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
@@ -2340,10 +2437,14 @@
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 link_kde_len,
+ const u8 *rsn_override_link_kde,
+ size_t rsn_override_link_kde_len)
{
- size_t rsne_len = 0, rsnxe_len = 0;
- const u8 *rsne = NULL, *rsnxe = NULL;
+ size_t rsne_len = 0, rsnxe_len = 0, rsnoe_len = 0, rsno2e_len = 0,
+ rsnxoe_len = 0;
+ const u8 *rsne = NULL, *rsnxe = NULL, *rsnoe = NULL, *rsno2e = NULL,
+ *rsnxoe = NULL;
if (!link_kde ||
link_kde_len < RSN_MLO_LINK_KDE_LINK_MAC_INDEX + ETH_ALEN) {
@@ -2404,14 +2505,14 @@
sm->mlo.links[link_id].ap_rsne_len,
rsne, rsne_len)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "RSN MLO: IE in 3/4 msg does not match with IE in Beacon/ProbeResp for link ID %u",
+ "RSN MLO: RSNE in 3/4 msg does not match with IE in Beacon/ProbeResp for link ID %u",
link_id);
wpa_hexdump(MSG_INFO, "RSNE in Beacon/ProbeResp",
sm->mlo.links[link_id].ap_rsne,
sm->mlo.links[link_id].ap_rsne_len);
wpa_hexdump(MSG_INFO, "RSNE in EAPOL-Key msg 3/4",
rsne, rsne_len);
- return -1;
+ goto fail;
}
if ((sm->mlo.links[link_id].ap_rsnxe && !rsnxe) ||
@@ -2428,11 +2529,89 @@
sm->mlo.links[link_id].ap_rsnxe_len);
wpa_hexdump(MSG_INFO, "RSNXE in EAPOL-Key msg 3/4",
rsnxe, rsnxe_len);
- wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
- return -1;
+ goto fail;
+ }
+
+ if (!wpa_sm_rsn_overriding_supported(sm))
+ return 0;
+
+ if (rsn_override_link_kde) {
+ rsnoe = get_vendor_ie(rsn_override_link_kde + 1,
+ rsn_override_link_kde_len - 1,
+ RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ if (rsnoe)
+ rsnoe_len = 2 + rsnoe[1];
+
+ rsno2e = get_vendor_ie(rsn_override_link_kde + 1,
+ rsn_override_link_kde_len - 1,
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+ if (rsno2e)
+ rsno2e_len = 2 + rsno2e[1];
+
+ rsnxoe = get_vendor_ie(rsn_override_link_kde + 1,
+ rsn_override_link_kde_len - 1,
+ RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+ if (rsnxoe)
+ rsnxoe_len = 2 + rsnxoe[1];
+ }
+
+ if ((sm->mlo.links[link_id].ap_rsnoe && !rsnoe) ||
+ (!sm->mlo.links[link_id].ap_rsnoe && rsnoe) ||
+ (sm->mlo.links[link_id].ap_rsnoe && rsnoe &&
+ wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+ sm->mlo.links[link_id].ap_rsnoe,
+ sm->mlo.links[link_id].ap_rsnoe_len,
+ rsnoe, rsnoe_len))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN MLO: RSNOE in 3/4 msg does not match with IE in Beacon/ProbeResp for link ID %u",
+ link_id);
+ wpa_hexdump(MSG_INFO, "RSNOE in Beacon/ProbeResp",
+ sm->mlo.links[link_id].ap_rsnoe,
+ sm->mlo.links[link_id].ap_rsnoe_len);
+ wpa_hexdump(MSG_INFO, "RSNOE in EAPOL-Key msg 3/4",
+ rsnoe, rsnoe_len);
+ goto fail;
+ }
+
+ if ((sm->mlo.links[link_id].ap_rsno2e && !rsno2e) ||
+ (!sm->mlo.links[link_id].ap_rsno2e && rsno2e) ||
+ (sm->mlo.links[link_id].ap_rsno2e && rsno2e &&
+ wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+ sm->mlo.links[link_id].ap_rsno2e,
+ sm->mlo.links[link_id].ap_rsno2e_len,
+ rsno2e, rsno2e_len))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN MLO: RSNO2E in 3/4 msg does not match with IE in Beacon/ProbeResp for link ID %u",
+ link_id);
+ wpa_hexdump(MSG_INFO, "RSNO2E in Beacon/ProbeResp",
+ sm->mlo.links[link_id].ap_rsno2e,
+ sm->mlo.links[link_id].ap_rsno2e_len);
+ wpa_hexdump(MSG_INFO, "RSNOE in EAPOL-Key msg 3/4",
+ rsno2e, rsno2e_len);
+ goto fail;
+ }
+
+ if ((sm->mlo.links[link_id].ap_rsnxoe && !rsnxoe) ||
+ (!sm->mlo.links[link_id].ap_rsnxoe && rsnxoe) ||
+ (sm->mlo.links[link_id].ap_rsnxoe && rsnxoe &&
+ (sm->mlo.links[link_id].ap_rsnxoe_len != rsnxoe_len ||
+ os_memcmp(sm->mlo.links[link_id].ap_rsnxoe, rsnxoe,
+ sm->mlo.links[link_id].ap_rsnxoe_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN MLO: RSNXOE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4 for link ID %u",
+ link_id);
+ wpa_hexdump(MSG_INFO, "RSNXOE in Beacon/ProbeResp",
+ sm->mlo.links[link_id].ap_rsnxoe,
+ sm->mlo.links[link_id].ap_rsnxoe_len);
+ wpa_hexdump(MSG_INFO, "RSNXOE in EAPOL-Key msg 3/4",
+ rsnxoe, rsnxoe_len);
+ goto fail;
}
return 0;
+fail:
+ wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
+ return -1;
}
@@ -2600,8 +2779,10 @@
if (!(sm->mlo.req_links & BIT(i)))
continue;
- if (wpa_supplicant_validate_link_kde(sm, i, ie.mlo_link[i],
- ie.mlo_link_len[i]) < 0)
+ if (wpa_supplicant_validate_link_kde(
+ sm, i, ie.mlo_link[i], ie.mlo_link_len[i],
+ ie.rsn_override_link[i],
+ ie.rsn_override_link_len[i]) < 0)
goto failed;
if (!(sm->mlo.valid_links & BIT(i)))
@@ -4174,9 +4355,15 @@
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
os_free(sm->ap_rsnxe);
+ os_free(sm->ap_rsne_override);
+ os_free(sm->ap_rsne_override_2);
+ os_free(sm->ap_rsnxe_override);
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);
+ os_free(sm->mlo.links[i].ap_rsnoe);
+ os_free(sm->mlo.links[i].ap_rsno2e);
+ os_free(sm->mlo.links[i].ap_rsnxoe);
}
wpa_sm_drop_sa(sm);
os_free(sm->ctx);
@@ -4551,27 +4738,12 @@
} else {
wpa_hexdump_link(MSG_DEBUG, i, "RSN: Set AP RSNE",
ie, len);
- if (ie[0] == WLAN_EID_VENDOR_SPECIFIC && len > 2 + 4) {
- sm->mlo.links[i].ap_rsne = os_malloc(len - 4);
- if (!sm->mlo.links[i].ap_rsne)
- return -1;
- sm->mlo.links[i].ap_rsne[0] = WLAN_EID_RSN;
- sm->mlo.links[i].ap_rsne[1] = len - 2 - 4;
- os_memcpy(&sm->mlo.links[i].ap_rsne[2],
- ie + 2 + 4, len - 2 - 4);
- sm->mlo.links[i].ap_rsne_len = len - 4;
- wpa_hexdump(MSG_DEBUG,
- "RSN: Converted RSNE override to RSNE",
- sm->mlo.links[i].ap_rsne,
- sm->mlo.links[i].ap_rsne_len);
- } else {
- sm->mlo.links[i].ap_rsne = os_memdup(ie, len);
- if (!sm->mlo.links[i].ap_rsne) {
- sm->mlo.links[i].ap_rsne_len = 0;
- return -1;
- }
- sm->mlo.links[i].ap_rsne_len = len;
+ sm->mlo.links[i].ap_rsne = os_memdup(ie, len);
+ if (!sm->mlo.links[i].ap_rsne) {
+ sm->mlo.links[i].ap_rsne_len = 0;
+ return -1;
}
+ sm->mlo.links[i].ap_rsne_len = len;
}
ie = mlo->links[i].ap_rsnxe;
@@ -4587,27 +4759,75 @@
} else {
wpa_hexdump_link(MSG_DEBUG, i, "RSN: Set AP RSNXE", ie,
len);
- if (ie[0] == WLAN_EID_VENDOR_SPECIFIC && len > 2 + 4) {
- sm->mlo.links[i].ap_rsnxe = os_malloc(len - 4);
- if (!sm->mlo.links[i].ap_rsnxe)
- return -1;
- sm->mlo.links[i].ap_rsnxe[0] = WLAN_EID_RSNX;
- sm->mlo.links[i].ap_rsnxe[1] = len - 2 - 4;
- os_memcpy(&sm->mlo.links[i].ap_rsnxe[2],
- ie + 2 + 4, len - 2 - 4);
- sm->mlo.links[i].ap_rsnxe_len = len - 4;
- wpa_hexdump(MSG_DEBUG,
- "RSN: Converted RSNXE override to RSNXE",
- sm->mlo.links[i].ap_rsnxe,
- sm->mlo.links[i].ap_rsnxe_len);
- } else {
- sm->mlo.links[i].ap_rsnxe = os_memdup(ie, len);
- if (!sm->mlo.links[i].ap_rsnxe) {
- sm->mlo.links[i].ap_rsnxe_len = 0;
- return -1;
- }
- sm->mlo.links[i].ap_rsnxe_len = len;
+ sm->mlo.links[i].ap_rsnxe = os_memdup(ie, len);
+ if (!sm->mlo.links[i].ap_rsnxe) {
+ sm->mlo.links[i].ap_rsnxe_len = 0;
+ return -1;
}
+ sm->mlo.links[i].ap_rsnxe_len = len;
+ }
+
+ ie = mlo->links[i].ap_rsnoe;
+ len = mlo->links[i].ap_rsnoe_len;
+ os_free(sm->mlo.links[i].ap_rsnoe);
+ if (!ie || len == 0) {
+ if (sm->mlo.links[i].ap_rsnoe)
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Clearing MLO link[%u] AP RSNOE",
+ i);
+ sm->mlo.links[i].ap_rsnoe = NULL;
+ sm->mlo.links[i].ap_rsnoe_len = 0;
+ } else {
+ wpa_hexdump_link(MSG_DEBUG, i, "RSN: Set AP RSNOE",
+ ie, len);
+ sm->mlo.links[i].ap_rsnoe = os_memdup(ie, len);
+ if (!sm->mlo.links[i].ap_rsnoe) {
+ sm->mlo.links[i].ap_rsnoe_len = 0;
+ return -1;
+ }
+ sm->mlo.links[i].ap_rsnoe_len = len;
+ }
+
+ ie = mlo->links[i].ap_rsno2e;
+ len = mlo->links[i].ap_rsno2e_len;
+ os_free(sm->mlo.links[i].ap_rsno2e);
+ if (!ie || len == 0) {
+ if (sm->mlo.links[i].ap_rsno2e)
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Clearing MLO link[%u] AP RSNO2E",
+ i);
+ sm->mlo.links[i].ap_rsno2e = NULL;
+ sm->mlo.links[i].ap_rsno2e_len = 0;
+ } else {
+ wpa_hexdump_link(MSG_DEBUG, i, "RSN: Set AP RSNO2E",
+ ie, len);
+ sm->mlo.links[i].ap_rsno2e = os_memdup(ie, len);
+ if (!sm->mlo.links[i].ap_rsno2e) {
+ sm->mlo.links[i].ap_rsno2e_len = 0;
+ return -1;
+ }
+ sm->mlo.links[i].ap_rsno2e_len = len;
+ }
+
+ ie = mlo->links[i].ap_rsnxoe;
+ len = mlo->links[i].ap_rsnxoe_len;
+ os_free(sm->mlo.links[i].ap_rsnxoe);
+ if (!ie || len == 0) {
+ if (sm->mlo.links[i].ap_rsnxoe)
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Clearing MLO link[%u] AP RSNXOE",
+ i);
+ sm->mlo.links[i].ap_rsnxoe = NULL;
+ sm->mlo.links[i].ap_rsnxoe_len = 0;
+ } else {
+ wpa_hexdump_link(MSG_DEBUG, i, "RSN: Set AP RSNXOE",
+ ie, len);
+ sm->mlo.links[i].ap_rsnxoe = os_memdup(ie, len);
+ if (!sm->mlo.links[i].ap_rsnxoe) {
+ sm->mlo.links[i].ap_rsnxoe_len = 0;
+ return -1;
+ }
+ sm->mlo.links[i].ap_rsnxoe_len = len;
}
}
@@ -4768,6 +4988,12 @@
case WPA_PARAM_SSID_PROTECTION:
sm->ssid_protection = value;
break;
+ case WPA_PARAM_RSN_OVERRIDE:
+ sm->rsn_override = value;
+ break;
+ case WPA_PARAM_RSN_OVERRIDE_SUPPORT:
+ sm->rsn_override_support = value;
+ break;
default:
break;
}
@@ -4776,6 +5002,23 @@
}
+static const u8 * wpa_sm_get_ap_rsne(struct wpa_sm *sm, size_t *len)
+{
+ if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE) {
+ *len = sm->ap_rsne_override_len;
+ return sm->ap_rsne_override;
+ }
+
+ if (sm->rsn_override == RSN_OVERRIDE_RSNE_OVERRIDE_2) {
+ *len = sm->ap_rsne_override_2_len;
+ return sm->ap_rsne_override_2;
+ }
+
+ *len = sm->ap_rsn_ie_len;
+ return sm->ap_rsn_ie;
+}
+
+
/**
* wpa_sm_get_status - Get WPA state machine
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -4793,6 +5036,10 @@
{
char *pos = buf, *end = buf + buflen;
int ret;
+ const u8 *rsne;
+ size_t rsne_len;
+
+ rsne = wpa_sm_get_ap_rsne(sm, &rsne_len);
ret = os_snprintf(pos, end - pos,
"pairwise_cipher=%s\n"
@@ -4814,10 +5061,10 @@
}
#endif /* CONFIG_DPP2 */
- if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) {
+ if (sm->mfp != NO_MGMT_FRAME_PROTECTION && rsne) {
struct wpa_ie_data rsn;
- if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn)
- >= 0 &&
+
+ if (wpa_parse_wpa_ie_rsn(rsne, rsne_len, &rsn) >= 0 &&
rsn.capabilities & (WPA_CAPABILITY_MFPR |
WPA_CAPABILITY_MFPC)) {
ret = os_snprintf(pos, end - pos, "pmf=%d\n"
@@ -4839,11 +5086,15 @@
int wpa_sm_pmf_enabled(struct wpa_sm *sm)
{
struct wpa_ie_data rsn;
+ const u8 *rsne;
+ size_t rsne_len;
- if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie)
+ rsne = wpa_sm_get_ap_rsne(sm, &rsne_len);
+
+ if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !rsne)
return 0;
- if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 &&
+ if (wpa_parse_wpa_ie_rsn(rsne, rsne_len, &rsn) >= 0 &&
rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC))
return 1;
@@ -4851,6 +5102,17 @@
}
+bool wpa_sm_rsn_overriding_supported(struct wpa_sm *sm)
+{
+ const u8 *rsne;
+ size_t rsne_len;
+
+ rsne = wpa_sm_get_ap_rsne(sm, &rsne_len);
+
+ return sm->rsn_override_support && rsne;
+}
+
+
int wpa_sm_ext_key_id(struct wpa_sm *sm)
{
return sm ? sm->ext_key_id : 0;
@@ -4866,12 +5128,14 @@
int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
struct wpa_ie_data rsn;
+ const u8 *rsne;
+ size_t rsne_len;
- if (!sm->ocv || !sm->ap_rsn_ie)
+ rsne = wpa_sm_get_ap_rsne(sm, &rsne_len);
+ if (!sm->ocv || !rsne)
return 0;
- return wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len,
- &rsn) >= 0 &&
+ return wpa_parse_wpa_ie_rsn(rsne, rsne_len, &rsn) >= 0 &&
(rsn.capabilities & WPA_CAPABILITY_OCVC);
}
@@ -5108,24 +5372,11 @@
sm->ap_rsn_ie_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len);
- if (ie[0] == WLAN_EID_VENDOR_SPECIFIC && len > 2 + 4) {
- sm->ap_rsn_ie = os_malloc(len - 4);
- if (!sm->ap_rsn_ie)
- return -1;
- sm->ap_rsn_ie[0] = WLAN_EID_RSN;
- sm->ap_rsn_ie[1] = len - 2 - 4;
- os_memcpy(&sm->ap_rsn_ie[2], ie + 2 + 4, len - 2 - 4);
- sm->ap_rsn_ie_len = len - 4;
- wpa_hexdump(MSG_DEBUG,
- "RSN: Converted RSNE override to RSNE",
- sm->ap_rsn_ie, sm->ap_rsn_ie_len);
- } else {
- sm->ap_rsn_ie = os_memdup(ie, len);
- if (sm->ap_rsn_ie == NULL)
- return -1;
+ sm->ap_rsn_ie = os_memdup(ie, len);
+ if (sm->ap_rsn_ie == NULL)
+ return -1;
- sm->ap_rsn_ie_len = len;
- }
+ sm->ap_rsn_ie_len = len;
}
return 0;
@@ -5154,24 +5405,86 @@
sm->ap_rsnxe_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "WPA: set AP RSNXE", ie, len);
- if (ie[0] == WLAN_EID_VENDOR_SPECIFIC && len > 2 + 4) {
- sm->ap_rsnxe = os_malloc(len - 4);
- if (!sm->ap_rsnxe)
- return -1;
- sm->ap_rsnxe[0] = WLAN_EID_RSNX;
- sm->ap_rsnxe[1] = len - 2 - 4;
- os_memcpy(&sm->ap_rsnxe[2], ie + 2 + 4, len - 2 - 4);
- sm->ap_rsnxe_len = len - 4;
- wpa_hexdump(MSG_DEBUG,
- "RSN: Converted RSNXE override to RSNXE",
- sm->ap_rsnxe, sm->ap_rsnxe_len);
- } else {
- sm->ap_rsnxe = os_memdup(ie, len);
- if (!sm->ap_rsnxe)
- return -1;
+ sm->ap_rsnxe = os_memdup(ie, len);
+ if (!sm->ap_rsnxe)
+ return -1;
- sm->ap_rsnxe_len = len;
- }
+ sm->ap_rsnxe_len = len;
+ }
+
+ return 0;
+}
+
+
+int wpa_sm_set_ap_rsne_override(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->ap_rsne_override);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Clearing AP RSNE Override element");
+ sm->ap_rsne_override = NULL;
+ sm->ap_rsne_override_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "RSN: Set AP RSNE Override element",
+ ie, len);
+ sm->ap_rsne_override = os_memdup(ie, len);
+ if (!sm->ap_rsne_override)
+ return -1;
+
+ sm->ap_rsne_override_len = len;
+ }
+
+ return 0;
+}
+
+
+int wpa_sm_set_ap_rsne_override_2(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->ap_rsne_override_2);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Clearing AP RSNE Override 2 element");
+ sm->ap_rsne_override_2 = NULL;
+ sm->ap_rsne_override_2_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "RSN: Set AP RSNE Override 2 element",
+ ie, len);
+ sm->ap_rsne_override_2 = os_memdup(ie, len);
+ if (!sm->ap_rsne_override_2)
+ return -1;
+
+ sm->ap_rsne_override_2_len = len;
+ }
+
+ return 0;
+}
+
+
+int wpa_sm_set_ap_rsnxe_override(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->ap_rsnxe_override);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Clearing AP RSNXE Override element");
+ sm->ap_rsnxe_override = NULL;
+ sm->ap_rsnxe_override_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "RSN: Set AP RSNXE Override element",
+ ie, len);
+ sm->ap_rsnxe_override = os_memdup(ie, len);
+ if (!sm->ap_rsnxe_override)
+ return -1;
+
+ sm->ap_rsnxe_override_len = len;
}
return 0;
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 231e088..ca64d8f 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -137,6 +137,15 @@
WPA_PARAM_ENCRYPT_EAPOL_M4,
WPA_PARAM_FT_PREPEND_PMKID,
WPA_PARAM_SSID_PROTECTION,
+ WPA_PARAM_RSN_OVERRIDE,
+ WPA_PARAM_RSN_OVERRIDE_SUPPORT,
+};
+
+enum wpa_rsn_override {
+ RSN_OVERRIDE_NOT_USED,
+ RSN_OVERRIDE_RSNE,
+ RSN_OVERRIDE_RSNE_OVERRIDE,
+ RSN_OVERRIDE_RSNE_OVERRIDE_2,
};
struct rsn_supp_config {
@@ -160,8 +169,9 @@
struct wpa_sm_link {
u8 addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
- u8 *ap_rsne, *ap_rsnxe;
- size_t ap_rsne_len, ap_rsnxe_len;
+ u8 *ap_rsne, *ap_rsnxe, *ap_rsnoe, *ap_rsno2e, *ap_rsnxoe;
+ size_t ap_rsne_len, ap_rsnxe_len, ap_rsnoe_len, ap_rsno2e_len,
+ ap_rsnxoe_len;;
struct wpa_gtk gtk;
struct wpa_gtk gtk_wnm_sleep;
struct wpa_igtk igtk;
@@ -204,6 +214,9 @@
int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_rsne_override(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_rsne_override_2(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_rsnxe_override(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
@@ -353,6 +366,24 @@
return -1;
}
+static inline int wpa_sm_set_ap_rsne_override(struct wpa_sm *sm, const u8 *ie,
+ size_t len)
+{
+ return -1;
+}
+
+static inline int wpa_sm_set_ap_rsne_override_2(struct wpa_sm *sm, const u8 *ie,
+ size_t len)
+{
+ return -1;
+}
+
+static inline int wpa_sm_set_ap_rsnxe_override(struct wpa_sm *sm, const u8 *ie,
+ size_t len)
+{
+ return -1;
+}
+
static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{
return 0;
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index d7e7805..ef26b24 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -120,6 +120,9 @@
size_t assoc_rsnxe_len;
u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
+ u8 *ap_rsne_override, *ap_rsne_override_2, *ap_rsnxe_override;
+ size_t ap_rsne_override_len, ap_rsne_override_2_len,
+ ap_rsnxe_override_len;
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
@@ -229,6 +232,9 @@
bool wmm_enabled;
bool driver_bss_selection;
bool ft_prepend_pmkid;
+
+ bool rsn_override_support;
+ enum wpa_rsn_override rsn_override;
};
@@ -542,5 +548,6 @@
void wpa_tdls_assoc(struct wpa_sm *sm);
void wpa_tdls_disassoc(struct wpa_sm *sm);
+bool wpa_sm_rsn_overriding_supported(struct wpa_sm *sm);
#endif /* WPA_I_H */
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index 8c50031..5361289 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -57,6 +57,31 @@
soc_specific: true,
}
+cc_library_headers {
+ name: "wpa_supplicant_headers_mainline",
+ export_include_dirs: [
+ ".",
+ "src",
+ "src/common",
+ "src/drivers",
+ "src/eap_common",
+ "src/eapol_supp",
+ "src/eap_peer",
+ "src/eap_server",
+ "src/l2_packet",
+ "src/radius",
+ "src/rsn_supp",
+ "src/tls",
+ "src/utils",
+ "src/wps",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.wifi",
+ ],
+ min_sdk_version: "30",
+}
+
filegroup {
name: "wpa_supplicant_template.conf",
srcs: ["wpa_supplicant_template.conf"],
@@ -129,7 +154,6 @@
"-DCONFIG_NO_RADIUS",
"-DCONFIG_NO_RADIUS",
"-DCONFIG_NO_RANDOM_POOL",
- "-DCONFIG_NO_ROAMING",
"-DCONFIG_NO_VLAN",
"-DCONFIG_OFFCHANNEL",
"-DCONFIG_OWE",
@@ -161,6 +185,7 @@
"-DEAP_MSCHAPv2",
"-DEAP_OTP",
"-DEAP_PEAP",
+ "-DCONFIG_PTKSA_CACHE",
"-DEAP_PWD",
"-DEAP_SERVER",
"-DEAP_SERVER_IDENTITY",
@@ -199,6 +224,21 @@
any @ driver: ["-D" + driver],
// Flag is optional, so no default value provided.
default: [],
+ }) +
+ select(soong_config_variable("wpa_supplicant", "roaming"), {
+ true: [],
+ default: ["-DCONFIG_NO_ROAMING"],
+ }) +
+ select(soong_config_variable("wpa_supplicant", "pasn"), {
+ false: [],
+ default: ["-DCONFIG_PASN"],
+ }) +
+ select(soong_config_variable("wpa_supplicant", "bgscan_simple"), {
+ true: [
+ "-DCONFIG_BGSCAN",
+ "-DCONFIG_BGSCAN_SIMPLE",
+ ],
+ default: [],
}),
// Similar to suppressing clang compiler warnings, here we
// suppress clang-tidy warnings to reduce noises in Android build.log.
@@ -264,7 +304,6 @@
"src/ap/ap_drv_ops.c",
"src/ap/ap_list.c",
"src/ap/comeback_token.c",
- "src/pasn/pasn_responder.c",
"src/ap/ap_mlme.c",
"src/ap/authsrv.c",
"src/ap/beacon.c",
@@ -432,7 +471,24 @@
"wpas_glue.c",
"wpa_supplicant.c",
"wps_supplicant.c",
- ],
+ ] +
+ select(soong_config_variable("wpa_supplicant", "bgscan_simple"), {
+ true: [
+ "bgscan.c",
+ "bgscan_simple.c",
+ ],
+ default: [],
+ }) +
+ select(soong_config_variable("wpa_supplicant", "pasn"), {
+ false: [],
+ default: [
+ "pasn_supplicant.c",
+ "src/pasn/pasn_initiator.c",
+ "src/pasn/pasn_responder.c",
+ "src/pasn/pasn_common.c",
+ ],
+ }),
+
}
// Generated by building wpa_cli and printing LOCAL_SRC_FILES
@@ -467,3 +523,960 @@
],
soc_specific: true,
}
+
+cc_library {
+ name: "libpasn",
+ vendor: true,
+ cflags: [
+ "-DANDROID_LOG_NAME=\"libpasn\"",
+ "-DANDROID_P2P",
+ "-DCONFIG_ACS",
+ "-DCONFIG_ANDROID_LOG",
+ "-DCONFIG_AP",
+ "-DCONFIG_BACKEND_FILE",
+ "-DCONFIG_CTRL_IFACE",
+ "-DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/vendor/wifi/wpa/sockets\"",
+ "-DCONFIG_CTRL_IFACE_DIR=\"/data/vendor/wifi/wpa/sockets\"",
+ "-DCONFIG_CTRL_IFACE_AIDL",
+ "-DCONFIG_CTRL_IFACE_UNIX",
+ "-DCONFIG_DPP",
+ "-DCONFIG_DPP2",
+ "-DCONFIG_DRIVER_NL80211",
+ "-DCONFIG_ECC",
+ "-DCONFIG_ERP",
+ "-DCONFIG_FILS",
+ "-DCONFIG_GAS",
+ "-DCONFIG_GAS_SERVER",
+ "-DCONFIG_AIDL",
+ "-DCONFIG_HMAC_SHA256_KDF",
+ "-DCONFIG_HMAC_SHA384_KDF",
+ "-DCONFIG_HMAC_SHA512_KDF",
+ "-DCONFIG_HS20",
+ "-DCONFIG_IEEE80211AC",
+ "-DCONFIG_IEEE80211R",
+ "-DCONFIG_INTERWORKING",
+ "-DCONFIG_IPV6",
+ "-DCONFIG_JSON",
+ "-DCONFIG_MBO",
+ "-DCONFIG_NO_ACCOUNTING",
+ "-DCONFIG_NO_RADIUS",
+ "-DCONFIG_NO_RADIUS",
+ "-DCONFIG_NO_RANDOM_POOL",
+ "-DCONFIG_NO_ROAMING",
+ "-DCONFIG_NO_VLAN",
+ "-DCONFIG_OFFCHANNEL",
+ "-DCONFIG_OWE",
+ "-DCONFIG_P2P",
+ "-DCONFIG_SAE",
+ "-DCONFIG_SAE_PK",
+ "-DCONFIG_SHA256",
+ "-DCONFIG_SHA384",
+ "-DCONFIG_SHA512",
+ "-DCONFIG_SMARTCARD",
+ "-DCONFIG_SME",
+ "-DCONFIG_SUITEB",
+ "-DCONFIG_SUITEB192",
+ "-DCONFIG_TDLS",
+ "-DCONFIG_WEP",
+ "-DCONFIG_WIFI_DISPLAY",
+ "-DCONFIG_WNM",
+ "-DCONFIG_WPA_CLI_HISTORY_DIR=\"/data/vendor/wifi/wpa\"",
+ "-DCONFIG_WPS",
+ "-DCONFIG_WPS_ER",
+ "-DCONFIG_WPS_NFC",
+ "-DCONFIG_WPS_OOB",
+ "-DCONFIG_WPS_UPNP",
+ "-DEAP_AKA",
+ "-DEAP_AKA_PRIME",
+ "-DEAP_GTC",
+ "-DEAP_LEAP",
+ "-DEAP_MD5",
+ "-DEAP_MSCHAPv2",
+ "-DEAP_OTP",
+ "-DEAP_PEAP",
+ "-DCONFIG_PASN",
+ "-DCONFIG_PTKSA_CACHE",
+ "-DEAP_PWD",
+ "-DEAP_SERVER",
+ "-DEAP_SERVER_IDENTITY",
+ "-DEAP_SERVER_WSC",
+ "-DEAP_SIM",
+ "-DEAP_TLS",
+ "-DEAP_TLS_OPENSSL",
+ "-DEAP_TTLS",
+ "-DEAP_WSC",
+ "-DIEEE8021X_EAPOL",
+ "-DNEED_AP_MLME",
+ "-DPKCS12_FUNCS",
+ "-DTLS_DEFAULT_CIPHERS=\"DEFAULT:!EXP:!LOW\"",
+ "-DWPA_IGNORE_CONFIG_ERRORS",
+ "-Wall",
+ "-Werror",
+ "-Wno-error=sometimes-uninitialized",
+ "-Wno-incompatible-pointer-types",
+ "-Wno-incompatible-pointer-types-discards-qualifiers",
+ "-Wno-macro-redefined",
+ "-Wno-parentheses-equality",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-variable",
+ ],
+ product_variables: {
+ debuggable: {
+ cflags: ["-DLOG_NDEBUG=0"],
+ },
+ },
+ local_include_dirs: [
+ ".",
+ "src",
+ "src/common",
+ "src/drivers",
+ "src/eap_common",
+ "src/eapol_supp",
+ "src/eap_peer",
+ "src/eap_server",
+ "src/l2_packet",
+ "src/radius",
+ "src/rsn_supp",
+ "src/tls",
+ "src/utils",
+ "src/wps",
+ ],
+ srcs: [
+ "src/utils/eloop.c",
+ "src/utils/wpa_debug.c",
+ "src/utils/wpabuf.c",
+ "src/utils/os_unix.c",
+ "src/utils/config.c",
+ "src/utils/common.c",
+ "src/utils/base64.c",
+ "src/common/sae.c",
+ "src/common/sae_pk.c",
+ "src/common/wpa_common.c",
+ "src/common/ieee802_11_common.c",
+ "src/common/dragonfly.c",
+ "src/common/ptksa_cache.c",
+ "src/rsn_supp/pmksa_cache.c",
+ "src/rsn_supp/wpa_ie.c",
+ "src/ap/comeback_token.c",
+ "src/ap/pmksa_cache_auth.c",
+ "src/eap_common/eap_common.c",
+ "src/eap_common/chap.c",
+ "src/eap_peer/eap.c",
+ "src/eap_peer/eap_methods.c",
+ "src/eapol_supp/eapol_supp_sm.c",
+ "src/crypto/crypto_openssl.c",
+ "src/crypto/tls_openssl.c",
+ "src/crypto/tls_openssl_ocsp.c",
+ "src/crypto/sha256-tlsprf.c",
+ "src/crypto/sha512-prf.c",
+ "src/crypto/sha384-prf.c",
+ "src/crypto/sha256-prf.c",
+ "src/crypto/sha512-kdf.c",
+ "src/crypto/sha384-kdf.c",
+ "src/crypto/sha256-kdf.c",
+ "src/crypto/dh_groups.c",
+ "src/crypto/aes-siv.c",
+ "src/crypto/aes-ctr.c",
+ "src/crypto/sha1-prf.c",
+ "src/crypto/sha1-tlsprf.c",
+ "src/pasn/pasn_initiator.c",
+ "src/pasn/pasn_responder.c",
+ "src/pasn/pasn_common.c",
+ ],
+ shared_libs: [
+ "libc",
+ "libcutils",
+ "liblog",
+ "libcrypto",
+ "libssl",
+ "libkeystore-engine-wifi-hidl",
+ ],
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
+
+// For converting the default to soong
+cc_defaults {
+ name: "wpa_supplicant_driver_srcs_default",
+ srcs: [
+ "src/drivers/driver_nl80211.c",
+ "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/linux_ioctl.c",
+ "src/drivers/netlink.c",
+ "src/drivers/rfkill.c",
+ "src/utils/radiotap.c",
+ ],
+}
+
+cc_defaults {
+ name: "wpa_supplicant_driver_cflags_default",
+ cflags: [
+ "-DCONFIG_DRIVER_NL80211",
+ // Because the original Android.mk will call hostapd's Android.mk first and it
+ // will make the flag share with wpa_supplicant, keep the original logic in hostapd.
+ ] + select(soong_config_variable("wpa_supplicant_8", "board_wlan_device"), {
+ "bcmdhd": ["-DCONFIG_DRIVER_NL80211_BRCM"],
+ "synadhd": ["-DCONFIG_DRIVER_NL80211_SYNA"],
+ "qcwcn": ["-DCONFIG_DRIVER_NL80211_QCA"],
+ default: ["-DCONFIG_DRIVER_NL80211_QCA"],
+ }),
+}
+
+cc_defaults {
+ name: "wpa_supplicant_includes_default",
+ local_include_dirs: [
+ ".",
+ "src",
+ "src/common",
+ "src/drivers",
+ "src/eap_common",
+ "src/eap_peer",
+ "src/eap_server",
+ "src/eapol_supp",
+ "src/l2_packet",
+ "src/pasn",
+ "src/radius",
+ "src/rsn_supp",
+ "src/tls",
+ "src/utils",
+ "src/wps",
+ ],
+ include_dirs: [
+ // There's an if condition for external/libnl but current code base should always have this.
+ "external/libnl/include",
+ "system/security/keystore/include",
+ ],
+}
+
+soong_config_module_type {
+ name: "wpa_supplicant_cc_defaults_type",
+ module_type: "cc_defaults",
+ config_namespace: "wpa_supplicant_8",
+ value_variables: [
+ "platform_version",
+ ],
+ properties: ["cflags"],
+}
+
+// Hostap related module share the same CFLAGS
+wpa_supplicant_cc_defaults_type {
+ name: "wpa_supplicant_no_aidl_cflags_default",
+ cflags: [
+ "-DANDROID_LOG_NAME=\"wpa_supplicant\"",
+ "-DANDROID_P2P",
+ "-DCONFIG_ACS",
+ "-DCONFIG_ANDROID_LOG",
+ "-DCONFIG_AP",
+ "-DCONFIG_BACKEND_FILE",
+ "-DCONFIG_CTRL_IFACE",
+ "-DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/vendor/wifi/wpa/sockets\"",
+ "-DCONFIG_CTRL_IFACE_DIR=\"/data/vendor/wifi/wpa/sockets\"",
+ "-DCONFIG_CTRL_IFACE_UNIX",
+ "-DCONFIG_DPP",
+ "-DCONFIG_DPP2",
+ "-DCONFIG_DRIVER_NL80211",
+ "-DCONFIG_DRIVER_NL80211_QCA",
+ "-DCONFIG_ECC",
+ "-DCONFIG_ERP",
+ "-DCONFIG_FILS",
+ "-DCONFIG_GAS",
+ "-DCONFIG_GAS_SERVER",
+ "-DCONFIG_HMAC_SHA256_KDF",
+ "-DCONFIG_HMAC_SHA384_KDF",
+ "-DCONFIG_HMAC_SHA512_KDF",
+ "-DCONFIG_HS20",
+ "-DCONFIG_IEEE80211AC",
+ "-DCONFIG_IEEE80211R",
+ "-DCONFIG_INTERWORKING",
+ "-DCONFIG_IPV6",
+ "-DCONFIG_JSON",
+ "-DCONFIG_MBO",
+ "-DCONFIG_NO_ACCOUNTING",
+ "-DCONFIG_NO_RADIUS",
+ "-DCONFIG_NO_RADIUS",
+ "-DCONFIG_NO_RANDOM_POOL",
+ "-DCONFIG_NO_ROAMING",
+ "-DCONFIG_NO_VLAN",
+ "-DCONFIG_OFFCHANNEL",
+ "-DCONFIG_OWE",
+ "-DCONFIG_P2P",
+ "-DCONFIG_PASN",
+ "-DCONFIG_PTKSA_CACHE",
+ "-DCONFIG_SAE",
+ "-DCONFIG_SAE_PK",
+ "-DCONFIG_SHA256",
+ "-DCONFIG_SHA384",
+ "-DCONFIG_SHA512",
+ "-DCONFIG_SMARTCARD",
+ "-DCONFIG_SME",
+ "-DCONFIG_SUITEB",
+ "-DCONFIG_SUITEB192",
+ "-DCONFIG_TDLS",
+ "-DCONFIG_WEP",
+ "-DCONFIG_WIFI_DISPLAY",
+ "-DCONFIG_WNM",
+ "-DCONFIG_WPA_CLI_HISTORY_DIR=\"/data/vendor/wifi/wpa\"",
+ "-DCONFIG_WPS",
+ "-DCONFIG_WPS_ER",
+ "-DCONFIG_WPS_NFC",
+ "-DCONFIG_WPS_OOB",
+ "-DCONFIG_WPS_UPNP",
+ "-DCRYPTO_RSA_OAEP_SHA256",
+ "-DEAP_AKA",
+ "-DEAP_AKA_PRIME",
+ "-DEAP_GTC",
+ "-DEAP_LEAP",
+ "-DEAP_MD5",
+ "-DEAP_MSCHAPv2",
+ "-DEAP_OTP",
+ "-DEAP_PEAP",
+ "-DEAP_PWD",
+ "-DEAP_SERVER",
+ "-DEAP_SERVER_IDENTITY",
+ "-DEAP_SERVER_WSC",
+ "-DEAP_SIM",
+ "-DEAP_TLS",
+ "-DEAP_TLSV1_3",
+ "-DEAP_TLS_OPENSSL",
+ "-DEAP_TTLS",
+ "-DEAP_WSC",
+ "-DIEEE8021X_EAPOL",
+ "-DNEED_AP_MLME",
+ "-DPKCS12_FUNCS",
+ "-DTLS_DEFAULT_CIPHERS=\"DEFAULT:!EXP:!LOW\"",
+ "-DWPA_IGNORE_CONFIG_ERRORS",
+ "-Wall",
+ "-Werror",
+ "-Wno-error=sometimes-uninitialized",
+ "-Wno-incompatible-pointer-types",
+ "-Wno-incompatible-pointer-types-discards-qualifiers",
+ "-Wno-macro-redefined",
+ "-Wno-parentheses-equality",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-variable",
+ ] + select(soong_config_variable("wpa_supplicant_8", "wpa_supplicant_use_stub_lib"), {
+ true: ["-DANDROID_LIB_STUB"],
+ default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "board_hostapd_config_80211w_mfp_optional"), {
+ true: ["-DENABLE_HOSTAPD_CONFIG_80211W_MFP_OPTIONAL"],
+ default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "board_wpa_supplicant_private_lib_event"), {
+ true: ["-DANDROID_LIB_EVENT"],
+ default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "wifi_priv_cmd_update_mbo_cell_status"), {
+ true: ["-DENABLE_PRIV_CMD_UPDATE_MBO_CELL_STATUS"],
+ default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "hostapd_11ax"), {
+ true: ["-DCONFIG_IEEE80211AX"],
+ default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "wifi_brcm_open_source_multi_akm"), {
+ true: ["-DWIFI_BRCM_OPEN_SOURCE_MULTI_AKM"],
+ default: [],
+ }),
+ arch: {
+ arm: {
+ cflags: [
+ "-mabi=aapcs-linux",
+ ],
+ },
+ },
+ defaults: [
+ "wpa_supplicant_driver_cflags_default",
+ ],
+ soong_config_variables: {
+ platform_version: {
+ cflags: ["-DVERSION_STR_POSTFIX=\"-%s\""],
+ },
+ },
+}
+
+cc_defaults {
+ name: "wpa_supplicant_cflags_default",
+ cflags: [
+ "-DCONFIG_AIDL",
+ "-DCONFIG_CTRL_IFACE_AIDL",
+ ],
+ defaults: [
+ "wpa_supplicant_no_aidl_cflags_default",
+ ],
+}
+
+wpa_supplicant_cc_defaults_type {
+ name: "wpa_supplicant_mainline_cflags_default",
+ cflags: [
+ "-DANDROID_LIB_STUB",
+ "-DANDROID_LOG_NAME=\"mainline_supplicant\"",
+ "-DCONFIG_ANDROID_LOG",
+ "-DCONFIG_BACKEND_FILE",
+ "-DCONFIG_CTRL_IFACE",
+ "-DCONFIG_CTRL_IFACE_UNIX",
+ "-DCONFIG_DRIVER_NL80211",
+ "-DCONFIG_NO_ACCOUNTING",
+ "-DCONFIG_NO_CONFIG_BLOBS",
+ "-DCONFIG_NO_CONFIG_WRITE",
+ "-DCONFIG_NO_RADIUS",
+ "-DCONFIG_NO_RANDOM_POOL",
+ "-DCONFIG_NO_ROAMING",
+ "-DCONFIG_NO_ROBUST_AV",
+ "-DCONFIG_NO_RRM",
+ "-DCONFIG_NO_SCAN_PROCESSING",
+ "-DCONFIG_NO_TKIP",
+ "-DCONFIG_NO_VLAN",
+ "-DCONFIG_NO_WMM_AC",
+ "-DCONFIG_NO_WPA",
+ "-DCONFIG_NO_WPA_PASSPHRASE",
+ "-DCONFIG_OFFCHANNEL",
+ "-DMAINLINE_SUPPLICANT",
+ "-DOPENSSL_NO_ENGINE",
+ "-DWPA_IGNORE_CONFIG_ERRORS",
+ "-Wall",
+ "-Werror",
+ "-Wno-error=sometimes-uninitialized",
+ "-Wno-incompatible-pointer-types",
+ "-Wno-incompatible-pointer-types-discards-qualifiers",
+ "-Wno-macro-redefined",
+ "-Wno-parentheses-equality",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-variable",
+ ],
+}
+
+cc_defaults {
+ name: "wpa_supplicant_srcs_default",
+ srcs: [
+ "ap.c",
+ "bss.c",
+ "bssid_ignore.c",
+ "config.c",
+ "config_file.c",
+ "ctrl_iface.c",
+ "ctrl_iface_unix.c",
+ "dpp_supplicant.c",
+ "eap_register.c",
+ "events.c",
+ "gas_query.c",
+ "hs20_supplicant.c",
+ "interworking.c",
+ "main.c",
+ "mbo.c",
+ "notify.c",
+ "offchannel.c",
+ "op_classes.c",
+ "p2p_supplicant.c",
+ "p2p_supplicant_sd.c",
+ "pasn_supplicant.c",
+ "robust_av.c",
+ "rrm.c",
+ "scan.c",
+ "sme.c",
+ "twt.c",
+ "wifi_display.c",
+ "wmm_ac.c",
+ "wnm_sta.c",
+ "wpa_supplicant.c",
+ "wpas_glue.c",
+ "wps_supplicant.c",
+ "src/ap/acs.c",
+ "src/ap/ap_config.c",
+ "src/ap/ap_drv_ops.c",
+ "src/ap/ap_list.c",
+ "src/ap/ap_mlme.c",
+ "src/ap/authsrv.c",
+ "src/ap/beacon.c",
+ "src/ap/bss_load.c",
+ "src/ap/comeback_token.c",
+ "src/ap/ctrl_iface_ap.c",
+ "src/ap/dfs.c",
+ "src/ap/dpp_hostapd.c",
+ "src/ap/drv_callbacks.c",
+ "src/ap/eap_user_db.c",
+ "src/ap/fils_hlp.c",
+ "src/ap/gas_query_ap.c",
+ "src/ap/gas_serv.c",
+ "src/ap/hostapd.c",
+ "src/ap/hs20.c",
+ "src/ap/hw_features.c",
+ "src/ap/ieee802_11.c",
+ "src/ap/ieee802_11_auth.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/mbo_ap.c",
+ "src/ap/neighbor_db.c",
+ "src/ap/p2p_hostapd.c",
+ "src/ap/pmksa_cache_auth.c",
+ "src/ap/rrm.c",
+ "src/ap/sta_info.c",
+ "src/ap/tkip_countermeasures.c",
+ "src/ap/utils.c",
+ "src/ap/wmm.c",
+ "src/ap/wpa_auth.c",
+ "src/ap/wpa_auth_glue.c",
+ "src/ap/wpa_auth_ie.c",
+ "src/ap/wps_hostapd.c",
+ "src/common/ctrl_iface_common.c",
+ "src/common/dpp.c",
+ "src/common/dpp_auth.c",
+ "src/common/dpp_backup.c",
+ "src/common/dpp_crypto.c",
+ "src/common/dpp_pkex.c",
+ "src/common/dpp_reconfig.c",
+ "src/common/dpp_tcp.c",
+ "src/common/dragonfly.c",
+ "src/common/gas.c",
+ "src/common/gas_server.c",
+ "src/common/hw_features_common.c",
+ "src/common/ieee802_11_common.c",
+ "src/common/ptksa_cache.c",
+ "src/common/sae.c",
+ "src/common/sae_pk.c",
+ "src/common/wpa_common.c",
+ "src/crypto/aes-ctr.c",
+ "src/crypto/aes-siv.c",
+ "src/crypto/crypto_openssl.c",
+ "src/crypto/dh_groups.c",
+ "src/crypto/fips_prf_openssl.c",
+ "src/crypto/ms_funcs.c",
+ "src/crypto/sha1-prf.c",
+ "src/crypto/sha1-tlsprf.c",
+ "src/crypto/sha256-kdf.c",
+ "src/crypto/sha256-prf.c",
+ "src/crypto/sha256-tlsprf.c",
+ "src/crypto/sha384-kdf.c",
+ "src/crypto/sha384-prf.c",
+ "src/crypto/sha512-kdf.c",
+ "src/crypto/sha512-prf.c",
+ "src/crypto/tls_openssl.c",
+ "src/crypto/tls_openssl_ocsp.c",
+ "src/drivers/driver_common.c",
+ "src/drivers/driver_nl80211.c",
+ "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/drivers.c",
+ "src/drivers/linux_ioctl.c",
+ "src/drivers/netlink.c",
+ "src/drivers/rfkill.c",
+ "src/eap_common/chap.c",
+ "src/eap_common/eap_common.c",
+ "src/eap_common/eap_peap_common.c",
+ "src/eap_common/eap_pwd_common.c",
+ "src/eap_common/eap_sim_common.c",
+ "src/eap_common/eap_wsc_common.c",
+ "src/eap_peer/eap.c",
+ "src/eap_peer/eap_aka.c",
+ "src/eap_peer/eap_gtc.c",
+ "src/eap_peer/eap_leap.c",
+ "src/eap_peer/eap_md5.c",
+ "src/eap_peer/eap_methods.c",
+ "src/eap_peer/eap_mschapv2.c",
+ "src/eap_peer/eap_otp.c",
+ "src/eap_peer/eap_peap.c",
+ "src/eap_peer/eap_pwd.c",
+ "src/eap_peer/eap_sim.c",
+ "src/eap_peer/eap_tls.c",
+ "src/eap_peer/eap_tls_common.c",
+ "src/eap_peer/eap_ttls.c",
+ "src/eap_peer/eap_wsc.c",
+ "src/eap_peer/mschapv2.c",
+ "src/eap_server/eap_server.c",
+ "src/eap_server/eap_server_identity.c",
+ "src/eap_server/eap_server_methods.c",
+ "src/eap_server/eap_server_wsc.c",
+ "src/eapol_auth/eapol_auth_sm.c",
+ "src/eapol_supp/eapol_supp_sm.c",
+ "src/l2_packet/l2_packet_linux.c",
+ "src/p2p/p2p.c",
+ "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_invitation.c",
+ "src/p2p/p2p_parse.c",
+ "src/p2p/p2p_pd.c",
+ "src/p2p/p2p_sd.c",
+ "src/p2p/p2p_utils.c",
+ "src/pasn/pasn_common.c",
+ "src/pasn/pasn_initiator.c",
+ "src/pasn/pasn_responder.c",
+ "src/rsn_supp/pmksa_cache.c",
+ "src/rsn_supp/preauth.c",
+ "src/rsn_supp/tdls.c",
+ "src/rsn_supp/wpa.c",
+ "src/rsn_supp/wpa_ft.c",
+ "src/rsn_supp/wpa_ie.c",
+ "src/tls/asn1.c",
+ "src/utils/base64.c",
+ "src/utils/bitfield.c",
+ "src/utils/common.c",
+ "src/utils/config.c",
+ "src/utils/crc32.c",
+ "src/utils/eloop.c",
+ "src/utils/ip_addr.c",
+ "src/utils/json.c",
+ "src/utils/os_unix.c",
+ "src/utils/radiotap.c",
+ "src/utils/uuid.c",
+ "src/utils/wpa_debug.c",
+ "src/utils/wpabuf.c",
+ "src/wps/http_client.c",
+ "src/wps/http_server.c",
+ "src/wps/httpread.c",
+ "src/wps/ndef.c",
+ "src/wps/upnp_xml.c",
+ "src/wps/wps.c",
+ "src/wps/wps_attr_build.c",
+ "src/wps/wps_attr_parse.c",
+ "src/wps/wps_attr_process.c",
+ "src/wps/wps_common.c",
+ "src/wps/wps_dev_attr.c",
+ "src/wps/wps_enrollee.c",
+ "src/wps/wps_er.c",
+ "src/wps/wps_er_ssdp.c",
+ "src/wps/wps_registrar.c",
+ "src/wps/wps_upnp.c",
+ "src/wps/wps_upnp_ap.c",
+ "src/wps/wps_upnp_event.c",
+ "src/wps/wps_upnp_ssdp.c",
+ "src/wps/wps_upnp_web.c",
+ ] + select(soong_config_variable("wpa_supplicant_8", "hostapd_11ax"), {
+ true: ["src/ap/ieee802_11_he.c"],
+ default: [],
+ }),
+ defaults: [
+ "wpa_supplicant_driver_srcs_default",
+ ],
+}
+
+cc_defaults {
+ name: "wpa_supplicant_mainline_srcs_default",
+ srcs: [
+ "bss.c",
+ "bssid_ignore.c",
+ "config.c",
+ "config_file.c",
+ "ctrl_iface.c",
+ "ctrl_iface_unix.c",
+ "eap_register.c",
+ "events.c",
+ "main.c",
+ "notify.c",
+ "offchannel.c",
+ "op_classes.c",
+ "rrm.c",
+ "scan.c",
+ "wpa_supplicant.c",
+ "wpas_glue.c",
+ "src/common/ctrl_iface_common.c",
+ "src/common/hw_features_common.c",
+ "src/common/ieee802_11_common.c",
+ "src/common/ptksa_cache.c",
+ "src/common/wpa_common.c",
+ "src/crypto/crypto_openssl.c",
+ "src/crypto/tls_none.c",
+ "src/drivers/driver_common.c",
+ "src/drivers/driver_nl80211.c",
+ "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/drivers.c",
+ "src/drivers/linux_ioctl.c",
+ "src/drivers/netlink.c",
+ "src/drivers/rfkill.c",
+ "src/l2_packet/l2_packet_linux.c",
+ "src/rsn_supp/pmksa_cache.c",
+ "src/utils/base64.c",
+ "src/utils/bitfield.c",
+ "src/utils/common.c",
+ "src/utils/config.c",
+ "src/utils/crc32.c",
+ "src/utils/eloop.c",
+ "src/utils/ip_addr.c",
+ "src/utils/os_unix.c",
+ "src/utils/radiotap.c",
+ "src/utils/wpa_debug.c",
+ "src/utils/wpabuf.c",
+ ],
+ defaults: [
+ "wpa_supplicant_driver_srcs_default",
+ ],
+}
+
+cc_binary {
+ name: "wpa_cli",
+ proprietary: true,
+ srcs: [
+ "wpa_cli.c",
+ "src/common/cli.c",
+ "src/common/wpa_ctrl.c",
+ "src/utils/common.c",
+ "src/utils/edit.c",
+ "src/utils/eloop.c",
+ "src/utils/os_unix.c",
+ "src/utils/wpa_debug.c",
+ ],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+ defaults: [
+ "wpa_supplicant_cflags_default",
+ "wpa_supplicant_includes_default",
+ ],
+}
+
+soong_config_module_type {
+ name: "wpa_supplicant_cc_binary",
+ module_type: "cc_binary",
+ config_namespace: "wpa_supplicant_8",
+ value_variables: [
+ "board_wpa_supplicant_private_lib",
+ ],
+ bool_variables: [
+ "wifi_hidl_unified_supplicant_service_rc_entry",
+ ],
+ properties: [
+ "init_rc",
+ "static_libs",
+ ],
+}
+
+wpa_supplicant_cc_binary {
+ name: "wpa_supplicant",
+ proprietary: true,
+ relative_install_path: "hw",
+ // vintf_fragments: wpa_supplicant only
+ // vintf_fragments: ["aidl/android.hardware.wifi.supplicant.xml"],
+ required: [
+ "android.hardware.wifi.supplicant.xml",
+ ],
+ // wpa_supplicant only
+ static_libs: [
+ "libwpa_aidl",
+ ],
+ shared_libs: [
+ // Share between wpa_supplicant and wpa_supplicant_macsec
+ "libc",
+ "libcrypto",
+ "libcutils",
+ "libkeystore-engine-wifi-hidl",
+ "liblog",
+ "libnl",
+ "libssl",
+ ] + [
+ // wpa_supplicant only
+ "android.hardware.wifi.supplicant-V4-ndk",
+ "android.system.keystore2-V1-ndk",
+ "libbase",
+ "libbinder_ndk",
+ "libutils",
+ ],
+ defaults: [
+ "wpa_supplicant_srcs_default",
+ "wpa_supplicant_cflags_default",
+ "wpa_supplicant_includes_default",
+ ],
+ soong_config_variables: {
+ board_wpa_supplicant_private_lib: {
+ static_libs: ["%s"],
+ },
+ // init_rc: wpa_supplicant only
+ wifi_hidl_unified_supplicant_service_rc_entry: {
+ init_rc: ["aidl/vendor/android.hardware.wifi.supplicant-service.rc"],
+ },
+ },
+}
+
+wpa_supplicant_cc_binary {
+ name: "wpa_supplicant_macsec",
+ proprietary: true,
+ relative_install_path: "hw",
+ srcs: [
+ // wpa_supplicant_macsec only
+ ":wpa_supplicant_macsec_extra_driver_srcs",
+ "wpas_kay.c",
+ "src/ap/wpa_auth_kay.c",
+ "src/pae/ieee802_1x_cp.c",
+ "src/pae/ieee802_1x_kay.c",
+ "src/pae/ieee802_1x_key.c",
+ "src/pae/ieee802_1x_secy_ops.c",
+ "src/pae/aidl/aidl_psk.cpp",
+ ],
+ shared_libs: [
+ // Share between wpa_supplicant and wpa_supplicant_macsec
+ "libc",
+ "libcrypto",
+ "libcutils",
+ "libkeystore-engine-wifi-hidl",
+ "liblog",
+ "libnl",
+ "libssl",
+ ] + [
+ // wpa_supplicant_macsec only
+ "android.hardware.macsec-V1-ndk",
+ "libbinder_ndk",
+ ],
+ cflags: [
+ "-DCONFIG_AIDL_MACSEC_PSK_METHODS",
+ "-DCONFIG_DRIVER_MACSEC_LINUX",
+ "-DCONFIG_MACSEC",
+ ],
+ local_include_dirs: [
+ // wpa_supplicant_macsec only
+ "aidl",
+ ],
+ defaults: [
+ "wpa_supplicant_srcs_default",
+ "wpa_supplicant_includes_default",
+ "wpa_supplicant_no_aidl_cflags_default",
+ ],
+ soong_config_variables: {
+ board_wpa_supplicant_private_lib: {
+ static_libs: ["%s"],
+ },
+ },
+}
+
+wpa_supplicant_cc_binary {
+ name: "wpa_supplicant_mainline",
+ shared_libs: [
+ "android.system.wifi.mainline_supplicant-ndk",
+ "libbase",
+ "libbinder_ndk",
+ "libc",
+ "libcrypto",
+ "libcutils_sockets",
+ "liblog",
+ "libnl",
+ "libssl",
+ ],
+ static_libs: [
+ "mainline_supplicant_aidl_bp",
+ ],
+ defaults: [
+ "wpa_supplicant_mainline_srcs_default",
+ "wpa_supplicant_includes_default",
+ "wpa_supplicant_mainline_cflags_default",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.wifi",
+ ],
+ min_sdk_version: "30",
+}
+
+cc_library_shared {
+ name: "libwpa_client",
+ proprietary: true,
+ srcs: [
+ "src/common/wpa_ctrl.c",
+ "src/utils/os_unix.c",
+ ],
+ shared_libs: [
+ "libc",
+ "libcutils",
+ "liblog",
+ ],
+ defaults: [
+ "wpa_supplicant_cflags_default",
+ "wpa_supplicant_includes_default",
+ ],
+}
+
+cc_fuzz {
+ name: "mainline_supplicant_service_fuzzer",
+ team: "trendy_team_fwk_wifi_hal",
+ srcs: [
+ "aidl/mainline/fuzzers/mainline_supplicant_service_fuzzer.cpp",
+ ],
+ defaults: [
+ "fuzzer_disable_leaks",
+ "service_fuzzer_defaults",
+ "wpa_supplicant_includes_default",
+ "wpa_supplicant_mainline_cflags_default",
+ "wpa_supplicant_mainline_srcs_default",
+ ],
+ shared_libs: [
+ "android.system.wifi.mainline_supplicant-ndk",
+ "libbase",
+ "libbinder_ndk",
+ "libc",
+ "libcrypto",
+ "libcutils_sockets",
+ "liblog",
+ "libnl",
+ "libssl",
+ ],
+ static_libs: [
+ "mainline_supplicant_aidl_bp",
+ ],
+ cflags: [
+ "-DSUPPLICANT_SERVICE_FUZZER",
+ ],
+ fuzz_config: {
+ triage_assignee: "android-wifi-team@google.com",
+ },
+ proto: {
+ type: "lite",
+ static: true,
+ },
+}
+
+//## Aidl service library ###
+//#######################
+cc_library_static {
+ name: "libwpa_aidl",
+ vendor: true,
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ "-Wno-unused-variable",
+ ],
+ srcs: [
+ "aidl/vendor/aidl.cpp",
+ "aidl/vendor/aidl_manager.cpp",
+ "aidl/vendor/certificate_utils.cpp",
+ "aidl/vendor/iface_config_utils.cpp",
+ "aidl/vendor/p2p_iface.cpp",
+ "aidl/vendor/p2p_network.cpp",
+ "aidl/vendor/sta_iface.cpp",
+ "aidl/vendor/sta_network.cpp",
+ "aidl/vendor/supplicant.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.wifi.supplicant-V4-ndk",
+ "android.system.keystore2-V1-ndk",
+ "libbinder_ndk",
+ "libbase",
+ "libutils",
+ "liblog",
+ "libssl",
+ ],
+ export_include_dirs: ["aidl"],
+ defaults: [
+ "wpa_supplicant_cflags_default",
+ "wpa_supplicant_includes_default",
+ ],
+}
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index f36b074..581d907 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -18,7 +18,11 @@
CONFIG_DRIVER_NL80211_QCA=y
endif
-include $(LOCAL_PATH)/android.config
+ifneq ($(SUPPLICANT_CUSTOM_DEF_CONFIG_FILE_PATH),)
+ include $(SUPPLICANT_CUSTOM_DEF_CONFIG_FILE_PATH)
+else
+ include $(LOCAL_PATH)/android.config
+endif
# To ignore possible wrong network configurations
L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
@@ -2117,21 +2121,3 @@
$(LOCAL_PATH)/aidl
include $(BUILD_STATIC_LIBRARY)
endif # WPA_SUPPLICANT_USE_AIDL == y
-
-ifeq ($(CONFIG_PASN), y)
-include $(CLEAR_VARS)
-LOCAL_MODULE = libpasn
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-BSD SPDX-license-identifier-BSD-3-Clause SPDX-license-identifier-ISC legacy_unencumbered
-LOCAL_LICENSE_CONDITIONS := notice unencumbered
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../LICENSE
-LOCAL_VENDOR_MODULE := true
-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 libkeystore-wifi-hidl
-LOCAL_SHARED_LIBRARIES += libkeystore-engine-wifi-hidl
-endif
-include $(BUILD_SHARED_LIBRARY)
-endif # CONFIG_PASN == y
diff --git a/wpa_supplicant/aidl/mainline/Android.bp b/wpa_supplicant/aidl/mainline/Android.bp
new file mode 100644
index 0000000..a2f5370
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/Android.bp
@@ -0,0 +1,67 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// 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.
+
+cc_library_headers {
+ name: "mainline_supplicant_aidl_headers",
+ export_include_dirs: ["."],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.wifi",
+ ],
+ min_sdk_version: "30",
+}
+
+cc_library_static {
+ name: "mainline_supplicant_aidl_bp",
+ srcs: ["*.cpp"],
+ shared_libs: [
+ "android.system.wifi.mainline_supplicant-ndk",
+ "libbase",
+ "libbinder_ndk",
+ ],
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ "-Wno-unused-variable",
+ ],
+ header_libs: [
+ // Shared headers with vendor supplicant
+ "libwpa_shared_aidl_headers_mainline",
+ // Mainline supplicant headers
+ "mainline_supplicant_aidl_headers",
+ // Core supplicant headers
+ "wpa_supplicant_headers_mainline",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.wifi",
+ ],
+ min_sdk_version: "30",
+}
+
+prebuilt_etc {
+ name: "mainline_supplicant_rc",
+ src: "config/mainline_supplicant.rc",
+ filename: "mainline_supplicant.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "mainline_supplicant_conf",
+ src: "config/mainline_supplicant.conf",
+ filename: "mainline_supplicant.conf",
+ installable: false,
+}
diff --git a/wpa_supplicant/aidl/mainline/config/mainline_supplicant.conf b/wpa_supplicant/aidl/mainline/config/mainline_supplicant.conf
new file mode 100644
index 0000000..57eb059
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/config/mainline_supplicant.conf
@@ -0,0 +1,2 @@
+ctrl_interface=/data/misc/wifi/mainline_supplicant/sockets
+p2p_disabled=1
diff --git a/wpa_supplicant/aidl/mainline/config/mainline_supplicant.rc b/wpa_supplicant/aidl/mainline/config/mainline_supplicant.rc
new file mode 100644
index 0000000..8c436c6
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/config/mainline_supplicant.rc
@@ -0,0 +1,9 @@
+service wpa_supplicant_mainline /apex/com.android.wifi/bin/wpa_supplicant_mainline \
+ -O/data/misc/wifi/mainline_supplicant/sockets -dd \
+ -g@android:wpa_wlan0
+ interface aidl wifi_mainline_supplicant
+ class main
+ user root
+ socket wpa_wlan0 dgram 660 wifi wifi
+ disabled
+ oneshot
diff --git a/wpa_supplicant/aidl/mainline/fuzzers/mainline_supplicant_service_fuzzer.cpp b/wpa_supplicant/aidl/mainline/fuzzers/mainline_supplicant_service_fuzzer.cpp
new file mode 100644
index 0000000..23b16ad
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/fuzzers/mainline_supplicant_service_fuzzer.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * 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 <android/binder_interface_utils.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+
+#include "aidl/mainline/mainline_supplicant.h"
+
+extern "C"
+{
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "utils/wpa_debug.h"
+#include "wpa_supplicant_i.h"
+}
+
+using namespace android;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ struct wpa_params params;
+ os_memset(¶ms, 0, sizeof(params));
+ params.wpa_debug_level = MSG_INFO;
+
+ struct wpa_global *global = wpa_supplicant_init(¶ms);
+ if (global == NULL) {
+ return 1;
+ }
+
+ std::shared_ptr<MainlineSupplicant> service = SharedRefBase::make<MainlineSupplicant>(global);
+ fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
+ return 0;
+}
diff --git a/wpa_supplicant/aidl/mainline/mainline_supplicant.cpp b/wpa_supplicant/aidl/mainline/mainline_supplicant.cpp
new file mode 100644
index 0000000..dd2babe
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/mainline_supplicant.cpp
@@ -0,0 +1,85 @@
+/*
+ * WPA Supplicant - Mainline supplicant AIDL implementation
+ * Copyright (c) 2024, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "aidl/shared/shared_utils.h"
+#include "mainline_supplicant.h"
+#include "utils.h"
+
+using ::ndk::ScopedAStatus;
+
+const std::string kConfigFilePath = "/apex/com.android.wifi/etc/mainline_supplicant.conf";
+
+MainlineSupplicant::MainlineSupplicant(struct wpa_global* global) {
+ wpa_global_ = global;
+}
+
+ndk::ScopedAStatus MainlineSupplicant::addUsdInterface(const std::string& ifaceName) {
+ if (ifaceName.empty()) {
+ wpa_printf(MSG_ERROR, "Empty iface name provided");
+ return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+ }
+
+ if (active_usd_ifaces_.find(ifaceName) != active_usd_ifaces_.end()) {
+ wpa_printf(MSG_INFO, "Interface %s already exists", ifaceName.c_str());
+ return ndk::ScopedAStatus::ok();
+ }
+
+ if (ensureConfigFileExistsAtPath(kConfigFilePath) != 0) {
+ wpa_printf(MSG_ERROR, "Unable to find config file at %s", kConfigFilePath.c_str());
+ return createStatusWithMsg(
+ SupplicantStatusCode::FAILURE_UNKNOWN, "Config file does not exist");
+ }
+
+ struct wpa_interface iface_params = {};
+ iface_params.driver = kIfaceDriverName;
+ iface_params.ifname = ifaceName.c_str();
+ iface_params.confname = kConfigFilePath.c_str();
+
+ struct wpa_supplicant* wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
+ if (!wpa_s) {
+ wpa_printf(MSG_ERROR, "Unable to add interface %s", ifaceName.c_str());
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+
+ wpa_printf(MSG_INFO, "Interface %s was added successfully", ifaceName.c_str());
+ active_usd_ifaces_.insert(ifaceName);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus MainlineSupplicant::removeUsdInterface(const std::string& ifaceName) {
+ if (ifaceName.empty()) {
+ wpa_printf(MSG_ERROR, "Empty iface name provided");
+ return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+ }
+
+ if (active_usd_ifaces_.find(ifaceName) == active_usd_ifaces_.end()) {
+ wpa_printf(MSG_ERROR, "Interface %s does not exist", ifaceName.c_str());
+ return createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN);
+ }
+
+ struct wpa_supplicant* wpa_s =
+ wpa_supplicant_get_iface(wpa_global_, ifaceName.c_str());
+ if (!wpa_s) {
+ wpa_printf(MSG_ERROR, "Interface %s does not exist", ifaceName.c_str());
+ return createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN);
+ }
+ if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0)) {
+ wpa_printf(MSG_ERROR, "Unable to remove interface %s", ifaceName.c_str());
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+
+ wpa_printf(MSG_INFO, "Interface %s was removed successfully", ifaceName.c_str());
+ active_usd_ifaces_.erase(ifaceName);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus MainlineSupplicant::terminate() {
+ wpa_printf(MSG_INFO, "Terminating...");
+ wpa_supplicant_terminate_proc(wpa_global_);
+ return ndk::ScopedAStatus::ok();
+}
diff --git a/wpa_supplicant/aidl/mainline/mainline_supplicant.h b/wpa_supplicant/aidl/mainline/mainline_supplicant.h
new file mode 100644
index 0000000..38a355f
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/mainline_supplicant.h
@@ -0,0 +1,43 @@
+/*
+ * WPA Supplicant - Mainline supplicant AIDL implementation
+ * Copyright (c) 2024, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MAINLINE_SUPPLICANT_IMPL_H
+#define MAINLINE_SUPPLICANT_IMPL_H
+
+#include <set>
+
+#include <aidl/android/system/wifi/mainline_supplicant/BnMainlineSupplicant.h>
+#include <aidl/android/system/wifi/mainline_supplicant/SupplicantStatusCode.h>
+
+extern "C"
+{
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "utils/wpa_debug.h"
+#include "wpa_supplicant_i.h"
+#include "scan.h"
+}
+
+using ::aidl::android::system::wifi::mainline_supplicant::BnMainlineSupplicant;
+using ::aidl::android::system::wifi::mainline_supplicant::SupplicantStatusCode;
+
+class MainlineSupplicant : public BnMainlineSupplicant {
+ public:
+ MainlineSupplicant(struct wpa_global* global);
+ ndk::ScopedAStatus addUsdInterface(const std::string& ifaceName);
+ ndk::ScopedAStatus removeUsdInterface(const std::string& ifaceName);
+ ndk::ScopedAStatus terminate();
+
+ private:
+ // Raw pointer to the global structure maintained by the core
+ struct wpa_global* wpa_global_;
+ // Names of all active USD interfaces
+ std::set<std::string> active_usd_ifaces_;
+};
+
+#endif // MAINLINE_SUPPLICANT_IMPL_H
diff --git a/wpa_supplicant/aidl/mainline/service.cpp b/wpa_supplicant/aidl/mainline/service.cpp
new file mode 100644
index 0000000..da343ea
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/service.cpp
@@ -0,0 +1,91 @@
+/*
+ * WPA Supplicant - Mainline supplicant service
+ * Copyright (c) 2024, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "mainline_supplicant.h"
+
+extern "C"
+{
+#include "aidl_i.h"
+#include "service.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/includes.h"
+#include "utils/wpa_debug.h"
+}
+
+using ::ndk::SharedRefBase;
+
+/* Handler for requests to the service */
+void aidl_sock_handler(int /* sock */, void * /* eloop_ctx */, void * /* sock_ctx */) {
+ // Suppress warning, since this service is only available after Android V
+ if (__builtin_available(android __ANDROID_API_V__, *)) {
+ ABinderProcess_handlePolledCommands();
+ }
+}
+
+bool register_service(struct wpa_global *global) {
+ wpa_printf(MSG_INFO, "Registering as a lazy service");
+ std::string service_name = "wifi_mainline_supplicant";
+ std::shared_ptr<MainlineSupplicant> service = SharedRefBase::make<MainlineSupplicant>(global);
+
+ // Suppress warning, since this service is only available after Android V
+ if (__builtin_available(android __ANDROID_API_V__, *)) {
+ int status =
+ AServiceManager_registerLazyService(service->asBinder().get(), service_name.c_str());
+ if (status != EX_NONE) {
+ wpa_printf(MSG_ERROR, "Registration failed with status %d", status);
+ }
+ return status == EX_NONE;
+ }
+ return false;
+}
+
+struct wpas_aidl_priv *mainline_aidl_init(struct wpa_global *global) {
+ wpa_printf(MSG_INFO, "Initializing the mainline supplicant service");
+ struct wpas_aidl_priv *priv = (wpas_aidl_priv *)os_zalloc(sizeof(*priv));
+ if (!priv) {
+ wpa_printf(MSG_ERROR, "Unable to allocate the global AIDL object");
+ return NULL;
+ }
+ priv->global = global;
+
+ // Suppress warning, since this service is only available after Android V
+ if (__builtin_available(android __ANDROID_API_V__, *)) {
+ ABinderProcess_setupPolling(&priv->aidl_fd);
+ }
+ if (priv->aidl_fd < 0) {
+ wpa_printf(MSG_ERROR, "Unable to set up polling");
+ mainline_aidl_deinit(priv);
+ return NULL;
+ }
+
+ if (eloop_register_read_sock(priv->aidl_fd, aidl_sock_handler, global, priv) < 0) {
+ wpa_printf(MSG_ERROR, "Unable to register eloop read socket");
+ mainline_aidl_deinit(priv);
+ return NULL;
+ }
+
+ if (!register_service(global)) {
+ wpa_printf(MSG_ERROR, "Unable to register service");
+ mainline_aidl_deinit(priv);
+ return NULL;
+ }
+
+ wpa_printf(MSG_INFO, "AIDL setup is complete");
+ return priv;
+}
+
+void mainline_aidl_deinit(struct wpas_aidl_priv *priv) {
+ if (!priv) return;
+ wpa_printf(MSG_INFO, "Deiniting the mainline supplicant service");
+ eloop_unregister_read_sock(priv->aidl_fd);
+ os_free(priv);
+}
diff --git a/wpa_supplicant/aidl/mainline/service.h b/wpa_supplicant/aidl/mainline/service.h
new file mode 100644
index 0000000..6d213e7
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/service.h
@@ -0,0 +1,27 @@
+/*
+ * WPA Supplicant - Mainline supplicant service
+ * Copyright (c) 2024, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MAINLINE_SUPPLICANT_SERVICE_H
+#define MAINLINE_SUPPLICANT_SERVICE_H
+
+#ifdef _cplusplus
+extern "C"
+{
+#endif // _cplusplus
+
+struct wpas_aidl_priv;
+struct wpa_global;
+
+struct wpas_aidl_priv *mainline_aidl_init(struct wpa_global *global);
+void mainline_aidl_deinit(struct wpas_aidl_priv *priv);
+
+#ifdef _cplusplus
+}
+#endif // _cplusplus
+
+#endif // MAINLINE_SUPPLICANT_SERVICE_H
diff --git a/wpa_supplicant/aidl/mainline/utils.h b/wpa_supplicant/aidl/mainline/utils.h
new file mode 100644
index 0000000..703b9ee
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/utils.h
@@ -0,0 +1,25 @@
+/*
+ * WPA Supplicant - Utilities for the mainline supplicant
+ * Copyright (c) 2024, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MAINLINE_SUPPLICANT_UTILS_H
+#define MAINLINE_SUPPLICANT_UTILS_H
+
+#include <aidl/android/system/wifi/mainline_supplicant/SupplicantStatusCode.h>
+
+inline ndk::ScopedAStatus createStatus(SupplicantStatusCode statusCode) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(statusCode));
+}
+
+inline ndk::ScopedAStatus createStatusWithMsg(
+ SupplicantStatusCode statusCode, std::string msg) {
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ static_cast<int32_t>(statusCode), msg.c_str());
+}
+
+#endif // MAINLINE_SUPPLICANT_UTILS_H
diff --git a/wpa_supplicant/aidl/shared/Android.bp b/wpa_supplicant/aidl/shared/Android.bp
new file mode 100644
index 0000000..25cb5fa
--- /dev/null
+++ b/wpa_supplicant/aidl/shared/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// 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.
+
+cc_library_headers {
+ name: "libwpa_shared_aidl_headers_vendor",
+ export_include_dirs: ["."],
+ soc_specific: true,
+}
+
+cc_library_headers {
+ name: "libwpa_shared_aidl_headers_mainline",
+ export_include_dirs: ["."],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.wifi",
+ ],
+ min_sdk_version: "30",
+}
diff --git a/wpa_supplicant/aidl/aidl_i.h b/wpa_supplicant/aidl/shared/aidl_i.h
similarity index 100%
rename from wpa_supplicant/aidl/aidl_i.h
rename to wpa_supplicant/aidl/shared/aidl_i.h
diff --git a/wpa_supplicant/aidl/shared/shared_utils.h b/wpa_supplicant/aidl/shared/shared_utils.h
new file mode 100644
index 0000000..97676f4
--- /dev/null
+++ b/wpa_supplicant/aidl/shared/shared_utils.h
@@ -0,0 +1,49 @@
+/*
+ * WPA Supplicant - Shared utility functions and constants
+ * Copyright (c) 2024, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHARED_UTILS_H
+#define SHARED_UTILS_H
+
+#include <android-base/file.h>
+#include <fcntl.h>
+
+extern "C"
+{
+#include "utils/common.h"
+}
+
+constexpr char kIfaceDriverName[] = "nl80211";
+constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+
+/**
+ * Ensure that the config file at |config_file_path| exists.
+ * Returns 0 on success, or errno otherwise.
+ */
+int ensureConfigFileExistsAtPath(const std::string& config_file_path) {
+ int ret = access(config_file_path.c_str(), R_OK);
+ if (ret == 0) {
+ return 0;
+ }
+ if (errno == EACCES) {
+ ret = chmod(config_file_path.c_str(), kConfigFileMode);
+ if (ret == 0) {
+ return 0;
+ } else {
+ wpa_printf(
+ MSG_ERROR, "Cannot set RW to %s. Errno: %s",
+ config_file_path.c_str(), strerror(errno));
+ }
+ } else if (errno != ENOENT) {
+ wpa_printf(
+ MSG_ERROR, "Cannot access %s. Errno: %s",
+ config_file_path.c_str(), strerror(errno));
+ }
+ return errno;
+}
+
+#endif // SHARED_UTILS_H
diff --git a/wpa_supplicant/aidl/.clang-format b/wpa_supplicant/aidl/vendor/.clang-format
similarity index 100%
rename from wpa_supplicant/aidl/.clang-format
rename to wpa_supplicant/aidl/vendor/.clang-format
diff --git a/wpa_supplicant/aidl/Android.bp b/wpa_supplicant/aidl/vendor/Android.bp
similarity index 90%
rename from wpa_supplicant/aidl/Android.bp
rename to wpa_supplicant/aidl/vendor/Android.bp
index a2ce7e8..a972dd6 100644
--- a/wpa_supplicant/aidl/Android.bp
+++ b/wpa_supplicant/aidl/vendor/Android.bp
@@ -56,6 +56,7 @@
header_libs: [
"wpa_supplicant_headers",
"libwpa_aidl_headers",
+ "libwpa_shared_aidl_headers_vendor",
],
}
@@ -83,3 +84,10 @@
},
},
}
+
+prebuilt_etc {
+ name: "android.hardware.wifi.supplicant.xml.prebuilt",
+ src: "android.hardware.wifi.supplicant.xml",
+ relative_install_path: "vintf",
+ installable: false,
+}
diff --git a/wpa_supplicant/aidl/aidl.cpp b/wpa_supplicant/aidl/vendor/aidl.cpp
similarity index 99%
rename from wpa_supplicant/aidl/aidl.cpp
rename to wpa_supplicant/aidl/vendor/aidl.cpp
index d1cf891..a0446fe 100644
--- a/wpa_supplicant/aidl/aidl.cpp
+++ b/wpa_supplicant/aidl/vendor/aidl.cpp
@@ -14,7 +14,7 @@
extern "C"
{
#include "aidl.h"
-#include "aidl_i.h"
+#include "aidl/shared/aidl_i.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/includes.h"
diff --git a/wpa_supplicant/aidl/aidl.h b/wpa_supplicant/aidl/vendor/aidl.h
similarity index 98%
rename from wpa_supplicant/aidl/aidl.h
rename to wpa_supplicant/aidl/vendor/aidl.h
index eb1426a..71620f4 100644
--- a/wpa_supplicant/aidl/aidl.h
+++ b/wpa_supplicant/aidl/vendor/aidl.h
@@ -110,8 +110,10 @@
void wpas_aidl_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, bool conn_status_requested);
void wpas_aidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s);
+#ifdef CONFIG_DPP
void wpas_aidl_notify_dpp_connection_status_sent(struct wpa_supplicant *wpa_s,
enum dpp_status_error result);
+#endif /* CONFIG_DPP */
void wpas_aidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s);
void wpas_aidl_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s);
void wpas_aidl_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s);
@@ -124,9 +126,11 @@
void wpas_aidl_notify_dpp_config_sent_wait_response(struct wpa_supplicant *wpa_s);
void wpas_aidl_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s);
void wpas_aidl_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s);
+#ifdef CONFIG_DPP
void wpas_aidl_notify_dpp_conn_status(struct wpa_supplicant *wpa_s,
enum dpp_status_error status, const char *ssid,
const char *channel_list, unsigned short band_list[], int size);
+#endif /* CONFIG_DPP */
void wpas_aidl_notify_pmk_cache_added(
struct wpa_supplicant *wpas, struct rsn_pmksa_cache_entry *pmksa_entry);
void wpas_aidl_notify_bss_tm_status(struct wpa_supplicant *wpa_s);
@@ -274,9 +278,11 @@
{}
static void wpas_aidl_notify_dpp_config_sent(struct wpa_supplicant *wpa_s)
{}
+#ifdef CONFIG_DPP
static void wpas_aidl_notify_dpp_connection_status_sent(struct wpa_supplicant *wpa_s,
enum dpp_status_error result)
{}
+#endif /* CONFIG_DPP */
static void wpas_aidl_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
{}
static void wpas_aidl_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s)
@@ -301,10 +307,12 @@
{}
static void wpas_aidl_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s)
{}
+#ifdef CONFIG_DPP
static void wpas_aidl_notify_dpp_conn_status(struct wpa_supplicant *wpa_s,
enum dpp_status_error status, const char *ssid,
const char *channel_list, unsigned short band_list[], int size)
{}
+#endif /* CONFIG_DPP */
static void wpas_aidl_notify_pmk_cache_added(struct wpa_supplicant *wpas,
struct rsn_pmksa_cache_entry *pmksa_entry)
{}
diff --git a/wpa_supplicant/aidl/aidl_manager.cpp b/wpa_supplicant/aidl/vendor/aidl_manager.cpp
similarity index 96%
rename from wpa_supplicant/aidl/aidl_manager.cpp
rename to wpa_supplicant/aidl/vendor/aidl_manager.cpp
index 707299d..177f478 100644
--- a/wpa_supplicant/aidl/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/vendor/aidl_manager.cpp
@@ -425,6 +425,12 @@
return expected_version <= aidl_client_version;
}
+int32_t AidlManager::areAidlServiceAndClientAtLeastVersion(int32_t expected_version)
+{
+ return isAidlServiceVersionAtLeast(expected_version)
+ && isAidlClientVersionAtLeast(expected_version);
+}
+
int AidlManager::registerAidlService(struct wpa_global *global)
{
// Create the main aidl service object and register it.
@@ -1356,7 +1362,7 @@
std::back_inserter(aidl_vendor_elems));
}
- if (isAidlServiceVersionAtLeast(3) && isAidlClientVersionAtLeast(3)) {
+ if (areAidlServiceAndClientAtLeastVersion(3)) {
P2pDeviceFoundEventParams params;
params.srcAddress = macAddrToArray(addr);
params.p2pDeviceAddress = macAddrToArray(info->p2p_device_addr);
@@ -1368,6 +1374,10 @@
params.wfdDeviceInfo = aidl_peer_wfd_device_info;
params.wfdR2DeviceInfo = aidl_peer_wfd_r2_device_info;
params.vendorElemBytes = aidl_vendor_elems;
+ if (areAidlServiceAndClientAtLeastVersion(4)) {
+ // TODO Fill the field when supplicant implementation is ready
+ params.pairingBootstrappingMethods = 0;
+ }
callWithEachP2pIfaceCallback(
misc_utils::charBufToString(wpa_s->ifname),
std::bind(
@@ -1529,6 +1539,10 @@
params.p2pClientIpInfo.ipAddressMask,
params.p2pClientIpInfo.ipAddressGo);
}
+ if (areAidlServiceAndClientAtLeastVersion(4)) {
+ // TODO Fill the field when supplicant implementation is ready
+ params.keyMgmtMask = 0;
+ }
callWithEachP2pIfaceCallback(
misc_utils::charBufToString(wpa_s->ifname),
std::bind(&ISupplicantP2pIfaceCallback::onGroupStartedWithParams,
@@ -1619,7 +1633,7 @@
}
bool aidl_is_request = (request == 1);
- if (isAidlServiceVersionAtLeast(3) && isAidlClientVersionAtLeast(3)) {
+ if (areAidlServiceAndClientAtLeastVersion(3)) {
P2pProvisionDiscoveryCompletedEventParams params;
params.p2pDeviceAddress = macAddrToArray(dev_addr);
params.isRequest = aidl_is_request;
@@ -1665,6 +1679,75 @@
byteArrToVec(tlvs, tlvs_len)));
}
+void AidlManager::notifyUsdBasedServiceDiscoveryResult(
+ struct wpa_supplicant *wpa_s, const u8 *peer_addr, int subscribe_id,
+ int peer_publish_id, int srv_proto_type, const u8 *ssi, size_t ssi_len)
+{
+ // TODO define the reason and map to AIDL defenition.
+ if (!wpa_s)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ if (!areAidlServiceAndClientAtLeastVersion(4)) {
+ return;
+ }
+ // TODO Fill the fields when supplicant implementation is ready
+ P2pUsdBasedServiceDiscoveryResultParams params;
+
+ callWithEachP2pIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname),
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onUsdBasedServiceDiscoveryResult,
+ std::placeholders::_1, params));
+}
+
+void AidlManager::notifyUsdBasedServiceDiscoveryTerminated(
+ struct wpa_supplicant *wpa_s, int subscribe_id, int reason)
+{
+ // TODO define the reason and map to AIDL defenition.
+ if (!wpa_s)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ if (!areAidlServiceAndClientAtLeastVersion(4)) {
+ return;
+ }
+
+ callWithEachP2pIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname),
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onUsdBasedServiceDiscoveryTerminated,
+ std::placeholders::_1, subscribe_id, UsdTerminateReasonCode::UNKNOWN));
+}
+
+void AidlManager::notifyUsdBasedServiceAdvertisementTerminated(
+ struct wpa_supplicant *wpa_s, int publish_id, int reason)
+{
+ // TODO define the reason and map to AIDL defenition.
+ if (!wpa_s)
+ return;
+
+ if (p2p_iface_object_map_.find(wpa_s->ifname) ==
+ p2p_iface_object_map_.end())
+ return;
+
+ if (!areAidlServiceAndClientAtLeastVersion(4)) {
+ return;
+ }
+
+ callWithEachP2pIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname),
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onUsdBasedServiceAdvertisementTerminated,
+ std::placeholders::_1, publish_id, UsdTerminateReasonCode::UNKNOWN));
+}
+
void AidlManager::notifyApStaAuthorized(
struct wpa_supplicant *wpa_group_s, const u8 *sta, const u8 *p2p_dev_addr,
const u8 *ip)
@@ -1675,7 +1758,7 @@
if (!wpa_s)
return;
- if (isAidlServiceVersionAtLeast(3) && isAidlClientVersionAtLeast(3)) {
+ if (areAidlServiceAndClientAtLeastVersion(3)) {
P2pPeerClientJoinedEventParams params;
params.groupInterfaceName = misc_utils::charBufToString(wpa_group_s->ifname);
params.clientInterfaceAddress = macAddrToArray(sta);
@@ -1686,6 +1769,10 @@
os_memcpy(&aidl_ip, &ip[0], 4);
}
params.clientIpAddress = aidl_ip;
+ if (areAidlServiceAndClientAtLeastVersion(4)) {
+ // TODO Fill the field when supplicant implementation is ready
+ params.keyMgmtMask = 0;
+ }
callWithEachP2pIfaceCallback(
misc_utils::charBufToString(wpa_s->ifname),
std::bind(
@@ -1711,7 +1798,7 @@
if (!wpa_s)
return;
- if (isAidlServiceVersionAtLeast(3) && isAidlClientVersionAtLeast(3)) {
+ if (areAidlServiceAndClientAtLeastVersion(3)) {
P2pPeerClientDisconnectedEventParams params;
params.groupInterfaceName = misc_utils::charBufToString(wpa_group_s->ifname);
params.clientInterfaceAddress = macAddrToArray(sta);
@@ -2060,7 +2147,7 @@
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
// number of tbtts to milliseconds
- duration_ms = wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125;
+ duration_ms = wpa_s->wnm_disassoc_timer * beacon_int * 128 / 125;
}
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
//wnm_bss_termination_duration contains 12 bytes of BSS
diff --git a/wpa_supplicant/aidl/aidl_manager.h b/wpa_supplicant/aidl/vendor/aidl_manager.h
similarity index 97%
rename from wpa_supplicant/aidl/aidl_manager.h
rename to wpa_supplicant/aidl/vendor/aidl_manager.h
index b3dfa82..46a40aa 100644
--- a/wpa_supplicant/aidl/aidl_manager.h
+++ b/wpa_supplicant/aidl/vendor/aidl_manager.h
@@ -120,6 +120,15 @@
void notifyP2pSdResponse(
struct wpa_supplicant *wpa_s, const u8 *sa, u16 update_indic,
const u8 *tlvs, size_t tlvs_len);
+ void notifyUsdBasedServiceDiscoveryResult(
+ struct wpa_supplicant *wpa_s, const u8 *peer_addr, int subscribe_id,
+ int peer_publish_id, int srv_proto_type, const u8 *ssi, size_t ssi_len);
+ void notifyUsdBasedServiceDiscoveryTerminated(
+ struct wpa_supplicant *wpa_s, int subscribe_id,
+ int reason);
+ void notifyUsdBasedServiceAdvertisementTerminated(
+ struct wpa_supplicant *wpa_s, int publish_id,
+ int reason);
void notifyApStaAuthorized(
struct wpa_supplicant *wpa_s, const u8 *sta,
const u8 *p2p_dev_addr, const u8 *ip);
@@ -173,6 +182,7 @@
// Methods called from aidl objects.
int32_t isAidlServiceVersionAtLeast(int32_t expected_version);
int32_t isAidlClientVersionAtLeast(int32_t expected_version);
+ int32_t areAidlServiceAndClientAtLeastVersion(int32_t expected_version);
void notifyExtRadioWorkStart(struct wpa_supplicant *wpa_s, uint32_t id);
void notifyExtRadioWorkTimeout(
struct wpa_supplicant *wpa_s, uint32_t id);
diff --git a/wpa_supplicant/aidl/aidl_return_util.h b/wpa_supplicant/aidl/vendor/aidl_return_util.h
similarity index 100%
rename from wpa_supplicant/aidl/aidl_return_util.h
rename to wpa_supplicant/aidl/vendor/aidl_return_util.h
diff --git a/wpa_supplicant/aidl/android.hardware.wifi.supplicant-service.rc b/wpa_supplicant/aidl/vendor/android.hardware.wifi.supplicant-service.rc
similarity index 100%
rename from wpa_supplicant/aidl/android.hardware.wifi.supplicant-service.rc
rename to wpa_supplicant/aidl/vendor/android.hardware.wifi.supplicant-service.rc
diff --git a/wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml b/wpa_supplicant/aidl/vendor/android.hardware.wifi.supplicant.xml
similarity index 100%
rename from wpa_supplicant/aidl/android.hardware.wifi.supplicant.xml
rename to wpa_supplicant/aidl/vendor/android.hardware.wifi.supplicant.xml
diff --git a/wpa_supplicant/aidl/certificate_utils.cpp b/wpa_supplicant/aidl/vendor/certificate_utils.cpp
similarity index 100%
rename from wpa_supplicant/aidl/certificate_utils.cpp
rename to wpa_supplicant/aidl/vendor/certificate_utils.cpp
diff --git a/wpa_supplicant/aidl/certificate_utils.h b/wpa_supplicant/aidl/vendor/certificate_utils.h
similarity index 100%
rename from wpa_supplicant/aidl/certificate_utils.h
rename to wpa_supplicant/aidl/vendor/certificate_utils.h
diff --git a/wpa_supplicant/aidl/iface_config_utils.cpp b/wpa_supplicant/aidl/vendor/iface_config_utils.cpp
similarity index 100%
rename from wpa_supplicant/aidl/iface_config_utils.cpp
rename to wpa_supplicant/aidl/vendor/iface_config_utils.cpp
diff --git a/wpa_supplicant/aidl/iface_config_utils.h b/wpa_supplicant/aidl/vendor/iface_config_utils.h
similarity index 100%
rename from wpa_supplicant/aidl/iface_config_utils.h
rename to wpa_supplicant/aidl/vendor/iface_config_utils.h
diff --git a/wpa_supplicant/aidl/misc_utils.h b/wpa_supplicant/aidl/vendor/misc_utils.h
similarity index 100%
rename from wpa_supplicant/aidl/misc_utils.h
rename to wpa_supplicant/aidl/vendor/misc_utils.h
diff --git a/wpa_supplicant/aidl/p2p_iface.cpp b/wpa_supplicant/aidl/vendor/p2p_iface.cpp
similarity index 92%
rename from wpa_supplicant/aidl/p2p_iface.cpp
rename to wpa_supplicant/aidl/vendor/p2p_iface.cpp
index 7afc8a1..b1cd1cd 100644
--- a/wpa_supplicant/aidl/p2p_iface.cpp
+++ b/wpa_supplicant/aidl/vendor/p2p_iface.cpp
@@ -29,6 +29,7 @@
const char kConfigMethodStrPbc[] = "pbc";
const char kConfigMethodStrDisplay[] = "display";
const char kConfigMethodStrKeypad[] = "keypad";
+const char kConfigMethodStrNone[] = "none";
constexpr char kSetMiracastMode[] = "MIRACAST ";
constexpr uint8_t kWfdDeviceInfoSubelemId = 0;
constexpr uint8_t kWfdR2DeviceInfoSubelemId = 11;
@@ -853,6 +854,79 @@
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&P2pIface::createGroupOwnerInternal, in_groupOwnerInfo);
}
+
+::ndk::ScopedAStatus P2pIface::getFeatureSet(int64_t* _aidl_return)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::getFeatureSetInternal, _aidl_return);
+}
+
+::ndk::ScopedAStatus P2pIface::startUsdBasedServiceDiscovery(
+ const P2pUsdBasedServiceDiscoveryConfig& in_serviceDiscoveryConfig,
+ int32_t* _aidl_return)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::startUsdBasedServiceDiscoveryInternal, _aidl_return,
+ in_serviceDiscoveryConfig);
+}
+
+::ndk::ScopedAStatus P2pIface::stopUsdBasedServiceDiscovery(int32_t in_sessionId)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::stopUsdBasedServiceDiscoveryInternal, in_sessionId);
+}
+
+::ndk::ScopedAStatus P2pIface::startUsdBasedServiceAdvertisement(
+ const P2pUsdBasedServiceAdvertisementConfig& in_serviceAdvertisementConfig,
+ int32_t* _aidl_return)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::startUsdBasedServiceAdvertisementInternal, _aidl_return,
+ in_serviceAdvertisementConfig);
+}
+
+::ndk::ScopedAStatus P2pIface::stopUsdBasedServiceAdvertisement(int32_t in_sessionId)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::stopUsdBasedServiceAdvertisementInternal, in_sessionId);
+}
+
+::ndk::ScopedAStatus P2pIface::provisionDiscoveryWithParams(
+ const P2pProvisionDiscoveryParams& in_params)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::provisionDiscoveryWithParamsInternal, in_params);
+}
+
+::ndk::ScopedAStatus P2pIface::getDirInfo(P2pDirInfo* _aidl_return)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::getDirInfoInternal, _aidl_return);
+}
+
+::ndk::ScopedAStatus P2pIface::validateDirInfo(const P2pDirInfo& in_dirInfo,
+ int32_t* _aidl_return)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::validateDirInfoInternal, _aidl_return, in_dirInfo);
+}
+
+::ndk::ScopedAStatus P2pIface::reinvokePersistentGroup(
+ const P2pReinvokePersistentGroupParams& in_reinvokeGroupParams)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
+ &P2pIface::reinvokePersistentGroupInternal, in_reinvokeGroupParams);
+}
+
std::pair<std::string, ndk::ScopedAStatus> P2pIface::getNameInternal()
{
return {ifname_, ndk::ScopedAStatus::ok()};
@@ -1051,6 +1125,9 @@
case WpsProvisionMethod::KEYPAD:
wps_method = WPS_PIN_KEYPAD;
break;
+ case WpsProvisionMethod::NONE:
+ wps_method = WPS_NOT_READY;
+ break;
}
int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
@@ -1061,7 +1138,8 @@
int new_pin = wpas_p2p_connect(
wpa_s, peer_address.data(), pin, wps_method, persistent, false,
join_existing_group, false, go_intent_signed, 0, 0, -1, false, ht40,
- vht, CONF_OPER_CHWIDTH_USE_HT, he, edmg, nullptr, 0, is6GhzAllowed(wpa_s));
+ vht, CONF_OPER_CHWIDTH_USE_HT, he, edmg, nullptr, 0, is6GhzAllowed(wpa_s),
+ false, 0, NULL);
if (new_pin < 0) {
return {"", createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
@@ -1107,6 +1185,10 @@
case WpsProvisionMethod::KEYPAD:
config_method_str = kConfigMethodStrKeypad;
break;
+ // TODO Handle pairing bootstrapping method when supplicant implementation is ready
+ case WpsProvisionMethod::NONE:
+ config_method_str = kConfigMethodStrNone;
+ break;
}
if (wpas_p2p_prov_disc(
wpa_s, peer_address.data(), config_method_str,
@@ -1943,6 +2025,70 @@
groupOwnerInfo.persistent, groupOwnerInfo.persistentNetworkId);
}
+std::pair<int64_t, ndk::ScopedAStatus> P2pIface::getFeatureSetInternal()
+{
+ // TODO Fill the field when supplicant implementation is ready
+ return {0, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<uint32_t, ndk::ScopedAStatus>
+P2pIface::startUsdBasedServiceDiscoveryInternal(
+ const P2pUsdBasedServiceDiscoveryConfig& serviceDiscoveryConfig)
+{
+ // TODO Fill the field when supplicant implementation is ready
+ return {0, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus P2pIface::stopUsdBasedServiceDiscoveryInternal(
+ uint32_t sessionId)
+{
+ // TODO Fill the field when supplicant implementation is ready
+ return ndk::ScopedAStatus::ok();
+}
+
+std::pair<uint32_t, ndk::ScopedAStatus>
+P2pIface::startUsdBasedServiceAdvertisementInternal(
+ const P2pUsdBasedServiceAdvertisementConfig& serviceAdvertisementConfig)
+{
+ // TODO Fill the field when supplicant implementation is ready
+ return {0, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus P2pIface::stopUsdBasedServiceAdvertisementInternal(
+ uint32_t sessionId)
+{
+ // TODO Fill the field when supplicant implementation is ready
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus P2pIface::provisionDiscoveryWithParamsInternal(
+ const P2pProvisionDiscoveryParams& params)
+{
+ // TODO Fill the field when supplicant implementation is ready
+ return ndk::ScopedAStatus::ok();
+}
+
+std::pair<P2pDirInfo, ndk::ScopedAStatus> P2pIface::getDirInfoInternal()
+{
+ // TODO Fill the field when supplicant implementation is ready
+ P2pDirInfo dirInfo = {};
+ return {dirInfo, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<int32_t, ndk::ScopedAStatus> P2pIface::validateDirInfoInternal(
+ const P2pDirInfo& dirInfo)
+{
+ // TODO Fill the field when supplicant implementation is ready
+ return {0, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus P2pIface::reinvokePersistentGroupInternal(
+ const P2pReinvokePersistentGroupParams& reinvokeGroupParams)
+{
+ // TODO Fill the field when supplicant implementation is ready
+ return ndk::ScopedAStatus::ok();
+}
+
/**
* Retrieve the underlying |wpa_supplicant| struct
* pointer for this iface.
diff --git a/wpa_supplicant/aidl/p2p_iface.h b/wpa_supplicant/aidl/vendor/p2p_iface.h
similarity index 88%
rename from wpa_supplicant/aidl/p2p_iface.h
rename to wpa_supplicant/aidl/vendor/p2p_iface.h
index 98556d1..545a6c9 100644
--- a/wpa_supplicant/aidl/p2p_iface.h
+++ b/wpa_supplicant/aidl/vendor/p2p_iface.h
@@ -184,6 +184,22 @@
const P2pAddGroupConfigurationParams& in_groupConfigurationParams) override;
::ndk::ScopedAStatus createGroupOwner(
const P2pCreateGroupOwnerInfo& in_groupOwnerInfo) override;
+ ::ndk::ScopedAStatus getFeatureSet(int64_t* _aidl_return) override;
+ ::ndk::ScopedAStatus startUsdBasedServiceDiscovery(
+ const P2pUsdBasedServiceDiscoveryConfig& in_serviceDiscoveryConfig,
+ int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus stopUsdBasedServiceDiscovery(int32_t in_sessionId) override;
+ ::ndk::ScopedAStatus startUsdBasedServiceAdvertisement(
+ const P2pUsdBasedServiceAdvertisementConfig& in_serviceAdvertisementConfig,
+ int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus stopUsdBasedServiceAdvertisement(int32_t in_sessionId) override;
+ ::ndk::ScopedAStatus provisionDiscoveryWithParams(
+ const P2pProvisionDiscoveryParams& in_params) override;
+ ::ndk::ScopedAStatus getDirInfo(P2pDirInfo* _aidl_return) override;
+ ::ndk::ScopedAStatus validateDirInfo(const P2pDirInfo &in_dirInfo,
+ int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus reinvokePersistentGroup(
+ const P2pReinvokePersistentGroupParams& in_reinvokeGroupParams) override;
private:
@@ -316,6 +332,20 @@
const P2pAddGroupConfigurationParams& groupConfigurationParams);
ndk::ScopedAStatus createGroupOwnerInternal(
const P2pCreateGroupOwnerInfo& groupOwnerInfo);
+ std::pair<int64_t, ndk::ScopedAStatus> getFeatureSetInternal();
+ std::pair<uint32_t, ndk::ScopedAStatus> startUsdBasedServiceDiscoveryInternal(
+ const P2pUsdBasedServiceDiscoveryConfig& serviceDiscoveryConfig);
+ ::ndk::ScopedAStatus stopUsdBasedServiceDiscoveryInternal(uint32_t sessionId);
+ std::pair<uint32_t, ndk::ScopedAStatus> startUsdBasedServiceAdvertisementInternal(
+ const P2pUsdBasedServiceAdvertisementConfig& serviceAdvertisementConfig);
+ ::ndk::ScopedAStatus stopUsdBasedServiceAdvertisementInternal(uint32_t sessionId);
+ ::ndk::ScopedAStatus provisionDiscoveryWithParamsInternal(
+ const P2pProvisionDiscoveryParams& params);
+ std::pair<P2pDirInfo, ndk::ScopedAStatus> getDirInfoInternal();
+ std::pair<int32_t, ndk::ScopedAStatus> validateDirInfoInternal(
+ const P2pDirInfo& dirInfo);
+ ::ndk::ScopedAStatus reinvokePersistentGroupInternal(
+ const P2pReinvokePersistentGroupParams& reinvokeGroupParams);
struct wpa_supplicant* retrieveIfacePtr();
struct wpa_supplicant* retrieveGroupIfacePtr(
diff --git a/wpa_supplicant/aidl/p2p_network.cpp b/wpa_supplicant/aidl/vendor/p2p_network.cpp
similarity index 100%
rename from wpa_supplicant/aidl/p2p_network.cpp
rename to wpa_supplicant/aidl/vendor/p2p_network.cpp
diff --git a/wpa_supplicant/aidl/p2p_network.h b/wpa_supplicant/aidl/vendor/p2p_network.h
similarity index 100%
rename from wpa_supplicant/aidl/p2p_network.h
rename to wpa_supplicant/aidl/vendor/p2p_network.h
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/vendor/sta_iface.cpp
similarity index 95%
rename from wpa_supplicant/aidl/sta_iface.cpp
rename to wpa_supplicant/aidl/vendor/sta_iface.cpp
index 3880a1d..1a6ae08 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/vendor/sta_iface.cpp
@@ -38,23 +38,10 @@
using aidl::android::hardware::wifi::supplicant::LegacyMode;
using aidl::android::hardware::wifi::supplicant::RxFilterType;
using aidl::android::hardware::wifi::supplicant::SupplicantStatusCode;
+using aidl::android::hardware::wifi::supplicant::WifiChannelWidthInMhz;
using aidl::android::hardware::wifi::supplicant::WifiTechnology;
using aidl::android::hardware::wifi::supplicant::misc_utils::createStatus;
-// Enum definition copied from the Vendor HAL interface.
-// See android.hardware.wifi.WifiChannelWidthInMhz
-enum WifiChannelWidthInMhz {
- WIDTH_20 = 0,
- WIDTH_40 = 1,
- WIDTH_80 = 2,
- WIDTH_160 = 3,
- WIDTH_80P80 = 4,
- WIDTH_5 = 5,
- WIDTH_10 = 6,
- WIDTH_320 = 7,
- WIDTH_INVALID = -1
-};
-
constexpr uint32_t kMaxAnqpElems = 100;
constexpr char kGetMacAddress[] = "MACADDR";
constexpr char kStartRxFilter[] = "RXFILTER-START";
@@ -856,6 +843,58 @@
&StaIface::disableMscsInternal);
}
+::ndk::ScopedAStatus StaIface::getUsdCapabilities(UsdCapabilities* _aidl_return)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::getUsdCapabilitiesInternal, _aidl_return);
+}
+
+::ndk::ScopedAStatus StaIface::startUsdPublish(int32_t in_cmdId,
+ const UsdPublishConfig& in_usdPublishConfig)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::startUsdPublishInternal, in_usdPublishConfig);
+}
+
+::ndk::ScopedAStatus StaIface::startUsdSubscribe(int32_t in_cmdId,
+ const UsdSubscribeConfig& in_usdSubscribeConfig)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::startUsdSubscribeInternal, in_usdSubscribeConfig);
+}
+
+::ndk::ScopedAStatus StaIface::updateUsdPublish(int32_t in_publishId,
+ const std::vector<uint8_t>& in_serviceSpecificInfo)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::updateUsdPublishInternal, in_publishId, in_serviceSpecificInfo);
+}
+
+::ndk::ScopedAStatus StaIface::cancelUsdPublish(int32_t in_publishId)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::cancelUsdPublishInternal, in_publishId);
+}
+
+::ndk::ScopedAStatus StaIface::cancelUsdSubscribe(int32_t in_subscribeId)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::cancelUsdSubscribeInternal, in_subscribeId);
+}
+
+::ndk::ScopedAStatus StaIface::sendUsdMessage(const UsdMessageInfo& in_messageInfo)
+{
+ return validateAndCall(
+ this, SupplicantStatusCode::FAILURE_UNKNOWN,
+ &StaIface::sendUsdMessageInternal, in_messageInfo);
+}
+
std::pair<std::string, ndk::ScopedAStatus> StaIface::getNameInternal()
{
return {ifname_, ndk::ScopedAStatus::ok()};
@@ -1851,32 +1890,32 @@
capa.technology = WifiTechnology::LEGACY;
if (wpas_freq_to_band(wpa_s->assoc_freq) == BAND_2_4_GHZ) {
capa.legacyMode = (wpa_s->connection_11b_only) ? LegacyMode::B_MODE
- : LegacyMode::G_MODE;
+ : LegacyMode::G_MODE;
} else {
capa.legacyMode = LegacyMode::A_MODE;
}
}
switch (wpa_s->connection_channel_bandwidth) {
case CHAN_WIDTH_20:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+ capa.channelBandwidth = static_cast<int32_t>(WifiChannelWidthInMhz::WIDTH_20);
break;
case CHAN_WIDTH_40:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_40;
+ capa.channelBandwidth = static_cast<int32_t>(WifiChannelWidthInMhz::WIDTH_40);
break;
case CHAN_WIDTH_80:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80;
+ capa.channelBandwidth = static_cast<int32_t>(WifiChannelWidthInMhz::WIDTH_80);
break;
case CHAN_WIDTH_160:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_160;
+ capa.channelBandwidth = static_cast<int32_t>(WifiChannelWidthInMhz::WIDTH_160);
break;
case CHAN_WIDTH_80P80:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_80P80;
+ capa.channelBandwidth = static_cast<int32_t>(WifiChannelWidthInMhz::WIDTH_80P80);
break;
case CHAN_WIDTH_320:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_320;
+ capa.channelBandwidth = static_cast<int32_t>(WifiChannelWidthInMhz::WIDTH_320);
break;
default:
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+ capa.channelBandwidth = static_cast<int32_t>(WifiChannelWidthInMhz::WIDTH_20);
break;
}
capa.maxNumberRxSpatialStreams = wpa_s->connection_max_nss_rx;
@@ -1884,7 +1923,7 @@
capa.apTidToLinkMapNegotiationSupported = wpa_s->ap_t2lm_negotiation_support;
} else {
capa.technology = WifiTechnology::UNKNOWN;
- capa.channelBandwidth = WifiChannelWidthInMhz::WIDTH_20;
+ capa.channelBandwidth = static_cast<int32_t>(WifiChannelWidthInMhz::WIDTH_20);
capa.maxNumberTxSpatialStreams = 1;
capa.maxNumberRxSpatialStreams = 1;
capa.legacyMode = LegacyMode::UNKNOWN;
@@ -2568,6 +2607,38 @@
return ndk::ScopedAStatus::ok();
}
+std::pair<UsdCapabilities, ndk::ScopedAStatus> StaIface::getUsdCapabilitiesInternal() {
+ UsdCapabilities capabilities;
+ return {capabilities, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus StaIface::startUsdPublishInternal(
+ const UsdPublishConfig& usdPublishConfig) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+}
+
+ndk::ScopedAStatus StaIface::startUsdSubscribeInternal(
+ const UsdSubscribeConfig& usdSubscribeConfig) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+}
+
+::ndk::ScopedAStatus StaIface::updateUsdPublishInternal(int32_t publishId,
+ const std::vector<uint8_t>& serviceSpecificInfo) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+}
+
+::ndk::ScopedAStatus StaIface::cancelUsdPublishInternal(int32_t publishId) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+}
+
+::ndk::ScopedAStatus StaIface::cancelUsdSubscribeInternal(int32_t subscribeId) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+}
+
+::ndk::ScopedAStatus StaIface::sendUsdMessageInternal(const UsdMessageInfo& messageInfo) {
+ return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+}
+
/**
* Retrieve the underlying |wpa_supplicant| struct
* pointer for this iface.
diff --git a/wpa_supplicant/aidl/sta_iface.h b/wpa_supplicant/aidl/vendor/sta_iface.h
similarity index 92%
rename from wpa_supplicant/aidl/sta_iface.h
rename to wpa_supplicant/aidl/vendor/sta_iface.h
index b52c6b0..6c6cfb9 100644
--- a/wpa_supplicant/aidl/sta_iface.h
+++ b/wpa_supplicant/aidl/vendor/sta_iface.h
@@ -167,6 +167,16 @@
std::vector<QosPolicyScsRequestStatus>* _aidl_return) override;
::ndk::ScopedAStatus configureMscs(const MscsParams& in_params) override;
::ndk::ScopedAStatus disableMscs() override;
+ ::ndk::ScopedAStatus getUsdCapabilities(UsdCapabilities* _aidl_return);
+ ::ndk::ScopedAStatus startUsdPublish(int32_t in_cmdId,
+ const UsdPublishConfig& in_usdPublishConfig);
+ ::ndk::ScopedAStatus startUsdSubscribe(int32_t in_cmdId,
+ const UsdSubscribeConfig& in_usdSubscribeConfig);
+ ::ndk::ScopedAStatus updateUsdPublish(int32_t in_publishId,
+ const std::vector<uint8_t>& in_serviceSpecificInfo);
+ ::ndk::ScopedAStatus cancelUsdPublish(int32_t in_publishId);
+ ::ndk::ScopedAStatus cancelUsdSubscribe(int32_t in_subscribeId);
+ ::ndk::ScopedAStatus sendUsdMessage(const UsdMessageInfo& in_messageInfo);
private:
// Corresponding worker functions for the AIDL methods.
@@ -281,6 +291,14 @@
const std::vector<uint8_t>& scsPolicyIds);
::ndk::ScopedAStatus configureMscsInternal(const MscsParams& params);
::ndk::ScopedAStatus disableMscsInternal();
+ std::pair<UsdCapabilities, ndk::ScopedAStatus> getUsdCapabilitiesInternal();
+ ::ndk::ScopedAStatus startUsdPublishInternal(const UsdPublishConfig& usdPublishConfig);
+ ::ndk::ScopedAStatus startUsdSubscribeInternal(const UsdSubscribeConfig& usdSubscribeConfig);
+ ::ndk::ScopedAStatus updateUsdPublishInternal(int32_t publishId,
+ const std::vector<uint8_t>& serviceSpecificInfo);
+ ::ndk::ScopedAStatus cancelUsdPublishInternal(int32_t publishId);
+ ::ndk::ScopedAStatus cancelUsdSubscribeInternal(int32_t subscribeId);
+ ::ndk::ScopedAStatus sendUsdMessageInternal(const UsdMessageInfo& messageInfo);
struct wpa_supplicant* retrieveIfacePtr();
diff --git a/wpa_supplicant/aidl/sta_network.cpp b/wpa_supplicant/aidl/vendor/sta_network.cpp
similarity index 100%
rename from wpa_supplicant/aidl/sta_network.cpp
rename to wpa_supplicant/aidl/vendor/sta_network.cpp
diff --git a/wpa_supplicant/aidl/sta_network.h b/wpa_supplicant/aidl/vendor/sta_network.h
similarity index 100%
rename from wpa_supplicant/aidl/sta_network.h
rename to wpa_supplicant/aidl/vendor/sta_network.h
diff --git a/wpa_supplicant/aidl/supplicant.cpp b/wpa_supplicant/aidl/vendor/supplicant.cpp
similarity index 96%
rename from wpa_supplicant/aidl/supplicant.cpp
rename to wpa_supplicant/aidl/vendor/supplicant.cpp
index ae1943f..0cb2342 100644
--- a/wpa_supplicant/aidl/supplicant.cpp
+++ b/wpa_supplicant/aidl/vendor/supplicant.cpp
@@ -12,6 +12,8 @@
#include "supplicant.h"
#include "p2p_iface.h"
+#include "aidl/shared/shared_utils.h"
+
#include <android-base/file.h>
#include <fcntl.h>
#include <sys/stat.h>
@@ -22,8 +24,6 @@
// Note: This may differ for other OEM's. So, modify this accordingly.
// When wpa_supplicant is in its APEX, overlay/template configurations should be
// loaded from the same APEX.
-constexpr char kIfaceDriverName[] = "nl80211";
-
constexpr char kStaIfaceConfPath[] =
"/data/vendor/wifi/wpa/wpa_supplicant.conf";
constexpr char kStaIfaceConfOverlayPath[] =
@@ -42,7 +42,6 @@
constexpr char kOldStaIfaceConfPath[] = "/data/misc/wifi/wpa_supplicant.conf";
constexpr char kOldP2pIfaceConfPath[] = "/data/misc/wifi/p2p_supplicant.conf";
-constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
std::string resolveVendorConfPath(const std::string& conf_path)
{
@@ -114,26 +113,15 @@
const std::string& config_file_path,
const std::string& old_config_file_path)
{
- int ret = access(config_file_path.c_str(), R_OK | W_OK);
+ // Check if config file already exists at |config_file_path|
+ int ret = ensureConfigFileExistsAtPath(config_file_path);
if (ret == 0) {
+ wpa_printf(MSG_INFO, "Config file already exists at %s", config_file_path.c_str());
return 0;
- }
- if (errno == EACCES) {
- ret = chmod(config_file_path.c_str(), kConfigFileMode);
- if (ret == 0) {
- return 0;
- } else {
- wpa_printf(
- MSG_ERROR, "Cannot set RW to %s. Errno: %s",
- config_file_path.c_str(), strerror(errno));
- return -1;
- }
- } else if (errno != ENOENT) {
- wpa_printf(
- MSG_ERROR, "Cannot acces %s. Errno: %s",
- config_file_path.c_str(), strerror(errno));
+ } else if (ret != ENOENT) {
return -1;
}
+
ret = copyFileIfItExists(old_config_file_path, config_file_path);
if (ret == 0) {
wpa_printf(
@@ -145,6 +133,7 @@
unlink(config_file_path.c_str());
return -1;
}
+
std::string vendor_template_conf_path = resolveVendorConfPath(kVendorTemplateConfPath);
ret = copyFileIfItExists(vendor_template_conf_path, config_file_path);
if (ret == 0) {
@@ -156,6 +145,7 @@
unlink(config_file_path.c_str());
return -1;
}
+
ret = copyFileIfItExists(kSystemTemplateConfPath, config_file_path);
if (ret == 0) {
wpa_printf(
@@ -166,6 +156,7 @@
unlink(config_file_path.c_str());
return -1;
}
+
// Did not create the conf file.
return -1;
}
diff --git a/wpa_supplicant/aidl/supplicant.h b/wpa_supplicant/aidl/vendor/supplicant.h
similarity index 100%
rename from wpa_supplicant/aidl/supplicant.h
rename to wpa_supplicant/aidl/vendor/supplicant.h
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index cab4ae2..bc9f324 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -280,6 +280,11 @@
params.num_ssids = 1;
params.ssids[0].ssid = data->ssid->ssid;
params.ssids[0].ssid_len = data->ssid->ssid_len;
+
+ /* Add OWE transition mode SSID of the current network */
+ wpa_add_owe_scan_ssid(wpa_s, ¶ms, data->ssid,
+ wpa_s->max_scan_ssids - params.num_ssids);
+
if (data->ssid->scan_freq)
params.freqs = data->ssid->scan_freq;
else {
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
index a90cf86..d9aaa63 100644
--- a/wpa_supplicant/bgscan_simple.c
+++ b/wpa_supplicant/bgscan_simple.c
@@ -89,6 +89,10 @@
params.ssids[0].ssid_len = data->ssid->ssid_len;
params.freqs = data->ssid->scan_freq;
+ /* Add OWE transition mode SSID of the current network */
+ wpa_add_owe_scan_ssid(wpa_s, ¶ms, data->ssid,
+ wpa_s->max_scan_ssids - params.num_ssids);
+
/*
* A more advanced bgscan module would learn about most like channels
* over time and request scans only for some channels (probing others
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index cf94d4b..39de8ba 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -273,6 +273,57 @@
return NULL;
}
+/**
+ * wpa_bss_get_connection - Fetch a BSS table entry based on BSSID and SSID.
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @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
+ *
+ * This function is similar to wpa_bss_get() but it will also return OWE
+ * transition mode encrypted networks for which transition-element matches
+ * @ssid.
+ */
+struct wpa_bss * wpa_bss_get_connection(struct wpa_supplicant *wpa_s,
+ const u8 *bssid,
+ const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_bss *bss;
+#ifdef CONFIG_OWE
+ const u8 *owe, *owe_bssid, *owe_ssid;
+ size_t owe_ssid_len;
+#endif /* CONFIG_OWE */
+
+ 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 (bssid && !ether_addr_equal(bss->bssid, bssid))
+ continue;
+
+ if (bss->ssid_len == ssid_len &&
+ os_memcmp(bss->ssid, ssid, ssid_len) == 0)
+ return bss;
+
+#ifdef CONFIG_OWE
+ /* Check if OWE transition mode element is present and matches
+ * the SSID */
+ owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
+ if (!owe)
+ continue;
+
+ if (wpas_get_owe_trans_network(owe, &owe_bssid, &owe_ssid,
+ &owe_ssid_len))
+ continue;
+
+ if (owe_ssid_len == ssid_len &&
+ os_memcmp(owe_ssid, ssid, ssid_len) == 0)
+ return bss;
+#endif /* CONFIG_OWE */
+ }
+ return NULL;
+}
+
void calculate_update_time(const struct os_reltime *fetch_time,
unsigned int age_ms,
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 508129c..31688fa 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -165,6 +165,9 @@
void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age);
struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *ssid, size_t ssid_len);
+struct wpa_bss * wpa_bss_get_connection(struct wpa_supplicant *wpa_s,
+ const u8 *bssid,
+ const u8 *ssid, size_t ssid_len);
struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
const u8 *bssid);
struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 0f98f77..5b08478 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -3096,6 +3096,7 @@
os_free(config->dpp_mud_url);
os_free(config->dpp_extra_conf_req_name);
os_free(config->dpp_extra_conf_req_value);
+ wpabuf_free(config->dik);
os_free(config);
}
@@ -5496,6 +5497,8 @@
{ INT(p2p_interface_random_mac_addr), 0 },
{ INT(p2p_6ghz_disable), 0 },
{ INT(p2p_dfs_chan_enable), 0 },
+ { INT(dik_cipher), 0},
+ { BIN(dik), 0 },
#endif /* CONFIG_P2P */
{ FUNC(country), CFG_CHANGED_COUNTRY },
{ INT(bss_max_count), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 7ea43a6..1281786 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1843,6 +1843,12 @@
int mld_force_single_link;
#endif /* CONFIG_TESTING_OPTIONS */
+
+ /* Cipher version type */
+ int dik_cipher;
+
+ /* DevIK */
+ struct wpabuf *dik;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index fa829eb..53614ae 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1634,7 +1634,11 @@
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);
+ fprintf(f, "ft_prepend_pmkid=%d\n", config->ft_prepend_pmkid);
+ if (config->dik) {
+ fprintf(f, "dik_cipher=%d\n", config->dik_cipher);
+ write_global_bin(f, "dik", config->dik);
+ }
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index d245531..a8fc962 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -6035,7 +6035,7 @@
return -1;
}
- bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+ bss = wpa_bss_get_connection(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
if (!bss) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
"from BSS table");
@@ -6376,6 +6376,10 @@
size_t group_ssid_len = 0;
int he;
bool allow_6ghz;
+ bool p2p2;
+ u16 bootstrap = 0;
+ const char *password = NULL;
+ char *token, *context = NULL;
if (!wpa_s->global->p2p_init_wpa_s)
return -1;
@@ -6385,10 +6389,12 @@
wpa_s = wpa_s->global->p2p_init_wpa_s;
}
- /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
+ /* <addr> <"pbc" | "pin" | "pair" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
- * [ht40] [vht] [he] [edmg] [auto] [ssid=<hexdump>] */
+ * [ht40] [vht] [he] [edmg] [auto] [ssid=<hexdump>]
+ * [p2p2] [bstrapmethod=<value>] [password=<string>]
+ */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -6422,6 +6428,7 @@
vht;
he = (os_strstr(cmd, " he") != NULL) || wpa_s->conf->p2p_go_he;
edmg = (os_strstr(cmd, " edmg") != NULL) || wpa_s->conf->p2p_go_edmg;
+ p2p2 = os_strstr(pos, " p2p2") != NULL;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -6477,6 +6484,8 @@
wps_method = WPS_PBC;
} else if (os_strstr(pos, "p2ps") != NULL) {
wps_method = WPS_P2PS;
+ } else if (os_strncmp(pos, "pair", 4) == 0 && p2p2) {
+ wps_method = WPS_NOT_READY;
} else {
pin = pos;
pos = os_strchr(pin, ' ');
@@ -6492,11 +6501,26 @@
}
}
+ pos2 = os_strstr(pos, "bstrapmethod=");
+ if (pos2) {
+ pos2 += 13;
+ bootstrap = atoi(pos2);
+ pd = true;
+ }
+
+ while ((token = str_token(pos, " ", &context))) {
+ if (os_strncmp(token, "password=", 9) == 0) {
+ password = token + 9;
+ continue;
+ }
+ }
+
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
auth, go_intent, freq, freq2, persistent_id,
pd, ht40, vht, max_oper_chwidth, he, edmg,
- group_ssid, group_ssid_len, allow_6ghz);
+ group_ssid, group_ssid_len, allow_6ghz, p2p2,
+ bootstrap, password);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -7172,7 +7196,7 @@
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, freq,
vht_center_freq2, ht40, vht,
vht_chwidth, he, edmg,
NULL, 0, 0, allow_6ghz, 0,
@@ -8650,6 +8674,7 @@
int ret;
ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
+#ifdef CONFIG_P2P
if (ret == 0) {
if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
struct p2p_data *p2p = wpa_s->global->p2p;
@@ -8665,6 +8690,7 @@
if (os_snprintf_error(buflen, ret))
ret = -1;
}
+#endif /* CONFIG_P2P */
return ret;
}
#endif /* ANDROID */
@@ -12202,6 +12228,7 @@
int ret = -1;
enum nan_service_protocol_type srv_proto_type = 0;
int *freq_list = NULL;
+ bool p2p = false;
os_memset(¶ms, 0, sizeof(params));
/* USD shall use both solicited and unsolicited transmissions */
@@ -12262,6 +12289,11 @@
continue;
}
+ if (os_strcmp(token, "p2p=1") == 0) {
+ p2p = true;
+ continue;
+ }
+
if (os_strcmp(token, "solicited=0") == 0) {
params.solicited = false;
continue;
@@ -12283,7 +12315,7 @@
}
publish_id = wpas_nan_usd_publish(wpa_s, service_name, srv_proto_type,
- ssi, ¶ms);
+ ssi, ¶ms, p2p);
if (publish_id > 0)
ret = os_snprintf(buf, buflen, "%d", publish_id);
fail:
@@ -12367,6 +12399,8 @@
struct wpabuf *ssi = NULL;
int ret = -1;
enum nan_service_protocol_type srv_proto_type = 0;
+ int *freq_list = NULL;
+ bool p2p = false;
os_memset(¶ms, 0, sizeof(params));
params.freq = NAN_USD_DEFAULT_FREQ;
@@ -12392,6 +12426,27 @@
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;
@@ -12406,6 +12461,11 @@
continue;
}
+ if (os_strcmp(token, "p2p=1") == 0) {
+ p2p = true;
+ continue;
+ }
+
wpa_printf(MSG_INFO,
"CTRL: Invalid NAN_SUBSCRIBE parameter: %s",
token);
@@ -12414,11 +12474,12 @@
subscribe_id = wpas_nan_usd_subscribe(wpa_s, service_name,
srv_proto_type, ssi,
- ¶ms);
+ ¶ms, p2p);
if (subscribe_id > 0)
ret = os_snprintf(buf, buflen, "%d", subscribe_id);
fail:
wpabuf_free(ssi);
+ os_free(freq_list);
return ret;
}
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 76e42ff..5ad5bcd 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -2396,6 +2396,10 @@
case WPAS_DBUS_PROP_ROAM_COMPLETE:
prop = "RoamComplete";
break;
+ case WPAS_DBUS_PROP_SCAN_IN_PROGRESS_6GHZ:
+ prop = "ScanInProgress6GHz";
+ flush = TRUE;
+ break;
case WPAS_DBUS_PROP_SESSION_LENGTH:
prop = "SessionLength";
break;
@@ -3984,6 +3988,12 @@
NULL
},
{
+ "ScanInProgress6GHz", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
+ wpas_dbus_getter_scan_in_progress_6ghz,
+ NULL,
+ NULL
+ },
+ {
"SessionLength", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
wpas_dbus_getter_session_length,
NULL,
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 952bb42..1db5fe8 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -36,6 +36,7 @@
WPAS_DBUS_PROP_ASSOC_STATUS_CODE,
WPAS_DBUS_PROP_ROAM_TIME,
WPAS_DBUS_PROP_ROAM_COMPLETE,
+ WPAS_DBUS_PROP_SCAN_IN_PROGRESS_6GHZ,
WPAS_DBUS_PROP_SESSION_LENGTH,
WPAS_DBUS_PROP_BSS_TM_STATUS,
WPAS_DBUS_PROP_MAC_ADDRESS,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 960b306..52e35a7 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -3836,6 +3836,29 @@
/**
+ * wpas_dbus_getter_scan_in_progress_6ghz - Get whether a 6 GHz scan is in
+ * progress
+ * @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 function for "ScanInProgress6GHz" property.
+ */
+dbus_bool_t wpas_dbus_getter_scan_in_progress_6ghz(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ dbus_bool_t scan_in_progress_6ghz = wpa_s->scan_in_progress_6ghz ?
+ TRUE : FALSE;
+
+ return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+ &scan_in_progress_6ghz, error);
+}
+
+
+/**
* wpas_dbus_getter_session_length - Get most recent BSS session length
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index acd6af7..7faf70a 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -173,6 +173,7 @@
DECLARE_ACCESSOR(wpas_dbus_getter_assoc_status_code);
DECLARE_ACCESSOR(wpas_dbus_getter_roam_time);
DECLARE_ACCESSOR(wpas_dbus_getter_roam_complete);
+DECLARE_ACCESSOR(wpas_dbus_getter_scan_in_progress_6ghz);
DECLARE_ACCESSOR(wpas_dbus_getter_session_length);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_tm_status);
DECLARE_ACCESSOR(wpas_dbus_getter_bss_expire_age);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 418a8fd..65bd478 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -473,7 +473,7 @@
if (ssid == NULL || ssid->disabled != 2)
goto inv_args;
- if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
+ if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, freq,
freq2, ht40, vht,
max_oper_chwidth, he, edmg,
NULL, 0, 0, allow_6ghz,
@@ -706,7 +706,7 @@
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
go_intent, freq, 0, -1, 0, 0, 0, 0, 0, 0,
- NULL, 0, false);
+ NULL, 0, false, 0, 0, NULL);
if (new_pin >= 0) {
char npin[9];
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 216224f..1b2c756 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -29,7 +29,7 @@
#include "scan.h"
#include "notify.h"
#include "dpp_supplicant.h"
-#include "aidl/aidl.h"
+#include "aidl/vendor/aidl.h"
static int wpas_dpp_listen_start(struct wpa_supplicant *wpa_s,
@@ -1433,6 +1433,17 @@
os_memcpy(ssid->ssid, conf->ssid, conf->ssid_len);
ssid->ssid_len = conf->ssid_len;
+#ifdef CONFIG_DPP3
+ if (conf->akm == DPP_AKM_SAE && conf->password_id[0]) {
+ size_t len = os_strlen(conf->password_id);
+
+ ssid->sae_password_id = os_zalloc(len + 1);
+ if (!ssid->sae_password_id)
+ goto fail;
+ os_memcpy(ssid->sae_password_id, conf->password_id, len);
+ }
+#endif /* CONFIG_DPP3 */
+
if (conf->connector) {
if (dpp_akm_dpp(conf->akm)) {
ssid->key_mgmt = WPA_KEY_MGMT_DPP;
@@ -1490,12 +1501,17 @@
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
else
ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
- if (conf->passphrase[0]) {
+ if (conf->passphrase[0] && dpp_akm_psk(conf->akm)) {
if (wpa_config_set_quoted(ssid, "psk",
conf->passphrase) < 0)
goto fail;
wpa_config_update_psk(ssid);
ssid->export_keys = 1;
+ } else if (conf->passphrase[0] && dpp_akm_sae(conf->akm)) {
+ if (wpa_config_set_quoted(ssid, "sae_password",
+ conf->passphrase) < 0)
+ goto fail;
+ ssid->export_keys = 1;
} else {
ssid->psk_set = conf->psk_set;
os_memcpy(ssid->psk, conf->psk, PMK_LEN);
@@ -1709,6 +1725,12 @@
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
hex);
}
+#ifdef CONFIG_DPP3
+ if (conf->password_id[0]) {
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_IDPASS "%s",
+ conf->password_id);
+ }
+#endif /* CONFIG_DPP3 */
if (conf->c_sign_key) {
char *hex;
size_t hexlen;
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index d01b52b..b6c7f50 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -9,6 +9,7 @@
#ifndef DRIVER_I_H
#define DRIVER_I_H
+#include "common/nan_de.h"
#include "drivers/driver.h"
/* driver_ops */
@@ -1175,4 +1176,75 @@
return wpa_s->driver->get_sta_mlo_info(wpa_s->drv_priv, mlo_info);
}
+static inline int
+wpas_drv_nan_flush(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->driver->nan_flush)
+ return 0;
+
+ return wpa_s->driver->nan_flush(wpa_s->drv_priv);
+}
+
+static inline int
+wpas_drv_nan_publish(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int publish_id, const char *service_name,
+ const u8 *service_id,
+ enum nan_service_protocol_type srv_proto_type,
+ const struct wpabuf *ssi, const struct wpabuf *elems,
+ struct nan_publish_params *params)
+{
+ if (!wpa_s->driver->nan_publish)
+ return 0;
+
+ return wpa_s->driver->nan_publish(wpa_s->drv_priv, addr, publish_id,
+ service_name, service_id,
+ srv_proto_type, ssi, elems, params);
+}
+
+static inline int
+wpas_drv_nan_cancel_publish(struct wpa_supplicant *wpa_s, int publish_id)
+{
+ if (!wpa_s->driver->nan_cancel_publish)
+ return 0;
+
+ return wpa_s->driver->nan_cancel_publish(wpa_s->drv_priv, publish_id);
+}
+
+static inline int
+wpas_drv_nan_update_publish(struct wpa_supplicant *wpa_s, int publish_id,
+ const struct wpabuf *ssi)
+{
+ if (!wpa_s->driver->nan_update_publish)
+ return 0;
+
+ return wpa_s->driver->nan_update_publish(wpa_s->drv_priv, publish_id,
+ ssi);
+}
+
+static inline int
+wpas_drv_nan_subscribe(struct wpa_supplicant *wpa_s, const u8 *addr,
+ int subscribe_id, const char *service_name,
+ const u8 *service_id,
+ enum nan_service_protocol_type srv_proto_type,
+ const struct wpabuf *ssi, const struct wpabuf *elems,
+ struct nan_subscribe_params *params)
+{
+ if (!wpa_s->driver->nan_subscribe)
+ return 0;
+
+ return wpa_s->driver->nan_subscribe(wpa_s->drv_priv, addr, subscribe_id,
+ service_name, service_id,
+ srv_proto_type, ssi, elems, params);
+}
+
+static inline int
+wpas_drv_nan_cancel_subscribe(struct wpa_supplicant *wpa_s, int subscribe_id)
+{
+ if (!wpa_s->driver->nan_cancel_subscribe)
+ return 0;
+
+ return wpa_s->driver->nan_cancel_subscribe(wpa_s->drv_priv,
+ subscribe_id);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 09a2bbb..2a665d7 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -9,6 +9,7 @@
#include "includes.h"
#include "common.h"
+#include "utils/crc32.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
#include "eloop.h"
@@ -1140,30 +1141,20 @@
const u8 **ret_ssid, size_t *ret_ssid_len)
{
#ifdef CONFIG_OWE
- const u8 *owe, *pos, *end, *bssid;
- u8 ssid_len;
+ const u8 *owe, *bssid;
owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
if (!owe || !wpa_bss_get_rsne(wpa_s, bss, NULL, false))
return;
- pos = owe + 6;
- end = owe + 2 + owe[1];
-
- if (end - pos < ETH_ALEN + 1)
- return;
- bssid = pos;
- pos += ETH_ALEN;
- ssid_len = *pos++;
- if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN)
+ if (wpas_get_owe_trans_network(owe, &bssid, ret_ssid, ret_ssid_len))
return;
/* Match the profile SSID against the OWE transition mode SSID on the
* open network. */
wpa_dbg(wpa_s, MSG_DEBUG, "OWE: transition mode BSSID: " MACSTR
- " SSID: %s", MAC2STR(bssid), wpa_ssid_txt(pos, ssid_len));
- *ret_ssid = pos;
- *ret_ssid_len = ssid_len;
+ " SSID: %s", MAC2STR(bssid),
+ wpa_ssid_txt(*ret_ssid, *ret_ssid_len));
if (!(bss->flags & WPA_BSS_OWE_TRANSITION)) {
struct wpa_ssid *ssid;
@@ -1171,8 +1162,8 @@
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (wpas_network_disabled(wpa_s, ssid))
continue;
- if (ssid->ssid_len == ssid_len &&
- os_memcmp(ssid->ssid, pos, ssid_len) == 0) {
+ if (ssid->ssid_len == *ret_ssid_len &&
+ os_memcmp(ssid->ssid, ret_ssid, *ret_ssid_len) == 0) {
/* OWE BSS in transition mode for a currently
* enabled OWE network. */
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -2411,6 +2402,78 @@
}
+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, false, false);
+ if (!wpa_supplicant_trigger_scan(wpa_s, ¶ms, true, true)) {
+ wpa_s->scan_in_progress_6ghz = true;
+ wpas_notify_scan_in_progress_6ghz(wpa_s);
+ os_free(params.freqs);
+ return 1;
+ }
+ wpa_dbg(wpa_s, MSG_INFO, "Failed to trigger 6GHz-only scan");
+ os_free(params.freqs);
+ return 0;
+}
+
+
+static bool wpas_short_ssid_match(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ size_t i;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ u32 current_ssid_short = ieee80211_crc32(ssid->ssid, ssid->ssid_len);
+
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *res = scan_res->res[i];
+ const u8 *rnr_ie, *ie_end;
+ const struct ieee80211_neighbor_ap_info *info;
+ size_t left;
+
+ rnr_ie = wpa_scan_get_ie(res, WLAN_EID_REDUCED_NEIGHBOR_REPORT);
+ if (!rnr_ie)
+ continue;
+
+ ie_end = rnr_ie + 2 + rnr_ie[1];
+ rnr_ie += 2;
+
+ left = ie_end - rnr_ie;
+ if (left < sizeof(struct ieee80211_neighbor_ap_info))
+ continue;
+
+ info = (const struct ieee80211_neighbor_ap_info *) rnr_ie;
+ if (info->tbtt_info_len < 11)
+ continue; /* short SSID not included */
+ left -= sizeof(struct ieee80211_neighbor_ap_info);
+ rnr_ie += sizeof(struct ieee80211_neighbor_ap_info);
+
+ while (left >= info->tbtt_info_len && rnr_ie + 11 <= ie_end) {
+ /* Skip TBTT offset and BSSID */
+ u32 short_ssid = WPA_GET_LE32(rnr_ie + 1 + ETH_ALEN);
+
+ if (short_ssid == current_ssid_short)
+ return true;
+
+ left -= info->tbtt_info_len;
+ rnr_ie += info->tbtt_info_len;
+ }
+ }
+
+ return false;
+}
+
+
/*
* Return a negative value if no scan results could be fetched or if scan
* results should not be shared with other virtual interfaces.
@@ -2428,6 +2491,7 @@
int ret = 0;
int ap = 0;
bool trigger_6ghz_scan;
+ bool short_ssid_match_found = false;
#ifndef CONFIG_NO_RANDOM_POOL
size_t i, num;
#endif /* CONFIG_NO_RANDOM_POOL */
@@ -2447,6 +2511,12 @@
scan_res = wpa_supplicant_get_scan_results(wpa_s,
data ? &data->scan_info :
NULL, 1, NULL);
+
+ if (wpa_s->scan_in_progress_6ghz) {
+ wpa_s->scan_in_progress_6ghz = false;
+ wpas_notify_scan_in_progress_6ghz(wpa_s);
+ }
+
if (scan_res == NULL) {
if (wpa_s->conf->ap_scan == 2 || ap ||
wpa_s->scan_res_handler == scan_only_handler)
@@ -2537,9 +2607,6 @@
return 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;
@@ -2569,10 +2636,19 @@
wpas_wps_update_ap_info(wpa_s, scan_res);
+ if (wnm_scan_process(wpa_s, false) > 0)
+ goto scan_work_done;
+
if (wpa_s->wpa_state >= WPA_AUTHENTICATING &&
wpa_s->wpa_state < WPA_COMPLETED)
goto scan_work_done;
+ if (wpa_s->current_ssid && trigger_6ghz_scan && own_request && data &&
+ wpas_short_ssid_match(wpa_s, scan_res)) {
+ wpa_dbg(wpa_s, MSG_INFO, "Short SSID match in scan results");
+ short_ssid_match_found = true;
+ }
+
wpa_scan_results_free(scan_res);
if (own_request && wpa_s->scan_work) {
@@ -2599,6 +2675,9 @@
if (wpa_s->supp_pbc_active && !wpas_wps_partner_link_scan_done(wpa_s))
return ret;
+ if (short_ssid_match_found && wpas_trigger_6ghz_scan(wpa_s, data) > 0)
+ return 1;
+
return wpas_select_network_from_last_scan(wpa_s, 1, own_request,
trigger_6ghz_scan, data);
@@ -2613,30 +2692,6 @@
}
-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
@@ -2727,7 +2782,7 @@
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)
+ wpas_trigger_6ghz_scan(wpa_s, data) > 0)
return 1;
/*
@@ -3375,13 +3430,17 @@
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
- int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
- const u8 *p;
+ int l, len, found = 0, wpa_found, rsn_found;
+#ifndef CONFIG_NO_WPA
+ int found_x = 0;
+#endif /* CONFIG_NO_WPA */
+ const u8 *p, *ie;
u8 bssid[ETH_ALEN];
bool bssid_known;
#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
- struct wpa_ie_data ie;
+ struct wpa_ie_data wpa_ie;
#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+ enum wpa_rsn_override rsn_override;
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
wpa_s->ssid_verified = false;
@@ -3510,18 +3569,22 @@
wpa_find_assoc_pmkid(wpa_s,
data->assoc_info.authorized);
}
+#ifndef CONFIG_NO_WPA
if (!found_x && p[0] == WLAN_EID_RSNX) {
if (wpa_sm_set_assoc_rsnxe(wpa_s->wpa, p, len))
break;
found_x = 1;
}
+#endif /* CONFIG_NO_WPA */
l -= len;
p += len;
}
if (!found && data->assoc_info.req_ies)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+#ifndef CONFIG_NO_WPA
if (!found_x && data->assoc_info.req_ies)
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+#endif /* CONFIG_NO_WPA */
#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
/* The WPA/RSN IE has been updated at this point. Since the Firmware could have roamed
@@ -3529,12 +3592,12 @@
* and pairwise suites from the assoc IE passed by the driver.
*/
if (wpas_driver_bss_selection(wpa_s)) {
- if (!(wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0)) {
+ if (!(wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &wpa_ie) < 0)) {
/* Check if firmware has roamed to a different security network */
- if(wpa_s->key_mgmt != ie.key_mgmt) {
+ if(wpa_s->key_mgmt != wpa_ie.key_mgmt) {
wpa_dbg(wpa_s, MSG_DEBUG, "Update to AKM suite 0x%x from Assoc IE",
- ie.key_mgmt);
- wpa_s->key_mgmt = ie.key_mgmt;
+ wpa_ie.key_mgmt);
+ wpa_s->key_mgmt = wpa_ie.key_mgmt;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
if (wpa_key_mgmt_wpa_psk_no_sae(wpa_s->key_mgmt)) {
@@ -3557,10 +3620,10 @@
}
}
}
- if(wpa_s->pairwise_cipher != ie.pairwise_cipher) {
+ if(wpa_s->pairwise_cipher != wpa_ie.pairwise_cipher) {
wpa_dbg(wpa_s, MSG_DEBUG, "Update to pairwise cipher suite 0x%x "
- "from Assoc IE", ie.pairwise_cipher);
- wpa_s->pairwise_cipher = ie.pairwise_cipher;
+ "from Assoc IE", wpa_ie.pairwise_cipher);
+ wpa_s->pairwise_cipher = wpa_ie.pairwise_cipher;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
wpa_s->pairwise_cipher);
}
@@ -3569,6 +3632,25 @@
}
#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+ rsn_override = RSN_OVERRIDE_NOT_USED;
+ ie = get_vendor_ie(data->assoc_info.req_ies,
+ data->assoc_info.req_ies_len,
+ RSN_SELECTION_IE_VENDOR_TYPE);
+ if (ie && ie[1] >= 4 + 1) {
+ switch (ie[2 + 4]) {
+ case RSN_SELECTION_RSNE:
+ rsn_override = RSN_OVERRIDE_RSNE;
+ break;
+ case RSN_SELECTION_RSNE_OVERRIDE:
+ rsn_override = RSN_OVERRIDE_RSNE_OVERRIDE;
+ break;
+ case RSN_SELECTION_RSNE_OVERRIDE_2:
+ rsn_override = RSN_OVERRIDE_RSNE_OVERRIDE_2;
+ break;
+ }
+ }
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE, rsn_override);
+
#ifdef CONFIG_FILS
#ifdef CONFIG_SME
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FILS ||
@@ -3764,28 +3846,20 @@
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
}
- if (wpas_rsn_overriding(wpa_s) &&
- p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
- WPA_GET_BE32(&p[2]) == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
- rsn_found = 1;
- wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
- }
+ if (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+ WPA_GET_BE32(&p[2]) == RSNE_OVERRIDE_2_IE_VENDOR_TYPE)
+ wpa_sm_set_ap_rsne_override_2(wpa_s->wpa, p, len);
- if (!rsn_found &&
- wpas_rsn_overriding(wpa_s) &&
- p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
- WPA_GET_BE32(&p[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
- rsn_found = 1;
- wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
- }
+ if (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+ WPA_GET_BE32(&p[2]) == RSNE_OVERRIDE_IE_VENDOR_TYPE)
+ wpa_sm_set_ap_rsne_override(wpa_s->wpa, p, len);
if (p[0] == WLAN_EID_RSNX && p[1] >= 1)
wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
- if (wpas_rsn_overriding(wpa_s) &&
- p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+ if (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
WPA_GET_BE32(&p[2]) == RSNXE_OVERRIDE_IE_VENDOR_TYPE)
- wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
+ wpa_sm_set_ap_rsnxe_override(wpa_s->wpa, p, len);
l -= len;
p += len;
@@ -3796,6 +3870,9 @@
if (!rsn_found && data->assoc_info.beacon_ies) {
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsne_override(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsne_override_2(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe_override(wpa_s->wpa, NULL, 0);
}
if (wpa_found || rsn_found)
wpa_s->ap_ies_from_associnfo = 1;
@@ -3831,6 +3908,7 @@
static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
{
const u8 *bss_wpa = NULL, *bss_rsn = NULL, *bss_rsnx = NULL;
+ const u8 *rsnoe, *rsno2e, *rsnxoe;
if (!wpa_s->current_bss || !wpa_s->current_ssid)
return -1;
@@ -3840,17 +3918,27 @@
bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
WPA_IE_VENDOR_TYPE);
- bss_rsn = wpa_bss_get_rsne(wpa_s, wpa_s->current_bss, NULL,
- wpa_s->valid_links);
- bss_rsnx = wpa_bss_get_rsnxe(wpa_s, wpa_s->current_bss, NULL,
- wpa_s->valid_links);
+ bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSNX);
+ rsnoe = wpa_bss_get_vendor_ie(wpa_s->current_bss,
+ RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ rsno2e = wpa_bss_get_vendor_ie(wpa_s->current_bss,
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+ rsnxoe = wpa_bss_get_vendor_ie(wpa_s->current_bss,
+ RSNXE_OVERRIDE_IE_VENDOR_TYPE);
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
bss_rsn ? 2 + bss_rsn[1] : 0) ||
wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
- bss_rsnx ? 2 + bss_rsnx[1] : 0))
+ bss_rsnx ? 2 + bss_rsnx[1] : 0) ||
+ wpa_sm_set_ap_rsne_override(wpa_s->wpa, rsnoe,
+ rsnoe ? 2 + rsnoe[1] : 0) ||
+ wpa_sm_set_ap_rsne_override_2(wpa_s->wpa, rsno2e,
+ rsno2e ? 2 + rsno2e[1] : 0) ||
+ wpa_sm_set_ap_rsnxe_override(wpa_s->wpa, rsnxoe,
+ rsnxoe ? 2 + rsnxoe[1] : 0))
return -1;
return 0;
@@ -4203,7 +4291,6 @@
{
struct driver_sta_mlo_info drv_mlo;
struct wpa_sm_mlo wpa_mlo;
- const u8 *bss_rsn = NULL, *bss_rsnx = NULL;
int i;
os_memset(&drv_mlo, 0, sizeof(drv_mlo));
@@ -4223,6 +4310,7 @@
for_each_link(drv_mlo.req_links, i) {
struct wpa_bss *bss;
+ const u8 *rsne, *rsnxe, *rsnoe, *rsno2e, *rsnxoe;
bss = wpa_supplicant_get_new_bss(wpa_s, drv_mlo.links[i].bssid);
if (!bss) {
@@ -4231,13 +4319,25 @@
return -1;
}
- bss_rsn = wpa_bss_get_rsne(wpa_s, bss, NULL, true);
- bss_rsnx = wpa_bss_get_rsnxe(wpa_s, bss, NULL, true);
+ rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ rsnoe = wpa_bss_get_vendor_ie(bss,
+ RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ rsno2e = wpa_bss_get_vendor_ie(bss,
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+ rsnxoe = wpa_bss_get_vendor_ie(bss,
+ RSNXE_OVERRIDE_IE_VENDOR_TYPE);
- wpa_mlo.links[i].ap_rsne = bss_rsn ? (u8 *) bss_rsn : NULL;
- wpa_mlo.links[i].ap_rsne_len = bss_rsn ? 2 + bss_rsn[1] : 0;
- wpa_mlo.links[i].ap_rsnxe = bss_rsnx ? (u8 *) bss_rsnx : NULL;
- wpa_mlo.links[i].ap_rsnxe_len = bss_rsnx ? 2 + bss_rsnx[1] : 0;
+ wpa_mlo.links[i].ap_rsne = rsne ? (u8 *) rsne : NULL;
+ wpa_mlo.links[i].ap_rsne_len = rsne ? 2 + rsne[1] : 0;
+ wpa_mlo.links[i].ap_rsnxe = rsnxe ? (u8 *) rsnxe : NULL;
+ wpa_mlo.links[i].ap_rsnxe_len = rsnxe ? 2 + rsnxe[1] : 0;
+ wpa_mlo.links[i].ap_rsnoe = rsnoe ? (u8 *) rsnoe : NULL;
+ wpa_mlo.links[i].ap_rsnoe_len = rsnoe ? 2 + rsnoe[1] : 0;
+ wpa_mlo.links[i].ap_rsno2e = rsno2e ? (u8 *) rsno2e : NULL;
+ wpa_mlo.links[i].ap_rsno2e_len = rsno2e ? 2 + rsno2e[1] : 0;
+ wpa_mlo.links[i].ap_rsnxoe = rsnxoe ? (u8 *) rsnxoe : NULL;
+ wpa_mlo.links[i].ap_rsnxoe_len = rsnxoe ? 2 + rsnxoe[1] : 0;
os_memcpy(wpa_mlo.links[i].bssid, drv_mlo.links[i].bssid,
ETH_ALEN);
@@ -6159,6 +6259,17 @@
wpa_s->valid_links);
}
+#ifdef MAINLINE_SUPPLICANT
+static bool is_event_allowlisted(enum wpa_event_type event) {
+ return event == EVENT_SCAN_STARTED ||
+ event == EVENT_SCAN_RESULTS ||
+ event == EVENT_RX_MGMT ||
+ event == EVENT_REMAIN_ON_CHANNEL ||
+ event == EVENT_CANCEL_REMAIN_ON_CHANNEL ||
+ event == EVENT_TX_WAIT_EXPIRE;
+}
+#endif /* MAINLINE_SUPPLICANT */
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
@@ -6170,6 +6281,15 @@
int level = MSG_DEBUG;
#endif /* CONFIG_NO_STDOUT_DEBUG */
+#ifdef MAINLINE_SUPPLICANT
+ if (!is_event_allowlisted(event)) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Ignore event %s (%d) which is not allowlisted",
+ event_to_string(event), event);
+ return;
+ }
+#endif /* MAINLINE_SUPPLICANT */
+
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
event != EVENT_INTERFACE_ENABLED &&
event != EVENT_INTERFACE_STATUS &&
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 9229eb5..517c6bc 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -178,7 +178,9 @@
}
#endif /* CONFIG_MATCH_IFACE */
-
+// Temporarily allow the fuzzer library to redefine main()
+// TODO: Remove this flag once mainline supplicant does not include this file
+#ifndef SUPPLICANT_SERVICE_FUZZER
int main(int argc, char *argv[])
{
int c, i;
@@ -409,3 +411,4 @@
return exitcode;
}
+#endif /* SUPPLICANT_SERVICE_FUZZER */
diff --git a/wpa_supplicant/nan_usd.c b/wpa_supplicant/nan_usd.c
index 657b302..1125f95 100644
--- a/wpa_supplicant/nan_usd.c
+++ b/wpa_supplicant/nan_usd.c
@@ -13,6 +13,8 @@
#include "wpa_supplicant_i.h"
#include "offchannel.h"
#include "driver_i.h"
+#include "notify.h"
+#include "p2p_supplicant.h"
#include "nan_usd.h"
@@ -241,19 +243,10 @@
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);
+ wpas_notify_nan_discovery_result(wpa_s, srv_proto_type, subscribe_id,
+ peer_publish_id, peer_addr, fsd,
+ fsd_gas, ssi, ssi_len);
}
@@ -263,34 +256,9 @@
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_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";
+ wpas_notify_nan_replied(wpa_s, srv_proto_type, publish_id,
+ peer_subscribe_id, peer_addr, ssi, ssi_len);
}
@@ -299,9 +267,7 @@
{
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));
+ wpas_notify_nan_publish_terminated(wpa_s, publish_id, reason);
}
@@ -310,9 +276,7 @@
{
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));
+ wpas_notify_nan_subscribe_terminated(wpa_s, subscribe_id, reason);
}
@@ -321,23 +285,28 @@
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);
+ wpas_notify_nan_receive(wpa_s, id, peer_instance_id, peer_addr,
+ ssi, ssi_len);
}
+#ifdef CONFIG_P2P
+static void wpas_nan_process_p2p_usd_elems(void *ctx, const u8 *buf,
+ u16 buf_len, const u8 *peer_addr,
+ unsigned int freq)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpas_p2p_process_usd_elems(wpa_s, buf, buf_len, peer_addr, freq);
+}
+#endif /* CONFIG_P2P */
+
+
int wpas_nan_usd_init(struct wpa_supplicant *wpa_s)
{
struct nan_callbacks cb;
+ bool offload = wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD;
os_memset(&cb, 0, sizeof(cb));
cb.ctx = wpa_s;
@@ -348,8 +317,11 @@
cb.publish_terminated = wpas_nan_de_publish_terminated;
cb.subscribe_terminated = wpas_nan_de_subscribe_terminated;
cb.receive = wpas_nan_de_receive;
+#ifdef CONFIG_P2P
+ cb.process_p2p_usd_elems = wpas_nan_process_p2p_usd_elems;
+#endif /* CONFIG_P2P */
- wpa_s->nan_de = nan_de_init(wpa_s->own_addr, false, &cb);
+ wpa_s->nan_de = nan_de_init(wpa_s->own_addr, offload, false, &cb);
if (!wpa_s->nan_de)
return -1;
return 0;
@@ -377,22 +349,42 @@
if (!wpa_s->nan_de)
return;
nan_de_flush(wpa_s->nan_de);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD)
+ wpas_drv_nan_flush(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)
+ struct nan_publish_params *params, bool p2p)
{
int publish_id;
struct wpabuf *elems = NULL;
+ const u8 *addr;
if (!wpa_s->nan_de)
return -1;
+ if (p2p) {
+ elems = wpas_p2p_usd_elems(wpa_s);
+ addr = wpa_s->global->p2p_dev_addr;
+ } else {
+ addr = wpa_s->own_addr;
+ }
+
publish_id = nan_de_publish(wpa_s->nan_de, service_name, srv_proto_type,
- ssi, elems, params);
+ ssi, elems, params, p2p);
+ if (publish_id >= 1 &&
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) &&
+ wpas_drv_nan_publish(wpa_s, addr, publish_id, service_name,
+ nan_de_get_service_id(wpa_s->nan_de,
+ publish_id),
+ srv_proto_type, ssi, elems, params) < 0) {
+ nan_de_cancel_publish(wpa_s->nan_de, publish_id);
+ publish_id = -1;
+ }
+
wpabuf_free(elems);
return publish_id;
}
@@ -403,15 +395,23 @@
if (!wpa_s->nan_de)
return;
nan_de_cancel_publish(wpa_s->nan_de, publish_id);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD)
+ wpas_drv_nan_cancel_publish(wpa_s, publish_id);
}
int wpas_nan_usd_update_publish(struct wpa_supplicant *wpa_s, int publish_id,
const struct wpabuf *ssi)
{
+ int ret;
+
if (!wpa_s->nan_de)
return -1;
- return nan_de_update_publish(wpa_s->nan_de, publish_id, ssi);
+ ret = nan_de_update_publish(wpa_s->nan_de, publish_id, ssi);
+ if (ret == 0 && (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) &&
+ wpas_drv_nan_cancel_publish(wpa_s, publish_id) < 0)
+ return -1;
+ return ret;
}
@@ -419,16 +419,35 @@
const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi,
- struct nan_subscribe_params *params)
+ struct nan_subscribe_params *params, bool p2p)
{
int subscribe_id;
struct wpabuf *elems = NULL;
+ const u8 *addr;
if (!wpa_s->nan_de)
return -1;
+ if (p2p) {
+ elems = wpas_p2p_usd_elems(wpa_s);
+ addr = wpa_s->global->p2p_dev_addr;
+ } else {
+ addr = wpa_s->own_addr;
+ }
+
subscribe_id = nan_de_subscribe(wpa_s->nan_de, service_name,
- srv_proto_type, ssi, elems, params);
+ srv_proto_type, ssi, elems, params,
+ p2p);
+ if (subscribe_id >= 1 &&
+ (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD) &&
+ wpas_drv_nan_subscribe(wpa_s, addr, subscribe_id, service_name,
+ nan_de_get_service_id(wpa_s->nan_de,
+ subscribe_id),
+ srv_proto_type, ssi, elems, params) < 0) {
+ nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id);
+ subscribe_id = -1;
+ }
+
wpabuf_free(elems);
return subscribe_id;
}
@@ -440,6 +459,8 @@
if (!wpa_s->nan_de)
return;
nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id);
+ if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_NAN_OFFLOAD)
+ wpas_drv_nan_cancel_subscribe(wpa_s, subscribe_id);
}
diff --git a/wpa_supplicant/nan_usd.h b/wpa_supplicant/nan_usd.h
index 149ac9e..ecb4973 100644
--- a/wpa_supplicant/nan_usd.h
+++ b/wpa_supplicant/nan_usd.h
@@ -21,7 +21,7 @@
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);
+ struct nan_publish_params *params, bool p2p);
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);
@@ -29,7 +29,7 @@
const char *service_name,
enum nan_service_protocol_type srv_proto_type,
const struct wpabuf *ssi,
- struct nan_subscribe_params *params);
+ struct nan_subscribe_params *params, bool p2p);
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,
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index d53ae56..2dc68b0 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "common/wpa_ctrl.h"
+#include "common/nan_de.h"
#include "config.h"
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
@@ -25,7 +26,11 @@
#include "p2p_supplicant.h"
#include "sme.h"
#include "notify.h"
-#include "aidl/aidl.h"
+#include "aidl/vendor/aidl.h"
+
+#ifdef MAINLINE_SUPPLICANT
+#include "aidl/mainline/service.h"
+#endif
int wpas_notify_supplicant_initialized(struct wpa_global *global)
{
@@ -47,6 +52,12 @@
}
#endif /* CONFIG_AIDL */
+#ifdef MAINLINE_SUPPLICANT
+ global->aidl = mainline_aidl_init(global);
+ if (!global->aidl)
+ return -1;
+#endif /* MAINLINE_SUPPLICANT */
+
return 0;
}
@@ -62,6 +73,12 @@
if (global->aidl)
wpas_aidl_deinit(global->aidl);
#endif /* CONFIG_AIDL */
+
+#ifdef MAINLINE_SUPPLICANT
+ if (global->aidl)
+ mainline_aidl_deinit(global->aidl);
+#endif /* MAINLINE_SUPPLICANT */
+
}
@@ -210,6 +227,16 @@
}
+void wpas_notify_scan_in_progress_6ghz(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->p2p_mgmt)
+ return;
+
+ wpas_dbus_signal_prop_changed(wpa_s,
+ WPAS_DBUS_PROP_SCAN_IN_PROGRESS_6GHZ);
+}
+
+
void wpas_notify_session_length(struct wpa_supplicant *wpa_s)
{
if (wpa_s->p2p_mgmt)
@@ -1195,6 +1222,7 @@
#endif /* CONFIG_DPP */
}
+#ifdef CONFIG_DPP
void wpas_notify_dpp_connection_status_sent(struct wpa_supplicant *wpa_s,
enum dpp_status_error result)
{
@@ -1205,6 +1233,7 @@
wpas_aidl_notify_dpp_connection_status_sent(wpa_s, result);
#endif /* CONFIG_DPP2 */
}
+#endif /* CONFIG_DPP */
/* DPP Progress notifications */
void wpas_notify_dpp_auth_success(struct wpa_supplicant *wpa_s)
@@ -1302,6 +1331,7 @@
#endif /* CONFIG_DPP2 */
}
+#ifdef CONFIG_DPP
void wpas_notify_dpp_conn_status(struct wpa_supplicant *wpa_s,
enum dpp_status_error status, const char *ssid,
const char *channel_list, unsigned short band_list[], int size)
@@ -1310,6 +1340,7 @@
wpas_aidl_notify_dpp_conn_status(wpa_s, status, ssid, channel_list, band_list, size);
#endif /* CONFIG_DPP2 */
}
+#endif /* CONFIG_DPP */
void wpas_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s)
{
@@ -1457,3 +1488,105 @@
wpas_dbus_signal_hs20_t_c_acceptance(wpa_s, url);
#endif /* CONFIG_HS20 */
}
+
+#ifdef CONFIG_NAN_USD
+
+void wpas_notify_nan_discovery_result(struct wpa_supplicant *wpa_s,
+ enum nan_service_protocol_type
+ srv_proto_type,
+ int subscribe_id, int peer_publish_id,
+ const u8 *peer_addr,
+ bool fsd, bool fsd_gas,
+ const u8 *ssi, size_t ssi_len)
+{
+ 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);
+}
+
+
+void wpas_notify_nan_replied(struct wpa_supplicant *wpa_s,
+ enum nan_service_protocol_type srv_proto_type,
+ int publish_id, int peer_subscribe_id,
+ const u8 *peer_addr,
+ const u8 *ssi, size_t ssi_len)
+{
+ 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_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);
+}
+
+
+void wpas_notify_nan_receive(struct wpa_supplicant *wpa_s, int id,
+ int peer_instance_id, const u8 *peer_addr,
+ const u8 *ssi, size_t ssi_len)
+{
+ 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);
+}
+
+
+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";
+}
+
+
+void wpas_notify_nan_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id,
+ enum nan_de_reason reason)
+{
+ wpa_msg(wpa_s, MSG_INFO, NAN_PUBLISH_TERMINATED
+ "publish_id=%d reason=%s",
+ publish_id, nan_reason_txt(reason));
+}
+
+
+void wpas_notify_nan_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id,
+ enum nan_de_reason reason)
+{
+ wpa_msg(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED
+ "subscribe_id=%d reason=%s",
+ subscribe_id, nan_reason_txt(reason));
+}
+
+#endif /* CONFIG_NAN_USD */
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index a584884..4e172de 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -20,6 +20,8 @@
struct tls_cert_data;
struct wpa_cred;
struct rsn_pmksa_cache_entry;
+enum nan_de_reason;
+enum nan_service_protocol_type;
int wpas_notify_supplicant_initialized(struct wpa_global *global);
void wpas_notify_supplicant_deinitialized(struct wpa_global *global);
@@ -35,6 +37,7 @@
void wpas_notify_auth_timeout(struct wpa_supplicant *wpa_s);
void wpas_notify_roam_time(struct wpa_supplicant *wpa_s);
void wpas_notify_roam_complete(struct wpa_supplicant *wpa_s);
+void wpas_notify_scan_in_progress_6ghz(struct wpa_supplicant *wpa_s);
void wpas_notify_session_length(struct wpa_supplicant *wpa_s);
void wpas_notify_bss_tm_status(struct wpa_supplicant *wpa_s);
void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
@@ -187,8 +190,10 @@
void wpas_notify_dpp_config_received(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, bool conn_status_requested);
void wpas_notify_dpp_config_sent(struct wpa_supplicant *wpa_s);
+#ifdef CONFIG_DPP
void wpas_notify_dpp_connection_status_sent(struct wpa_supplicant *wpa_s,
enum dpp_status_error result);
+#endif /* CONFIG_DPP */
void wpas_notify_dpp_auth_success(struct wpa_supplicant *wpa_s);
void wpas_notify_dpp_resp_pending(struct wpa_supplicant *wpa_s);
void wpas_notify_dpp_not_compatible(struct wpa_supplicant *wpa_s);
@@ -198,9 +203,11 @@
void wpas_notify_dpp_auth_failure(struct wpa_supplicant *wpa_s);
void wpas_notify_dpp_failure(struct wpa_supplicant *wpa_s);
void wpas_notify_dpp_config_sent_wait_response(struct wpa_supplicant *wpa_s);
+#ifdef CONFIG_DPP
void wpas_notify_dpp_conn_status(struct wpa_supplicant *wpa_s,
enum dpp_status_error status, const char *ssid,
const char *channel_list, unsigned short band_list[], int size);
+#endif /* CONFIG_DPP */
void wpas_notify_dpp_config_accepted(struct wpa_supplicant *wpa_s);
void wpas_notify_dpp_config_rejected(struct wpa_supplicant *wpa_s);
void wpas_notify_transition_disable(struct wpa_supplicant *wpa_s,
@@ -234,5 +241,26 @@
enum mlo_info_change_reason reason);
void wpas_notify_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s,
const char *url);
+void wpas_notify_nan_discovery_result(struct wpa_supplicant *wpa_s,
+ enum nan_service_protocol_type
+ srv_proto_type,
+ int subscribe_id, int peer_publish_id,
+ const u8 *peer_addr,
+ bool fsd, bool fsd_gas,
+ const u8 *ssi, size_t ssi_len);
+void wpas_notify_nan_replied(struct wpa_supplicant *wpa_s,
+ enum nan_service_protocol_type srv_proto_type,
+ int publish_id, int peer_subscribe_id,
+ const u8 *peer_addr,
+ const u8 *ssi, size_t ssi_len);
+void wpas_notify_nan_receive(struct wpa_supplicant *wpa_s, int id,
+ int peer_instance_id, const u8 *peer_addr,
+ const u8 *ssi, size_t ssi_len);
+void wpas_notify_nan_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id,
+ enum nan_de_reason reason);
+void wpas_notify_nan_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id,
+ enum nan_de_reason reason);
#endif /* NOTIFY_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 9c20ee5..768b917 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -4501,7 +4501,8 @@
}
-static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
+static void wpas_p2ps_prov_complete(void *ctx, enum p2p_status_code status,
+ const u8 *dev,
const u8 *adv_mac, const u8 *ses_mac,
const u8 *grp_mac, u32 adv_id, u32 ses_id,
u8 conncap, int passwd_id,
@@ -4858,6 +4859,70 @@
WPA_IF_P2P_CLIENT, len, freq_list);
}
+
+static void wpas_p2p_send_bootstrap_comeback(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "P2P2: Send bootstrapping comeback PD Request");
+ wpas_p2p_connect(wpa_s, wpa_s->p2p_bootstrap_dev_addr, wpa_s->p2p_pin,
+ wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
+ 0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
+ wpa_s->p2p_go_vht_center_freq2,
+ wpa_s->p2p_persistent_id,
+ wpa_s->p2p_pd_before_go_neg,
+ wpa_s->p2p_go_ht40,
+ wpa_s->p2p_go_vht,
+ wpa_s->p2p_go_max_oper_chwidth,
+ wpa_s->p2p_go_he,
+ wpa_s->p2p_go_edmg,
+ NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p),
+ wpa_s->p2p2, wpa_s->p2p_bootstrap, NULL);
+}
+
+
+static void wpas_p2p_register_bootstrap_comeback(void *ctx, const u8 *addr,
+ u16 comeback_after)
+{
+ unsigned int timeout_us;
+ struct wpa_supplicant *wpa_s = ctx;
+
+ timeout_us = comeback_after * 1024;
+ os_memcpy(wpa_s->p2p_bootstrap_dev_addr, addr, ETH_ALEN);
+
+ eloop_cancel_timeout(wpas_p2p_send_bootstrap_comeback, wpa_s, NULL);
+ eloop_register_timeout(0, timeout_us, wpas_p2p_send_bootstrap_comeback,
+ wpa_s, NULL);
+}
+
+
+static void wpas_bootstrap_req_rx(void *ctx, const u8 *addr,
+ u16 bootstrap_method)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_BOOTSTRAP_REQUEST MACSTR
+ " bootstrap_method=%u", MAC2STR(addr), bootstrap_method);
+}
+
+
+static void wpas_bootstrap_completed(void *ctx, const u8 *addr,
+ enum p2p_status_code status, int freq)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ if (status) {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_BOOTSTRAP_FAILURE MACSTR " status=%d",
+ MAC2STR(addr), status);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_BOOTSTRAP_SUCCESS MACSTR " status=%d",
+ MAC2STR(addr), status);
+ }
+}
+
+
int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
{
int ret = 0;
@@ -4982,6 +5047,9 @@
p2p.get_pref_freq_list = wpas_p2p_get_pref_freq_list;
p2p.p2p_6ghz_disable = wpa_s->conf->p2p_6ghz_disable;
p2p.p2p_dfs_chan_enable = wpa_s->conf->p2p_dfs_chan_enable;
+ p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback;
+ p2p.bootstrap_req_rx = wpas_bootstrap_req_rx;
+ p2p.bootstrap_completed = wpas_bootstrap_completed;
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
@@ -5097,6 +5165,34 @@
else
p2p.passphrase_len = 8;
+ if (wpa_s->conf->dik &&
+ wpabuf_len(wpa_s->conf->dik) <= DEVICE_IDENTITY_KEY_MAX_LEN) {
+ p2p.pairing_config.dik_cipher = wpa_s->conf->dik_cipher;
+ p2p.pairing_config.dik_len = wpabuf_len(wpa_s->conf->dik);
+ os_memcpy(p2p.pairing_config.dik_data,
+ wpabuf_head(wpa_s->conf->dik),
+ p2p.pairing_config.dik_len);
+ } else {
+ p2p.pairing_config.dik_cipher = DIRA_CIPHER_VERSION_128;
+ p2p.pairing_config.dik_len = DEVICE_IDENTITY_KEY_LEN;
+ if (os_get_random(p2p.pairing_config.dik_data,
+ p2p.pairing_config.dik_len) < 0)
+ return -1;
+
+ wpa_s->conf->dik =
+ wpabuf_alloc_copy(p2p.pairing_config.dik_data,
+ p2p.pairing_config.dik_len);
+ if (!wpa_s->conf->dik)
+ return -1;
+
+ wpa_s->conf->dik_cipher = p2p.pairing_config.dik_cipher;
+
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf))
+ wpa_printf(MSG_DEBUG,
+ "P2P: Failed to update configuration");
+ }
+
global->p2p = p2p_init(&p2p);
if (global->p2p == NULL)
return -1;
@@ -5151,6 +5247,7 @@
wpa_s->p2p_send_action_work = NULL;
}
eloop_cancel_timeout(wpas_p2p_send_action_work_timeout, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_p2p_send_bootstrap_comeback, wpa_s, NULL);
wpabuf_free(wpa_s->p2p_oob_dev_pw);
wpa_s->p2p_oob_dev_pw = NULL;
@@ -5233,7 +5330,8 @@
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
- struct wpa_ssid *ssid, unsigned int pref_freq)
+ struct wpa_ssid *ssid, unsigned int pref_freq,
+ bool p2p2, u16 bootstrap, const char *password)
{
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
@@ -5251,7 +5349,7 @@
ssid ? ssid->ssid_len : 0,
wpa_s->p2p_pd_before_go_neg, pref_freq,
wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
- 0);
+ 0, p2p2, bootstrap, password);
}
@@ -5260,7 +5358,8 @@
enum p2p_wps_method wps_method,
int go_intent, const u8 *own_interface_addr,
unsigned int force_freq, int persistent_group,
- struct wpa_ssid *ssid, unsigned int pref_freq)
+ struct wpa_ssid *ssid, unsigned int pref_freq,
+ u16 bootstrap, const char *password)
{
if (persistent_group && wpa_s->conf->persistent_reconnect)
persistent_group = 2;
@@ -5270,7 +5369,7 @@
persistent_group, ssid ? ssid->ssid : NULL,
ssid ? ssid->ssid_len : 0, pref_freq,
wps_method == WPS_NFC ? wpa_s->p2p_oob_dev_pw_id :
- 0);
+ 0, bootstrap, password);
}
@@ -5454,7 +5553,9 @@
wpa_s->p2p_go_he,
wpa_s->p2p_go_edmg,
NULL, 0,
- is_p2p_allow_6ghz(wpa_s->global->p2p));
+ is_p2p_allow_6ghz(wpa_s->global->p2p),
+ wpa_s->p2p2, wpa_s->p2p_bootstrap,
+ NULL);
return;
}
@@ -5970,6 +6071,9 @@
HOSTAPD_MODE_IEEE80211A, true))
return false;
+ if (wpa_s->p2p2)
+ return true;
+
if (!p2p_wfd_enabled(wpa_s->global->p2p))
return false;
if (peer_addr && !p2p_peer_wfd_enabled(wpa_s->global->p2p, peer_addr))
@@ -6021,6 +6125,10 @@
* @group_ssid: Specific Group SSID for join or %NULL if not set
* @group_ssid_len: Length of @group_ssid in octets
* @allow_6ghz: Allow P2P connection on 6 GHz channels
+ * @p2p2: Whether device is in P2P R2 mode
+ * @bootstrap: Requested bootstrap method for pairing in P2P2
+ * @password: Password for pairing setup or NULL for oppurtunistic method
+ * in P2P2
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
* failure, -2 on failure due to channel not currently available,
* -3 if forced channel is not supported
@@ -6032,7 +6140,8 @@
int persistent_id, int pd, int ht40, int vht,
unsigned int vht_chwidth, int he, int edmg,
const u8 *group_ssid, size_t group_ssid_len,
- bool allow_6ghz)
+ bool allow_6ghz, bool p2p2, u16 bootstrap,
+ const char *password)
{
int force_freq = 0, pref_freq = 0;
int ret = 0, res;
@@ -6052,6 +6161,8 @@
return -1;
}
+ wpa_s->p2p2 = p2p2;
+
if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq))
return -2;
@@ -6082,6 +6193,7 @@
wpa_s->p2p_go_max_oper_chwidth = vht_chwidth;
wpa_s->p2p_go_he = !!he;
wpa_s->p2p_go_edmg = !!edmg;
+ wpa_s->p2p_bootstrap = bootstrap;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -6167,14 +6279,15 @@
if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr,
force_freq, persistent_group, ssid,
- pref_freq) < 0)
+ pref_freq, bootstrap, password) < 0)
return -1;
return ret;
}
if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
go_intent, if_addr, force_freq,
- persistent_group, ssid, pref_freq) < 0) {
+ persistent_group, ssid, pref_freq, p2p2,
+ bootstrap, password) < 0) {
if (wpa_s->create_p2p_iface)
wpas_p2p_remove_pending_group_interface(wpa_s);
return -1;
@@ -8828,7 +8941,8 @@
wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he,
wpa_s->p2p_go_edmg,
- NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p));
+ NULL, 0, is_p2p_allow_6ghz(wpa_s->global->p2p),
+ wpa_s->p2p2, wpa_s->p2p_bootstrap, NULL);
return ret;
}
@@ -9366,7 +9480,8 @@
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
params->go_ssid_len ? params->go_ssid : NULL,
- params->go_ssid_len, false);
+ params->go_ssid_len, false, wpa_s->p2p2,
+ wpa_s->p2p_bootstrap, NULL);
}
@@ -9445,7 +9560,8 @@
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
- NULL, 0, false);
+ NULL, 0, false, wpa_s->p2p2,
+ wpa_s->p2p_bootstrap, NULL);
}
@@ -9462,7 +9578,8 @@
forced_freq, wpa_s->p2p_go_vht_center_freq2,
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
- NULL, 0, false);
+ NULL, 0, false, wpa_s->p2p2,
+ wpa_s->p2p_bootstrap, NULL);
if (res)
return res;
@@ -10330,3 +10447,25 @@
wpa_s->p2p_lo_started = 0;
return ret;
}
+
+
+struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ if (wpa_s->global->p2p_disabled || !p2p)
+ return NULL;
+ return p2p_usd_elems(p2p);
+}
+
+
+void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
+ u16 buf_len, const u8 *peer_addr,
+ unsigned int freq)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ if (wpa_s->global->p2p_disabled || !p2p)
+ return;
+ p2p_process_usd_elems(p2p, buf, buf_len, peer_addr, freq);
+}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index d71f770..a0fbddc 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -39,7 +39,8 @@
int persistent_id, int pd, int ht40, int vht,
unsigned int vht_chwidth, int he, int edmg,
const u8 *group_ssid, size_t group_ssid_len,
- bool allow_6ghz);
+ bool allow_6ghz, bool p2p2, u16 bootstrap,
+ const char *password);
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
int freq, struct wpa_ssid *ssid);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
@@ -178,6 +179,9 @@
void wpas_p2p_pbc_overlap_cb(void *eloop_ctx, void *timeout_ctx);
int wpas_p2p_try_edmg_channel(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params);
+void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
+ u16 buf_len, const u8 *peer_addr,
+ unsigned int freq);
#ifdef CONFIG_P2P
@@ -225,6 +229,7 @@
unsigned int count);
int wpas_p2p_lo_stop(struct wpa_supplicant *wpa_s);
int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s);
#else /* CONFIG_P2P */
@@ -351,6 +356,11 @@
return 0;
}
+static inline struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s)
+{
+ return NULL;
+}
+
#endif /* CONFIG_P2P */
#endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 8b59e40..f0ab122 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -940,9 +940,9 @@
}
-static void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params,
- struct wpa_ssid *ssid, size_t max_ssids)
+void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ const struct wpa_ssid *ssid, size_t max_ssids)
{
#ifdef CONFIG_OWE
struct wpa_bss *bss;
@@ -954,8 +954,7 @@
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
- const u8 *owe, *pos, *end;
- const u8 *owe_ssid;
+ const u8 *owe, *owe_bssid, *owe_ssid;
size_t owe_ssid_len;
if (bss->ssid_len != ssid->ssid_len ||
@@ -966,21 +965,9 @@
if (!owe || owe[1] < 4)
continue;
- pos = owe + 6;
- end = owe + 2 + owe[1];
-
- /* Must include BSSID and ssid_len */
- if (end - pos < ETH_ALEN + 1)
- return;
-
- /* Skip BSSID */
- pos += ETH_ALEN;
- owe_ssid_len = *pos++;
- owe_ssid = pos;
-
- if ((size_t) (end - pos) < owe_ssid_len ||
- owe_ssid_len > SSID_MAX_LEN)
- return;
+ if (wpas_get_owe_trans_network(owe, &owe_bssid, &owe_ssid,
+ &owe_ssid_len))
+ continue;
wpa_printf(MSG_DEBUG,
"OWE: scan_ssids: transition mode OWE ssid=%s",
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index d4c06c1..7ea9992 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -104,5 +104,8 @@
enum chan_width cw);
int wpas_adjust_snr_by_chanwidth(const u8 *ies, size_t ies_len,
enum chan_width max_cw, int snr);
+void wpa_add_owe_scan_ssid(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params,
+ const struct wpa_ssid *ssid, size_t max_ssids);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 57c9b38..e4be388 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -2471,26 +2471,46 @@
wpa_s->sme.assoc_req_ie_len += multi_ap_ie_len;
}
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE_SUPPORT,
+ wpas_rsn_overriding(wpa_s));
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_NOT_USED);
if (wpas_rsn_overriding(wpa_s) &&
wpas_ap_supports_rsn_overriding(wpa_s, wpa_s->current_bss) &&
wpa_s->sme.assoc_req_ie_len + 2 + 4 <=
sizeof(wpa_s->sme.assoc_req_ie)) {
u8 *pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
- u32 type = 0;
const u8 *ie;
+ enum rsn_selection_variant variant = RSN_SELECTION_RSNE;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE);
ie = wpa_bss_get_rsne(wpa_s, wpa_s->current_bss, ssid,
wpa_s->valid_links);
- if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4)
- type = WPA_GET_BE32(&ie[2]);
+ if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4) {
+ u32 type;
- if (type) {
- /* Indicate support for RSN overriding */
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = 4;
- WPA_PUT_BE32(pos, type);
- wpa_s->sme.assoc_req_ie_len += 2 + 4;
+ type = WPA_GET_BE32(&ie[2]);
+ if (type == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
+ variant = RSN_SELECTION_RSNE_OVERRIDE;
+ wpa_sm_set_param(wpa_s->wpa,
+ WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE_OVERRIDE);
+ } else if (type == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
+ variant = RSN_SELECTION_RSNE_OVERRIDE_2;
+ wpa_sm_set_param(wpa_s->wpa,
+ WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE_OVERRIDE_2);
+ }
}
+
+ /* Indicate which RSNE variant was used */
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 + 1;
+ WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
+ pos += 4;
+ *pos = variant;
+ wpa_s->sme.assoc_req_ie_len += 2 + 4 + 1;
}
params.bssid = bssid;
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index ea79ae6..3bb621d 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -27,7 +27,6 @@
#define MAX_TFS_IE_LEN 1024
#define WNM_MAX_NEIGHBOR_REPORT 10
-#define WNM_SCAN_RESULT_AGE 2 /* 2 seconds */
/* get the TFS IE from driver */
static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
@@ -556,7 +555,7 @@
}
freq = ieee80211_chan_to_freq(country, op_class, chan);
- if (freq <= 0 && op_class == 0) {
+ if (freq <= 0 && (op_class == 0 || op_class == 255)) {
/*
* Some APs do not advertise correct operating class
* information. Try to determine the most likely operating
@@ -740,7 +739,7 @@
}
static struct wpa_bss *
-compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs,
+compare_scan_neighbor_results(struct wpa_supplicant *wpa_s,
enum mbo_transition_reject_reason *reason)
{
u8 i;
@@ -761,11 +760,6 @@
struct neighbor_report *nei;
nei = &wpa_s->wnm_neighbor_report_elements[i];
- if (nei->preference_present && nei->preference == 0) {
- wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR,
- MAC2STR(nei->bssid));
- continue;
- }
target = wpa_bss_get_bssid(wpa_s, nei->bssid);
if (!target) {
@@ -777,19 +771,6 @@
continue;
}
- if (age_secs) {
- struct os_reltime now;
-
- if (os_get_reltime(&now) == 0 &&
- os_reltime_expired(&now, &target->last_update,
- age_secs)) {
- wpa_printf(MSG_DEBUG,
- "Candidate BSS is more than %ld seconds old",
- age_secs);
- continue;
- }
- }
-
/*
* TODO: Could consider allowing transition to another ESS if
* PMF was enabled for the association.
@@ -1192,8 +1173,13 @@
goto send_bss_resp_fail;
}
+ if (!pre_scan_check && !wpa_s->wnm_transition_scan)
+ return 0;
+
+ wpa_s->wnm_transition_scan = false;
+
/* Compare the Neighbor Report and scan results */
- bss = compare_scan_neighbor_results(wpa_s, 0, &reason);
+ bss = compare_scan_neighbor_results(wpa_s, &reason);
/*
* If this is a pre-scan check, returning 0 will trigger a scan and
@@ -1235,11 +1221,19 @@
return 1;
send_bss_resp_fail:
- /* Send reject response for all the failures */
+ if (wpa_s->wnm_reply) {
+ /* If disassoc imminent is set, we must not reject */
+ if (wpa_s->wnm_mode &
+ (WNM_BSS_TM_REQ_DISASSOC_IMMINENT |
+ WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Accept BTM request because disassociation imminent bit is set");
+ status = WNM_BSS_TM_ACCEPT;
+ }
- if (wpa_s->wnm_reply)
wnm_send_bss_transition_mgmt_resp(wpa_s, status, reason,
0, NULL);
+ }
wnm_btm_reset(wpa_s);
@@ -1376,6 +1370,63 @@
}
+static int wnm_parse_candidate_list(struct wpa_supplicant *wpa_s,
+ const u8 *pos, const u8 *end,
+ int *num_valid_candidates)
+{
+ *num_valid_candidates = 0;
+
+ while (end - pos >= 2 &&
+ wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) {
+ u8 tag = *pos++;
+ u8 len = *pos++;
+
+ wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", tag);
+ if (len > end - pos) {
+ wpa_printf(MSG_DEBUG, "WNM: Truncated request");
+ return -1;
+ }
+ if (tag == WLAN_EID_NEIGHBOR_REPORT) {
+ struct neighbor_report *rep;
+
+ if (!wpa_s->wnm_num_neighbor_report) {
+ wpa_s->wnm_neighbor_report_elements = os_calloc(
+ WNM_MAX_NEIGHBOR_REPORT,
+ sizeof(struct neighbor_report));
+ if (!wpa_s->wnm_neighbor_report_elements)
+ return -1;
+ }
+
+ 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;
+
+ if (rep->preference_present && rep->preference)
+ *num_valid_candidates += 1;
+
+ wpa_s->wnm_num_neighbor_report++;
+#ifdef CONFIG_MBO
+ if (wpa_s->wnm_mbo_trans_reason_present &&
+ wpa_s->wnm_num_neighbor_report == 1) {
+ rep->is_first = 1;
+ wpa_printf(MSG_DEBUG,
+ "WNM: First transition candidate is "
+ MACSTR, MAC2STR(rep->bssid));
+ }
+#endif /* CONFIG_MBO */
+ }
+
+ pos += len;
+ }
+
+ return 0;
+}
+
+
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
const u8 *pos, const u8 *end,
int reply)
@@ -1386,6 +1437,7 @@
const u8 *vendor;
#endif /* CONFIG_MBO */
bool disassoc_imminent;
+ int num_valid_candidates;
if (wpa_s->disable_mbo_oce || wpa_s->conf->disable_btm)
return;
@@ -1409,7 +1461,7 @@
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_disassoc_timer = WPA_GET_LE16(pos + 2);
wpa_s->wnm_link_removal = false;
valid_int = pos[4];
wpa_s->wnm_reply = reply;
@@ -1418,7 +1470,12 @@
"dialog_token=%u request_mode=0x%x "
"disassoc_timer=%u validity_interval=%u",
wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
- wpa_s->wnm_dissoc_timer, valid_int);
+ wpa_s->wnm_disassoc_timer, valid_int);
+
+ if (!wpa_s->wnm_dialog_token) {
+ wpa_printf(MSG_DEBUG, "WNM: Invalid dialog token");
+ goto reset;
+ }
#if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS)
if (wpa_s->reject_btm_req_reason) {
@@ -1428,7 +1485,7 @@
wnm_send_bss_transition_mgmt_resp(
wpa_s, wpa_s->reject_btm_req_reason,
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
- return;
+ goto reset;
}
#endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */
@@ -1437,7 +1494,7 @@
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
if (end - pos < 12) {
wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
- return;
+ goto reset;
}
os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12);
pos += 12; /* BSS Termination Duration */
@@ -1450,13 +1507,13 @@
if (end - pos < 1) {
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
"Management Request (URL)");
- return;
+ goto reset;
}
url_len = *pos++;
if (url_len > end - pos) {
wpa_printf(MSG_DEBUG,
"WNM: Invalid BSS Transition Management Request (URL truncated)");
- return;
+ goto reset;
}
os_memcpy(url, pos, url_len);
url[url_len] = '\0';
@@ -1464,7 +1521,8 @@
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);
+ wpa_s->wnm_disassoc_timer * beacon_int * 128 / 125,
+ url);
}
#ifdef CONFIG_MBO
@@ -1505,77 +1563,34 @@
wnm_send_bss_transition_mgmt_resp(
wpa_s, WNM_BSS_TM_ACCEPT, 0, 0, NULL);
- return;
+ goto reset;
}
/* 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->wnm_disassoc_mld = false;
+ os_memcpy(wpa_s->wnm_disassoc_addr,
wpa_s->links[wpa_s->mlo_assoc_link_id].bssid,
ETH_ALEN);
+ } else if (wpa_s->valid_links) {
+ wpa_s->wnm_disassoc_mld = true;
+ os_memcpy(wpa_s->wnm_disassoc_addr, wpa_s->ap_mld_addr,
+ ETH_ALEN);
} else {
- os_memcpy(wpa_s->wnm_dissoc_addr, wpa_s->valid_links ?
- wpa_s->ap_mld_addr : wpa_s->bssid, ETH_ALEN);
+ wpa_s->wnm_disassoc_mld = false;
+ os_memcpy(wpa_s->wnm_disassoc_addr, wpa_s->bssid, ETH_ALEN);
}
- if (disassoc_imminent) {
+ 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 &&
- (!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);
- }
- }
+ "Disassociation Timer %u", wpa_s->wnm_disassoc_timer);
+
+ if (wnm_parse_candidate_list(wpa_s, pos, end,
+ &num_valid_candidates) < 0)
+ goto reset;
if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
- unsigned int valid_ms;
-
- wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
- wpa_s->wnm_neighbor_report_elements = os_calloc(
- WNM_MAX_NEIGHBOR_REPORT,
- sizeof(struct neighbor_report));
- if (wpa_s->wnm_neighbor_report_elements == NULL)
- return;
-
- while (end - pos >= 2 &&
- wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT)
- {
- u8 tag = *pos++;
- u8 len = *pos++;
-
- wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u",
- tag);
- if (len > end - pos) {
- wpa_printf(MSG_DEBUG, "WNM: Truncated request");
- return;
- }
- if (tag == WLAN_EID_NEIGHBOR_REPORT) {
- struct neighbor_report *rep;
- 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 &&
- wpa_s->wnm_num_neighbor_report == 1) {
- rep->is_first = 1;
- wpa_printf(MSG_DEBUG,
- "WNM: First transition candidate is "
- MACSTR, MAC2STR(rep->bssid));
- }
-#endif /* CONFIG_MBO */
- }
-
- pos += len;
- }
-
if (!wpa_s->wnm_num_neighbor_report) {
wpa_printf(MSG_DEBUG,
"WNM: Candidate list included bit is set, but no candidates found");
@@ -1583,18 +1598,13 @@
wpa_s, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
NULL);
- return;
+ goto reset;
}
+ wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
+ }
- 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;
- }
+ if (wpa_s->wnm_num_neighbor_report) {
+ unsigned int valid_ms;
wnm_sort_cand_list(wpa_s);
wnm_dump_cand_list(wpa_s);
@@ -1602,40 +1612,12 @@
wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms",
valid_ms);
os_get_reltime(&wpa_s->wnm_cand_valid_until);
- wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000;
- wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000;
- wpa_s->wnm_cand_valid_until.sec +=
- wpa_s->wnm_cand_valid_until.usec / 1000000;
- wpa_s->wnm_cand_valid_until.usec %= 1000000;
-
- /*
- * 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;
- 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) {
- os_memcpy(wpa_s->next_scan_bssid,
- wpa_s->wnm_neighbor_report_elements[0].bssid,
- ETH_ALEN);
- wpa_printf(MSG_DEBUG,
- "WNM: Scan only for a specific BSSID since there is only a single candidate "
- MACSTR, MAC2STR(wpa_s->next_scan_bssid));
- }
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else if (reply) {
+ os_reltime_add_ms(&wpa_s->wnm_cand_valid_until, valid_ms);
+ } else if (!disassoc_imminent) {
enum bss_trans_mgmt_status_code status;
+ /* No candidate list and disassociation is not imminent */
+
if ((wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) ||
wpa_s->wnm_link_removal)
status = WNM_BSS_TM_ACCEPT;
@@ -1643,10 +1625,66 @@
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, status,
- MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0, NULL);
+
+ if (reply)
+ wnm_send_bss_transition_mgmt_resp(
+ wpa_s, status,
+ MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
+ NULL);
+
+ goto reset;
}
+
+ /*
+ * 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;
+ wpa_printf(MSG_DEBUG,
+ "WNM: No valid match in previous scan results - try a new scan");
+
+ /*
+ * If we have a fixed BSSID configured, just reject at this point.
+ * NOTE: We could actually check if we are allowed to stay (and we do
+ * above if we have scan results available).
+ */
+ if (wpa_s->current_ssid && wpa_s->current_ssid->bssid_set) {
+ wpa_printf(MSG_DEBUG, "WNM: Fixed BSSID, rejecting request");
+
+ if (reply)
+ wnm_send_bss_transition_mgmt_resp(
+ wpa_s, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES,
+ MBO_TRANSITION_REJECT_REASON_UNSPECIFIED, 0,
+ NULL);
+
+ goto reset;
+ }
+
+ wnm_set_scan_freqs(wpa_s);
+ if (num_valid_candidates == 1) {
+ /* Any invalid candidate was sorted to the end */
+ os_memcpy(wpa_s->next_scan_bssid,
+ wpa_s->wnm_neighbor_report_elements[0].bssid,
+ ETH_ALEN);
+ wpa_printf(MSG_DEBUG,
+ "WNM: Scan only for a specific BSSID since there is only a single candidate "
+ MACSTR, MAC2STR(wpa_s->next_scan_bssid));
+ }
+ wpa_s->wnm_transition_scan = true;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ /* Continue from scan handler */
+ return;
+
+reset:
+ wnm_btm_reset(wpa_s);
}
@@ -2067,22 +2105,41 @@
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;
+ int i;
/*
* 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;
+ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
+ if (!wpa_s->wnm_disassoc_mld) {
+ if (ether_addr_equal(bss->bssid,
+ wpa_s->wnm_disassoc_addr))
+ return true;
+ } else {
+ if (ether_addr_equal(bss->mld_addr,
+ wpa_s->wnm_disassoc_addr))
+ return true;
+ }
}
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ struct neighbor_report *nei;
+
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+ if (!ether_addr_equal(nei->bssid, bss->bssid))
+ continue;
+
+ if (nei->preference_present && nei->preference == 0)
+ return true;
+
+ break;
+ }
+
+ /* If the abridged bit is set, the BSS must be a known neighbor. */
+ if ((wpa_s->wnm_mode & WNM_BSS_TM_REQ_ABRIDGED) &&
+ wpa_s->wnm_num_neighbor_report == i)
+ return true;
+
return false;
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 15a859f..e3ed858 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -70,7 +70,7 @@
#include "ap/ap_config.h"
#include "ap/hostapd.h"
#endif /* CONFIG_MESH */
-#include "aidl/aidl.h"
+#include "aidl/vendor/aidl.h"
const char *const wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
@@ -418,8 +418,13 @@
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsne_override(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsne_override_2(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe_override(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+#ifndef CONFIG_NO_WPA
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+#endif /* CONFIG_NO_WPA */
wpa_s->rsnxe_len = 0;
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
@@ -1838,12 +1843,31 @@
!!(ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)));
if (bss || !wpa_s->ap_ies_from_associnfo) {
+ const u8 *rsnoe = NULL, *rsno2e = NULL, *rsnxoe = NULL;
+
+ if (bss) {
+ bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ rsnoe = wpa_bss_get_vendor_ie(
+ bss, RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ rsno2e = wpa_bss_get_vendor_ie(
+ bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+ rsnxoe = wpa_bss_get_vendor_ie(
+ bss, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+ }
+
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
bss_rsn ? 2 + bss_rsn[1] : 0) ||
wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
- bss_rsnx ? 2 + bss_rsnx[1] : 0))
+ bss_rsnx ? 2 + bss_rsnx[1] : 0) ||
+ wpa_sm_set_ap_rsne_override(wpa_s->wpa, rsnoe,
+ rsnoe ? 2 + rsnoe[1] : 0) ||
+ wpa_sm_set_ap_rsne_override_2(wpa_s->wpa, rsno2e,
+ rsno2e ? 2 + rsno2e[1] : 0) ||
+ wpa_sm_set_ap_rsnxe_override(wpa_s->wpa, rsnxoe,
+ rsnxoe ? 2 + rsnxoe[1] : 0))
return -1;
}
@@ -2145,6 +2169,7 @@
return -1;
}
+#ifndef CONFIG_NO_WPA
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)) {
@@ -2152,6 +2177,7 @@
"RSN: Failed to generate RSNXE");
return -1;
}
+#endif /* CONFIG_NO_WPA */
}
if (0) {
@@ -3968,57 +3994,48 @@
wpa_ie_len += multi_ap_ie_len;
}
- if (!wpas_driver_bss_selection(wpa_s) &&
- wpas_rsn_overriding(wpa_s) &&
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE_SUPPORT,
+ wpas_rsn_overriding(wpa_s));
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_NOT_USED);
+ if (wpas_rsn_overriding(wpa_s) &&
wpas_ap_supports_rsn_overriding(wpa_s, bss) &&
- wpa_ie_len + 2 + 4 <= max_wpa_ie_len) {
- u8 *pos = wpa_ie + wpa_ie_len;
- u32 type = 0;
+ wpa_ie_len + 2 + 4 + 1 <= max_wpa_ie_len) {
+ u8 *pos = wpa_ie + wpa_ie_len, *start = pos;
const u8 *ie;
+ enum rsn_selection_variant variant = RSN_SELECTION_RSNE;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE);
ie = wpa_bss_get_rsne(wpa_s, bss, ssid, wpa_s->valid_links);
- if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4)
+ if (ie && ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie[1] >= 4) {
+ u32 type;
+
type = WPA_GET_BE32(&ie[2]);
-
- if (type) {
- /* Indicate support for RSN overriding */
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = 4;
- WPA_PUT_BE32(pos, type);
- pos += 4;
- wpa_hexdump(MSG_MSGDUMP, "RSNE Override", wpa_ie,
- pos - wpa_ie);
- wpa_ie_len += 2 + 4;
+ if (type == RSNE_OVERRIDE_IE_VENDOR_TYPE) {
+ variant = RSN_SELECTION_RSNE_OVERRIDE;
+ wpa_sm_set_param(wpa_s->wpa,
+ WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE_OVERRIDE);
+ } else if (type == RSNE_OVERRIDE_2_IE_VENDOR_TYPE) {
+ variant = RSN_SELECTION_RSNE_OVERRIDE_2;
+ wpa_sm_set_param(wpa_s->wpa,
+ WPA_PARAM_RSN_OVERRIDE,
+ RSN_OVERRIDE_RSNE_OVERRIDE_2);
+ }
}
+
+ /* Indicate which RSNE variant was used */
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 + 1;
+ WPA_PUT_BE32(pos, RSN_SELECTION_IE_VENDOR_TYPE);
+ pos += 4;
+ *pos++ = variant;
+ wpa_hexdump(MSG_MSGDUMP, "RSN Selection", start, pos - start);
+ wpa_ie_len += pos - start;
}
- if (wpas_driver_bss_selection(wpa_s) &&
- wpas_rsn_overriding(wpa_s)) {
- if (wpa_ie_len + 2 + 4 <= max_wpa_ie_len) {
- u8 *pos = wpa_ie + wpa_ie_len;
-
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = 4;
- WPA_PUT_BE32(pos, RSNE_OVERRIDE_IE_VENDOR_TYPE);
- pos += 4;
- wpa_hexdump(MSG_MSGDUMP, "RSNE Override", wpa_ie,
- pos - wpa_ie);
- wpa_ie_len += 2 + 4;
- }
-
- if (wpa_ie_len + 2 + 4 <= max_wpa_ie_len) {
- u8 *pos = wpa_ie + wpa_ie_len;
-
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = 4;
- WPA_PUT_BE32(pos, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
- pos += 4;
- wpa_hexdump(MSG_MSGDUMP, "RSNE Override 2",
- wpa_ie, pos - wpa_ie);
- wpa_ie_len += 2 + 4;
- }
- }
-
+ params->rsn_overriding = wpas_rsn_overriding(wpa_s);
params->wpa_ie = wpa_ie;
params->wpa_ie_len = wpa_ie_len;
params->auth_alg = algs;
@@ -4283,7 +4300,9 @@
/* Starting new association, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+#ifndef CONFIG_NO_WPA
wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+#endif /* CONFIG_NO_WPA */
wpa_s->rsnxe_len = 0;
#ifndef CONFIG_NO_ROBUST_AV
wpa_s->mscs_setup_done = false;
@@ -4755,8 +4774,10 @@
}
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
+#ifndef CONFIG_NO_WPA
if (bss)
wpa_sm_set_ssid(wpa_s->wpa, bss->ssid, bss->ssid_len);
+#endif /* CONFIG_NO_WPA */
wpa_supplicant_initiate_eapol(wpa_s);
if (old_ssid != wpa_s->current_ssid)
wpas_notify_network_changed(wpa_s);
@@ -5511,8 +5532,8 @@
static int owe_trans_ssid_match(struct wpa_supplicant *wpa_s, const u8 *bssid,
const u8 *entry_ssid, size_t entry_ssid_len)
{
- const u8 *owe, *pos, *end;
- u8 ssid_len;
+ const u8 *owe, *owe_bssid, *owe_ssid;
+ size_t owe_ssid_len;
struct wpa_bss *bss;
/* Check network profile SSID aganst the SSID in the
@@ -5526,18 +5547,12 @@
if (!owe)
return 0;
- pos = owe + 6;
- end = owe + 2 + owe[1];
-
- if (end - pos < ETH_ALEN + 1)
- return 0;
- pos += ETH_ALEN;
- ssid_len = *pos++;
- if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN)
+ if (wpas_get_owe_trans_network(owe, &owe_bssid, &owe_ssid,
+ &owe_ssid_len))
return 0;
- return entry_ssid_len == ssid_len &&
- os_memcmp(pos, entry_ssid, ssid_len) == 0;
+ return entry_ssid_len == owe_ssid_len &&
+ os_memcmp(owe_ssid, entry_ssid, owe_ssid_len) == 0;
}
#endif /* CONFIG_OWE */
@@ -7517,9 +7532,11 @@
#ifdef CONFIG_PASN
wpa_pasn_sm_set_caps(wpa_s->wpa, wpa_s->drv_flags2);
#endif /* CONFIG_PASN */
+#ifndef CONFIG_NO_WPA
wpa_sm_set_driver_bss_selection(wpa_s->wpa,
!!(wpa_s->drv_flags &
WPA_DRIVER_FLAGS_BSS_SELECTION));
+#endif /* CONFIG_NO_WPA */
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
@@ -9787,3 +9804,34 @@
return false;
}
+
+
+int wpas_get_owe_trans_network(const u8 *owe_ie, const u8 **bssid,
+ const u8 **ssid, size_t *ssid_len)
+{
+#ifdef CONFIG_OWE
+ const u8 *pos, *end;
+ u8 ssid_len_tmp;
+
+ if (!owe_ie)
+ return -1;
+
+ pos = owe_ie + 6;
+ end = owe_ie + 2 + owe_ie[1];
+
+ if (end - pos < ETH_ALEN + 1)
+ return -1;
+ *bssid = pos;
+ pos += ETH_ALEN;
+ ssid_len_tmp = *pos++;
+ if (end - pos < ssid_len_tmp || ssid_len_tmp > SSID_MAX_LEN)
+ return -1;
+
+ *ssid = pos;
+ *ssid_len = ssid_len_tmp;
+
+ return 0;
+#else /* CONFIG_OWE */
+ return -1;
+#endif /* CONFIG_OWE */
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 245ac93..84b7bd5 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1135,6 +1135,7 @@
int pending_pd_before_join;
u8 pending_join_iface_addr[ETH_ALEN];
u8 pending_join_dev_addr[ETH_ALEN];
+ u8 p2p_bootstrap_dev_addr[ETH_ALEN];
int pending_join_wps_method;
u8 p2p_join_ssid[SSID_MAX_LEN];
size_t p2p_join_ssid_len;
@@ -1189,6 +1190,8 @@
unsigned int p2ps_method_config_any:1;
unsigned int p2p_cli_probe:1;
unsigned int p2p_go_allow_dfs:1;
+ unsigned int p2p2:1;
+ u16 p2p_bootstrap;
enum hostapd_hw_mode p2p_go_acs_band;
int p2p_persistent_go_freq;
int p2p_persistent_id;
@@ -1324,13 +1327,15 @@
u8 *mac_addr_pno;
#ifdef CONFIG_WNM
+ bool wnm_transition_scan;
u8 wnm_dialog_token;
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;
+ bool wnm_disassoc_mld;
+ u8 wnm_disassoc_addr[ETH_ALEN];
+ u16 wnm_disassoc_timer;
u8 wnm_bss_termination_duration[12];
struct neighbor_report *wnm_neighbor_report_elements;
struct os_reltime wnm_cand_valid_until;
@@ -1607,6 +1612,7 @@
bool wps_scan_done; /* Set upon receiving scan results event */
bool supp_pbc_active; /* Set for interface when PBC is triggered */
bool wps_overlap;
+ bool scan_in_progress_6ghz; /* Set upon a 6 GHz scan being triggered */
#ifdef CONFIG_PASN
struct pasn_data pasn;
@@ -2057,5 +2063,7 @@
struct wpa_bss *bss);
bool wpas_ap_supports_rsn_overriding_2(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss);
+int wpas_get_owe_trans_network(const u8 *owe_ie, const u8 **bssid,
+ const u8 **ssid, size_t *ssid_len);
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index 6a2fbd3..cec26c4 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -9,4 +9,3 @@
sae_pwe=2
p2p_optimize_listen_chan=1
wowlan_disconnect_on_deinit=1
-sae_pmkid_in_assoc=1
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index de216d2..741ac6c 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -148,6 +148,7 @@
{
struct wpa_supplicant *wpa_s = ctx;
u8 *msg, *dst, bssid[ETH_ALEN];
+ struct driver_sta_mlo_info drv_mlo;
size_t msglen;
int res;
@@ -197,11 +198,16 @@
if (is_zero_ether_addr(wpa_s->bssid)) {
wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an "
"EAPOL frame");
+ os_memset(&drv_mlo, 0, sizeof(drv_mlo));
if (wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+ (!wpa_s->valid_links ||
+ wpas_drv_get_sta_mlo_info(wpa_s, &drv_mlo) == 0) &&
!is_zero_ether_addr(bssid)) {
- dst = bssid;
- wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR
+ dst = drv_mlo.valid_links ? drv_mlo.ap_mld_addr : bssid;
+ wpa_printf(MSG_DEBUG, "Using current %s " MACSTR
" from the driver as the EAPOL destination",
+ drv_mlo.valid_links ? "AP MLD MAC address" :
+ "BSSID",
MAC2STR(dst));
} else {
dst = wpa_s->last_eapol_src;
@@ -211,9 +217,10 @@
MAC2STR(dst));
}
} else {
- /* BSSID was already set (from (Re)Assoc event, so use it as
- * the EAPOL destination. */
- dst = wpa_s->bssid;
+ /* BSSID was already set (from (Re)Assoc event, so use BSSID or
+ * AP MLD MAC address (in the case of MLO connection) as the
+ * EAPOL destination. */
+ dst = wpa_s->valid_links ? wpa_s->ap_mld_addr : wpa_s->bssid;
}
msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL);
@@ -441,13 +448,29 @@
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
ret = -1;
- ie = wpa_bss_get_rsne(wpa_s, curr, ssid, false);
+ ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
ret = -1;
- ie = wpa_bss_get_rsnxe(wpa_s, curr, ssid, false);
+ ie = wpa_bss_get_ie(curr, WLAN_EID_RSNX);
if (wpa_sm_set_ap_rsnxe(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
ret = -1;
+
+ ie = wpa_bss_get_vendor_ie(curr, RSNE_OVERRIDE_IE_VENDOR_TYPE);
+ if (wpa_sm_set_ap_rsne_override(wpa_s->wpa, ie,
+ ie ? 2 + ie[1] : 0))
+ ret = -1;
+
+ ie = wpa_bss_get_vendor_ie(curr,
+ RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
+ if (wpa_sm_set_ap_rsne_override_2(wpa_s->wpa, ie,
+ ie ? 2 + ie[1] : 0))
+ ret = -1;
+
+ ie = wpa_bss_get_vendor_ie(curr, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
+ if (wpa_sm_set_ap_rsnxe_override(wpa_s->wpa, ie,
+ ie ? 2 + ie[1] : 0))
+ ret = -1;
} else {
ret = -1;
}