[automerger skipped] Merge 25Q1 (ab/12770256) to aosp-main-future am: 9a20af373f -s ours
am skip reason: Merged-In I2d7b02e2d8fbf84431da41163c39af1109fd835c with SHA-1 e1dbf79252 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/external/wpa_supplicant_8/+/31817402
Change-Id: Ie8546f1df5dc776eab22657c81594d36ee6b53de
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/apex/Android.bp b/apex/Android.bp
new file mode 100644
index 0000000..5fca381
--- /dev/null
+++ b/apex/Android.bp
@@ -0,0 +1,36 @@
+prebuilt_etc {
+ name: "wpa_supplicant.conf.prebuilt",
+ src: ":wpa_supplicant_template.conf",
+ filename: "wpa_supplicant.conf",
+ relative_install_path: "wifi",
+ installable: false,
+}
+
+apex {
+ name: "com.android.hardware.wpa_supplicant",
+ manifest: "apex_manifest.json",
+ file_contexts: "file_contexts",
+ // TODO: b/363080108 - Replace placeholder key with release key
+ key: "com.android.hardware.key",
+ certificate: ":com.android.hardware.certificate",
+ updatable: false,
+ vendor: true,
+
+ enabled: select(soong_config_variable("wpa_supplicant_8", "wpa_build_hostapd"), {
+ true: true,
+ default: false,
+ }),
+ binaries: [
+ "wpa_supplicant",
+ "hostapd",
+ ],
+ prebuilts: [
+ "com.android.hardware.wpa_supplicant.rc",
+ "com.android.hardware.hostapd.rc",
+ "wpa_supplicant.conf.prebuilt",
+ ],
+ vintf_fragment_modules: [
+ "android.hardware.wifi.hostapd.xml",
+ "android.hardware.wifi.supplicant.xml",
+ ],
+}
diff --git a/apex/apex_manifest.json b/apex/apex_manifest.json
new file mode 100644
index 0000000..58b0640
--- /dev/null
+++ b/apex/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.wpa_supplicant",
+ "version": 1
+}
\ No newline at end of file
diff --git a/apex/file_contexts b/apex/file_contexts
new file mode 100644
index 0000000..64599d6
--- /dev/null
+++ b/apex/file_contexts
@@ -0,0 +1,4 @@
+(/.*)? u:object_r:vendor_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
+/bin/hw/wpa_supplicant u:object_r:hal_wifi_supplicant_default_exec:s0
+/bin/hw/hostapd u:object_r:hal_wifi_hostapd_default_exec:s0
\ No newline at end of file
diff --git a/hostapd/Android.bp b/hostapd/Android.bp
index 4f76a30..4753644 100644
--- a/hostapd/Android.bp
+++ b/hostapd/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// The hostapd related modules are split into 2 sections:
+// 1. For cuttlefish series products, start from `hostapd_headers` to `hostapd_cli_srcs`.
+// 2. For non-cuttlefish series products, ex: physical devices created by oems,
+// the section starts from `hostapd_driver_srcs_default` to the end of this file.
+
package {
default_applicable_licenses: [
"external_wpa_supplicant_8_license",
@@ -29,6 +34,9 @@
],
}
+// The section below is for cuttlefish series products. For non-cuttlefish
+// products please update the section starting at `hostapd_driver_srcs_default`.
+// Start of cuttlefish section.
cc_library_headers {
name: "hostapd_headers",
export_include_dirs: [
@@ -363,7 +371,29 @@
installable: false,
}
-// For converting the default to soong
+// End of cuttlefish section.
+
+// The section starting below is for non-cuttlefish products.
+// For cuttlefish series please update the section starting from `hostapd_headers`.
+
+// If you need to add a new build setting based on a product config, ex:
+// ifeq ($(BOARD_HOSTAPD_CONFIG_80211W_MFP_OPTIONAL),true)
+// L_CFLAGS += -DENABLE_HOSTAPD_CONFIG_80211W_MFP_OPTIONAL
+// endif
+
+// In order to export the Makefile variable to soong, you will need to use a `soong_config_set` method
+// under `build/core/board_config_wpa_supplicant.mk`. Ex:
+// ifeq ($(BOARD_HOSTAPD_CONFIG_80211W_MFP_OPTIONAL),true)
+// $(call soong_config_set_bool,wpa_supplicant_8,board_hostapd_config_80211w_mfp_optional,true)
+// endif
+
+// And then use the select statement in Android.bp to reflect the condition you need, ex:
+// select(soong_config_variable("wpa_supplicant_8", "board_hostapd_config_80211w_mfp_optional"), {
+// true: ["-DENABLE_HOSTAPD_CONFIG_80211W_MFP_OPTIONAL"],
+// default: [],
+// })
+
+// Start of non-cuttlefish section
cc_defaults {
name: "hostapd_driver_srcs_default",
srcs: [
@@ -451,6 +481,9 @@
}) + select(soong_config_variable("wpa_supplicant_8", "hostapd_11ax"), {
true: ["-DCONFIG_IEEE80211AX"],
default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "hostapd_11be"), {
+ true: ["-DCONFIG_IEEE80211BE"],
+ default: [],
}) + select(soong_config_variable("wpa_supplicant_8", "board_hostapd_config_80211w_mfp_optional"), {
true: ["-DENABLE_HOSTAPD_CONFIG_80211W_MFP_OPTIONAL"],
default: [],
@@ -602,6 +635,10 @@
] + select(soong_config_variable("wpa_supplicant_8", "hostapd_11ax"), {
true: ["src/ap/ieee802_11_he.c"],
default: [],
+ }) +
+ select(soong_config_variable("wpa_supplicant_8", "hostapd_11be"), {
+ true: ["src/ap/ieee802_11_eht.c"],
+ default: [],
}),
defaults: [
"hostapd_driver_srcs_default",
@@ -704,3 +741,18 @@
"hostapd_includes_default",
],
}
+
+// End of non-cuttlefish section
+
+genrule {
+ name: "com.android.hardware.hostapd.rc-gen",
+ srcs: ["hostapd.android.rc"],
+ out: ["com.android.hardware.hostapd.rc"],
+ cmd: "sed -E 's@/vendor/bin@/apex/com.android.hardware.wpa_supplicant/bin@' $(in) > $(out)",
+}
+
+prebuilt_etc {
+ name: "com.android.hardware.hostapd.rc",
+ src: ":com.android.hardware.hostapd.rc-gen",
+ installable: false,
+}
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 680c572..5674962 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -276,6 +276,7 @@
ifdef CONFIG_SAE_PK
L_CFLAGS += -DCONFIG_SAE_PK
NEED_AES_SIV=y
+NEED_BASE64=y
OBJS += src/common/sae_pk.c
endif
NEED_ECC=y
@@ -956,6 +957,17 @@
endif
endif
+ifdef CONFIG_SAE
+ifdef NEED_SHA384
+# Need to add HMAC-SHA384 KDF as well, if SHA384 was enabled.
+NEED_HMAC_SHA384_KDF=y
+endif
+ifdef NEED_SHA512
+# Need to add HMAC-SHA512 KDF as well, if SHA512 was enabled.
+NEED_HMAC_SHA512_KDF=y
+endif
+endif
+
L_CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), gnutls)
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 489922c..4c31ba9 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -299,6 +299,7 @@
ifdef CONFIG_SAE_PK
CFLAGS += -DCONFIG_SAE_PK
NEED_AES_SIV=y
+NEED_BASE64=y
OBJS += ../src/common/sae_pk.o
endif
NEED_ECC=y
@@ -1069,6 +1070,17 @@
endif
endif
+ifdef CONFIG_SAE
+ifdef NEED_SHA384
+# Need to add HMAC-SHA384 KDF as well, if SHA384 was enabled.
+NEED_HMAC_SHA384_KDF=y
+endif
+ifdef NEED_SHA512
+# Need to add HMAC-SHA512 KDF as well, if SHA512 was enabled.
+NEED_HMAC_SHA512_KDF=y
+endif
+endif
+
CFLAGS += -DCONFIG_SHA256
ifneq ($(CONFIG_TLS), openssl)
ifneq ($(CONFIG_TLS), linux)
@@ -1369,6 +1381,8 @@
SOBJS += ../src/common/sae_pk.o
SOBJS += ../src/common/dragonfly.o
SOBJS += $(AESOBJS)
+SOBJS += ../src/crypto/sha384.o
+SOBJS += ../src/crypto/sha512.o
SOBJS += ../src/crypto/sha256-prf.o
SOBJS += ../src/crypto/sha384-prf.o
SOBJS += ../src/crypto/sha512-prf.o
@@ -1376,6 +1390,10 @@
SOBJS += ../src/crypto/sha256-kdf.o
SOBJS += ../src/crypto/sha384-kdf.o
SOBJS += ../src/crypto/sha512-kdf.o
+SOBJS += ../src/common/wpa_common.o
+SOBJS += ../src/crypto/random.o
+SOBJS += ../src/crypto/sha1-prf.o
+SOBJS += ../src/utils/eloop.o
_OBJS_VAR := NOBJS
include ../src/objs.mk
diff --git a/hostapd/README-MULTI-AP b/hostapd/README-MULTI-AP
index ccee69e..6190cac 100644
--- a/hostapd/README-MULTI-AP
+++ b/hostapd/README-MULTI-AP
@@ -155,6 +155,6 @@
----------
[1] https://www.wi-fi.org/discover-wi-fi/wi-fi-easymesh
-[2] https://github.com/prplfoundation/prplMesh
+[2] https://gitlab.com/prpl-foundation/prplmesh/prplMesh
[3] https://www.wi-fi.org/file/multi-ap-specification-v10
(requires registration)
diff --git a/hostapd/aidl/hostapd.cpp b/hostapd/aidl/hostapd.cpp
index 12d0d9e..745fab8 100644
--- a/hostapd/aidl/hostapd.cpp
+++ b/hostapd/aidl/hostapd.cpp
@@ -138,6 +138,12 @@
int32_t aidl_client_version = 0;
int32_t aidl_service_version = 0;
+inline std::array<uint8_t, ETH_ALEN> macAddrToArray(const uint8_t* mac_addr) {
+ std::array<uint8_t, ETH_ALEN> arr;
+ std::copy(mac_addr, mac_addr + ETH_ALEN, std::begin(arr));
+ return arr;
+}
+
/**
* Check that the AIDL service is running at least the expected version.
* Use to avoid the case where the AIDL interface version
@@ -875,7 +881,7 @@
"%s\n"
"interface=%s\n"
"driver=nl80211\n"
- "ctrl_interface=/data/vendor/wifi/hostapd/ctrl_%s\n"
+ "ctrl_interface=/data/vendor/wifi/hostapd/ctrl\n"
// ssid2 signals to hostapd that the value is not a literal value
// for use as a SSID. In this case, we're giving it a hex
// std::string and hostapd needs to expect that.
@@ -901,7 +907,6 @@
"%s\n",
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,
@@ -922,20 +927,40 @@
ap_isolation_as_string.c_str());
}
-Generation getGeneration(hostapd_hw_modes *current_mode)
+Generation getGeneration(hostapd_hw_modes *current_mode,
+ bool is_conf_enable_11ax,
+ bool is_conf_enable_11be)
{
wpa_printf(MSG_DEBUG, "getGeneration hwmode=%d, ht_enabled=%d,"
- " vht_enabled=%d, he_supported=%d",
- current_mode->mode, current_mode->ht_capab != 0,
- current_mode->vht_capab != 0, current_mode->he_capab->he_supported);
+ " vht_enabled=%d, he_supported=%d, eht_supported=%d,"
+ " ieee80211ax = %d, ieee80211be=%d",
+ current_mode->mode, current_mode->ht_capab != 0,
+ current_mode->vht_capab != 0,
+ current_mode->he_capab[IEEE80211_MODE_AP].he_supported,
+ current_mode->eht_capab[IEEE80211_MODE_AP].eht_supported,
+ is_conf_enable_11ax,
+ is_conf_enable_11be);
switch (current_mode->mode) {
case HOSTAPD_MODE_IEEE80211B:
return Generation::WIFI_STANDARD_LEGACY;
case HOSTAPD_MODE_IEEE80211G:
+ if (is_conf_enable_11be
+ && current_mode->eht_capab[IEEE80211_MODE_AP].eht_supported) {
+ return Generation::WIFI_STANDARD_11BE;
+ }
+ if (is_conf_enable_11ax
+ && current_mode->he_capab[IEEE80211_MODE_AP].he_supported) {
+ return Generation::WIFI_STANDARD_11AX;
+ }
return current_mode->ht_capab == 0 ?
Generation::WIFI_STANDARD_LEGACY : Generation::WIFI_STANDARD_11N;
case HOSTAPD_MODE_IEEE80211A:
- if (current_mode->he_capab->he_supported) {
+ if (is_conf_enable_11be
+ && current_mode->eht_capab[IEEE80211_MODE_AP].eht_supported) {
+ return Generation::WIFI_STANDARD_11BE;
+ }
+ if (is_conf_enable_11ax
+ && current_mode->he_capab[IEEE80211_MODE_AP].he_supported) {
return Generation::WIFI_STANDARD_11AX;
}
return current_mode->vht_capab == 0 ?
@@ -1279,7 +1304,7 @@
return hapd;
}
}
-#endif
+#endif /* CONFIG_IEEE80211BE */
return NULL;
}
@@ -1299,19 +1324,32 @@
const std::string owe_transition_ifname)
{
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())) {
+ if (hostapd_get_iface_by_link_id(interfaces_, std::stoi(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, "Instance interface %s already present",
- iface_params.usesMlo ? br_name.c_str() : iface_params.name.c_str());
- return createStatus(HostapdStatusCode::FAILURE_IFACE_EXISTS);
+#ifdef CONFIG_IEEE80211BE
+ // The MLO AP uses the same interface name for all links. Thus, make sure the
+ // interface name wasn't used for non-mld AP only when adding a new interface.
+ // Also it is valid to have a hostapd_data with the same interface name when adding
+ // the second link instance.
+ struct hostapd_data* hapd = hostapd_get_iface(interfaces_, br_name.c_str());
+ if (hapd && !hapd->conf->mld_ap) {
+ wpa_printf(
+ MSG_ERROR, "Instance interface %s already present",
+ br_name.c_str());
+ return createStatus(HostapdStatusCode::FAILURE_IFACE_EXISTS);
+ }
+#endif
+ } else {
+ if (hostapd_get_iface(interfaces_, iface_params.name.c_str())) {
+ wpa_printf(
+ MSG_ERROR, "Instance interface %s already present",
+ iface_params.name.c_str());
+ return createStatus(HostapdStatusCode::FAILURE_IFACE_EXISTS);
+ }
}
const auto conf_params = CreateHostapdConfig(iface_params, channelParams, nw_params,
br_name, owe_transition_ifname);
@@ -1339,7 +1377,7 @@
// 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_by_link_id(interfaces_, std::stoi(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) {
@@ -1374,7 +1412,7 @@
&& strlen(iface_hapd->conf->bridge) == 0) {
instanceName = std::to_string(iface_hapd->mld_link_id);
}
-#endif
+#endif /* CONFIG_IEEE80211BE */
for (const auto& callback : callbacks_) {
auto status = callback->onFailure(
strlen(iface_hapd->conf->bridge) > 0 ?
@@ -1403,7 +1441,7 @@
&& strlen(iface_hapd->conf->bridge) == 0) {
instanceName = std::to_string(iface_hapd->mld_link_id);
}
-#endif
+#endif /* CONFIG_IEEE80211BE */
info.apIfaceInstance = instanceName;
info.clientAddress.assign(mac_addr, mac_addr + ETH_ALEN);
info.isConnected = authorized;
@@ -1439,16 +1477,23 @@
if (iface_hapd->conf->mld_ap && strlen(iface_hapd->conf->bridge) == 0) {
instanceName = std::to_string(iface_hapd->mld_link_id);
}
-#endif
+#endif /* CONFIG_IEEE80211BE */
ApInfo info;
info.ifaceName = strlen(iface_hapd->conf->bridge) > 0 ?
iface_hapd->conf->bridge : 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);
+ info.generation =
+ getGeneration(iface_hapd->iface->current_mode,
+ iface_hapd->iconf->ieee80211ax, iface_hapd->iconf->ieee80211be);
info.apIfaceInstanceMacAddress.assign(iface_hapd->own_addr,
iface_hapd->own_addr + ETH_ALEN);
+#ifdef CONFIG_IEEE80211BE
+ if (iface_hapd->conf->mld_ap) {
+ info.mldMacAddress = macAddrToArray(iface_hapd->mld->mld_addr);
+ }
+#endif /* CONFIG_IEEE80211BE */
for (const auto &callback : callbacks_) {
auto status = callback->onApInstanceInfoChanged(info);
if (!status.isOk()) {
@@ -1464,7 +1509,7 @@
if (iface_hapd->conf->mld_ap && strlen(iface_hapd->conf->bridge) == 0) {
instanceName = std::to_string(iface_hapd->mld_link_id);
}
-#endif
+#endif /* CONFIG_IEEE80211BE */
// Invoke the failure callback on all registered clients.
for (const auto& callback : callbacks_) {
auto status =
@@ -1589,18 +1634,26 @@
::ndk::ScopedAStatus Hostapd::removeLinkFromMultipleLinkBridgedApIfaceInternal(
const std::string& iface_name, const std::string& linkIdentity)
{
+#ifdef CONFIG_IEEE80211BE
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());
+ hostapd_get_iface_by_link_id(interfaces_, std::stoi(linkIdentity.c_str()));
if (iface_hapd) {
+// Currently, hostapd_link_remove is still under CONFIG_TESTING_OPTIONS.
+// TODO: b/340821197 - Make sure to take out the hostapd_link_remove() and other related code
+// out of CONFIG_TESTING_OPTIONS.
+#ifdef CONFIG_TESTING_OPTIONS
if (0 == hostapd_link_remove(iface_hapd, 1)) {
return ndk::ScopedAStatus::ok();
}
+#endif /* CONFIG_TESTING_OPTIONS */
}
return createStatus(HostapdStatusCode::FAILURE_ARGS_INVALID);
+#endif /* CONFIG_IEEE80211BE */
+ return createStatus(HostapdStatusCode::FAILURE_UNKNOWN);
}
} // namespace hostapd
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 9470cae..f4a6aeb 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2756,8 +2756,6 @@
return 1;
}
bss->eap_teap_auth = val;
- } else if (os_strcmp(buf, "eap_teap_pac_no_inner") == 0) {
- bss->eap_teap_pac_no_inner = atoi(pos);
} else if (os_strcmp(buf, "eap_teap_separate_result") == 0) {
bss->eap_teap_separate_result = atoi(pos);
} else if (os_strcmp(buf, "eap_teap_id") == 0) {
@@ -3964,6 +3962,10 @@
return 1;
}
conf->mbssid = mbssid;
+ } else if (os_strcmp(buf, "mbssid_index") == 0) {
+ bss->mbssid_index = atoi(pos);
+ } else if (os_strcmp(buf, "mbssid_max") == 0) {
+ conf->mbssid_max = atoi(pos);
#endif /* CONFIG_IEEE80211AX */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -5132,6 +5134,10 @@
if (val < 0 || val > 1)
return 1;
bss->ssid_protection = val;
+ } else if (os_strcmp(buf, "channel_usage") == 0) {
+ conf->channel_usage = atoi(pos);
+ } else if (os_strcmp(buf, "peer_to_peer_twt") == 0) {
+ conf->peer_to_peer_twt = atoi(pos);
#ifdef CONFIG_IEEE80211BE
} else if (os_strcmp(buf, "ieee80211be") == 0) {
conf->ieee80211be = atoi(pos);
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index ea19ba7..dd445d8 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -2707,7 +2707,7 @@
}
ret = hostapd_ctrl_check_freq_params(&settings.freq_params,
- settings.punct_bitmap);
+ settings.freq_params.punct_bitmap);
if (ret) {
wpa_printf(MSG_INFO,
"chanswitch: invalid frequency settings provided");
@@ -3210,6 +3210,7 @@
#ifdef NEED_AP_MLME
+
static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
@@ -3243,6 +3244,35 @@
return pos - buf;
}
+
+
+static int hostapd_ctrl_iface_dump_beacon(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ struct beacon_data beacon;
+ char *pos, *end;
+ int ret;
+
+ if (hostapd_build_beacon_data(hapd, &beacon) < 0)
+ return -1;
+
+ if (2 * (beacon.head_len + beacon.tail_len) > buflen)
+ return -1;
+
+ pos = buf;
+ end = buf + buflen;
+
+ ret = wpa_snprintf_hex(pos, end - pos, beacon.head, beacon.head_len);
+ pos += ret;
+
+ ret = wpa_snprintf_hex(pos, end - pos, beacon.tail, beacon.tail_len);
+ pos += ret;
+
+ free_beacon_data(&beacon);
+
+ return pos - buf;
+}
+
#endif /* NEED_AP_MLME */
@@ -4026,7 +4056,7 @@
}
ret = hostapd_nan_usd_transmit(hapd, handle, ssi, NULL, peer_addr,
- req_instance_id);
+ req_instance_id);
fail:
wpabuf_free(ssi);
return ret;
@@ -4347,6 +4377,9 @@
} else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) {
reply_len = hostapd_ctrl_iface_track_sta_list(
hapd, reply, reply_size);
+ } else if (os_strcmp(buf, "DUMP_BEACON") == 0) {
+ reply_len = hostapd_ctrl_iface_dump_beacon(hapd, reply,
+ reply_size);
#endif /* NEED_AP_MLME */
} else if (os_strcmp(buf, "PMKSA") == 0) {
reply_len = hostapd_ctrl_iface_pmksa_list(hapd, reply,
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index 5caa779..291acf9 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -1,6 +1,6 @@
/*
* HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
- * Copyright (c) 2005-2007, 2012-2017, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2007, 2012-2024, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -66,6 +66,7 @@
static int sqn_changes = 0;
static int ind_len = 5;
static int stdout_debug = 1;
+static bool stop = false;
/* GSM triplets */
struct gsm_triplet {
@@ -877,6 +878,12 @@
if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0)
return aka_auts(cmd + 9, resp, resp_len);
+ if (strncmp(cmd, "TERMINATE", 9) == 0) {
+ stop = true;
+ resp[0] = '\0';
+ return 0;
+ }
+
printf("Unknown request: %s\n", cmd);
return -1;
}
@@ -931,10 +938,13 @@
struct gsm_triplet *g, *gprev;
struct milenage_parameters *m, *prev;
- if (update_milenage && milenage_file && sqn_changes)
+ if (update_milenage && milenage_file && sqn_changes) {
+ sqn_changes = 0;
update_milenage_file(milenage_file);
+ }
g = gsm_db;
+ gsm_db = NULL;
while (g) {
gprev = g;
g = g->next;
@@ -942,16 +952,21 @@
}
m = milenage_db;
+ milenage_db = NULL;
while (m) {
prev = m;
m = m->next;
os_free(prev);
}
- if (serv_sock >= 0)
+ if (serv_sock >= 0) {
close(serv_sock);
- if (socket_path)
+ serv_sock = -1;
+ }
+ if (socket_path) {
unlink(socket_path);
+ socket_path = NULL;
+ }
#ifdef CONFIG_SQLITE
if (sqlite_db) {
@@ -965,6 +980,7 @@
static void handle_term(int sig)
{
printf("Signal %d - terminate\n", sig);
+ cleanup();
exit(0);
}
@@ -973,7 +989,7 @@
{
printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
"database/authenticator\n"
- "Copyright (c) 2005-2017, Jouni Malinen <j@w1.fi>\n"
+ "Copyright (c) 2005-2024, Jouni Malinen <j@w1.fi>\n"
"\n"
"usage:\n"
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
@@ -1081,8 +1097,9 @@
signal(SIGTERM, handle_term);
signal(SIGINT, handle_term);
- for (;;)
+ while (!stop)
process(serv_sock);
+ cleanup();
} else {
char buf[1000];
socket_path = NULL;
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 93524cf..b1e8ac5 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1030,6 +1030,18 @@
# Valid range: 0..20 TUs; default is 0 (disabled)
#unsol_bcast_probe_resp_interval=0
+#channel_usage: Whether Channel Usage procedures is supported by AP.
+# 0 = Channel Usage support is disabled (default)
+# 1 = Channel Usage support is enabled
+#channel_usage=0
+
+#peer_to_peer_twt: Indicates an HE AP supports negotiating a peer-to-peer
+# TWT schedule that is requested by a non-AP STA to establish a
+# channel-usage-aidable BSS or an off-channel TDLS direct link.
+# 0 = Does not support Peer-to-peer TWT (default)
+# 1 = Supports Peer-to-peer TWT
+#peer_to_peer_twt=0
+
##### IEEE 802.11be related configuration #####################################
#ieee80211be: Whether IEEE 802.11be (EHT) is enabled
@@ -3411,6 +3423,18 @@
# 2 = Enhanced multiple BSSID advertisement enabled.
#mbssid=0
#
+# Maximum number of BSSs that can be added into a Multiple BSSID set
+# This is a radio level parameter. If not set (or 0), the maximum is determined
+# automatically based on the configured BSSs which may limit dynamic addition
+# of new BSSs.
+#mbssid_max=0
+#
+# Multiple BSSID Index override
+# This is a BSS level parameter. If not set (or 0), the BSSID index is
+# determined automatically based on the configured BSSs which may limit dynamic
+# addition of new BSSs.
+#mbssid_index=0
+#
# The transmitting interface should be added with the 'interface' option while
# the non-transmitting interfaces should be added using the 'bss' option.
# Security configuration should be added separately per interface, if required.
diff --git a/hostapd/main.c b/hostapd/main.c
index 50b9f04..5769fa0 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -162,6 +162,7 @@
struct wpa_driver_capa capa;
#ifdef CONFIG_IEEE80211BE
struct hostapd_data *h_hapd = NULL;
+ void *shared_hapd = NULL;
#endif /* CONFIG_IEEE80211BE */
if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
@@ -170,8 +171,11 @@
}
#ifdef CONFIG_IEEE80211BE
- if (conf->mld_ap)
+ if (conf->mld_ap) {
+ if (!hapd->mld)
+ hostapd_bss_setup_multi_link(hapd, iface->interfaces);
h_hapd = hostapd_mld_get_first_bss(hapd);
+ }
if (h_hapd) {
hapd->drv_priv = h_hapd->drv_priv;
@@ -255,6 +259,42 @@
params.own_addr = hapd->own_addr;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->driver->can_share_drv &&
+ hapd->driver->can_share_drv(hapd, ¶ms, &shared_hapd)) {
+ char force_ifname[IFNAMSIZ];
+ const u8 *addr = params.bssid;
+ u8 if_addr[ETH_ALEN];
+
+ if (!shared_hapd) {
+ wpa_printf(MSG_ERROR, "Failed to get the shared drv");
+ os_free(params.bridge);
+ return -1;
+ }
+
+ /* Share an already initialized driver interface instance
+ * using an AP mode BSS in it instead of adding a new driver
+ * interface instance for the same driver. */
+ if (hostapd_if_add(shared_hapd, WPA_IF_AP_BSS,
+ params.ifname, addr, hapd,
+ &hapd->drv_priv, force_ifname, if_addr,
+ params.num_bridge && params.bridge[0] ?
+ params.bridge[0] : NULL,
+ 0)) {
+ wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
+ MACSTR ")", MAC2STR(hapd->own_addr));
+ os_free(params.bridge);
+ return -1;
+ }
+ os_free(params.bridge);
+
+ hapd->interface_added = 1;
+ os_memcpy(params.own_addr, addr ? addr : if_addr, ETH_ALEN);
+
+ goto pre_setup_mld;
+ }
+#endif /* CONFIG_IEEE80211BE */
+
hapd->drv_priv = hapd->driver->hapd_init(hapd, ¶ms);
os_free(params.bridge);
if (hapd->drv_priv == NULL) {
@@ -265,6 +305,7 @@
}
#ifdef CONFIG_IEEE80211BE
+pre_setup_mld:
/*
* This is the first interface added to the AP MLD, so have the
* interface hardware address be the MLD address, while the link address
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 55f3b64..d33ba9d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -451,7 +451,6 @@
int pac_key_lifetime;
int pac_key_refresh_time;
int eap_teap_auth;
- int eap_teap_pac_no_inner;
int eap_teap_separate_result;
int eap_teap_id;
int eap_teap_method_sequence;
@@ -995,6 +994,7 @@
bool mld_indicate_disabled;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211BE */
+ int mbssid_index;
};
/**
@@ -1248,9 +1248,13 @@
MBSSID_ENABLED = 1,
ENHANCED_MBSSID_ENABLED = 2,
} mbssid;
+ unsigned int mbssid_max;
/* Whether to enable TWT responder in HT and VHT modes */
bool ht_vht_twt_responder;
+
+ bool channel_usage;
+ bool peer_to_peer_twt;
};
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 92dbc16..65e83f4 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -116,9 +116,11 @@
goto fail;
#endif /* CONFIG_FILS */
- pos = hostapd_eid_rsnxe(hapd, buf, sizeof(buf));
- if (add_buf_data(&assocresp, buf, pos - buf) < 0)
- goto fail;
+ if (!hapd->conf->rsn_override_omit_rsnxe) {
+ pos = hostapd_eid_rsnxe(hapd, buf, sizeof(buf));
+ if (add_buf_data(&assocresp, buf, pos - buf) < 0)
+ goto fail;
+ }
if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
@@ -472,7 +474,8 @@
size_t eht_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
- int set, const u8 *link_addr, bool mld_link_sta)
+ int set, const u8 *link_addr, bool mld_link_sta,
+ u16 eml_cap)
{
struct hostapd_sta_add_params params;
@@ -512,6 +515,9 @@
params.mld_link_id = hapd->mld_link_id;
params.mld_link_addr = link_addr;
params.mld_link_sta = mld_link_sta;
+ /* Copy EML capabilities of ML STA */
+ if (link_addr)
+ params.eml_cap = eml_cap;
}
#endif /* CONFIG_IEEE80211BE */
@@ -781,6 +787,12 @@
int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params)
{
+ params->link_id = -1;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap)
+ params->link_id = hapd->mld_link_id;
+#endif /* CONFIG_IEEE80211BE */
+
if (hapd->driver && hapd->driver->scan2)
return hapd->driver->scan2(hapd->drv_priv, params);
return -1;
@@ -916,9 +928,50 @@
}
+#ifdef CONFIG_IEEE80211BE
+static bool hostapd_is_action_frame_link_agnostic(u8 category, u8 sub_category)
+{
+ /* As per IEEE P802.11be/D7.0, 35.3.14 (MLD individually addressed
+ * Management frame delivery), between an AP MLD and a non-AP MLD, the
+ * following individually addressed MMPDUs shall be intended for an MLD.
+ */
+ switch (category) {
+ case WLAN_ACTION_BLOCK_ACK:
+ case WLAN_ACTION_FT:
+ case WLAN_ACTION_SA_QUERY:
+ case WLAN_ACTION_WNM:
+ switch (sub_category) {
+ case WNM_BSS_TRANS_MGMT_REQ:
+ case WNM_BSS_TRANS_MGMT_RESP:
+ case WNM_SLEEP_MODE_REQ:
+ case WNM_SLEEP_MODE_RESP:
+ return true;
+ default:
+ return false;
+ }
+ case WLAN_ACTION_ROBUST_AV_STREAMING:
+ switch (sub_category) {
+ case ROBUST_AV_SCS_REQ:
+ case ROBUST_AV_SCS_RESP:
+ case ROBUST_AV_MSCS_REQ:
+ case ROBUST_AV_MSCS_RESP:
+ return true;
+ default:
+ return false;
+ }
+ /* TODO: Handle EHT/EPCS related action frames once the support is
+ * added. */
+ default:
+ return false;
+ }
+}
+#endif /* CONFIG_IEEE80211BE */
+
+
static int hapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst,
- const u8 *data, size_t len, bool addr3_ap)
+ const u8 *data, size_t len, bool addr3_ap,
+ const u8 *forced_a3)
{
const u8 *own_addr = hapd->own_addr;
const u8 *bssid;
@@ -926,12 +979,15 @@
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
struct sta_info *sta;
+ int link_id = -1;
if (!hapd->driver || !hapd->driver->send_action || !hapd->drv_priv)
return 0;
bssid = hapd->own_addr;
- if (!addr3_ap && !is_multicast_ether_addr(dst) &&
- len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
+ if (forced_a3) {
+ bssid = forced_a3;
+ } else if (!addr3_ap && !is_multicast_ether_addr(dst) &&
+ len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
/*
* Public Action frames to a STA that is not a member of the BSS
* shall use wildcard BSSID value.
@@ -956,11 +1012,15 @@
own_addr = hapd->mld->mld_addr;
bssid = own_addr;
}
+
+ if (!hostapd_is_action_frame_link_agnostic(data[0], data[1]))
+ link_id = hapd->mld_link_id;
#endif /* CONFIG_IEEE80211BE */
}
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
- own_addr, bssid, data, len, 0);
+ own_addr, bssid, data, len, 0,
+ link_id);
}
@@ -968,7 +1028,8 @@
unsigned int wait, const u8 *dst, const u8 *data,
size_t len)
{
- return hapd_drv_send_action(hapd, freq, wait, dst, data, len, false);
+ return hapd_drv_send_action(hapd, freq, wait, dst, data, len, false,
+ NULL);
}
@@ -977,7 +1038,19 @@
unsigned int wait, const u8 *dst,
const u8 *data, size_t len)
{
- return hapd_drv_send_action(hapd, freq, wait, dst, data, len, true);
+ return hapd_drv_send_action(hapd, freq, wait, dst, data, len, true,
+ NULL);
+}
+
+
+int hostapd_drv_send_action_forced_addr3(struct hostapd_data *hapd,
+ unsigned int freq,
+ unsigned int wait, const u8 *dst,
+ const u8 *a3,
+ const u8 *data, size_t len)
+{
+ return hapd_drv_send_action(hapd, freq, wait, dst, data, len, false,
+ a3);
}
@@ -1018,6 +1091,12 @@
}
data.radar_background = radar_background;
+ data.link_id = -1;
+#ifdef CONFIG_IEEE80211BE
+ if (hapd->conf->mld_ap)
+ data.link_id = hapd->mld_link_id;
+#endif /* CONFIG_IEEE80211BE */
+
res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
if (!res) {
if (radar_background)
@@ -1261,3 +1340,27 @@
return hapd->driver->get_multi_hw_info(hapd->drv_priv, num_multi_hws);
}
+
+
+int hostapd_drv_add_pmkid(struct hostapd_data *hapd,
+ struct wpa_pmkid_params *params)
+{
+ if (!hapd->driver || !hapd->driver->add_pmkid || !hapd->drv_priv)
+ return 0;
+ return hapd->driver->add_pmkid(hapd->drv_priv, params);
+}
+
+
+int hostapd_add_pmkid(struct hostapd_data *hapd, const u8 *bssid, const u8 *pmk,
+ size_t pmk_len, const u8 *pmkid, int akmp)
+{
+ struct wpa_pmkid_params params;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.bssid = bssid;
+ params.pmkid = pmkid;
+ params.pmk = pmk;
+ params.pmk_len = pmk_len;
+
+ return hostapd_drv_add_pmkid(hapd, ¶ms);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 6b7f02a..cbb8044 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -49,7 +49,8 @@
size_t eht_capab_len,
const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab,
u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps,
- int set, const u8 *link_addr, bool mld_link_sta);
+ int set, const u8 *link_addr, bool mld_link_sta,
+ u16 eml_cap);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len);
@@ -116,6 +117,11 @@
unsigned int freq,
unsigned int wait, const u8 *dst,
const u8 *data, size_t len);
+int hostapd_drv_send_action_forced_addr3(struct hostapd_data *hapd,
+ unsigned int freq,
+ unsigned int wait, const u8 *dst,
+ const u8 *a3,
+ const u8 *data, size_t len);
static inline void
hostapd_drv_send_action_cancel_wait(struct hostapd_data *hapd)
{
@@ -482,4 +488,9 @@
hostapd_get_multi_hw_info(struct hostapd_data *hapd,
unsigned int *num_multi_hws);
+int hostapd_drv_add_pmkid(struct hostapd_data *hapd,
+ struct wpa_pmkid_params *params);
+int hostapd_add_pmkid(struct hostapd_data *hapd, const u8 *bssid, const u8 *pmk,
+ size_t pmk_len, const u8 *pmkid, int akmp);;
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 837b690..630cef6 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -224,7 +224,6 @@
cfg->pac_key_lifetime = hapd->conf->pac_key_lifetime;
cfg->pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
cfg->eap_teap_auth = hapd->conf->eap_teap_auth;
- cfg->eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner;
cfg->eap_teap_separate_result = hapd->conf->eap_teap_separate_result;
cfg->eap_teap_id = hapd->conf->eap_teap_id;
cfg->eap_teap_method_sequence = hapd->conf->eap_teap_method_sequence;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 2e3d904..542768d 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -262,6 +262,7 @@
{
u8 *pos = eid;
u8 *end = eid + max_len;
+ bool force_global;
if (!hapd->iconf->ieee80211d || max_len < 6 ||
hapd->iface->current_mode == NULL)
@@ -272,11 +273,23 @@
os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
pos += 3;
- if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ /* The 6 GHz band uses global operating classes */
+ force_global = is_6ghz_op_class(hapd->iconf->op_class);
+
+#ifdef CONFIG_MBO
+ /* Wi-Fi Agile Muiltiband AP is required to use a global operating
+ * class. */
+ if (hapd->conf->mbo_enabled)
+ force_global = true;
+#endif /* CONFIG_MBO */
+
+ if (force_global) {
/* Force the third octet of the country string to indicate
* Global Operating Class (Table E-4) */
eid[4] = 0x04;
+ }
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
/* Operating Triplet field */
/* Operating Extension Identifier (>= 201 to indicate this is
* not a Subband Triplet field) */
@@ -2909,7 +2922,15 @@
is_identical_vendor_ies = true;
num_own_elem_vendor_ies++;
}
- continue;
+
+ /* 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;
}
/* No need to include this non-matching Vendor Specific
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index b93a5d2..4a51e63 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -475,6 +475,10 @@
#ifdef CONFIG_IEEE80211BE
if (sta->mld_info.mld_sta) {
+ u16 mld_sta_capa = sta->mld_info.common_info.mld_capa;
+ u8 max_simul_links = mld_sta_capa &
+ EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK;
+
for (i = 0; i < MAX_NUM_MLD_LINKS; ++i) {
if (!sta->mld_info.links[i].valid)
continue;
@@ -485,6 +489,11 @@
if (!os_snprintf_error(buflen - len, ret))
len += ret;
}
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "max_simul_links=%d\n", max_simul_links);
+ if (!os_snprintf_error(buflen - len, ret))
+ len += ret;
}
#endif /* CONFIG_IEEE80211BE */
@@ -917,6 +926,15 @@
len += ret;
}
+ if (hapd->iconf->punct_bitmap) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "punct_bitmap=0x%x\n",
+ hapd->iconf->punct_bitmap);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
if (hapd->conf->mld_ap) {
struct hostapd_data *link_bss;
@@ -951,6 +969,15 @@
return len;
len += ret;
}
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "ap_mld_type=%s\n",
+ (hapd->iface->mld_mld_capa &
+ EHT_ML_MLD_CAPA_AP_MLD_TYPE_IND_MASK)
+ ? "NSTR" : "STR");
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
}
}
#endif /* CONFIG_IEEE80211BE */
@@ -1127,20 +1154,11 @@
} \
} while (0)
-#define SET_CSA_SETTING_EXT(str) \
- do { \
- const char *pos2 = os_strstr(pos, " " #str "="); \
- if (pos2) { \
- pos2 += sizeof(" " #str "=") - 1; \
- settings->str = atoi(pos2); \
- } \
- } while (0)
-
SET_CSA_SETTING(center_freq1);
SET_CSA_SETTING(center_freq2);
SET_CSA_SETTING(bandwidth);
SET_CSA_SETTING(sec_channel_offset);
- SET_CSA_SETTING_EXT(punct_bitmap);
+ SET_CSA_SETTING(punct_bitmap);
settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
settings->freq_params.eht_enabled = !!os_strstr(pos, " eht");
@@ -1148,7 +1166,6 @@
settings->freq_params.eht_enabled;
settings->block_tx = !!os_strstr(pos, " blocktx");
#undef SET_CSA_SETTING
-#undef SET_CSA_SETTING_EXT
return 0;
}
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index d1bffa8..3dc4639 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -1382,6 +1382,21 @@
}
+static void hostapd_gas_req_wait(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct dpp_authentication *auth = hapd->dpp_auth;
+
+ if (!auth)
+ return;
+
+ wpa_printf(MSG_DEBUG, "DPP: Timeout while waiting for Config Request");
+ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
+ dpp_auth_deinit(auth);
+ hapd->dpp_auth = NULL;
+}
+
+
static void hostapd_dpp_auth_success(struct hostapd_data *hapd, int initiator)
{
wpa_printf(MSG_DEBUG, "DPP: Authentication succeeded");
@@ -1400,6 +1415,9 @@
if (!hapd->dpp_auth->configurator)
hostapd_dpp_start_gas_client(hapd);
+ else
+ eloop_register_timeout(10, 0, hostapd_gas_req_wait,
+ hapd, NULL);
}
@@ -3079,6 +3097,7 @@
struct wpabuf *resp;
wpa_printf(MSG_DEBUG, "DPP: GAS request from " MACSTR, MAC2STR(sa));
+ eloop_cancel_timeout(hostapd_gas_req_wait, hapd, NULL);
if (!auth || (!auth->auth_success && !auth->reconfig_success) ||
!ether_addr_equal(sa, auth->peer_mac_addr)) {
#ifdef CONFIG_DPP2
@@ -3359,6 +3378,7 @@
#ifdef CONFIG_DPP3
hostapd_dpp_push_button_stop(hapd);
#endif /* CONFIG_DPP3 */
+ eloop_cancel_timeout(hostapd_gas_req_wait, hapd, NULL);
}
@@ -3512,6 +3532,7 @@
eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
+ eloop_cancel_timeout(hostapd_gas_req_wait, hapd, NULL);
#ifdef CONFIG_DPP2
eloop_cancel_timeout(hostapd_dpp_reconfig_reply_wait_timeout,
hapd, NULL);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 05adc41..82a922e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -18,6 +18,7 @@
#include "common/dpp.h"
#include "common/sae.h"
#include "common/hw_features_common.h"
+#include "common/nan_de.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -677,6 +678,13 @@
goto fail;
}
#endif /* CONFIG_SAE */
+
+ wpa_auth_set_ssid_protection(
+ sta->wpa_sm,
+ hapd->conf->ssid_protection &&
+ ieee802_11_rsnx_capab_len(
+ elems.rsnxe, elems.rsnxe_len,
+ WLAN_RSNX_CAPAB_SSID_PROTECTION));
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
@@ -950,6 +958,10 @@
}
#endif /* CONFIG_P2P */
+ if (elems.wfa_capab)
+ hostapd_wfa_capab(hapd, sta, elems.wfa_capab,
+ elems.wfa_capab + elems.wfa_capab_len);
+
return 0;
fail:
@@ -1787,8 +1799,8 @@
pos = mgmt->u.action.u.vs_public_action.variable;
end = drv_mgmt->frame + drv_mgmt->frame_len;
pos++;
- hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, drv_mgmt->freq,
- pos, end - pos);
+ hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, mgmt->bssid,
+ drv_mgmt->freq, pos, end - pos);
return;
}
#endif /* CONFIG_NAN_USD */
@@ -1855,6 +1867,11 @@
if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
return HAPD_BROADCAST;
+#ifdef CONFIG_NAN_USD
+ if (nan_de_is_nan_network_id(bssid))
+ return HAPD_BROADCAST; /* Process NAN Network ID like broadcast
+ */
+#endif /* CONFIG_NAN_USD */
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *hapd;
@@ -1988,18 +2005,19 @@
{
struct ieee80211_hdr *hdr;
struct hostapd_data *orig_hapd, *tmp_hapd;
+ const u8 *bssid;
orig_hapd = hapd;
hdr = (struct ieee80211_hdr *) buf;
hapd = switch_link_hapd(hapd, link_id);
- tmp_hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len), link_id);
+ bssid = get_hdr_bssid(hdr, len);
+ tmp_hapd = get_hapd_bssid(hapd->iface, bssid, link_id);
if (tmp_hapd) {
hapd = tmp_hapd;
#ifdef CONFIG_IEEE80211BE
- } else if (hapd->conf->mld_ap &&
- ether_addr_equal(hapd->mld->mld_addr,
- get_hdr_bssid(hdr, len))) {
+ } else if (hapd->conf->mld_ap && bssid &&
+ ether_addr_equal(hapd->mld->mld_addr, bssid)) {
/* AP MLD address match - use hapd pointer as-is */
#endif /* CONFIG_IEEE80211BE */
} else {
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 7d92489..4bc6b3a 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -242,6 +242,10 @@
if (os_strcmp(newconf->bss[i]->iface,
oldconf->bss[i]->iface) != 0)
return 1;
+#ifdef CONFIG_IEEE80211BE
+ if (newconf->bss[i]->mld_ap != oldconf->bss[i]->mld_ap)
+ return 1;
+#endif /* CONFIG_IEEE80211BE */
}
return 0;
@@ -302,7 +306,6 @@
"Failed to enable interface on config reload");
return res;
}
- iface->conf = newconf;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
@@ -330,6 +333,7 @@
hostapd_reload_bss(hapd);
}
+ iface->conf = newconf;
hostapd_config_free(oldconf);
@@ -521,7 +525,10 @@
authsrv_deinit(hapd);
- if (hapd->interface_added) {
+ /* For single drv, first bss would have interface_added flag set.
+ * Don't remove interface now. Driver deinit part will take care
+ */
+ if (hapd->interface_added && hapd->iface->bss[0] != hapd) {
hapd->interface_added = 0;
if (hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
wpa_printf(MSG_WARNING,
@@ -633,7 +640,7 @@
}
/* Put all freeing logic above this */
- if (!hapd->mld->num_links)
+ if (!hapd->mld || !hapd->mld->num_links)
return;
/* If not started, not yet linked to the MLD. However, the first
@@ -703,6 +710,7 @@
acs_cleanup(iface);
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
iface->hw_features = NULL;
+ iface->num_hw_features = 0;
iface->current_mode = NULL;
os_free(iface->current_rates);
iface->current_rates = NULL;
@@ -1794,26 +1802,26 @@
int hostapd_set_acl(struct hostapd_data *hapd)
{
- struct hostapd_config *conf = hapd->iconf;
+ struct hostapd_bss_config *conf = hapd->conf;
int err = 0;
u8 accept_acl;
if (hapd->iface->drv_max_acl_mac_addrs == 0)
return 0;
- if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
+ if (conf->macaddr_acl == DENY_UNLESS_ACCEPTED) {
accept_acl = 1;
- err = hostapd_set_acl_list(hapd, conf->bss[0]->accept_mac,
- conf->bss[0]->num_accept_mac,
+ err = hostapd_set_acl_list(hapd, conf->accept_mac,
+ conf->num_accept_mac,
accept_acl);
if (err) {
wpa_printf(MSG_DEBUG, "Failed to set accept acl");
return -1;
}
- } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
+ } else if (conf->macaddr_acl == ACCEPT_UNLESS_DENIED) {
accept_acl = 0;
- err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
- conf->bss[0]->num_deny_mac,
+ err = hostapd_set_acl_list(hapd, conf->deny_mac,
+ conf->num_deny_mac,
accept_acl);
if (err) {
wpa_printf(MSG_DEBUG, "Failed to set deny acl");
@@ -1906,18 +1914,30 @@
static int hostapd_no_ir_channel_list_updated(struct hostapd_iface *iface,
void *ctx)
{
+ struct hostapd_data *hapd = iface->bss[0];
bool all_no_ir, is_6ghz;
int i, j;
struct hostapd_hw_modes *mode = NULL;
+ struct hostapd_hw_modes *hw_features;
+ u16 num_hw_features, flags;
+ u8 dfs_domain;
- if (hostapd_get_hw_features(iface))
- return 0;
+ if (hostapd_drv_none(hapd))
+ return -1;
+
+ hw_features = hostapd_get_hw_feature_data(hapd, &num_hw_features,
+ &flags, &dfs_domain);
+ if (!hw_features) {
+ wpa_printf(MSG_DEBUG,
+ "Could not fetching hardware channel list");
+ return -1;
+ }
all_no_ir = true;
is_6ghz = false;
- for (i = 0; i < iface->num_hw_features; i++) {
- mode = &iface->hw_features[i];
+ for (i = 0; i < num_hw_features; i++) {
+ mode = &hw_features[i];
if (mode->mode == iface->conf->hw_mode) {
if (iface->freq > 0 &&
@@ -1939,26 +1959,25 @@
}
if (!mode || !is_6ghz)
- return 0;
- iface->current_mode = mode;
+ goto free_hw_features;
if (iface->state == HAPD_IFACE_ENABLED) {
if (!all_no_ir) {
struct hostapd_channel_data *chan;
- chan = hw_get_channel_freq(iface->current_mode->mode,
+ chan = hw_get_channel_freq(mode->mode,
iface->freq, NULL,
- iface->hw_features,
- iface->num_hw_features);
+ hw_features,
+ num_hw_features);
if (!chan) {
wpa_printf(MSG_ERROR,
"NO_IR: Could not derive chan from freq");
- return 0;
+ goto free_hw_features;
}
if (!(chan->flag & HOSTAPD_CHAN_NO_IR))
- return 0;
+ goto free_hw_features;
wpa_printf(MSG_DEBUG,
"NO_IR: The current channel has NO_IR flag now, stop AP.");
} else {
@@ -1975,20 +1994,20 @@
if (all_no_ir) {
wpa_printf(MSG_DEBUG,
"NO_IR: AP in NO_IR and all chan in the new chanlist are NO_IR. Ignore");
- return 0;
+ goto free_hw_features;
}
if (!iface->conf->acs) {
struct hostapd_channel_data *chan;
- chan = hw_get_channel_freq(iface->current_mode->mode,
+ chan = hw_get_channel_freq(mode->mode,
iface->freq, NULL,
- iface->hw_features,
- iface->num_hw_features);
+ hw_features,
+ num_hw_features);
if (!chan) {
wpa_printf(MSG_ERROR,
"NO_IR: Could not derive chan from freq");
- return 0;
+ goto free_hw_features;
}
/* If the last operating channel is NO_IR, trigger ACS.
@@ -1999,13 +2018,15 @@
if (acs_init(iface) != HOSTAPD_CHAN_ACS)
wpa_printf(MSG_ERROR,
"NO_IR: Could not start ACS");
- return 0;
+ goto free_hw_features;
}
}
setup_interface2(iface);
}
+free_hw_features:
+ hostapd_free_hw_features(hw_features, num_hw_features);
return 0;
}
@@ -3080,14 +3101,17 @@
#endif /* CONFIG_IEEE80211BE */
-static void hostapd_bss_setup_multi_link(struct hostapd_data *hapd,
- struct hapd_interfaces *interfaces)
+void hostapd_bss_setup_multi_link(struct hostapd_data *hapd,
+ struct hapd_interfaces *interfaces)
{
#ifdef CONFIG_IEEE80211BE
struct hostapd_mld *mld, **all_mld;
struct hostapd_bss_config *conf;
size_t i;
+ if (hapd->mld)
+ return;
+
conf = hapd->conf;
if (!hapd->iconf || !hapd->iconf->ieee80211be || !conf->mld_ap ||
@@ -3445,8 +3469,7 @@
* still being used by some other BSS before de-initiallizing. */
if (!iface->bss[0]->conf->mld_ap) {
driver->hapd_deinit(drv_priv);
- } else if (hostapd_mld_is_first_bss(iface->bss[0]) &&
- driver->is_drv_shared &&
+ } else if (driver->is_drv_shared &&
!driver->is_drv_shared(drv_priv,
iface->bss[0]->mld_link_id)) {
driver->hapd_deinit(drv_priv);
@@ -3611,8 +3634,6 @@
int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
{
size_t j;
- const struct wpa_driver_ops *driver;
- void *drv_priv;
if (hapd_iface == NULL)
return -1;
@@ -3627,8 +3648,6 @@
}
wpa_msg(hapd_iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
- driver = hapd_iface->bss[0]->driver;
- drv_priv = hapd_iface->bss[0]->drv_priv;
hapd_iface->driver_ap_teardown =
!!(hapd_iface->drv_flags &
@@ -3647,7 +3666,8 @@
hostapd_free_hapd_data(hapd);
}
- hostapd_deinit_driver(driver, drv_priv, hapd_iface);
+ hostapd_deinit_driver(hapd_iface->bss[0]->driver,
+ hapd_iface->bss[0]->drv_priv, hapd_iface);
/* From hostapd_cleanup_iface: These were initialized in
* hostapd_setup_interface and hostapd_setup_interface_complete
@@ -4068,6 +4088,7 @@
#endif /* CONFIG_IEEE80211BE */
ap_sta_clear_disconnect_timeouts(hapd, sta);
+ ap_sta_clear_assoc_timeout(hapd, sta);
sta->post_csa_sa_query = 0;
#ifdef CONFIG_P2P
@@ -4085,7 +4106,13 @@
* IEEE 802.1X/WPA code will start accounting after the station has
* been authorized. */
if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) {
- ap_sta_set_authorized(hapd, sta, 1);
+ if (ap_sta_set_authorized(hapd, sta, 1)) {
+ /* Update driver authorized flag for the STA to cover
+ * the case where AP SME is in the driver and there is
+ * no separate event for handling TX status event for
+ * the (Re)Association Response frame. */
+ hostapd_set_sta_flags(hapd, sta);
+ }
os_get_reltime(&sta->connected_time);
accounting_sta_start(hapd, sta);
}
@@ -4200,8 +4227,8 @@
}
-static int hostapd_build_beacon_data(struct hostapd_data *hapd,
- struct beacon_data *beacon)
+int hostapd_build_beacon_data(struct hostapd_data *hapd,
+ struct beacon_data *beacon)
{
struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra;
struct wpa_driver_ap_params params;
@@ -4382,6 +4409,10 @@
hostapd_set_oper_centr_freq_seg0_idx(conf, seg0);
hostapd_set_oper_centr_freq_seg1_idx(conf, seg1);
+#ifdef CONFIG_IEEE80211BE
+ conf->punct_bitmap = params->punct_bitmap;
+#endif /* CONFIG_IEEE80211BE */
+
/* TODO: maybe call here hostapd_config_check here? */
return 0;
@@ -4394,9 +4425,6 @@
struct hostapd_iface *iface = hapd->iface;
struct hostapd_freq_params old_freq;
int ret;
-#ifdef CONFIG_IEEE80211BE
- u16 old_punct_bitmap;
-#endif /* CONFIG_IEEE80211BE */
u8 chan, bandwidth;
os_memset(&old_freq, 0, sizeof(old_freq));
@@ -4445,16 +4473,9 @@
if (ret)
return ret;
-#ifdef CONFIG_IEEE80211BE
- old_punct_bitmap = iface->conf->punct_bitmap;
- iface->conf->punct_bitmap = settings->punct_bitmap;
-#endif /* CONFIG_IEEE80211BE */
ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
/* change back the configuration */
-#ifdef CONFIG_IEEE80211BE
- iface->conf->punct_bitmap = old_punct_bitmap;
-#endif /* CONFIG_IEEE80211BE */
hostapd_change_config_freq(iface->bss[0], iface->conf,
&old_freq, NULL);
@@ -4768,6 +4789,7 @@
struct cca_settings settings;
int ret;
+ os_memset(&settings, 0, sizeof(settings));
hostapd_cleanup_cca_params(bss);
bss->cca_color = r;
bss->cca_count = 10;
@@ -5042,6 +5064,28 @@
link_bss->drv_priv = NULL;
}
+
+/* Return the number of currently active links, not counting the calling link
+ * (i.e., a value that is suitable to be used as-is in fields that use encoding
+ * of the value minus 1). */
+u8 hostapd_get_active_links(struct hostapd_data *hapd)
+{
+ struct hostapd_data *link_bss;
+ u8 active_links = 0;
+
+ if (!hapd || !hapd->conf->mld_ap)
+ return 0;
+
+ for_each_mld_link(link_bss, hapd) {
+ if (link_bss == hapd || !link_bss->started)
+ continue;
+
+ active_links++;
+ }
+
+ return active_links;
+}
+
#endif /* CONFIG_IEEE80211BE */
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 5d91d85..846535a 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -768,6 +768,8 @@
struct hostapd_iface *
hostapd_interface_init_bss(struct hapd_interfaces *interfaces, const char *phy,
const char *config_fname, int debug);
+void hostapd_bss_setup_multi_link(struct hostapd_data *hapd,
+ struct hapd_interfaces *interfaces);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
void hostapd_interface_deinit_free(struct hostapd_iface *iface);
@@ -859,8 +861,11 @@
u8 hostapd_get_mld_id(struct hostapd_data *hapd);
int hostapd_mld_add_link(struct hostapd_data *hapd);
int hostapd_mld_remove_link(struct hostapd_data *hapd);
+u8 hostapd_get_active_links(struct hostapd_data *hapd);
struct hostapd_data * hostapd_mld_get_first_bss(struct hostapd_data *hapd);
+int hostapd_build_beacon_data(struct hostapd_data *hapd,
+ struct beacon_data *beacon);
void free_beacon_data(struct beacon_data *beacon);
int hostapd_fill_cca_settings(struct hostapd_data *hapd,
struct cca_settings *settings);
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 02d6759..cef3817 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -528,12 +528,6 @@
else
ieee80211n_scan_channels_5g(iface, ¶ms);
- params.link_id = -1;
-#ifdef CONFIG_IEEE80211BE
- if (iface->bss[0]->conf->mld_ap)
- params.link_id = iface->bss[0]->mld_link_id;
-#endif /* CONFIG_IEEE80211BE */
-
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
iface->num_ht40_scan_tries++;
os_free(params.freqs);
@@ -585,11 +579,6 @@
else
ieee80211n_scan_channels_5g(iface, ¶ms);
- params.link_id = -1;
-#ifdef CONFIG_IEEE80211BE
- if (iface->bss[0]->conf->mld_ap)
- params.link_id = iface->bss[0]->mld_link_id;
-#endif /* CONFIG_IEEE80211BE */
ret = hostapd_driver_scan(iface->bss[0], ¶ms);
os_free(params.freqs);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index d4552f2..a9ed6eb 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -26,6 +26,7 @@
#include "common/wpa_common.h"
#include "common/wpa_ctrl.h"
#include "common/ptksa_cache.h"
+#include "common/nan_de.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -576,12 +577,12 @@
pk = pw->pk;
break;
}
- if (!password) {
+ if (!password && !rx_id) {
password = hapd->conf->ssid.wpa_passphrase;
pt = hapd->conf->ssid.pt;
}
- if (!password && sta) {
+ if (!password && sta && !rx_id) {
for (psk = sta->psk; psk; psk = psk->next) {
if (psk->is_passphrase) {
password = psk->passphrase;
@@ -620,7 +621,8 @@
#endif /* CONFIG_IEEE80211BE */
if (sta->sae->tmp) {
- rx_id = sta->sae->tmp->pw_id;
+ rx_id = sta->sae->tmp->parsed_pw_id ?
+ sta->sae->tmp->parsed_pw_id : sta->sae->tmp->pw_id;
use_pt = sta->sae->h2e;
#ifdef CONFIG_SAE_PK
os_memcpy(sta->sae->tmp->own_addr, own_addr, ETH_ALEN);
@@ -712,7 +714,8 @@
u16 status;
data = auth_build_sae_commit(hapd, sta, update, status_code);
- if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
+ if (!data && sta->sae->tmp &&
+ (sta->sae->tmp->pw_id || sta->sae->tmp->parsed_pw_id))
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -1001,7 +1004,9 @@
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
- if (sta->sae->tmp) {
+ struct sae_temporary_data *tmp = sta->sae->tmp;
+
+ if (tmp) {
sta->sae->h2e =
(status_code ==
WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
@@ -1011,8 +1016,21 @@
}
ret = auth_sae_send_commit(hapd, sta,
!allow_reuse, status_code);
+ if (ret == WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER)
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER
+ MACSTR, MAC2STR(sta->addr));
if (ret)
return ret;
+
+ if (tmp && tmp->parsed_pw_id && !tmp->pw_id) {
+ tmp->pw_id = tmp->parsed_pw_id;
+ tmp->parsed_pw_id = NULL;
+ wpa_printf(MSG_DEBUG,
+ "SAE: Known Password Identifier bound to this STA: '%s'",
+ tmp->pw_id);
+ }
+
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
if (sae_process_commit(sta->sae) < 0)
@@ -1374,6 +1392,8 @@
resp = -1;
goto remove_sta;
}
+ if (!hostapd_sae_pw_id_in_use(hapd->conf))
+ sta->sae->no_pw_id = 1;
sae_set_state(sta, SAE_NOTHING, "Init");
sta->sae->sync = 0;
}
@@ -1512,6 +1532,8 @@
sae_clear_retransmit_timer(hapd, sta);
sae_set_state(sta, SAE_NOTHING,
"Unknown Password Identifier");
+ if (sta->sae->state == SAE_NOTHING)
+ goto reply;
goto remove_sta;
}
@@ -1634,14 +1656,6 @@
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) {
- wpa_printf(MSG_DEBUG,
- "SAE: Clear stored password identifier since this SAE commit was not accepted");
- os_free(sta->sae->tmp->pw_id);
- sta->sae->tmp->pw_id = NULL;
- }
}
remove_sta:
@@ -2506,6 +2520,8 @@
fils->erp_resp = erp_resp;
ret = handle_auth_pasn_resp(sta->pasn, hapd->own_addr, sta->addr, NULL,
WLAN_STATUS_SUCCESS);
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
fils->erp_resp = NULL;
if (ret) {
@@ -2819,6 +2835,32 @@
const struct ieee80211_mgmt *mgmt, size_t len,
u16 trans_seq, u16 status)
{
+ int ret;
+#ifdef CONFIG_P2P
+ struct ieee802_11_elems elems;
+
+ if (len < 24) {
+ wpa_printf(MSG_DEBUG, "PASN: Too short Management frame");
+ return;
+ }
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ return;
+ }
+
+ if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) ==
+ (P2P_ENABLED | P2P_GROUP_OWNER) &&
+ hapd->p2p && elems.p2p2_ie && elems.p2p2_ie_len) {
+ p2p_pasn_auth_rx(hapd->p2p, mgmt, len, hapd->iface->freq);
+ return;
+ }
+#endif /* CONFIG_P2P */
+
if (hapd->conf->wpa != WPA_PROTO_RSN) {
wpa_printf(MSG_INFO, "PASN: RSN is not configured");
return;
@@ -2850,8 +2892,11 @@
hapd_initialize_pasn(hapd, sta);
hapd_pasn_update_params(hapd, sta, mgmt, len);
- if (handle_auth_pasn_1(sta->pasn, hapd->own_addr,
- sta->addr, mgmt, len, false) < 0)
+ ret = handle_auth_pasn_1(sta->pasn, hapd->own_addr, sta->addr,
+ mgmt, len, false);
+ wpabuf_free(sta->pasn->frame);
+ sta->pasn->frame = NULL;
+ if (ret < 0)
ap_free_sta(hapd, sta);
} else if (trans_seq == 3) {
if (!sta->pasn) {
@@ -3369,7 +3414,10 @@
if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1)
return 0;
- num_bss_nontx = hapd->iface->num_bss - 1;
+ if (hapd->iface->conf->mbssid_max > 0)
+ num_bss_nontx = hapd->iface->conf->mbssid_max - 1;
+ else
+ num_bss_nontx = hapd->iface->conf->num_bss - 1;
while (num_bss_nontx > 0) {
max_bssid_ind++;
num_bss_nontx >>= 1;
@@ -4441,6 +4489,10 @@
hapd->conf->max_acceptable_idle_period;
}
+ if (elems->wfa_capab)
+ hostapd_wfa_capab(hapd, sta, elems->wfa_capab,
+ elems->wfa_capab + elems->wfa_capab_len);
+
return WLAN_STATUS_SUCCESS;
}
@@ -4565,9 +4617,8 @@
if (!mlbuf)
goto out;
- if (ieee802_11_parse_link_assoc_req(ies, ies_len, &elems, mlbuf,
- hapd->mld_link_id, true) ==
- ParseFailed) {
+ if (ieee802_11_parse_link_assoc_req(&elems, mlbuf, hapd->mld_link_id,
+ true) == ParseFailed) {
wpa_printf(MSG_DEBUG,
"MLD: link: Failed to parse association request Multi-Link element");
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -4752,6 +4803,7 @@
int set = 1;
const u8 *mld_link_addr = NULL;
bool mld_link_sta = false;
+ u16 eml_cap = 0;
#ifdef CONFIG_IEEE80211BE
if (ap_sta_is_mld(hapd, sta)) {
@@ -4762,6 +4814,7 @@
if (hapd->mld_link_id != sta->mld_assoc_link_id)
set = 0;
+ eml_cap = sta->mld_info.common_info.eml_capa;
}
#endif /* CONFIG_IEEE80211BE */
@@ -4842,7 +4895,7 @@
sta->he_6ghz_capab,
sta->flags | WLAN_STA_ASSOC, sta->qosinfo,
sta->vht_opmode, sta->p2p_ie ? 1 : 0,
- set, mld_link_addr, mld_link_sta)) {
+ set, mld_link_addr, mld_link_sta, eml_cap)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE,
"Could not %s STA to kernel driver",
@@ -5606,7 +5659,12 @@
resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
- omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
+#ifdef CONFIG_IEEE80211R_AP
+ if (reassoc && sta->auth_alg == WLAN_AUTH_FT)
+ omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX);
+#endif /* CONFIG_IEEE80211R_AP */
+ if (hapd->conf->rsn_override_omit_rsnxe)
+ omit_rsnxe = 1;
if (hostapd_get_aid(hapd, sta) < 0) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -5998,10 +6056,51 @@
}
+static int hostapd_action_vs(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ unsigned int freq, bool protected)
+{
+ const u8 *pos, *end;
+ u32 oui_type;
+
+ pos = &mgmt->u.action.category;
+ end = ((const u8 *) mgmt) + len;
+
+ if (end - pos < 1 + 4)
+ return -1;
+ pos++;
+
+ oui_type = WPA_GET_BE32(pos);
+ pos += 4;
+
+ switch (oui_type) {
+ case WFA_CAPAB_VENDOR_TYPE:
+ hostapd_wfa_capab(hapd, sta, pos, end);
+ return 0;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "Ignore unknown Vendor Specific Action frame OUI/type %08x%s",
+ oui_type, protected ? " (protected)" : "");
+ break;
+ }
+
+ return -1;
+}
+
+
static int robust_action_frame(u8 category)
{
return category != WLAN_ACTION_PUBLIC &&
- category != WLAN_ACTION_HT;
+ category != WLAN_ACTION_HT &&
+ category != WLAN_ACTION_UNPROTECTED_WNM &&
+ category != WLAN_ACTION_SELF_PROTECTED &&
+ category != WLAN_ACTION_UNPROTECTED_DMG &&
+ category != WLAN_ACTION_VHT &&
+ category != WLAN_ACTION_UNPROTECTED_S1G &&
+ category != WLAN_ACTION_HE &&
+ category != WLAN_ACTION_EHT &&
+ category != WLAN_ACTION_VENDOR_SPECIFIC;
}
@@ -6148,8 +6247,8 @@
pos = mgmt->u.action.u.vs_public_action.variable;
end = ((const u8 *) mgmt) + len;
pos++;
- hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, freq,
- pos, end - pos);
+ hostapd_nan_usd_rx_sdf(hapd, mgmt->sa, mgmt->bssid,
+ freq, pos, end - pos);
return 1;
}
#endif /* CONFIG_NAN_USD */
@@ -6170,6 +6269,14 @@
(u8 *) mgmt, len, freq) == 0)
return 1;
}
+ if (sta &&
+ hostapd_action_vs(hapd, sta, mgmt, len, freq, false) == 0)
+ return 1;
+ break;
+ case WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED:
+ if (sta &&
+ hostapd_action_vs(hapd, sta, mgmt, len, freq, true) == 0)
+ return 1;
break;
#ifndef CONFIG_NO_RRM
case WLAN_ACTION_RADIO_MEASUREMENT:
@@ -6263,6 +6370,8 @@
#ifdef CONFIG_NAN_USD
static const u8 nan_network_id[ETH_ALEN] =
{ 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 };
+ static const u8 p2p_network_id[ETH_ALEN] =
+ { 0x51, 0x6f, 0x9a, 0x02, 0x00, 0x00 };
#endif /* CONFIG_NAN_USD */
if (len < 24)
@@ -6295,6 +6404,10 @@
}
if (!is_broadcast_ether_addr(mgmt->bssid) &&
+#ifdef CONFIG_NAN_USD
+ !nan_de_is_nan_network_id(mgmt->bssid) &&
+ !nan_de_is_p2p_network_id(mgmt->bssid) &&
+#endif /* CONFIG_NAN_USD */
#ifdef CONFIG_P2P
/* Invitation responses can be sent with the peer MAC as BSSID */
!((hapd->conf->p2p & P2P_GROUP_OWNER) &&
@@ -6332,6 +6445,7 @@
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_NAN_USD
!ether_addr_equal(mgmt->da, nan_network_id) &&
+ !ether_addr_equal(mgmt->da, p2p_network_id) &&
#endif /* CONFIG_NAN_USD */
!ether_addr_equal(mgmt->da, hapd->own_addr)) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -7254,32 +7368,29 @@
{
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. */
+ /* bandwidth: 0: 40, 1: 80, 160, 80+80, 4 to 255 reserved as per
+ * IEEE P802.11-REVme/D7.0, 9.4.2.159 and Table 9-316.
+ */
switch (hapd->cs_freq_params.bandwidth) {
- case 40:
- bw = 0;
- break;
- case 80:
- bw = 1;
- break;
- case 160:
- bw = 1;
- break;
case 320:
- bw = 4;
- break;
- default:
- /* not valid VHT bandwidth or not in CSA */
- return eid;
- }
+ /* As per IEEE P802.11be/D7.0, 35.15.3,
+ * For EHT BSS operating channel width wider than 160 MHz,
+ * the announced BSS bandwidth in the Wide Bandwidth
+ * Channel Switch element is less than the BSS bandwidth
+ * in the Bandwidth Indication element
+ */
- *eid++ = WLAN_EID_WIDE_BW_CHSWITCH;
- *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
- *eid++ = bw; /* New Channel Width */
- if (hapd->cs_freq_params.bandwidth == 160) {
+ /* Modifying the center frequency to 160 MHz */
+ if (hapd->cs_freq_params.channel < chan1)
+ chan1 -= 16;
+ else
+ chan1 += 16;
+
+ /* fallthrough */
+ case 160:
/* Update the CCFS0 and CCFS1 values in the element based on
- * IEEE P802.11-REVme/D4.0, Table 9-314 */
+ * IEEE P802.11-REVme/D7.0, Table 9-316
+ */
/* CCFS1 - The channel center frequency index of the 160 MHz
* channel. */
@@ -7291,7 +7402,23 @@
chan1 -= 8;
else
chan1 += 8;
+
+ bw = 1;
+ break;
+ case 80:
+ bw = 1;
+ break;
+ case 40:
+ bw = 0;
+ break;
+ default:
+ /* not valid VHT bandwidth or not in CSA */
+ return eid;
}
+
+ *eid++ = WLAN_EID_WIDE_BW_CHSWITCH;
+ *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
+ *eid++ = bw; /* New Channel Width */
*eid++ = chan1; /* New Channel Center Frequency Segment 0 */
*eid++ = chan2; /* New Channel Center Frequency Segment 1 */
@@ -7305,9 +7432,9 @@
static u8 * hostapd_eid_bw_indication(struct hostapd_data *hapd, u8 *eid,
u8 chan1, u8 chan2)
{
- u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
+ u16 punct_bitmap = hapd->cs_freq_params.punct_bitmap;
struct ieee80211_bw_ind_element *bw_ind_elem;
- size_t elen = 3;
+ size_t elen = 4;
if (hapd->cs_freq_params.bandwidth <= 160 && !punct_bitmap)
return eid;
@@ -8221,11 +8348,13 @@
for (i = *bss_index; i < hapd->iface->num_bss; i++) {
struct hostapd_data *bss = hapd->iface->bss[i];
struct hostapd_bss_config *conf;
+ struct hostapd_bss_config *tx_conf = tx_bss->conf;
u8 *eid_len_pos, *nontx_bss_start = eid;
const u8 *auth, *rsn = NULL, *rsnx = NULL;
u8 ie_count = 0, non_inherit_ie[3];
size_t auth_len = 0;
u16 capab_info;
+ u8 mbssindex = i;
if (!bss || !bss->conf || !bss->started ||
mbssid_known_bss(i, known_bss, known_bss_len))
@@ -8246,10 +8375,14 @@
os_memcpy(eid, conf->ssid.ssid, conf->ssid.ssid_len);
eid += conf->ssid.ssid_len;
+ if (conf->mbssid_index &&
+ conf->mbssid_index > tx_conf->mbssid_index)
+ mbssindex = conf->mbssid_index - tx_conf->mbssid_index;
+
*eid++ = WLAN_EID_MULTIPLE_BSSID_INDEX;
if (frame_type == WLAN_FC_STYPE_BEACON) {
*eid++ = 3;
- *eid++ = i; /* BSSID Index */
+ *eid++ = mbssindex; /* BSSID Index */
if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED &&
(conf->dtim_period % elem_count))
conf->dtim_period = elem_count;
@@ -8265,7 +8398,7 @@
/* Probe Request frame does not include DTIM Period and
* DTIM Count fields. */
*eid++ = 1;
- *eid++ = i; /* BSSID Index */
+ *eid++ = mbssindex; /* BSSID Index */
}
auth = wpa_auth_get_wpa_ie(bss->wpa_auth, &auth_len);
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index abf48ab..2bcc29e 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -130,6 +130,8 @@
int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
enum ieee80211_op_mode mode);
bool hostapd_get_ht_vht_twt_responder(struct hostapd_data *hapd);
+void hostapd_wfa_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, const u8 *end);
u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
index aea69ab..e778041 100644
--- a/src/ap/ieee802_11_eht.c
+++ b/src/ap/ieee802_11_eht.c
@@ -503,7 +503,7 @@
mld_cap = hapd->iface->mld_mld_capa;
max_simul_links = mld_cap & EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK;
- active_links = hapd->mld->num_links - 1;
+ active_links = hostapd_get_active_links(hapd);
if (active_links > max_simul_links) {
wpa_printf(MSG_ERROR,
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index a2deda6..cd9f8bc 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -221,7 +221,7 @@
if (is_6ghz_op_class(hapd->iconf->op_class)) {
enum oper_chan_width oper_chwidth =
- hostapd_get_oper_chwidth(hapd->iconf);
+ hapd->iconf->he_oper_chwidth;
u8 seg0 = hapd->iconf->he_oper_centr_freq_seg0_idx;
u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
u8 control;
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 4c39e40..9bc0461 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -457,6 +457,7 @@
iface->num_sta_ht40_intolerant--;
if (iface->num_sta_ht40_intolerant == 0 &&
+ iface->conf->obss_interval &&
(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
(iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
unsigned int delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 3dd3a6a..5e67216 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -476,6 +476,14 @@
*pos |= 0x01; /* Bit 88 - SAE PK Exclusively */
#endif /* CONFIG_SAE_PK */
break;
+ case 12: /* Bits 96-103 */
+ if (hapd->iconf->peer_to_peer_twt)
+ *pos |= 0x10; /* Bit 100 - Peer to Peer TWT */
+ break;
+ case 13: /* Bits 104-111 */
+ if (hapd->iconf->channel_usage)
+ *pos |= 0x01; /* Bit 104 - Channel Usage support */
+ break;
}
}
@@ -1226,3 +1234,47 @@
(hapd->iface->drv_flags2 &
WPA_DRIVER_FLAGS2_HT_VHT_TWT_RESPONDER);
}
+
+
+static void hostapd_wfa_gen_capab(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *capab, size_t len)
+{
+ char *hex;
+ size_t buflen;
+
+ wpa_printf(MSG_DEBUG,
+ "WFA: Received indication of generational capabilities from "
+ MACSTR, MAC2STR(sta->addr));
+ wpa_hexdump(MSG_DEBUG, "WFA: Generational Capabilities", capab, len);
+
+ buflen = 2 * len + 1;
+ hex = os_zalloc(buflen);
+ if (!hex)
+ return;
+ wpa_snprintf_hex(hex, buflen, capab, len);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, WFA_GEN_CAPAB_RX MACSTR " %s",
+ MAC2STR(sta->addr), hex);
+ os_free(hex);
+}
+
+
+void hostapd_wfa_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, const u8 *end)
+{
+ u8 capab_len;
+ const u8 *gen_capa;
+
+ if (end - pos < 1)
+ return;
+ capab_len = *pos++;
+ if (capab_len > end - pos)
+ return;
+ pos += capab_len; /* skip the Capabilities field */
+
+ /* Wi-Fi Alliance Capabilities attributes use a header that is similar
+ * to the one used in Information Elements. */
+ gen_capa = get_ie(pos, end - pos, WFA_CAPA_ATTR_GENERATIONAL_CAPAB);
+ if (gen_capa)
+ hostapd_wfa_gen_capab(hapd, sta, gen_capa + 2, gen_capa[1]);
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index f4103ac..e8d21ff 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -149,7 +149,7 @@
bool authorized)
{
#ifdef CONFIG_IEEE80211BE
- unsigned int i, link_id;
+ unsigned int i;
if (!hostapd_is_mld_ap(hapd))
return;
@@ -161,32 +161,30 @@
if (authorized && hapd->mld_link_id != sta->mld_assoc_link_id)
return;
- for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
- struct mld_link_info *link = &sta->mld_info.links[link_id];
+ for (i = 0; i < hapd->iface->interfaces->count; i++) {
+ struct sta_info *tmp_sta;
+ struct mld_link_info *link;
+ struct hostapd_data *tmp_hapd =
+ hapd->iface->interfaces->iface[i]->bss[0];
+ if (!hostapd_is_ml_partner(hapd, tmp_hapd))
+ continue;
+
+ link = &sta->mld_info.links[tmp_hapd->mld_link_id];
if (!link->valid)
continue;
- for (i = 0; i < hapd->iface->interfaces->count; i++) {
- struct sta_info *tmp_sta;
- struct hostapd_data *tmp_hapd =
- hapd->iface->interfaces->iface[i]->bss[0];
-
- if (!hostapd_is_ml_partner(hapd, tmp_hapd))
+ for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
+ tmp_sta = tmp_sta->next) {
+ if (tmp_sta == sta ||
+ tmp_sta->mld_assoc_link_id !=
+ sta->mld_assoc_link_id ||
+ tmp_sta->aid != sta->aid)
continue;
- for (tmp_sta = tmp_hapd->sta_list; tmp_sta;
- tmp_sta = tmp_sta->next) {
- if (tmp_sta == sta ||
- tmp_sta->mld_assoc_link_id !=
- sta->mld_assoc_link_id ||
- tmp_sta->aid != sta->aid)
- continue;
-
- ieee802_1x_set_authorized(tmp_hapd, tmp_sta,
- authorized, true);
- break;
- }
+ ieee802_1x_set_authorized(tmp_hapd, tmp_sta,
+ authorized, true);
+ break;
}
}
#endif /* CONFIG_IEEE80211BE */
@@ -1252,6 +1250,27 @@
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
"received EAPOL-Start from STA");
+#ifdef CONFIG_IEEE80211R_AP
+ if (hapd->conf->wpa && sta->wpa_sm &&
+ (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) ||
+ sta->auth_alg == WLAN_AUTH_FT)) {
+ /* When FT is used, reauthentication to generate a new
+ * PMK-R0 would be complicated since the current AP
+ * might not be the one with which the currently used
+ * PMK-R0 was generated. IEEE Std 802.11-2020, 13.4.2
+ * (FT initial mobility domain association in an RSN)
+ * mandates STA to perform a new FT initial mobility
+ * domain association whenever its Supplicant would
+ * trigger sending of an EAPOL-Start frame. As such,
+ * this EAPOL-Start frame should not have been sent.
+ * Discard it to avoid unexpected behavior. */
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE8021X,
+ HOSTAPD_LEVEL_DEBUG,
+ "discard unexpected EAPOL-Start from STA that uses FT");
+ break;
+ }
+#endif /* CONFIG_IEEE80211R_AP */
sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
if (pmksa) {
diff --git a/src/ap/nan_usd_ap.c b/src/ap/nan_usd_ap.c
index 570abfc..4623f67 100644
--- a/src/ap/nan_usd_ap.c
+++ b/src/ap/nan_usd_ap.c
@@ -29,8 +29,10 @@
wpabuf_len(buf));
/* TODO: Force use of OFDM */
- return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
- wpabuf_head(buf), wpabuf_len(buf));
+ return hostapd_drv_send_action_forced_addr3(hapd, hapd->iface->freq, 0,
+ dst, bssid,
+ wpabuf_head(buf),
+ wpabuf_len(buf));
}
@@ -158,7 +160,7 @@
cb.subscribe_terminated = hostapd_nan_de_subscribe_terminated;
cb.receive = hostapd_nan_de_receive;
- hapd->nan_de = nan_de_init(hapd->own_addr, false, true, &cb);
+ hapd->nan_de = nan_de_init(hapd->own_addr, false, true, 0, &cb);
if (!hapd->nan_de)
return -1;
return 0;
@@ -173,11 +175,12 @@
void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src,
- unsigned int freq, const u8 *buf, size_t len)
+ const u8 *a3, unsigned int freq,
+ const u8 *buf, size_t len)
{
if (!hapd->nan_de)
return;
- nan_de_rx_sdf(hapd->nan_de, src, freq, buf, len);
+ nan_de_rx_sdf(hapd->nan_de, src, a3, freq, buf, len);
}
@@ -258,7 +261,8 @@
int hostapd_nan_usd_transmit(struct hostapd_data *hapd, int handle,
const struct wpabuf *ssi,
const struct wpabuf *elems,
- const u8 *peer_addr, u8 req_instance_id)
+ const u8 *peer_addr,
+ u8 req_instance_id)
{
if (!hapd->nan_de)
return -1;
diff --git a/src/ap/nan_usd_ap.h b/src/ap/nan_usd_ap.h
index 0571643..b7e8b76 100644
--- a/src/ap/nan_usd_ap.h
+++ b/src/ap/nan_usd_ap.h
@@ -16,6 +16,7 @@
int hostapd_nan_usd_init(struct hostapd_data *hapd);
void hostapd_nan_usd_deinit(struct hostapd_data *hapd);
void hostapd_nan_usd_rx_sdf(struct hostapd_data *hapd, const u8 *src,
+ const u8 *a3,
unsigned int freq, const u8 *buf, size_t len);
void hostapd_nan_usd_flush(struct hostapd_data *hapd);
int hostapd_nan_usd_publish(struct hostapd_data *hapd, const char *service_name,
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index aa7e156..9d49569 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -334,6 +334,7 @@
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
ap_sta_clear_disconnect_timeouts(hapd, sta);
+ ap_sta_clear_assoc_timeout(hapd, sta);
sae_clear_retransmit_timer(hapd, sta);
ieee802_1x_free_station(hapd, sta);
@@ -791,6 +792,25 @@
}
+static void ap_sta_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = timeout_ctx;
+
+ if (sta->flags & WLAN_STA_ASSOC)
+ return;
+
+ wpa_printf(MSG_DEBUG, "STA " MACSTR
+ " did not complete association in time - remove it",
+ MAC2STR(sta->addr));
+ if (sta->flags & WLAN_STA_AUTH)
+ ap_sta_deauthenticate(hapd, sta,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ else
+ ap_free_sta(hapd, sta);
+}
+
+
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
@@ -856,6 +876,9 @@
&sta->probe_ie_taxonomy);
#endif /* CONFIG_TAXONOMY */
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ eloop_register_timeout(60, 0, ap_sta_assoc_timeout, hapd, sta);
+
return sta;
}
@@ -953,6 +976,18 @@
}
+static void ap_sta_disassociate_common(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 reason)
+{
+ sta->disassoc_reason = reason;
+ sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
+ eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+ eloop_register_timeout(hapd->iface->drv_flags &
+ WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+ ap_sta_disassoc_cb_timeout, hapd, sta);
+}
+
+
static void ap_sta_handle_disassociate(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason)
{
@@ -971,13 +1006,7 @@
}
ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DISASSOC);
-
- sta->disassoc_reason = reason;
- sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
- eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
- eloop_register_timeout(hapd->iface->drv_flags &
- WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
- ap_sta_disassoc_cb_timeout, hapd, sta);
+ ap_sta_disassociate_common(hapd, sta, reason);
}
@@ -993,25 +1022,9 @@
}
-static void ap_sta_handle_deauthenticate(struct hostapd_data *hapd,
+static void ap_sta_deauthenticate_common(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason)
{
- if (hapd->iface->current_mode &&
- hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
- /* Deauthentication is not used in DMG/IEEE 802.11ad;
- * disassociate the STA instead. */
- ap_sta_disassociate(hapd, sta, reason);
- return;
- }
-
- wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
- hapd->conf->iface, MAC2STR(sta->addr));
-
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
-
- sta->timeout_next = STA_REMOVE;
- ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH);
-
sta->deauth_reason = reason;
sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
@@ -1021,9 +1034,46 @@
}
+static void ap_sta_handle_deauthenticate(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 reason)
+{
+ wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
+
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+
+ sta->timeout_next = STA_REMOVE;
+ ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH);
+ ap_sta_deauthenticate_common(hapd, sta, reason);
+}
+
+
+static void ap_sta_handle_disconnect(struct hostapd_data *hapd,
+ struct sta_info *sta, u16 reason)
+{
+ wpa_printf(MSG_DEBUG, "%s: disconnect STA " MACSTR,
+ hapd->conf->iface, MAC2STR(sta->addr));
+
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ sta->timeout_next = STA_REMOVE;
+
+ sta->deauth_reason = reason;
+ ap_sta_disconnect_common(hapd, sta, AP_MAX_INACTIVITY_AFTER_DEAUTH);
+ ap_sta_deauthenticate_common(hapd, sta, reason);
+}
+
+
+enum ap_sta_disconnect_op {
+ AP_STA_DEAUTHENTICATE,
+ AP_STA_DISASSOCIATE,
+ AP_STA_DISCONNECT
+};
+
static bool ap_sta_ml_disconnect(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason,
- bool disassoc)
+ enum ap_sta_disconnect_op op)
{
#ifdef CONFIG_IEEE80211BE
struct hostapd_data *assoc_hapd, *tmp_hapd;
@@ -1072,25 +1122,30 @@
tmp_sta->aid != assoc_sta->aid)
continue;
- if (disassoc)
+ if (op == AP_STA_DISASSOCIATE)
ap_sta_handle_disassociate(tmp_hapd,
tmp_sta,
reason);
- else
+ else if (op == AP_STA_DEAUTHENTICATE)
ap_sta_handle_deauthenticate(tmp_hapd,
tmp_sta,
reason);
-
+ else
+ ap_sta_handle_disconnect(tmp_hapd,
+ tmp_sta,
+ reason);
break;
}
}
}
/* Disconnect the station on which the association was performed. */
- if (disassoc)
+ if (op == AP_STA_DISASSOCIATE)
ap_sta_handle_disassociate(assoc_hapd, assoc_sta, reason);
- else
+ else if (op == AP_STA_DEAUTHENTICATE)
ap_sta_handle_deauthenticate(assoc_hapd, assoc_sta, reason);
+ else
+ ap_sta_handle_disconnect(assoc_hapd, assoc_sta, reason);
return true;
#else /* CONFIG_IEEE80211BE */
@@ -1102,7 +1157,7 @@
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
- if (ap_sta_ml_disconnect(hapd, sta, reason, true))
+ if (ap_sta_ml_disconnect(hapd, sta, reason, AP_STA_DISASSOCIATE))
return;
ap_sta_handle_disassociate(hapd, sta, reason);
@@ -1112,7 +1167,15 @@
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
- if (ap_sta_ml_disconnect(hapd, sta, reason, false))
+ if (hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
+ /* Deauthentication is not used in DMG/IEEE 802.11ad;
+ * disassociate the STA instead. */
+ ap_sta_disassociate(hapd, sta, reason);
+ return;
+ }
+
+ if (ap_sta_ml_disconnect(hapd, sta, reason, AP_STA_DEAUTHENTICATE))
return;
ap_sta_handle_deauthenticate(hapd, sta, reason);
@@ -1596,12 +1659,13 @@
}
-void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+bool ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
if (!ap_sta_set_authorized_flag(hapd, sta, authorized))
- return;
+ return false;
ap_sta_set_authorized_event(hapd, sta, authorized);
+ return true;
}
@@ -1625,41 +1689,19 @@
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);
- wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
- ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
- wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout "
- "for " MACSTR " (%d seconds - "
- "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
- hapd->conf->iface, __func__, MAC2STR(sta->addr),
- AP_MAX_INACTIVITY_AFTER_DEAUTH);
- eloop_cancel_timeout(ap_handle_timer, hapd, sta);
- eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
- ap_handle_timer, hapd, sta);
- sta->timeout_next = STA_REMOVE;
if (hapd->iface->current_mode &&
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) {
/* Deauthentication is not used in DMG/IEEE 802.11ad;
* disassociate the STA instead. */
- sta->disassoc_reason = reason;
- sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
- eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
- eloop_register_timeout(hapd->iface->drv_flags &
- WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ?
- 2 : 0, 0, ap_sta_disassoc_cb_timeout,
- hapd, sta);
+ ap_sta_disassociate_common(hapd, sta, reason);
return;
}
- sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
- eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
- eloop_register_timeout(hapd->iface->drv_flags &
- WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
- ap_sta_deauth_cb_timeout, hapd, sta);
+ if (ap_sta_ml_disconnect(hapd, sta, reason, AP_STA_DISCONNECT))
+ return;
+
+ ap_sta_handle_disconnect(hapd, sta, reason);
}
@@ -1712,6 +1754,13 @@
}
+void ap_sta_clear_assoc_timeout(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ eloop_cancel_timeout(ap_sta_assoc_timeout, hapd, sta);
+}
+
+
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
{
int res;
@@ -1826,6 +1875,7 @@
{
const u8 *mld_link_addr = NULL;
bool mld_link_sta = false;
+ u16 eml_cap = 0;
/*
* If a station that is already associated to the AP, is trying to
@@ -1841,6 +1891,7 @@
mld_link_sta = sta->mld_assoc_link_id != mld_link_id;
mld_link_addr = sta->mld_info.links[mld_link_id].peer_addr;
+ eml_cap = sta->mld_info.common_info.eml_capa;
/*
* In case the AP is affiliated with an AP MLD, we need to
@@ -1859,7 +1910,7 @@
sta->supported_rates_len,
0, NULL, NULL, NULL, 0, NULL, 0, NULL,
sta->flags, 0, 0, 0, 0,
- mld_link_addr, mld_link_sta)) {
+ mld_link_addr, mld_link_sta, eml_cap)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 5b01c1e..d22e86d 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -386,7 +386,7 @@
int authorized);
void ap_sta_set_authorized_event(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
-void ap_sta_set_authorized(struct hostapd_data *hapd,
+bool ap_sta_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
static inline int ap_sta_is_authorized(struct sta_info *sta)
{
@@ -397,6 +397,8 @@
void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
struct sta_info *sta);
+void ap_sta_clear_assoc_timeout(struct hostapd_data *hapd,
+ struct sta_info *sta);
int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 3af3404..5531aae 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -133,11 +133,8 @@
return;
for_each_sm_auth(sm, link_id) {
- if (link_id == release_link_id) {
- wpa_group_put(sm->mld_links[link_id].wpa_auth,
- sm->mld_links[link_id].wpa_auth->group);
+ if (link_id == release_link_id)
sm->mld_links[link_id].wpa_auth = NULL;
- }
}
}
@@ -368,6 +365,25 @@
#endif /* CONFIG_MESH */
+static inline int wpa_auth_get_drv_flags(struct wpa_authenticator *wpa_auth,
+ u64 *drv_flags, u64 *drv_flags2)
+{
+ if (!wpa_auth->cb->get_drv_flags)
+ return -1;
+ return wpa_auth->cb->get_drv_flags(wpa_auth->cb_ctx, drv_flags,
+ drv_flags2);
+}
+
+
+static bool wpa_auth_4way_handshake_offload(struct wpa_authenticator *wpa_auth)
+{
+ u64 drv_flags = 0, drv_flags2 = 0;
+
+ return wpa_auth_get_drv_flags(wpa_auth, &drv_flags, &drv_flags2) == 0 &&
+ (drv_flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK);
+}
+
+
int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx)
@@ -1003,7 +1019,13 @@
if (wpa_sm_step(sm) == 1)
return 1; /* should not really happen */
sm->Init = false;
- sm->AuthenticationRequest = true;
+
+ if (wpa_auth_4way_handshake_offload(sm->wpa_auth))
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "Skip EAPOL for 4-way handshake offload case");
+ else
+ sm->AuthenticationRequest = true;
+
return wpa_sm_step(sm);
}
@@ -1049,11 +1071,8 @@
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,
- sm->mld_links[link_id].wpa_auth->group);
+ for_each_sm_auth(sm, link_id)
sm->mld_links[link_id].wpa_auth = NULL;
- }
#endif /* CONFIG_IEEE80211BE */
wpa_group_put(sm->wpa_auth, sm->group);
#ifdef CONFIG_DPP2
@@ -2361,7 +2380,12 @@
if (wpa_sm_step(sm) == 1)
return 1; /* should not really happen */
sm->Init = false;
- sm->AuthenticationRequest = true;
+
+ if (wpa_auth_4way_handshake_offload(sm->wpa_auth))
+ wpa_printf(MSG_DEBUG,
+ "Skip EAPOL for 4-way handshake offload case");
+ else
+ sm->AuthenticationRequest = true;
break;
}
@@ -3820,7 +3844,6 @@
key_data_buf_len = key_data_length;
if (aes_unwrap(PTK.kek, PTK.kek_len, key_data_length / 8,
key_data, key_data_buf)) {
- bin_clear_free(key_data_buf, key_data_buf_len);
wpa_printf(MSG_INFO,
"RSN: AES unwrap failed - could not decrypt EAPOL-Key key data");
goto out;
@@ -6613,6 +6636,26 @@
}
+int wpa_auth_pmksa_get_pmk(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr, const u8 **pmk, size_t *pmk_len,
+ const u8 **pmkid)
+{
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = wpa_auth_pmksa_get(wpa_auth, sta_addr, NULL);
+ if (!pmksa) {
+ wpa_printf(MSG_DEBUG, "RSN: Failed to get PMKSA for " MACSTR,
+ MAC2STR(sta_addr));
+ return -1;
+ }
+
+ *pmk = pmksa->pmk;
+ *pmk_len = pmksa->pmk_len;
+ *pmkid = pmksa->pmkid;
+ return 0;
+}
+
+
void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
struct wpa_state_machine *sm,
struct wpa_authenticator *wpa_auth,
@@ -7467,11 +7510,8 @@
ctx.wpa_auth = NULL;
wpa_auth_for_each_auth(sm->wpa_auth,
wpa_get_link_sta_auth, &ctx);
- if (ctx.wpa_auth) {
+ if (ctx.wpa_auth)
sm_link->wpa_auth = ctx.wpa_auth;
- wpa_group_get(sm_link->wpa_auth,
- sm_link->wpa_auth->group);
- }
} else {
sm_link->wpa_auth = sm->wpa_auth;
}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 0b692ad..d4ef49c 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -531,6 +531,9 @@
struct rsn_pmksa_cache_entry *
wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
const u8 *pmkid);
+int wpa_auth_pmksa_get_pmk(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr, const u8 **pmk, size_t *pmk_len,
+ const u8 **pmkid);
struct rsn_pmksa_cache_entry *
wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr, const u8 *pmkid);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 43d9c1d..ce7f90a 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -1247,6 +1247,10 @@
&data.pmkid[i * PMKID_LEN], PMKID_LEN);
sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
&data.pmkid[i * PMKID_LEN]);
+ if (!sm->pmksa && !is_zero_ether_addr(sm->p2p_dev_addr))
+ sm->pmksa = pmksa_cache_auth_get(
+ wpa_auth->pmksa, sm->p2p_dev_addr,
+ &data.pmkid[i * PMKID_LEN]);
if (sm->pmksa) {
pmkid = sm->pmksa->pmkid;
break;
@@ -1297,7 +1301,21 @@
!!(drv_flags2 &
WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP);
- if (!ap_sae_offload && data.num_pmkid && !sm->pmksa) {
+ /* Authenticator needs to have a PMKSA corresponding to a
+ * PMKID (if present) included by the STA in (Re)Association
+ * Request frame if PMKSA caching is attempted to be used. In
+ * case of SAE, this follows Open System authentication. IEEE
+ * Std 802.11 mandates the AP to reject (re)association trying
+ * to use PMKSA caching for SAE authentication. While the
+ * PMKID (if any) in the RSNE in (Re)Association Request frame
+ * following SAE authentication (i.e., in the case of no PMKSA
+ * caching) is not really supposed to include an unknown PMKID,
+ * the standard does not require the AP to reject association.
+ * The PMKSA that was just derived using SAE authentication
+ * can be used regardless of which PMKID(s) are indicated in the
+ * (Re)Association Request frame. */
+ if (!ap_sae_offload && data.num_pmkid && !sm->pmksa &&
+ sm->auth_alg == WLAN_AUTH_OPEN) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
"No PMKSA cache entry found for SAE");
return WPA_INVALID_PMKID;
diff --git a/src/common/defs.h b/src/common/defs.h
index 754c4e4..467051f 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -537,6 +537,12 @@
SAE_PWE_NOT_SET = 4,
};
+enum wpa_p2p_mode {
+ WPA_P2P_MODE_WFD_R1 = 0,
+ WPA_P2P_MODE_WFD_R2 = 1,
+ WPA_P2P_MODE_WFD_PCC = 2,
+};
+
#define USEC_80211_TU 1024
#define USEC_TO_TU(m) ((m) / USEC_80211_TU)
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index bffb440..78a68aa 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -432,6 +432,27 @@
}
+static void punct_update_legacy_bw_320(u16 bitmap, u8 pri,
+ enum oper_chan_width *width, u8 *seg0)
+{
+ if (pri < *seg0) {
+ *seg0 -= 16;
+ if (bitmap & 0x00FF) {
+ *width = 1;
+ punct_update_legacy_bw_160(bitmap & 0xFF, pri, width,
+ seg0);
+ }
+ } else {
+ *seg0 += 16;
+ if (bitmap & 0xFF00) {
+ *width = 1;
+ punct_update_legacy_bw_160((bitmap & 0xFF00) >> 8,
+ pri, width, seg0);
+ }
+ }
+}
+
+
void punct_update_legacy_bw(u16 bitmap, u8 pri, enum oper_chan_width *width,
u8 *seg0, u8 *seg1)
{
@@ -446,7 +467,10 @@
punct_update_legacy_bw_160(bitmap & 0xFF, pri, width, seg0);
}
- /* TODO: 320 MHz */
+ if (*width == CONF_OPER_CHWIDTH_320MHZ && (bitmap & 0xFFFF)) {
+ *width = CONF_OPER_CHWIDTH_160MHZ;
+ punct_update_legacy_bw_320(bitmap & 0xFFFF, pri, width, seg0);
+ }
}
@@ -481,6 +505,7 @@
data->sec_channel_offset = sec_channel_offset;
data->center_freq1 = freq + sec_channel_offset * 10;
data->center_freq2 = 0;
+ data->punct_bitmap = punct_bitmap;
if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
data->bandwidth = 80;
else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index c9b2d37..1c36be5 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -140,6 +140,10 @@
elems->sae_pk = pos + 4;
elems->sae_pk_len = elen - 4;
break;
+ case WFA_CAPA_OUI_TYPE:
+ elems->wfa_capab = pos + 4;
+ elems->wfa_capab_len = elen - 4;
+ break;
case WFA_RSNE_OVERRIDE_OUI_TYPE:
elems->rsne_override = pos;
elems->rsne_override_len = elen;
@@ -148,6 +152,10 @@
elems->rsne_override_2 = pos;
elems->rsne_override_2_len = elen;
break;
+ case WFA_RSNXE_OVERRIDE_OUI_TYPE:
+ elems->rsnxe_override = pos;
+ elems->rsnxe_override_len = elen;
+ break;
case WFA_RSN_SELECTION_OUI_TYPE:
if (elen < 4 + 1) {
wpa_printf(MSG_DEBUG,
@@ -993,14 +1001,14 @@
}
-ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len,
- struct ieee802_11_elems *elems,
+ParseRes ieee802_11_parse_link_assoc_req(struct ieee802_11_elems *elems,
struct wpabuf *mlbuf,
u8 link_id, bool show_errors)
{
const struct ieee80211_eht_ml *ml;
const u8 *pos;
ParseRes res = ParseFailed;
+ size_t len;
pos = wpabuf_head(mlbuf);
len = wpabuf_len(mlbuf);
@@ -3152,7 +3160,7 @@
if (flen > 4)
flen = 4;
for (i = 0; i < flen; i++)
- capabs |= rsnxe[i] << (8 * i);
+ capabs |= (u32) rsnxe[i] << (8 * i);
return !!(capabs & BIT(capab));
}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 62090ce..009073c 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -120,7 +120,9 @@
const u8 *mbssid;
const u8 *rsne_override;
const u8 *rsne_override_2;
+ const u8 *rsnxe_override;
const u8 *rsn_selection;
+ const u8 *wfa_capab;
u8 ssid_len;
u8 supp_rates_len;
@@ -188,7 +190,9 @@
u8 mbssid_len;
size_t rsne_override_len;
size_t rsne_override_2_len;
+ size_t rsnxe_override_len;
size_t rsn_selection_len;
+ u8 wfa_capab_len;
struct mb_ies_info mb_ies;
@@ -210,8 +214,7 @@
const u8 *ids, size_t num);
void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems,
const u8 *ids, size_t num);
-ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len,
- struct ieee802_11_elems *elems,
+ParseRes ieee802_11_parse_link_assoc_req(struct ieee802_11_elems *elems,
struct wpabuf *mlbuf,
u8 link_id, bool show_errors);
int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 7ce7591..c662e0a 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -619,6 +619,7 @@
#define WLAN_RSNX_CAPAB_SECURE_RTT 9
#define WLAN_RSNX_CAPAB_URNM_MFPR_X20 10
#define WLAN_RSNX_CAPAB_URNM_MFPR 15
+#define WLAN_RSNX_CAPAB_KEK_IN_PASN 18
#define WLAN_RSNX_CAPAB_SSID_PROTECTION 21
/* Multiple BSSID element subelements */
@@ -2865,6 +2866,7 @@
#define EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_ALL_TO_ALL 0x0020
#define EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_ALL_TO_ONE 0x0040
#define EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_NEG_SUPP_MSK 0x0060
+#define EHT_ML_MLD_CAPA_AP_MLD_TYPE_IND_MASK 0x0080
#define EHT_ML_MLD_CAPA_FREQ_SEP_FOR_STR_MASK 0x0f80
#define EHT_ML_MLD_CAPA_AAR_SUPP 0x1000
@@ -3156,6 +3158,15 @@
#endif /* (CONFIG_DRIVER_NL80211_BRCM && !WIFI_BRCM_OPEN_SOURCE_MULTI_AKM) ||
* CONFIG_DRIVER_NL80211_SYNA */
+/* Wi-Fi Alliance Capabilities attributes */
+enum wfa_capa_attr_id {
+ WFA_CAPA_ATTR_GENERATIONAL_CAPAB = 1,
+ WFA_CAPA_ATTR_VENDOR_SPECIFIC = 221,
+};
+
+/* Wi-Fi Alliance Capabilities frame */
+#define WFA_CAPAB_VENDOR_TYPE 0x506f9a1b
+
struct ieee80211_neighbor_ap_info {
u8 tbtt_info_hdr;
u8 tbtt_info_len;
diff --git a/src/common/nan_de.c b/src/common/nan_de.c
index acde4f3..2c1d0c4 100644
--- a/src/common/nan_de.c
+++ b/src/common/nan_de.c
@@ -18,14 +18,18 @@
static const u8 nan_network_id[ETH_ALEN] =
{ 0x51, 0x6f, 0x9a, 0x01, 0x00, 0x00 };
-static const u8 wildcard_bssid[ETH_ALEN] =
-{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
enum nan_de_service_type {
NAN_DE_PUBLISH,
NAN_DE_SUBSCRIBE,
};
+static const u8 p2p_network_id[ETH_ALEN] =
+{ 0x51, 0x6f, 0x9a, 0x02, 0x00, 0x00 };
+
+static const u8 wildcard_bssid[ETH_ALEN] =
+{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
struct nan_de_service {
int id;
enum nan_de_service_type type;
@@ -40,11 +44,12 @@
struct os_reltime end_time;
struct os_reltime last_multicast;
struct os_reltime first_discovered;
- struct os_reltime last_followup;
bool needs_fsd;
unsigned int freq;
unsigned int default_freq;
int *freq_list;
+ u8 a3[ETH_ALEN];
+ bool a3_set;
/* pauseState information for Publish function */
struct os_reltime pause_state_end;
@@ -65,6 +70,7 @@
u8 nmi[ETH_ALEN];
bool offload;
bool ap;
+ unsigned int max_listen;
struct nan_callbacks cb;
struct nan_de_service *service[NAN_DE_MAX_SERVICE];
@@ -79,7 +85,20 @@
};
+bool nan_de_is_nan_network_id(const u8 *addr)
+{
+ return ether_addr_equal(addr, nan_network_id);
+}
+
+
+bool nan_de_is_p2p_network_id(const u8 *addr)
+{
+ return ether_addr_equal(addr, p2p_network_id);
+}
+
+
struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap,
+ unsigned int max_listen,
const struct nan_callbacks *cb)
{
struct nan_de *de;
@@ -91,6 +110,7 @@
os_memcpy(de->nmi, nmi, ETH_ALEN);
de->offload = offload;
de->ap = ap;
+ de->max_listen = max_listen ? max_listen : 1000;
os_memcpy(&de->cb, cb, sizeof(*cb));
return de;
@@ -152,6 +172,9 @@
wpa_printf(MSG_DEBUG, "NAN: Start pauseState");
os_get_reltime(&srv->pause_state_end);
srv->pause_state_end.sec += 60;
+ if (os_reltime_initialized(&srv->end_time) &&
+ os_reltime_before(&srv->end_time, &srv->pause_state_end))
+ srv->pause_state_end = srv->end_time;
os_memcpy(srv->sel_peer_addr, peer_addr, ETH_ALEN);
srv->sel_peer_id = peer_id;
}
@@ -206,7 +229,7 @@
static void nan_de_tx_sdf(struct nan_de *de, struct nan_de_service *srv,
unsigned int wait_time,
enum nan_service_control_type type,
- const u8 *dst, u8 req_instance_id,
+ const u8 *dst, const u8 *a3, u8 req_instance_id,
const struct wpabuf *ssi)
{
struct wpabuf *buf;
@@ -268,10 +291,7 @@
wpabuf_put_buf(buf, srv->elems);
}
- /* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD,
- * but there is no synchronization in USD as as such, no NAN Cluster
- * either. Use Wildcard BSSID instead. */
- nan_de_tx(de, srv->freq, wait_time, dst, de->nmi, wildcard_bssid, buf);
+ nan_de_tx(de, srv->freq, wait_time, dst, de->nmi, a3, buf);
wpabuf_free(buf);
}
@@ -335,6 +355,8 @@
{
enum nan_service_control_type type;
unsigned int wait_time = 100;
+ const u8 *network_id;
+ const u8 *bssid;
if (srv->type == NAN_DE_PUBLISH) {
int ms;
@@ -352,7 +374,15 @@
return;
}
- nan_de_tx_sdf(de, srv, wait_time, type, nan_network_id,
+ if (srv->is_p2p) {
+ network_id = p2p_network_id;
+ bssid = wildcard_bssid;
+ } else {
+ network_id = nan_network_id;
+ bssid = nan_network_id;
+ }
+
+ nan_de_tx_sdf(de, srv, wait_time, type, network_id, bssid,
req_instance_id, srv->ssi);
os_get_reltime(&srv->last_multicast);
}
@@ -398,11 +428,6 @@
return false;
if (!srv->publish.fsd)
return true;
- if (os_reltime_initialized(&srv->last_followup) &&
- !os_reltime_expired(now, &srv->last_followup, 1))
- return false;
- if (os_reltime_expired(now, &srv->last_multicast, 1))
- return true;
}
if (srv->type == NAN_DE_SUBSCRIBE) {
@@ -412,11 +437,6 @@
return false;
if (!srv->needs_fsd)
return true;
- if (os_reltime_initialized(&srv->last_followup) &&
- !os_reltime_expired(now, &srv->last_followup, 1))
- return false;
- if (os_reltime_expired(now, &srv->first_discovered, 1))
- return true;
}
return false;
@@ -481,6 +501,16 @@
next = tmp;
}
+ if (srv->type == NAN_DE_PUBLISH &&
+ srv->publish.fsd &&
+ os_reltime_initialized(&srv->pause_state_end)) {
+ os_reltime_sub(&srv->pause_state_end, now, &diff);
+ tmp = os_reltime_in_ms(&diff);
+ if (next == -1 || tmp < next)
+ next = tmp;
+ return next;
+ }
+
tmp = nan_de_next_multicast(de, srv, now);
if (tmp >= 0 && (next == -1 || tmp < next))
next = tmp;
@@ -583,16 +613,37 @@
if (srv->type == NAN_DE_PUBLISH &&
os_reltime_initialized(&srv->pause_state_end) &&
- (os_reltime_before(&srv->pause_state_end, &now) ||
- (srv->publish.fsd &&
- os_reltime_initialized(&srv->last_followup) &&
- os_reltime_expired(&now, &srv->last_followup, 1))))
+ (os_reltime_before(&srv->pause_state_end, &now)))
nan_de_unpause_state(srv);
srv_next = nan_de_srv_time_to_next(de, srv, &now);
if (srv_next >= 0 && (next == -1 || srv_next < next))
next = srv_next;
+ if (srv->type == NAN_DE_PUBLISH &&
+ srv->publish.fsd &&
+ os_reltime_initialized(&srv->pause_state_end) &&
+ de->tx_wait_end_freq == 0 &&
+ de->listen_freq == 0 && de->ext_listen_freq == 0) {
+ struct os_reltime diff;
+ int duration;
+
+ os_reltime_sub(&srv->pause_state_end, &now, &diff);
+ duration = os_reltime_in_ms(&diff);
+ if (duration < 0)
+ continue;
+ if ((unsigned int) duration > de->max_listen)
+ duration = de->max_listen;
+ if (de->cb.listen(de->cb.ctx, srv->freq, duration) ==
+ 0) {
+ wpa_printf(MSG_DEBUG,
+ "NAN: Publisher in pauseState - started listen on %u MHz",
+ srv->freq);
+ de->listen_freq = srv->freq;
+ return;
+ }
+ }
+
if (srv_next == 0 && !started && !de->offload &&
de->listen_freq == 0 && de->ext_listen_freq == 0 &&
de->tx_wait_end_freq == 0 &&
@@ -629,7 +680,7 @@
if (next == 0)
next = 1;
- wpa_printf(MSG_DEBUG, "NAN: Next timer in %u ms", next);
+
eloop_register_timeout(next / 1000, (next % 1000) * 1000, nan_de_timer,
de, NULL);
}
@@ -679,6 +730,10 @@
void nan_de_tx_wait_ended(struct nan_de *de)
{
+ if (de->tx_wait_end_freq)
+ wpa_printf(MSG_DEBUG,
+ "NAN: TX wait for response ended (freq=%u)",
+ de->tx_wait_end_freq);
de->tx_wait_end_freq = 0;
nan_de_run_timer(de);
}
@@ -806,7 +861,7 @@
static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
- const u8 *peer_addr, u8 instance_id,
+ const u8 *peer_addr, const u8 *a3, u8 instance_id,
u8 req_instance_id, u16 sdea_control,
enum nan_service_protocol_type srv_proto_type,
const u8 *ssi, size_t ssi_len)
@@ -877,7 +932,8 @@
static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv,
- const u8 *peer_addr, u8 instance_id,
+ const u8 *peer_addr, const u8 *a3,
+ u8 instance_id,
const u8 *matching_filter,
size_t matching_filter_len,
enum nan_service_protocol_type srv_proto_type,
@@ -887,6 +943,7 @@
size_t len = 0, sda_len, sdea_len;
u8 ctrl = 0;
u16 sdea_ctrl = 0;
+ const u8 *network_id;
/* Publish function processing of a receive Subscribe message */
@@ -963,15 +1020,23 @@
wpabuf_put_buf(buf, srv->elems);
}
- /* Wi-Fi Aware specification v4.0 uses NAN Cluster ID as A3 for USD,
- * but there is no synchronization in USD as as such, no NAN Cluster
- * either. Use Wildcard BSSID instead. */
+ if (srv->is_p2p)
+ network_id = p2p_network_id;
+ else
+ network_id = nan_network_id;
+
+ if (srv->publish.solicited_multicast || !a3)
+ a3 = network_id;
+ else if (srv->is_p2p)
+ a3 = de->nmi;
+
nan_de_tx(de, srv->freq, 100,
- srv->publish.solicited_multicast ? nan_network_id : peer_addr,
- de->nmi, wildcard_bssid, buf);
+ srv->publish.solicited_multicast ? network_id : peer_addr,
+ de->nmi, a3, buf);
wpabuf_free(buf);
- nan_de_pause_state(srv, peer_addr, instance_id);
+ if (!srv->is_p2p)
+ nan_de_pause_state(srv, peer_addr, instance_id);
offload:
if (!srv->publish.disable_events && de->cb.replied)
@@ -981,8 +1046,8 @@
static void nan_de_rx_follow_up(struct nan_de *de, struct nan_de_service *srv,
- const u8 *peer_addr, u8 instance_id,
- const u8 *ssi, size_t ssi_len)
+ const u8 *peer_addr, const u8 *a3,
+ u8 instance_id, const u8 *ssi, size_t ssi_len)
{
/* Follow-up function processing of a receive Follow-up message for a
* Subscribe or Publish instance */
@@ -997,18 +1062,19 @@
return;
}
- os_get_reltime(&srv->last_followup);
-
if (srv->type == NAN_DE_PUBLISH && !ssi)
nan_de_pause_state(srv, peer_addr, instance_id);
+ os_memcpy(srv->a3, a3, ETH_ALEN);
+ srv->a3_set = true;
+
if (de->cb.receive)
de->cb.receive(de->cb.ctx, srv->id, instance_id, ssi, ssi_len,
peer_addr);
}
-static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr,
+static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr, const u8 *a3,
unsigned int freq, const u8 *buf, size_t len,
const u8 *sda, size_t sda_len)
{
@@ -1135,20 +1201,20 @@
switch (type) {
case NAN_SRV_CTRL_PUBLISH:
- nan_de_rx_publish(de, srv, peer_addr, instance_id,
+ nan_de_rx_publish(de, srv, peer_addr, a3, instance_id,
req_instance_id,
sdea_control, srv_proto_type,
ssi, ssi_len);
break;
case NAN_SRV_CTRL_SUBSCRIBE:
- nan_de_rx_subscribe(de, srv, peer_addr, instance_id,
+ nan_de_rx_subscribe(de, srv, peer_addr, a3, instance_id,
matching_filter,
matching_filter_len,
srv_proto_type,
ssi, ssi_len);
break;
case NAN_SRV_CTRL_FOLLOW_UP:
- nan_de_rx_follow_up(de, srv, peer_addr, instance_id,
+ nan_de_rx_follow_up(de, srv, peer_addr, a3, instance_id,
ssi, ssi_len);
break;
}
@@ -1156,8 +1222,8 @@
}
-void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq,
- const u8 *buf, size_t len)
+void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, const u8 *a3,
+ unsigned int freq, const u8 *buf, size_t len)
{
const u8 *sda;
u16 sda_len;
@@ -1179,7 +1245,7 @@
sda++;
sda_len = WPA_GET_LE16(sda);
sda += 2;
- nan_de_rx_sda(de, peer_addr, freq, buf, len, sda, sda_len);
+ nan_de_rx_sda(de, peer_addr, a3, freq, buf, len, sda, sda_len);
}
}
@@ -1442,6 +1508,8 @@
const u8 *peer_addr, u8 req_instance_id)
{
struct nan_de_service *srv;
+ const u8 *a3;
+ const u8 *network_id;
if (handle < 1 || handle > NAN_DE_MAX_SERVICE)
return -1;
@@ -1450,9 +1518,17 @@
if (!srv)
return -1;
- nan_de_tx_sdf(de, srv, 100, NAN_SRV_CTRL_FOLLOW_UP,
- peer_addr, req_instance_id, ssi);
+ if (srv->is_p2p)
+ network_id = p2p_network_id;
+ else
+ network_id = nan_network_id;
- os_get_reltime(&srv->last_followup);
+ if (srv->a3_set)
+ a3 = srv->a3;
+ else
+ a3 = network_id;
+ nan_de_tx_sdf(de, srv, 100, NAN_SRV_CTRL_FOLLOW_UP,
+ peer_addr, a3, req_instance_id, ssi);
+
return 0;
}
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index f369a57..9c1df31 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -59,7 +59,10 @@
unsigned int freq);
};
+bool nan_de_is_nan_network_id(const u8 *addr);
+bool nan_de_is_p2p_network_id(const u8 *addr);
struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap,
+ unsigned int max_listen,
const struct nan_callbacks *cb);
void nan_de_flush(struct nan_de *de);
void nan_de_deinit(struct nan_de *de);
@@ -70,8 +73,8 @@
void nan_de_tx_status(struct nan_de *de, unsigned int freq, const u8 *dst);
void nan_de_tx_wait_ended(struct nan_de *de);
-void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, unsigned int freq,
- const u8 *buf, size_t len);
+void nan_de_rx_sdf(struct nan_de *de, const u8 *peer_addr, const u8 *a3,
+ 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 {
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index ddf1966..6c80589 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1298,6 +1298,33 @@
*
* The attributes used with this command are defined in
* enum qca_wlan_vendor_attr_chan_usage_req.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_FW_SCAN_REPORT: Vendor subcommand that can be
+ * used to fetch the current snapshot of scan data stored by firmware
+ * during the offload scans such as PNO (Preferred Network Offload), RTT,
+ * and roaming scans when the Apps or host is in suspended state. This scan
+ * data comprises of only limited information of the scanned BSSs due to
+ * memory limits of the firmware. The BSS information stored in the
+ * firmware may not be pushed to the kernel (cfg80211) scan cache after
+ * Apps or host coming out from suspended state if full Beacon or Probe
+ * Response frame information is not available.
+ *
+ * The attributes used with this command are defined in
+ * enum qca_wlan_vendor_attr_fw_scan_report.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_IDLE_SHUTDOWN: If there are no active Wi-Fi
+ * interfaces for a certain duration, the host driver might trigger idle
+ * shutdown. The host driver rejects the user space commands between start
+ * and completion of the idle shutdown. If a command is rejected, user
+ * space can use this event to determine when to retry the specific
+ * command.
+ *
+ * This is a wiphy specific vendor event and it indicates user space that
+ * the host driver has reached the idle timer and has started or completed
+ * idle shutdown procedure.
+ *
+ * The attributes used with this event are defined in
+ * enum qca_wlan_vendor_attr_idle_shutdown.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -1534,6 +1561,9 @@
QCA_NL80211_VENDOR_SUBCMD_CONNECT_EXT = 250,
QCA_NL80211_VENDOR_SUBCMD_SET_P2P_MODE = 251,
QCA_NL80211_VENDOR_SUBCMD_CHAN_USAGE_REQ = 252,
+ QCA_NL80211_VENDOR_SUBCMD_GET_FW_SCAN_REPORT = 253,
+ QCA_NL80211_VENDOR_SUBCMD_IDLE_SHUTDOWN = 254,
+ /* 255 - reserved for QCA */
};
/* Compatibility defines for previously used subcmd names.
@@ -2015,7 +2045,9 @@
*
* @QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST: Required and type is NLA_UNSPEC.
* Used with command to configure channel list using an array of
- * channel numbers (u8).
+ * channel numbers (u8). This represents the list of allowed channels for
+ * the primary and non-primary channel operation. Channels which are not present
+ * in the specified list shouldn't be used as a primary or non-primary channel.
* Note: If both the driver and user-space application supports the 6 GHz band,
* the driver mandates use of QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST whereas
* QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is optional.
@@ -2047,7 +2079,10 @@
*
* @QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST: Required and type is NLA_UNSPEC.
* Used with command to configure the channel list using an array of channel
- * center frequencies in MHz (u32).
+ * center frequencies in MHz (u32). This represents the list of allowed
+ * frequencies for the primary and non-primary channel operation. Frequencies
+ * which are not present in the specified list shouldn't be used as a primary or
+ * non-primary channel.
* Note: If both the driver and user-space application supports the 6 GHz band,
* the driver first parses the frequency list and if it fails to get a frequency
* list, parses the channel list specified using
@@ -2110,6 +2145,15 @@
* Used with command to configure ACS operation for a specific link affiliated
* to an AP MLD.
*
+ * @QCA_WLAN_VENDOR_ATTR_ACS_EXCLUDE_6GHZ_NON_PSC_PRIMARY: Optional flag
+ * attribute. Used with command to indicate whether the driver is allowed to use
+ * a 6 GHz non-PSC channel as a primary channel. If this flag is indicated the
+ * driver shall not use 6 GHz non-PSC channels as a primary channel even if
+ * %QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST includes 6 GHz non-PSC channels.
+ * However, the driver is still allowed to use 6 GHz non-PSC channels specified
+ * in %QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST as non-primary channels. User space is
+ * allowed to specify this flag only when the driver indicates support for
+ * %QCA_WLAN_VENDOR_FEATURE_ACS_PREFER_6GHZ_PSC.
*/
enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
@@ -2134,6 +2178,7 @@
QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED = 19,
QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME = 20,
QCA_WLAN_VENDOR_ATTR_ACS_LINK_ID = 21,
+ QCA_WLAN_VENDOR_ATTR_ACS_EXCLUDE_6GHZ_NON_PSC_PRIMARY = 22,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
@@ -2271,6 +2316,10 @@
* @QCA_WLAN_VENDOR_FEATURE_NAN_USD_OFFLOAD: Flag indicates that the driver
* supports Unsynchronized Service Discovery to be offloaded to it.
*
+ * @QCA_WLAN_VENDOR_FEATURE_ACS_PREFER_6GHZ_PSC: Flag indicates that the driver
+ * supports preferring 6 GHz PSC channel as a primary channel in ACS
+ * result.
+ *
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
@@ -2301,6 +2350,7 @@
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,
+ QCA_WLAN_VENDOR_FEATURE_ACS_PREFER_6GHZ_PSC = 27,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -3754,6 +3804,51 @@
*/
QCA_WLAN_VENDOR_ATTR_CONFIG_P2P_GO_BEACON_INTERVAL = 122,
+ /* 8-bit unsigned value. Disable DFS owner capability
+ * 1: disable DFS owner capability in the driver.
+ * 0: reset DFS owner capability to the default DFS owner capability of
+ * the driver.
+ *
+ * If DFS owner capability is disabled, the driver will not start AP
+ * mode operations on DFS channels, and all the features depending on
+ * DFS owner functionality will not be supported.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_DFS_OWNER_DISABLE = 123,
+
+ /* 16-bit unsigned value. For probing RSSI on other antennas, this
+ * attribute specifies the number of WLAN probes.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_COUNT_WLAN = 124,
+
+ /* 16-bit unsigned value. For probing RSSI on other antennas, this
+ * attribute specifies the number of BT probes.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_COUNT_BT = 125,
+
+ /* 16-bit unsigned value. This attribute specifies the WLAN RSSI
+ * threshold. The firmware will start to probe RSSI on other antenna
+ * if WLAN RSSI is lower than the threshold.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_WLAN_RSSI_THRESHOLD = 126,
+
+ /* 16-bit unsigned value. This attribute specifies the BT RSSI
+ * threshold. The firmware will start to probe RSSI on other antenna
+ * if BT RSSI is lower than the threshold.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_BT_RSSI_THRESHOLD = 127,
+
+ /* 16-bit unsigned value. This attribute specifies the WLAN RSSI
+ * difference. The firmware will select a better antenna if WLAN RSSI
+ * difference is larger than the value.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SWITCH_WLAN_RSSI_DIFF = 128,
+
+ /* 16-bit unsigned value. This attribute specifies the BT RSSI
+ * difference. The firmware will select a better antenna if WLAN RSSI
+ * difference larger than the value.
+ */
+ QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SWITCH_BT_RSSI_DIFF = 129,
+
/* keep last */
QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
@@ -10783,6 +10878,42 @@
};
/**
+ * enum qca_wlan_twt_session_suspendable: The values used with
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_SUSPENDABLE.
+ *
+ * @QCA_WLAN_TWT_SESSION_NOT_SUSPENDABLE: TWT session cannot be suspended.
+ * @QCA_WLAN_TWT_SESSION_SUSPENDABLE: TWT session can be suspended.
+ */
+enum qca_wlan_twt_session_suspendable {
+ QCA_WLAN_TWT_SESSION_NOT_SUSPENDABLE = 0,
+ QCA_WLAN_TWT_SESSION_SUSPENDABLE = 1,
+};
+
+/**
+ * enum qca_wlan_twt_session_updatable: Define the values used with
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_UPDATABLE.
+ *
+ * @QCA_WLAN_TWT_SESSION_NOT_UPDATABLE: TWT session cannot be updated.
+ * @QCA_WLAN_TWT_SESSION_UPDATABLE: TWT session can be updated.
+ */
+enum qca_wlan_twt_session_updatable {
+ QCA_WLAN_TWT_SESSION_NOT_UPDATABLE = 0,
+ QCA_WLAN_TWT_SESSION_UPDATABLE = 1,
+};
+
+/**
+ * enum qca_wlan_twt_session_implicit: Define the values used with
+ * %QCA_WLAN_VENDOR_ATTR_TWT_SETUP_IMPLICIT.
+ *
+ * @QCA_WLAN_TWT_SESSION_NOT_IMPLICIT: TWT session cannot be implicit.
+ * @QCA_WLAN_TWT_SESSION_IMPLICIT: TWT session can be implicit.
+ */
+enum qca_wlan_twt_session_implicit {
+ QCA_WLAN_TWT_SESSION_NOT_IMPLICIT = 0,
+ QCA_WLAN_TWT_SESSION_IMPLICIT = 1,
+};
+
+/**
* enum qca_wlan_vendor_attr_twt_setup: Represents attributes for
* TWT (Target Wake Time) setup request. These attributes are sent as part of
* %QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP and
@@ -10974,9 +11105,10 @@
* The Broadcast TWT Recommendation subfield contains a value that indicates
* recommendations on the types of frames that are transmitted by TWT
* scheduled STAs and scheduling AP during the broadcast TWT SP.
- * The allowed values are 0 - 3.
+ * The allowed values are 0 - 4.
* This parameter is used for
* 1. TWT SET Request
+ * 2. R-TWT SET Request
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE: Optional (u8)
* This attribute is used to configure Broadcast TWT Persistence.
@@ -11011,6 +11143,38 @@
*
* @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PAD: Attribute used for padding for 64-bit
* alignment.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_SUSPENDABLE: Optional (u8)
+ * This attribute indicates whether the TWT session being negotiated can be
+ * suspended.
+ * Refers the enum qca_wlan_twt_session_suspendable.
+ * This parameter is used for
+ * 1. TWT SET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RTWT_DOWNLINK_TID_BITMAP: Optional (u32)
+ * This attribute is used to configure downlink TIDs for R-TWT scheduling.
+ * This attribute only applicable when requesting R-TWT schedules.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RTWT_UPLINK_TID_BITMAP: Optional (u32)
+ * This attribute is used to configure uplink TIDs for R-TWT scheduling.
+ * This attribute only applicable when requesting R-TWT schedules.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_UPDATABLE: Optional (u8)
+ * This attribute indicates whether the parameters of the TWT session being
+ * negotiated (like wake interval, wake duration, etc.) can be updated after
+ * session setup.
+ * Refers the enum qca_wlan_twt_session_updatable.
+ * This parameter is used for
+ * 1. TWT SET Response
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_SETUP_IMPLICIT: Optional (u8)
+ * This attribute indicates whether the TWT session being negotiated is
+ * an implicit TWT, where the requesting STA calculates the start time of the
+ * next TWT service period, or an explicit TWT, where the responding STA
+ * calculates the start time of the next TWT service period.
+ * Refers the enum qca_wlan_twt_session_implicit.
+ * This parameter is used for
+ * 1. TWT SET Response
*/
enum qca_wlan_vendor_attr_twt_setup {
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_INVALID = 0,
@@ -11048,6 +11212,11 @@
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT = 26,
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PAD = 27,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_SUSPENDABLE = 28,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RTWT_DOWNLINK_TID_BITMAP = 29,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RTWT_UPLINK_TID_BITMAP = 30,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_UPDATABLE = 31,
+ QCA_WLAN_VENDOR_ATTR_TWT_SETUP_IMPLICIT = 32,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_SETUP_AFTER_LAST,
@@ -11103,6 +11272,16 @@
* required bit in its capabilities.
* @QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED: The peer has cleared
* the TWT required bit(1->0) in its capabilities.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_MULTIPLE_LINKS_ACTIVE_TERMINATE: FW terminated
+ * the TWT session due to more than one MLO link becoming active. Used on the
+ * TWT_TERMINATE notification from the driver/firmware.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_TWT_ALREADY_RESUMED: TWT session already in
+ * resumed state. Used on the TWT_RESUME notification from the driver/firmware.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_PEER_REJECTED: Requested TWT operation is
+ * rejected by the peer. Used on the TWT_SET notification from the
+ * driver/firmware.
+ * @QCA_WLAN_VENDOR_TWT_STATUS_TIMEOUT: Requested TWT operation has timed out.
+ * Used on the TWT_SET, TWT_TERMINATE notification from the driver/firmware.
*/
enum qca_wlan_vendor_twt_status {
QCA_WLAN_VENDOR_TWT_STATUS_OK = 0,
@@ -11130,6 +11309,10 @@
QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE = 22,
QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED = 23,
QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED = 24,
+ QCA_WLAN_VENDOR_TWT_STATUS_MULTIPLE_LINKS_ACTIVE_TERMINATE = 25,
+ QCA_WLAN_VENDOR_TWT_STATUS_TWT_ALREADY_RESUMED = 26,
+ QCA_WLAN_VENDOR_TWT_STATUS_PEER_REJECTED = 27,
+ QCA_WLAN_VENDOR_TWT_STATUS_TIMEOUT = 28,
};
/**
@@ -11312,6 +11495,16 @@
* Status of the TWT GET STATISTICS request.
* This contains status values in enum qca_wlan_vendor_twt_status
* Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_EOSP_DUR_US: Optional (u32)
+ * Average of duration of the early terminated TWT service periods
+ * in micro seconds.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_STATS_EOSP_COUNT: Optional (u32)
+ * Number of early terminated TWT service periods observed over
+ * QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS.
+ * Obtained in the QCA_WLAN_TWT_GET_STATS response from the firmware.
*/
enum qca_wlan_vendor_attr_twt_stats {
QCA_WLAN_VENDOR_ATTR_TWT_STATS_INVALID = 0,
@@ -11327,6 +11520,8 @@
QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE = 10,
QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE = 11,
QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS = 12,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_EOSP_DUR_US = 13,
+ QCA_WLAN_VENDOR_ATTR_TWT_STATS_EOSP_COUNT = 14,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_STATS_AFTER_LAST,
@@ -11384,12 +11579,28 @@
* @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER: (u16).
* Peer TWT capabilities. Carries a bitmap of TWT capabilities specified in
* enum qca_wlan_twt_capa.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MIN_WAKE_INTVL: (u32).
+ * Minimum tolerance limit of wake interval parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAX_WAKE_INTVL: (u32).
+ * Maximum tolerance limit of wake interval parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MIN_WAKE_DURATION: (u32).
+ * Minimum tolerance limit of wake duration parameter in microseconds.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAX_WAKE_DURATION: (u32).
+ * Maximum tolerance limit of wake duration parameter in microseconds.
*/
enum qca_wlan_vendor_attr_twt_capability {
QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAC_ADDR = 1,
QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF = 2,
QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER = 3,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MIN_WAKE_INTVL = 4,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAX_WAKE_INTVL = 5,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MIN_WAKE_DURATION = 6,
+ QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_MAX_WAKE_DURATION = 7,
/* keep last */
QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_AFTER_LAST,
@@ -11458,11 +11669,31 @@
* which the STA may accept.
* @QCA_WLAN_VENDOR_TWT_SETUP_DEMAND: STA is not willing to accept any
* alternate parameters than the requested ones.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_TWT_GROUPING: TWT responding STA suggests TWT
+ * group parameters that are different from the suggested or demanded TWT
+ * parameters of the TWT requesting STA.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_ACCEPT_TWT: TWT responding STA or TWT scheduling
+ * AP accepts the TWT request with the TWT parameters indicated in the TWT
+ * element transmitted by the TWT requesting STA or TWT scheduled STA.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_ALTERNATE_TWT: TWT responding STA or TWT
+ * scheduling AP suggests TWT parameters that are different from those suggested
+ * by the TWT requesting STA or TWT scheduled STA.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_DICTATE_TWT: TWT responding STA or TWT scheduling
+ * dictates TWT parameters that are different from those suggested by the
+ * TWT requesting STA or TWT scheduled STA.
+ * @QCA_WLAN_VENDOR_TWT_SETUP_REJECT_TWT: A TWT responding STA or TWT scheduling
+ * AP rejects setup or terminates an existing broadcast TWT, or a TWT scheduled
+ * STA terminates its membership in a broadcast TWT.
*/
enum qca_wlan_vendor_twt_setup_req_type {
QCA_WLAN_VENDOR_TWT_SETUP_REQUEST = 1,
QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST = 2,
QCA_WLAN_VENDOR_TWT_SETUP_DEMAND = 3,
+ QCA_WLAN_VENDOR_TWT_SETUP_TWT_GROUPING = 4,
+ QCA_WLAN_VENDOR_TWT_SETUP_ACCEPT_TWT = 5,
+ QCA_WLAN_VENDOR_TWT_SETUP_ALTERNATE_TWT = 6,
+ QCA_WLAN_VENDOR_TWT_SETUP_DICTATE_TWT = 7,
+ QCA_WLAN_VENDOR_TWT_SETUP_REJECT_TWT = 8,
};
/**
@@ -14496,6 +14727,22 @@
QCA_WLAN_VENDOR_MONITOR_CTRL_TRIGGER_FRAME = BIT(1),
};
+/*
+ * enum qca_wlan_vendor_monitor_operating_type: Attributes used by vendor
+ * attribute %QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_OPERATING_TYPE
+ *
+ * @QCA_WLAN_VENDOR_MONITOR_OPERATING_TYPE_LPC: Local packet capture.
+ * Capture frames sent and received by the current client interface from the
+ * BSS.
+ *
+ * @QCA_WLAN_VENDOR_MONITOR_OPERATING_TYPE_OCC: Operating channel capture.
+ * Capture all frames on the current operating channel of client interface.
+ */
+enum qca_wlan_vendor_monitor_operating_type {
+ QCA_WLAN_VENDOR_MONITOR_OPERATING_TYPE_LPC = 0,
+ QCA_WLAN_VENDOR_MONITOR_OPERATING_TYPE_OCC = 1,
+};
+
/**
* enum qca_wlan_vendor_attr_set_monitor_mode - Used by the
* vendor command QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE to set the
@@ -14532,6 +14779,12 @@
* Represents the interval in milliseconds only for the connected Beacon frames,
* expecting the connected BSS's Beacon frames to be sent on the monitor
* interface at this specific interval.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_OPERATING_TYPE: u32 attribute.
+ * Represents the monitor operating type (u32). These operating types are
+ * defined in enum qca_wlan_vendor_monitor_operating_type.
+ * If this attribute is not included, default operating type LPC ("local
+ * packet capture") used.
*/
enum qca_wlan_vendor_attr_set_monitor_mode {
QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_INVALID = 0,
@@ -14542,6 +14795,7 @@
QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE = 5,
QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE = 6,
QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL = 7,
+ QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_OPERATING_TYPE = 8,
/* keep last */
QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_AFTER_LAST,
@@ -18380,4 +18634,161 @@
QCA_WLAN_VENDOR_ATTR_CHAN_USAGE_REQ_AFTER_LAST - 1,
};
+/**
+ * enum qca_wlan_fw_scan_bss_flags - Flags for
+ * %QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_FLAGS
+ *
+ * @QCA_WLAN_FW_SCAN_BSS_HT_OPS: This indicates HT Operation element
+ * (IEEE Std 802.11-2020, 9.4.2.56) is present in the Beacon or Probe Response
+ * frame of the BSS.
+ *
+ * @QCA_WLAN_FW_SCAN_BSS_VHT_OPS: This indicates VHT Operation element
+ * (IEEE Std 802.11-2020, 9.4.2.158) is present in the Beacon or Probe Response
+ * frame of the BSS.
+ *
+ * @QCA_WLAN_FW_SCAN_BSS_HE_OPS: This indicates HE Operation element
+ * (IEEE Std 802.11ax-2021, 9.4.2.249) is present in the Beacon or Probe
+ * Response frame of the BSS.
+ *
+ * @QCA_WLAN_FW_SCAN_BSS_EHT_OPS: This indicates EHT Operation element
+ * (IEEE P802.11be/D7.0, 9.4.2.321) is present in the Beacon or Probe Response
+ * frame of the BSS.
+ *
+ * @QCA_WLAN_FW_SCAN_BSS_FTM_RESPONDER: This indicates Fine Timing Measurement
+ * Responder bit is set to 1 in the Extended Capabilities field of the Extended
+ * Capabilities element (IEEE Std 802.11-2020, 9.4.2.26) in the Beacon or Probe
+ * Response frame of the BSS.
+ *
+ * @NUM_QCA_WLAN_FW_SCAN_BSS_FLAGS: Number of assigned feature bits.
+ */
+enum qca_wlan_fw_scan_bss_flags {
+ QCA_WLAN_FW_SCAN_BSS_HT_OPS = 0,
+ QCA_WLAN_FW_SCAN_BSS_VHT_OPS = 1,
+ QCA_WLAN_FW_SCAN_BSS_HE_OPS = 2,
+ QCA_WLAN_FW_SCAN_BSS_EHT_OPS = 3,
+ QCA_WLAN_FW_SCAN_BSS_FTM_RESPONDER = 4,
+
+ NUM_QCA_WLAN_FW_SCAN_BSS_FLAGS /* keep last */
+};
+
+/* enum qca_wlan_vendor_attr_fw_scan_bss: Attributes used inside
+ * %QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_BSS_LIST nested attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_MS_AGO: Required (u32). Indicates how many
+ * milliseconds ago from %QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_TIMESTAMP this BSS
+ * was last scanned (i.e., Beacon or Probe Response frame received).
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_BSSID: Required (6-byte MAC address). BSSID
+ * of the BSS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_SSID: Required (binary attribute,
+ * 0..32 octets). SSID of the BSS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_RSSI: Required (s8). RSSI of the last
+ * received Beacon or Probe Response frame.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_CAPABILITY: Required (CPU byte order, u16).
+ * The Capability Information field from the last received Beacon or Probe
+ * Response frame.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_FLAGS: BSS capability flags contained in a
+ * byte array. The flags are identified by their bit index (see &enum
+ * qca_wlan_fw_scan_bss_flags) with the first byte being the least significant
+ * one and the last one being the most significant one. This information will be
+ * populated from the last received Beacon or Probe Response frame. This is a
+ * mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_PRIMARY_FREQ: Required (u32). Indicates
+ * primary 20 MHz channel center frequency in MHz of the BSS.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_CHAN_WIDTH: Required (u8). Indicates
+ * channel width of the BSS. This uses values defined in
+ * enum nl80211_chan_width.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_CENTER_FREQ1: Required (u32). Indicates the
+ * center frequency (MHz) of the first segment.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_CENTER_FREQ2: Optional (u32). Indicates the
+ * center frequency (MHz) of the second segment. Used only for
+ * %NL80211_CHAN_WIDTH_80P80 value in
+ * %QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_CHAN_WIDTH.
+ */
+enum qca_wlan_vendor_attr_fw_scan_bss {
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_MS_AGO = 1,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_BSSID = 2,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_SSID = 3,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_RSSI = 4,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_CAPABILITY = 5,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_FLAGS = 6,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_PRIMARY_FREQ = 7,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_CHAN_WIDTH = 8,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_CENTER_FREQ1 = 9,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_CENTER_FREQ2 = 10,
+
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_MAX =
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_BSS_AFTER_LAST - 1,
+};
+
+/* enum qca_wlan_vendor_attr_fw_scan_report: Attributes used by vendor command
+ * %QCA_NL80211_VENDOR_SUBCMD_GET_FW_SCAN_REPORT.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_TIMESTAMP: 64-bit unsigned value to
+ * indicate the timestamp when this report is generated, timestamp in
+ * microseconds from system boot. A mandatory attribute.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_FREQ_LIST: Nested attribute of u32
+ * attributes. This indicates the list of frequencies that were scanned. This is
+ * an optional attribute. If this is not specified, all frequencies allowed in
+ * the current regulatory domain were scanned.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_BSS_LIST: Nested attribute.
+ * This indicates information of the scanned BSSs by the firmware. This is an
+ * optional attribute.
+ *
+ * The attributes defined in enum qca_wlan_vendor_attr_fw_scan_bss are nested
+ * in this attribute.
+ */
+enum qca_wlan_vendor_attr_fw_scan_report {
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_TIMESTAMP = 1,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_FREQ_LIST = 2,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_BSS_LIST = 3,
+
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_MAX =
+ QCA_WLAN_VENDOR_ATTR_FW_SCAN_REPORT_AFTER_LAST - 1,
+};
+
+/*
+ * enum qca_wlan_idle_shutdown_status: Represents idle shutdown status.
+ *
+ * @QCA_WLAN_IDLE_SHUTDOWN_STARTED: Indicates idle shutdown is started in the
+ * host driver.
+ * @QCA_WLAN_IDLE_SHUTDOWN_COMPLETED: Indicates idle shutdown is completed in
+ * the host driver.
+ */
+enum qca_wlan_idle_shutdown_status {
+ QCA_WLAN_IDLE_SHUTDOWN_STARTED = 0,
+ QCA_WLAN_IDLE_SHUTDOWN_COMPLETED = 1,
+};
+
+/*
+ * enum qca_wlan_vendor_attr_idle_shutdown: Attributes used by vendor event
+ * %QCA_NL80211_VENDOR_SUBCMD_IDLE_SHUTDOWN.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_IDLE_SHUTDOWN_STATUS: Required u8 attribute. Indicates
+ * the status of the idle shutdown from one of the values in enum
+ * qca_wlan_idle_shutdown_status.
+ */
+enum qca_wlan_vendor_attr_idle_shutdown {
+ QCA_WLAN_VENDOR_ATTR_IDLE_SHUTDOWN_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_IDLE_SHUTDOWN_STATUS = 1,
+
+ QCA_WLAN_VENDOR_ATTR_IDLE_SHUTDOWN_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_IDLE_SHUTDOWN_MAX =
+ QCA_WLAN_VENDOR_ATTR_IDLE_SHUTDOWN_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index a65da61..ce282db 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -114,6 +114,7 @@
wpabuf_free(tmp->own_rejected_groups);
wpabuf_free(tmp->peer_rejected_groups);
os_free(tmp->pw_id);
+ os_free(tmp->parsed_pw_id);
bin_clear_free(tmp, sizeof(*tmp));
sae->tmp = NULL;
}
@@ -121,12 +122,16 @@
void sae_clear_data(struct sae_data *sae)
{
+ unsigned int no_pw_id;
+
if (sae == NULL)
return;
sae_clear_temp_data(sae);
crypto_bignum_deinit(sae->peer_commit_scalar, 0);
crypto_bignum_deinit(sae->peer_commit_scalar_accepted, 0);
+ no_pw_id = sae->no_pw_id;
os_memset(sae, 0, sizeof(*sae));
+ sae->no_pw_id = no_pw_id;
}
@@ -1093,12 +1098,13 @@
}
-struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+struct sae_pt * sae_derive_pt(const int *groups,
+ const u8 *ssid, size_t ssid_len,
const u8 *password, size_t password_len,
const char *identifier)
{
struct sae_pt *pt = NULL, *last = NULL, *tmp;
- int default_groups[] = { 19, 0 };
+ const int default_groups[] = { 19, 0 };
int i;
if (!groups)
@@ -1877,8 +1883,6 @@
const u8 *pos, const u8 *end,
const u8 **token, size_t *token_len)
{
- wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
- pos, end - pos);
if (!sae_is_token_container_elem(pos, end))
return;
*token = pos + 3;
@@ -2045,14 +2049,12 @@
}
-static int sae_parse_password_identifier(struct sae_data *sae,
+static int sae_parse_password_identifier(struct sae_data *sae, bool h2e,
const u8 **pos, const u8 *end)
{
const u8 *epos;
u8 len;
- wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
- *pos, end - *pos);
if (!sae_is_password_id_elem(*pos, end)) {
if (sae->tmp->pw_id) {
wpa_printf(MSG_DEBUG,
@@ -2060,8 +2062,8 @@
sae->tmp->pw_id);
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
}
- os_free(sae->tmp->pw_id);
- sae->tmp->pw_id = NULL;
+ os_free(sae->tmp->parsed_pw_id);
+ sae->tmp->parsed_pw_id = NULL;
return WLAN_STATUS_SUCCESS; /* No Password Identifier */
}
@@ -2073,6 +2075,18 @@
epos++; /* skip ext ID */
len--;
+ if (!h2e) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Password Identifier included, but H2E is not used");
+ return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
+ }
+
+ if (sae->no_pw_id) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Password Identifier included, but none has been enabled");
+ return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
+ }
+
if (sae->tmp->pw_id &&
(len != os_strlen(sae->tmp->pw_id) ||
os_memcmp(sae->tmp->pw_id, epos, len) != 0)) {
@@ -2082,14 +2096,14 @@
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
}
- os_free(sae->tmp->pw_id);
- sae->tmp->pw_id = os_malloc(len + 1);
- if (!sae->tmp->pw_id)
+ os_free(sae->tmp->parsed_pw_id);
+ sae->tmp->parsed_pw_id = os_malloc(len + 1);
+ if (!sae->tmp->parsed_pw_id)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- os_memcpy(sae->tmp->pw_id, epos, len);
- sae->tmp->pw_id[len] = '\0';
+ os_memcpy(sae->tmp->parsed_pw_id, epos, len);
+ sae->tmp->parsed_pw_id[len] = '\0';
wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
- sae->tmp->pw_id, len);
+ sae->tmp->parsed_pw_id, len);
*pos = epos + len;
return WLAN_STATUS_SUCCESS;
}
@@ -2101,8 +2115,6 @@
const u8 *epos;
u8 len;
- wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
- *pos, end - *pos);
if (!sae_is_rejected_groups_elem(*pos, end)) {
wpabuf_free(sae->tmp->peer_rejected_groups);
sae->tmp->peer_rejected_groups = NULL;
@@ -2141,8 +2153,6 @@
const u8 *epos;
u8 len;
- wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
- *pos, end - *pos);
if (!sae_is_akm_suite_selector_elem(*pos, end))
return WLAN_STATUS_SUCCESS;
@@ -2195,8 +2205,13 @@
if (ie_offset)
*ie_offset = pos - data;
+ if (end > pos)
+ wpa_hexdump(MSG_DEBUG,
+ "SAE: Possible elements at the end of the frame",
+ pos, end - pos);
+
/* Optional Password Identifier element */
- res = sae_parse_password_identifier(sae, &pos, end);
+ res = sae_parse_password_identifier(sae, h2e, &pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
diff --git a/src/common/sae.h b/src/common/sae.h
index a353aa8..8f74353 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -59,6 +59,7 @@
struct crypto_bignum *order_buf;
struct wpabuf *anti_clogging_token;
char *pw_id;
+ char *parsed_pw_id;
int vlan_id;
u8 bssid[ETH_ALEN];
struct wpabuf *own_rejected_groups;
@@ -120,6 +121,7 @@
u16 rc; /* protocol instance variable: Rc (received send-confirm) */
unsigned int h2e:1;
unsigned int pk:1;
+ unsigned int no_pw_id:1;
struct sae_temporary_data *tmp;
};
@@ -146,7 +148,8 @@
const char * sae_state_txt(enum sae_state state);
size_t sae_ecc_prime_len_2_hash_len(size_t prime_len);
size_t sae_ffc_prime_len_2_hash_len(size_t prime_len);
-struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+struct sae_pt * sae_derive_pt(const int *groups,
+ const u8 *ssid, size_t ssid_len,
const u8 *password, size_t password_len,
const char *identifier);
struct crypto_ec_point *
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index a8c7c41..9c96269 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -582,6 +582,7 @@
ptk->kek2_len = 0;
ptk->kck2_len = 0;
+ ptk->ptk_len = ptk_len;
os_memset(tmp, 0, sizeof(tmp));
os_memset(data, 0, data_len);
return 0;
@@ -1560,6 +1561,7 @@
ptk->kdk, ptk->kdk_len);
}
+ ptk->ptk_len = ptk_len;
forced_memzero(tmp, sizeof(tmp));
ret = 0;
err:
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index e608d3c..9f1a539 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -268,6 +268,7 @@
size_t kck2_len;
size_t kek2_len;
size_t kdk_len;
+ size_t ptk_len;
size_t ltf_keyseed_len;
int installed; /* 1 if key has already been installed to driver */
};
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 2ea8ab3..40628e8 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -456,6 +456,11 @@
/* Event triggered for received management frame */
#define AP_MGMT_FRAME_RECEIVED "AP-MGMT-FRAME-RECEIVED "
+/* Event triggerred on AP receiving Wi-Fi Alliance Generational Capabilities
+ * indication.
+ * Parameters: <STA addr> <Generational Capabilities Indication body> */
+#define WFA_GEN_CAPAB_RX "WFA-GEN-CAPAB "
+
#ifndef BIT
#define BIT(x) (1U << (x))
#endif
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 765ea59..9ce5ec0 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -892,6 +892,14 @@
bool eht_enabled;
/**
+ * punct_bitmap - Preamble puncturing bitmap
+ * Each bit corresponds to a 20 MHz subchannel, the lowest bit for the
+ * channel with the lowest frequency. A bit set to 1 indicates that the
+ * subchannel is punctured, otherwise active.
+ */
+ u16 punct_bitmap;
+
+ /**
* link_id: If >=0 indicates the link of the AP MLD to configure
*/
int link_id;
@@ -2492,6 +2500,10 @@
unsigned int mbssid_max_interfaces;
/* Maximum profile periodicity for enhanced MBSSID advertisement */
unsigned int ema_max_periodicity;
+
+ /* Maximum number of bytes of extra IE(s) that can be added to Probe
+ * Request frames */
+ size_t max_probe_req_ie_len;
};
@@ -2598,6 +2610,7 @@
bool mld_link_sta;
s8 mld_link_id;
const u8 *mld_link_addr;
+ u16 eml_cap;
};
struct mac_address {
@@ -2772,7 +2785,6 @@
* @beacon_after: Next beacon/probe resp/asooc resp info
* @counter_offset_beacon: Offset to the count field in beacon's tail
* @counter_offset_presp: Offset to the count field in probe resp.
- * @punct_bitmap - Preamble puncturing bitmap
* @link_id: Link ID to determine the link for MLD; -1 for non-MLD
* @ubpr: Unsolicited broadcast Probe Response frame data
*/
@@ -2787,7 +2799,6 @@
u16 counter_offset_beacon[2];
u16 counter_offset_presp[2];
- u16 punct_bitmap;
int link_id;
struct unsol_bcast_probe_resp ubpr;
@@ -3503,12 +3514,15 @@
* e.g., wpa_supplicant_event()
* @ifname: interface name, e.g., wlan0
* @global_priv: private driver global data from global_init()
+ * @p2p_mode: P2P mode for a GO (not applicable for other interface
+ * types)
* Returns: Pointer to private data, %NULL on failure
*
* This function can be used instead of init() if the driver wrapper
* uses global data.
*/
- void * (*init2)(void *ctx, const char *ifname, void *global_priv);
+ void * (*init2)(void *ctx, const char *ifname, void *global_priv,
+ enum wpa_p2p_mode p2p_mode);
/**
* get_interfaces - Get information about available interfaces
@@ -4044,7 +4058,10 @@
* @bssid: BSSID (Address 3)
* @data: Frame body
* @data_len: data length in octets
- @ @no_cck: Whether CCK rates must not be used to transmit this frame
+ * @no_cck: Whether CCK rates must not be used to transmit this frame
+ * @link_id: Link ID of the specified link; -1 for non-MLO cases and for
+ * frames that target the MLD instead of a specific link in MLO
+ * cases
* Returns: 0 on success, -1 on failure
*
* This command can be used to request the driver to transmit an action
@@ -4065,7 +4082,8 @@
*/
int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
const u8 *dst, const u8 *src, const u8 *bssid,
- const u8 *data, size_t data_len, int no_cck);
+ const u8 *data, size_t data_len, int no_cck,
+ int link_id);
/**
* send_action_cancel_wait - Cancel action frame TX wait
@@ -5333,6 +5351,25 @@
*/
int (*nan_cancel_subscribe)(void *priv, int subscribe_id);
+ /**
+ * can_share_drv - Check whether driver interface can be shared
+ * @ctx: Pointer to hostapd context
+ * @params: Configuration for the driver wrapper
+ * @hapd: Pointer for overwriting the hapd context or %NULL
+ * if can't find a shared drv
+ *
+ * Checks whether the driver interface with same phy name is
+ * already present under the global driver which can be shared
+ * instead of creating a new driver interface instance. If present,
+ * @hapd will be overwritten with the hapd pointer which this shared
+ * drv's first BSS is using. This will help the caller to later call
+ * if_add().
+ *
+ * Returns: true if it can be shared or else false.
+ */
+ bool (*can_share_drv)(void *ctx, struct wpa_init_params *params,
+ void **hapd);
+
#ifdef CONFIG_TESTING_OPTIONS
int (*register_frame)(void *priv, u16 type,
const u8 *match, size_t match_len,
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 82d8a01..0979fc5 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -998,7 +998,8 @@
}
static void *
-bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params)
+bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params,
+ enum wpa_p2p_mode p2p_mode)
{
struct bsd_driver_data *drv;
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5890ac6..95e678f 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -167,7 +167,8 @@
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
const u8 *set_addr, int first,
- const char *driver_params);
+ const char *driver_params,
+ enum wpa_p2p_mode p2p_mode);
static int nl80211_send_frame_cmd(struct i802_bss *bss,
unsigned int freq, unsigned int wait,
const u8 *buf, size_t buf_len,
@@ -351,6 +352,7 @@
int err;
struct nl_msg *orig_msg;
struct nl80211_err_info *err_info;
+ struct wpa_driver_nl80211_data *drv;
};
static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
@@ -387,8 +389,12 @@
if (tb[NLMSGERR_ATTR_MSG]) {
len = strnlen((char *) nla_data(tb[NLMSGERR_ATTR_MSG]),
nla_len(tb[NLMSGERR_ATTR_MSG]));
- wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
- len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
+ if (err_args->drv)
+ wpa_msg(err_args->drv->ctx, MSG_ERROR, "nl80211: kernel reports: %*s",
+ len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
+ else
+ wpa_printf(MSG_ERROR, "nl80211: kernel reports: %*s",
+ len, (char *) nla_data(tb[NLMSGERR_ATTR_MSG]));
}
if (!err_args->err_info)
@@ -493,13 +499,14 @@
}
-int send_and_recv(struct nl80211_global *global,
- struct nl_sock *nl_handle, struct nl_msg *msg,
- int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data,
- int (*ack_handler_custom)(struct nl_msg *, void *),
- void *ack_data,
- struct nl80211_err_info *err_info)
+int send_and_recv_glb(struct nl80211_global *global,
+ struct wpa_driver_nl80211_data *drv, /* may be NULL */
+ struct nl_sock *nl_handle, struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data,
+ struct nl80211_err_info *err_info)
{
struct nl_cb *cb, *s_nl_cb;
struct nl80211_ack_err_args err;
@@ -541,6 +548,7 @@
err.err = 1;
err.orig_msg = msg;
err.err_info = err_info;
+ err.drv = drv;
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err.err);
@@ -656,8 +664,8 @@
return -1;
}
- ret = send_and_recv(global, global->nl, msg, family_handler, &res,
- NULL, NULL, NULL);
+ ret = send_and_recv_glb(global, NULL, global->nl, msg, family_handler,
+ &res, NULL, NULL, NULL);
if (ret == 0)
ret = res.id;
return ret;
@@ -852,7 +860,7 @@
return -1;
}
- ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL,
+ ret = send_and_recv(drv, w->nl_beacons, msg, NULL, NULL,
NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
@@ -1109,7 +1117,7 @@
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
struct nl_msg *msg;
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_INTERFACE);
if (send_and_recv_resp(drv, msg, get_mlo_info,
&drv->sta_mlo_info))
return -1;
@@ -1220,7 +1228,8 @@
nl80211_check_global(drv->global);
wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
"interface");
- if (wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL) < 0)
+ if (wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL,
+ WPA_P2P_MODE_WFD_R1) < 0)
return -1;
return 1;
}
@@ -1841,7 +1850,7 @@
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_INTERFACE);
return send_and_recv_resp(drv, msg, get_channel_info, ci);
}
@@ -2290,7 +2299,8 @@
static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
void *global_priv, int hostapd,
const u8 *set_addr,
- const char *driver_params)
+ const char *driver_params,
+ enum wpa_p2p_mode p2p_mode)
{
struct wpa_driver_nl80211_data *drv;
struct i802_bss *bss;
@@ -2353,7 +2363,8 @@
if (nl80211_init_bss(bss))
goto failed;
- if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
+ if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params,
+ p2p_mode))
goto failed;
if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_TX_STATUS) {
@@ -2416,10 +2427,11 @@
* Returns: Pointer to private data, %NULL on failure
*/
static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
- void *global_priv)
+ void *global_priv,
+ enum wpa_p2p_mode p2p_mode)
{
return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
- NULL);
+ NULL, p2p_mode);
}
@@ -2447,7 +2459,7 @@
return -1;
}
- ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL,
+ ret = send_and_recv(drv, nl_handle, msg, NULL, NULL,
NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
@@ -2727,7 +2739,7 @@
int ret;
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
- ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL,
+ ret = send_and_recv(bss->drv, bss->nl_mgmt, msg, NULL, NULL,
NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
@@ -2774,6 +2786,9 @@
if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
ret = -1;
#endif /* CONFIG_FST */
+ /* Vendor-specific Protected */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x7e", 1) < 0)
+ ret = -1;
/* Vendor-specific */
if (nl80211_register_action_frame(bss, (u8 *) "\x7f", 1) < 0)
ret = -1;
@@ -2976,10 +2991,67 @@
}
+#ifdef CONFIG_DRIVER_NL80211_QCA
+static int nl80211_set_p2p_mode(void *priv, enum wpa_p2p_mode mode)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *container;
+ int ret;
+ enum qca_wlan_vendor_p2p_mode drv_mode;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Set P2P mode: %d", mode);
+
+ switch (mode) {
+ case WPA_P2P_MODE_WFD_R1:
+ drv_mode = QCA_P2P_MODE_WFD_R1;
+ break;
+ case WPA_P2P_MODE_WFD_R2:
+ drv_mode = QCA_P2P_MODE_WFD_R2;
+ break;
+ case WPA_P2P_MODE_WFD_PCC:
+ drv_mode = QCA_P2P_MODE_WFD_PCC;
+ break;
+ default:
+ return -1;
+ }
+
+ 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_SET_P2P_MODE))
+ goto fail;
+
+ container = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+ if (!container)
+ goto fail;
+
+ if (nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_SET_P2P_MODE_CONFIG, drv_mode))
+ goto fail;
+
+ nla_nest_end(msg, container);
+
+ ret = send_and_recv_cmd(drv, msg);
+ if (ret)
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to set P2P Mode: ret=%d (%s)",
+ ret, strerror(-ret));
+ return ret;
+
+fail:
+ nlmsg_free(msg);
+ return -1;
+}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
static int
wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
const u8 *set_addr, int first,
- const char *driver_params)
+ const char *driver_params,
+ enum wpa_p2p_mode p2p_mode)
{
struct i802_bss *bss = drv->first_bss;
int send_rfkill_event = 0;
@@ -3038,6 +3110,11 @@
wpa_driver_nl80211_drv_init_rfkill(drv);
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ if (nlmode == NL80211_IFTYPE_P2P_GO)
+ nl80211_set_p2p_mode(bss, p2p_mode);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
if (!rfkill_is_blocked(drv->rfkill)) {
int ret = i802_set_iface_flags(bss, 1);
if (ret) {
@@ -3860,7 +3937,7 @@
return -1;
}
- ret = send_and_recv(drv->global, bss->nl_connect, msg,
+ ret = send_and_recv(drv, bss->nl_connect, msg,
NULL, NULL, NULL, NULL, NULL);
if (ret) {
wpa_dbg(drv->ctx, MSG_DEBUG,
@@ -4062,7 +4139,7 @@
wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
drv->ifindex);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_AUTHENTICATE);
if (!msg)
goto fail;
@@ -4395,7 +4472,8 @@
encrypt = 0;
}
- if (is_sta_interface(drv->nlmode) &&
+ if ((is_sta_interface(drv->nlmode) ||
+ drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
if (freq == 0 &&
@@ -4567,7 +4645,7 @@
nla_total_size(acl_nla_sz);
nlmsg_sz = nlmsg_total_size(nla_sz);
if (!(msg = nl80211_ifindex_msg_build(drv, nlmsg_alloc_size(nlmsg_sz),
- drv->ifindex, 0,
+ bss->ifindex, 0,
NL80211_CMD_SET_MAC_ACL)) ||
nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
@@ -4621,7 +4699,7 @@
struct nl_msg *msg;
int ret;
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MESH_CONFIG);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_MESH_CONFIG);
if (!msg)
return -1;
@@ -5506,7 +5584,7 @@
if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
goto fail;
- ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
+ ret = send_and_recv(drv, bss->nl_connect, msg, NULL, NULL, NULL,
NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
@@ -5577,7 +5655,7 @@
freq->he_enabled, freq->eht_enabled, freq->bandwidth,
freq->center_freq1, freq->center_freq2);
- msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
+ msg = nl80211_bss_msg(bss, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
NL80211_CMD_SET_WIPHY);
if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
nlmsg_free(msg);
@@ -5763,6 +5841,15 @@
goto fail;
}
+ /* Set EML capabilities of ML STA */
+ if (params->mld_link_addr && params->eml_cap) {
+ wpa_printf(MSG_DEBUG, " * eml_cap =%u",
+ params->eml_cap);
+ if (nla_put_u16(msg, NL80211_ATTR_EML_CAPABILITY,
+ params->eml_cap))
+ goto fail;
+ }
+
if (is_ap_interface(drv->nlmode) &&
nla_put_u8(msg, NL80211_ATTR_STA_SUPPORT_P2P_PS,
params->support_p2p_ps ?
@@ -6353,7 +6440,7 @@
os_memset(&ext_arg, 0, sizeof(struct nl80211_ack_ext_arg));
ext_arg.ext_data = &cookie;
- ret = send_and_recv(bss->drv->global, bss->drv->global->nl, msg,
+ ret = send_and_recv(bss->drv, bss->drv->global->nl, msg,
NULL, NULL, ack_handler_cookie, &ext_arg, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -6594,7 +6681,7 @@
int ret;
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
- ret = send_and_recv(drv->global, drv->first_bss->nl_connect, msg, NULL,
+ ret = send_and_recv(drv, drv->first_bss->nl_connect, msg, NULL,
NULL, NULL, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
@@ -6744,7 +6831,7 @@
if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
goto fail;
- ret = send_and_recv(drv->global, drv->first_bss->nl_connect, msg, NULL,
+ ret = send_and_recv(drv, drv->first_bss->nl_connect, msg, NULL,
NULL, NULL, NULL, NULL);
msg = NULL;
if (ret) {
@@ -7298,7 +7385,7 @@
nl80211_connect_ext(drv, params);
wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONNECT);
if (!msg)
return -1;
@@ -7375,7 +7462,7 @@
if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
goto fail;
- ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
+ ret = send_and_recv(drv, bss->nl_connect, msg, NULL, NULL, NULL,
NULL, NULL);
msg = NULL;
if (ret) {
@@ -7460,7 +7547,7 @@
wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
drv->ifindex);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_ASSOCIATE);
if (!msg)
return -1;
@@ -7491,7 +7578,7 @@
if (!TEST_FAIL_TAG("assoc")) {
if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
goto fail;
- ret = send_and_recv(drv->global, drv->first_bss->nl_connect,
+ ret = send_and_recv(drv, drv->first_bss->nl_connect,
msg, NULL, NULL, NULL, NULL, &err_info);
msg = NULL;
} else {
@@ -7906,7 +7993,7 @@
else
val = rts;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY)) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
nlmsg_free(msg);
return -ENOBUFS;
@@ -7934,7 +8021,7 @@
else
val = frag;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY)) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
nlmsg_free(msg);
return -ENOBUFS;
@@ -7967,6 +8054,8 @@
* XXX: FIX! this needs to flush all VLANs too
*/
msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
+ if (!msg)
+ goto fail;
if (link_id >= 0 && (bss->valid_links & BIT(link_id)) &&
nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, link_id))
goto fail;
@@ -8796,7 +8885,8 @@
bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
params->global_priv, 1,
- params->bssid, params->driver_params);
+ params->bssid, params->driver_params,
+ WPA_P2P_MODE_WFD_R1);
if (bss == NULL)
return NULL;
@@ -9330,7 +9420,7 @@
const u8 *dst, const u8 *src,
const u8 *bssid,
const u8 *data, size_t data_len,
- int no_cck)
+ int no_cck, int link_id)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
@@ -9347,9 +9437,9 @@
wpa_printf(MSG_DEBUG,
"nl80211: Send Action frame (ifindex=%d, freq=%u MHz wait=%d ms no_cck=%d offchanok=%d dst="
- MACSTR " src=" MACSTR " bssid=" MACSTR ")",
+ MACSTR " src=" MACSTR " bssid=" MACSTR ", link_id=%d)",
drv->ifindex, freq, wait_time, no_cck, offchanok,
- MAC2STR(dst), MAC2STR(src), MAC2STR(bssid));
+ MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), link_id);
buf = os_zalloc(24 + data_len);
if (buf == NULL)
@@ -9398,12 +9488,12 @@
!drv->use_monitor))
ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
0, freq, no_cck, offchanok,
- wait_time, NULL, 0, 0, -1);
+ wait_time, NULL, 0, 0,
+ link_id);
else
ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
24 + data_len, 1, no_cck, 0,
- offchanok, NULL, 0,
- NL80211_DRV_LINK_ID_NA);
+ offchanok, NULL, 0, link_id);
os_free(buf);
return ret;
@@ -10486,7 +10576,7 @@
dl_list_init(&survey_results->survey_list);
- msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+ msg = nl80211_bss_msg(bss, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
if (!msg)
return -ENOBUFS;
@@ -10683,15 +10773,29 @@
return -1;
}
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_RADAR_DETECT)) ||
nl80211_put_freq_params(msg, freq) < 0) {
nlmsg_free(msg);
return -1;
}
+ if (nl80211_link_valid(bss->valid_links, freq->link_id)) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Radar detection (CAC) on link_id=%d",
+ freq->link_id);
+
+ if (nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, freq->link_id)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
+
ret = send_and_recv_cmd(drv, msg);
- if (ret == 0)
+ if (ret == 0) {
+ nl80211_link_set_freq(bss, freq->link_id, freq->freq);
return 0;
+ }
+
wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
"%d (%s)", ret, strerror(-ret));
return -1;
@@ -10779,7 +10883,7 @@
if (link_id < 0 && drv->sta_mlo_info.valid_links)
link_id = drv->sta_mlo_info.assoc_link_id;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_TDLS_MGMT)) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
@@ -10834,7 +10938,7 @@
return -EINVAL;
}
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_TDLS_OPER)) ||
nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
nlmsg_free(msg);
@@ -11099,11 +11203,12 @@
const u8 *dst, const u8 *src,
const u8 *bssid,
const u8 *data, size_t data_len,
- int no_cck)
+ int no_cck, int link_id)
{
struct i802_bss *bss = priv;
return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
- bssid, data, data_len, no_cck);
+ bssid, data, data_len, no_cck,
+ link_id);
}
@@ -11124,7 +11229,7 @@
u16 mdid = WPA_GET_LE16(md);
wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UPDATE_FT_IES)) ||
nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
nlmsg_free(msg);
@@ -11373,7 +11478,8 @@
"capa.max_sched_scan_plan_interval=%u\n"
"capa.max_sched_scan_plan_iterations=%u\n"
"capa.mbssid_max_interfaces=%u\n"
- "capa.ema_max_periodicity=%u\n",
+ "capa.ema_max_periodicity=%u\n"
+ "capa.max_probe_req_ie_len=%zu\n",
drv->capa.key_mgmt,
drv->capa.enc,
drv->capa.auth,
@@ -11398,7 +11504,8 @@
drv->capa.max_sched_scan_plan_interval,
drv->capa.max_sched_scan_plan_iterations,
drv->capa.mbssid_max_interfaces,
- drv->capa.ema_max_periodicity);
+ drv->capa.ema_max_periodicity,
+ drv->capa.max_probe_req_ie_len);
if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -11470,7 +11577,7 @@
settings->freq_params.bandwidth,
settings->freq_params.center_freq1,
settings->freq_params.center_freq2,
- settings->punct_bitmap,
+ settings->freq_params.punct_bitmap,
settings->link_id,
settings->freq_params.ht_enabled ? " ht" : "",
settings->freq_params.vht_enabled ? " vht" : "",
@@ -11543,9 +11650,9 @@
(ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
(settings->block_tx &&
nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)) ||
- (settings->punct_bitmap &&
+ (settings->freq_params.punct_bitmap &&
nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP,
- settings->punct_bitmap)) ||
+ settings->freq_params.punct_bitmap)) ||
(settings->link_id != NL80211_DRV_LINK_ID_NA &&
nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->link_id)))
goto error;
@@ -11855,7 +11962,7 @@
/* This test vendor_cmd can be used with nl80211 commands that
* need the connect nl_sock, so use the variant that takes in
* bss->nl_connect as the handle. */
- ret = send_and_recv(drv->global, bss->nl_connect, msg,
+ ret = send_and_recv(drv, bss->nl_connect, msg,
cmd_reply_handler, buf, NULL, NULL, NULL);
if (ret)
wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
@@ -11942,7 +12049,7 @@
wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status");
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_WOWLAN);
ret = send_and_recv_resp(drv, msg, get_wowlan_handler, &wowlan_enabled);
if (ret) {
@@ -12015,7 +12122,7 @@
return -1;
}
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 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_ROAMING) ||
@@ -12046,7 +12153,7 @@
if (!drv->set_wifi_conf_vendor_cmd_avail)
return -1;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
@@ -12081,7 +12188,7 @@
if (!drv->roam_vendor_cmd_avail)
return -1;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 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_ROAM) ||
@@ -12135,7 +12242,7 @@
wpa_printf(MSG_DEBUG, "nl80211: Add STA node");
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 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_ADD_STA_NODE) ||
@@ -12319,7 +12426,7 @@
int ret = -1;
wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_JOIN_MESH);
if (!msg ||
nl80211_put_freq_params(msg, ¶ms->freq) ||
nl80211_put_basic_rates(msg, params->basic_rates) ||
@@ -12365,7 +12472,7 @@
if (nla_put_flag(msg, NL80211_ATTR_SOCKET_OWNER))
return -1;
- ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
+ ret = send_and_recv(drv, bss->nl_connect, msg, NULL, NULL, NULL,
NULL, NULL);
msg = NULL;
if (ret) {
@@ -12422,8 +12529,8 @@
int ret;
wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
- ret = send_and_recv(drv->global, bss->nl_connect, msg, NULL, NULL, NULL,
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_LEAVE_MESH);
+ ret = send_and_recv(drv, bss->nl_connect, msg, NULL, NULL, NULL,
NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
@@ -12452,7 +12559,7 @@
struct nl_msg *msg;
int ret;
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_PROBE_MESH_LINK);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_MESH_LINK);
if (!msg ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
nla_put(msg, NL80211_ATTR_FRAME, len, eth)) {
@@ -12889,7 +12996,7 @@
"nl80211: QCA_BAND_MASK = 0x%x, QCA_BAND_VALUE = %d",
qca_band_mask, qca_band_value);
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
@@ -13086,7 +13193,7 @@
param.num = *num;
param.freq_list = freq_list;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
@@ -13140,7 +13247,7 @@
"nl80211: Set P2P probable operating freq %u for ifindex %d",
freq, bss->ifindex);
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL) ||
@@ -13190,7 +13297,7 @@
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
return -1;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 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_P2P_LISTEN_OFFLOAD_START))
@@ -13242,7 +13349,7 @@
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_P2P_LISTEN_OFFLOAD))
return -1;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 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_P2P_LISTEN_OFFLOAD_STOP)) {
@@ -13273,7 +13380,7 @@
else
tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 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_CONFIGURE_TDLS))
@@ -13410,7 +13517,7 @@
static struct wpa_bss_candidate_info *
-nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
+qca_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -13443,7 +13550,7 @@
*/
info->num = params->n_candidates;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 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_FETCH_BSS_TRANSITION_STATUS))
@@ -13517,7 +13624,7 @@
if (!drv->set_wifi_conf_vendor_cmd_avail)
return -1;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
@@ -13565,7 +13672,7 @@
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: PASN authentication response for %d entries",
params->num_peers);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR);
if (!msg ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
@@ -13648,7 +13755,7 @@
"nl80211: Secure ranging context for " MACSTR,
MAC2STR(params->peer_addr));
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR);
if (!msg ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
@@ -13727,7 +13834,7 @@
wpa_printf(MSG_DEBUG, "nl80211: NAN USD flush");
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR);
if (!msg ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
@@ -13743,12 +13850,10 @@
nla_nest_end(msg, container);
ret = send_and_recv_cmd(drv, msg);
- if (ret) {
+ if (ret)
wpa_printf(MSG_ERROR,
"nl80211: Failed to send NAN USD flush");
- goto fail;
- }
- return 0;
+ return ret;
fail:
nlmsg_free(msg);
@@ -13774,7 +13879,7 @@
params->freq, params->ttl);
wpa_hexdump_buf(MSG_MSGDUMP, "nl80211: USD elements", elems);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR);
if (!msg ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
@@ -13807,16 +13912,15 @@
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) {
+ if (ret)
wpa_printf(MSG_ERROR,
"nl80211: Failed to send NAN USD publish");
- goto fail;
- }
- return 0;
+ return ret;
fail:
nlmsg_free(msg);
@@ -13834,7 +13938,7 @@
wpa_printf(MSG_DEBUG, "nl80211: NAN USD cancel publish");
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR);
if (!msg ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
@@ -13854,12 +13958,10 @@
nla_nest_end(msg, container);
ret = send_and_recv_cmd(drv, msg);
- if (ret) {
+ if (ret)
wpa_printf(MSG_ERROR,
"nl80211: Failed to send NAN USD cancel publish");
- goto fail;
- }
- return 0;
+ return ret;
fail:
nlmsg_free(msg);
@@ -13879,7 +13981,7 @@
wpa_printf(MSG_DEBUG, "nl80211: NAN USD update publish: id=%d",
publish_id);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR);
if (!msg ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
@@ -13900,12 +14002,10 @@
nla_nest_end(msg, container);
ret = send_and_recv_cmd(drv, msg);
- if (ret) {
+ if (ret)
wpa_printf(MSG_ERROR,
"nl80211: Failed to send NAN USD update publish");
- goto fail;
- }
- return 0;
+ return ret;
fail:
nlmsg_free(msg);
@@ -13931,7 +14031,7 @@
params->freq, params->ttl);
wpa_hexdump_buf(MSG_MSGDUMP, "nl80211: USD elements", elems);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR);
if (!msg ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
@@ -13969,12 +14069,10 @@
nla_nest_end(msg, container);
ret = send_and_recv_cmd(drv, msg);
- if (ret) {
+ if (ret)
wpa_printf(MSG_ERROR,
"nl80211: Failed to send NAN USD subscribe");
- goto fail;
- }
- return 0;
+ return ret;
fail:
nlmsg_free(msg);
@@ -13992,7 +14090,7 @@
wpa_printf(MSG_DEBUG, "nl80211: NAN USD cancel subscribe");
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR);
if (!msg ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
@@ -14010,12 +14108,10 @@
nla_nest_end(msg, container);
ret = send_and_recv_cmd(drv, msg);
- if (ret) {
+ if (ret)
wpa_printf(MSG_ERROR,
"nl80211: Failed to send NAN USD cancel subscribe");
- goto fail;
- }
- return 0;
+ return ret;
fail:
nlmsg_free(msg);
@@ -14103,6 +14199,60 @@
}
+#ifdef CONFIG_MBO
+static struct wpa_bss_candidate_info *
+nl80211_get_bss_transition_status(void *priv, struct wpa_bss_trans_info *params)
+{
+#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
+ /* This only exists for testing purposes, disable unless requested */
+ if (TEST_FAIL_TAG("simulate")) {
+ struct wpa_bss_candidate_info *info;
+ int i;
+
+ info = os_zalloc(sizeof(*info));
+ if (!info)
+ return NULL;
+
+ info->candidates = os_calloc(params->n_candidates,
+ sizeof(*info->candidates));
+ if (!info->candidates) {
+ os_free(info);
+ return NULL;
+ }
+
+ info->num = params->n_candidates;
+ for (i = 0; i < params->n_candidates; i++) {
+ char bssid_str[ETH_ALEN * 3];
+
+ os_memcpy(info->candidates[i].bssid,
+ ¶ms->bssid[i * ETH_ALEN], ETH_ALEN);
+
+ os_snprintf(bssid_str, sizeof(bssid_str), MACSTR,
+ MAC2STR(info->candidates[i].bssid));
+
+ if (TEST_FAIL_TAG(bssid_str)) {
+ info->candidates[i].is_accept = 0;
+ info->candidates[i].reject_reason =
+ MBO_TRANSITION_REJECT_REASON_FRAME_LOSS;
+ } else {
+ info->candidates[i].is_accept = 1;
+ info->candidates[i].reject_reason = 0;
+ }
+ }
+
+ return info;
+ }
+#endif /* defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) */
+
+#ifdef CONFIG_DRIVER_NL80211_QCA
+ return qca_get_bss_transition_status(priv, params);
+#else /* CONFIG_DRIVER_NL80211_QCA */
+ return NULL;
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+}
+#endif /* CONFIG_MBO */
+
+
static int nl80211_write_to_file(const char *name, unsigned int val)
{
int fd, len;
@@ -14308,7 +14458,7 @@
}
#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UPDATE_CONNECT_PARAMS);
if (!msg)
goto fail;
@@ -14368,7 +14518,7 @@
wpa_dbg(drv->ctx, MSG_DEBUG,
"nl80211: External auth status: %u", params->status);
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_EXTERNAL_AUTH);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_EXTERNAL_AUTH);
if (!msg ||
nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, params->status) ||
(params->ssid && params->ssid_len &&
@@ -14565,6 +14715,7 @@
#ifdef CONFIG_IEEE80211BE
+
static int wpa_driver_nl80211_link_sta_remove(void *priv, u8 link_id,
const u8 *addr)
{
@@ -14591,6 +14742,124 @@
return ret;
}
+
+
+static int wpa_driver_get_wiphy_name_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct wpa_driver_nl80211_data *drv = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_WIPHY_NAME])
+ return NL_SKIP;
+
+ os_strlcpy(drv->phyname, nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
+ sizeof(drv->phyname));
+
+ return NL_SKIP;
+}
+
+
+static int wpa_driver_get_phyname(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ u32 feat, nl_flags;
+
+ feat = get_nl80211_protocol_features(drv);
+ if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+ nl_flags = NLM_F_DUMP;
+
+ if (!(msg = nl80211_cmd_msg(drv->first_bss, nl_flags,
+ NL80211_CMD_GET_WIPHY)) ||
+ nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+ nlmsg_free(msg);
+ return -1;
+ }
+
+ if (send_and_recv_resp(drv, msg, wpa_driver_get_wiphy_name_handler,
+ drv))
+ return -1;
+
+ return 0;
+}
+
+
+static bool
+wpa_driver_nl80211_name_match(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_nl80211_data **match_drv)
+{
+ struct wpa_driver_nl80211_data *drv2;
+
+ dl_list_for_each(drv2, &drv->global->interfaces,
+ struct wpa_driver_nl80211_data, list) {
+ if (os_strcmp(drv2->phyname, drv->phyname) == 0) {
+ if (match_drv)
+ *match_drv = drv2;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static bool wpa_driver_nl80211_can_share_drv(void *ctx,
+ struct wpa_init_params *params,
+ void **hapd)
+{
+ struct wpa_driver_nl80211_data *drv, *match_drv = NULL;
+ struct i802_bss *bss;
+ bool ret = false;
+
+ if (!params->global_priv)
+ return false;
+
+ /* Create a temporary drv to read the phyname */
+ drv = os_zalloc(sizeof(*drv));
+ if (!drv)
+ return false;
+ drv->global = params->global_priv;
+ drv->ctx = ctx;
+
+ drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
+ if (!drv->first_bss) {
+ os_free(drv);
+ return false;
+ }
+
+ bss = drv->first_bss;
+ bss->drv = drv;
+ bss->ctx = ctx;
+
+ os_strlcpy(bss->ifname, params->ifname, sizeof(bss->ifname));
+
+ if (nl80211_init_bss(bss))
+ goto free_all;
+
+ drv->ifindex = if_nametoindex(bss->ifname);
+ bss->ifindex = drv->ifindex;
+
+ if (wpa_driver_get_phyname(drv) ||
+ !wpa_driver_nl80211_name_match(drv, &match_drv) ||
+ !match_drv)
+ goto free_all;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Driver for phy %s already exist",
+ match_drv->phyname);
+
+ *hapd = match_drv->first_bss->ctx;
+ ret = true;
+
+free_all:
+ nl80211_destroy_bss(bss);
+ os_free(bss);
+ os_free(drv);
+ return ret;
+}
+
#endif /* CONFIG_IEEE80211BE */
@@ -14775,7 +15044,6 @@
.set_default_scan_ies = nl80211_set_default_scan_ies,
.set_tdls_mode = nl80211_set_tdls_mode,
#ifdef CONFIG_MBO
- .get_bss_transition_status = nl80211_get_bss_transition_status,
.ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
#endif /* CONFIG_MBO */
.set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow,
@@ -14794,6 +15062,9 @@
#endif /* CONFIG_NAN_USD */
#endif /* CONFIG_DRIVER_NL80211_QCA */
.do_acs = nl80211_do_acs,
+#ifdef CONFIG_MBO
+ .get_bss_transition_status = nl80211_get_bss_transition_status,
+#endif /* CONFIG_MBO */
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
.get_ext_capab = nl80211_get_ext_capab,
.get_mld_capab = nl80211_get_mld_capab,
@@ -14809,6 +15080,7 @@
.link_remove = driver_nl80211_link_remove,
.is_drv_shared = nl80211_is_drv_shared,
.link_sta_remove = wpa_driver_nl80211_link_sta_remove,
+ .can_share_drv = wpa_driver_nl80211_can_share_drv,
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_TESTING_OPTIONS
.register_frame = testing_nl80211_register_frame,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index bf1bf4e..da74030 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -284,13 +284,28 @@
uint8_t cmd);
struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
-int send_and_recv(struct nl80211_global *global,
- struct nl_sock *nl_handle, struct nl_msg *msg,
- int (*valid_handler)(struct nl_msg *, void *),
- void *valid_data,
- int (*ack_handler_custom)(struct nl_msg *, void *),
- void *ack_data,
- struct nl80211_err_info *err_info);
+int send_and_recv_glb(struct nl80211_global *global,
+ struct wpa_driver_nl80211_data *drv, /* may be NULL */
+ struct nl_sock *nl_handle, struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data,
+ struct nl80211_err_info *err_info);
+
+static inline int
+send_and_recv(struct wpa_driver_nl80211_data *drv,
+ struct nl_sock *nl_handle, struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data,
+ int (*ack_handler_custom)(struct nl_msg *, void *),
+ void *ack_data,
+ struct nl80211_err_info *err_info)
+{
+ return send_and_recv_glb(drv->global, drv, nl_handle, msg,
+ valid_handler, valid_data,
+ ack_handler_custom, ack_data, err_info);
+}
// This function is not used in supplicant anymore. But keeping this wrapper
// functions for libraries outside wpa_supplicant to build (For eg: lib_driver_cmd_XX)
@@ -302,7 +317,7 @@
int (*ack_handler_custom)(struct nl_msg *, void *),
void *ack_data)
{
- return send_and_recv(drv->global, drv->global->nl, msg,
+ return send_and_recv(drv, drv->global->nl, msg,
valid_handler, valid_data,
ack_handler_custom, ack_data, NULL);
}
@@ -311,7 +326,7 @@
send_and_recv_cmd(struct wpa_driver_nl80211_data *drv,
struct nl_msg *msg)
{
- return send_and_recv(drv->global, drv->global->nl, msg,
+ return send_and_recv(drv, drv->global->nl, msg,
NULL, NULL, NULL, NULL, NULL);
}
@@ -321,7 +336,7 @@
int (*valid_handler)(struct nl_msg *, void *),
void *valid_data)
{
- return send_and_recv(drv->global, drv->global->nl, msg,
+ return send_and_recv(drv, drv->global->nl, msg,
valid_handler, valid_data, NULL, NULL, NULL);
}
@@ -432,5 +447,6 @@
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);
+u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv);
#endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 58fb71d..1aaeae9 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -35,7 +35,7 @@
}
-static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
+u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
{
u32 feat = 0;
struct nl_msg *msg;
@@ -958,6 +958,10 @@
capa->max_scan_ssids =
nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
+ if (tb[NL80211_ATTR_MAX_SCAN_IE_LEN])
+ capa->max_probe_req_ie_len =
+ nla_get_u16(tb[NL80211_ATTR_MAX_SCAN_IE_LEN]);
+
if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
capa->max_sched_scan_ssids =
nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
@@ -1204,6 +1208,10 @@
info->capa = &drv->capa;
info->drv = drv;
+ /* Default to large buffer of extra IE(s) to maintain previous behavior
+ * if the driver does not support reporting an accurate limit. */
+ info->capa->max_probe_req_ie_len = 1500;
+
feat = get_nl80211_protocol_features(drv);
if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
flags = NLM_F_DUMP;
@@ -1735,6 +1743,8 @@
chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_80;
if (tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ])
chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_160;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_320MHZ])
+ chan->allowed_bw &= ~HOSTAPD_CHAN_WIDTH_320;
if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
enum nl80211_dfs_state state =
@@ -1836,6 +1846,8 @@
[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_NO_80MHZ] = { .type = NLA_FLAG },
[NL80211_FREQUENCY_ATTR_NO_160MHZ] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_320MHZ] = { .type = NLA_FLAG },
+
};
int new_channels = 0;
struct hostapd_channel_data *channel;
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index d301701..f297e40 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -2510,29 +2510,62 @@
}
-static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
- struct nlattr **tb)
+static void nl80211_process_radar_event(struct i802_bss *bss,
+ union wpa_event_data *data,
+ enum nl80211_radar_event event_type)
{
+ wpa_printf(MSG_DEBUG,
+ "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz, link_id=%d",
+ data->dfs_event.freq, data->dfs_event.ht_enabled,
+ data->dfs_event.chan_offset, data->dfs_event.chan_width,
+ data->dfs_event.cf1, data->dfs_event.cf2,
+ data->dfs_event.link_id);
+
+ switch (event_type) {
+ case NL80211_RADAR_DETECTED:
+ wpa_supplicant_event(bss->ctx, EVENT_DFS_RADAR_DETECTED, data);
+ break;
+ case NL80211_RADAR_CAC_FINISHED:
+ wpa_supplicant_event(bss->ctx, EVENT_DFS_CAC_FINISHED, data);
+ break;
+ case NL80211_RADAR_CAC_ABORTED:
+ wpa_supplicant_event(bss->ctx, EVENT_DFS_CAC_ABORTED, data);
+ break;
+ case NL80211_RADAR_NOP_FINISHED:
+ wpa_supplicant_event(bss->ctx, EVENT_DFS_NOP_FINISHED, data);
+ break;
+ case NL80211_RADAR_PRE_CAC_EXPIRED:
+ wpa_supplicant_event(bss->ctx, EVENT_DFS_PRE_CAC_EXPIRED,
+ data);
+ break;
+ case NL80211_RADAR_CAC_STARTED:
+ wpa_supplicant_event(bss->ctx, EVENT_DFS_CAC_STARTED, data);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Unknown radar event %d received",
+ event_type);
+ break;
+ }
+}
+
+
+static void nl80211_radar_event(struct i802_bss *bss, struct nlattr **tb)
+{
+ struct wpa_driver_nl80211_data *drv = bss->drv;
union wpa_event_data data;
enum nl80211_radar_event event_type;
+ struct i802_bss *bss_iter;
+ int i;
+ bool hit = false;
if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
return;
os_memset(&data, 0, sizeof(data));
- data.dfs_event.link_id = NL80211_DRV_LINK_ID_NA;
data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
- if (tb[NL80211_ATTR_MLO_LINK_ID]) {
- data.dfs_event.link_id =
- nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]);
- } else if (data.dfs_event.freq) {
- data.dfs_event.link_id =
- nl80211_get_link_id_by_freq(drv->first_bss,
- data.dfs_event.freq);
- }
-
/* Check HT params */
if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
data.dfs_event.ht_enabled = 1;
@@ -2564,37 +2597,62 @@
data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
wpa_printf(MSG_DEBUG,
- "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz, link_id=%d",
- data.dfs_event.freq, data.dfs_event.ht_enabled,
- data.dfs_event.chan_offset, data.dfs_event.chan_width,
- data.dfs_event.cf1, data.dfs_event.cf2,
- data.dfs_event.link_id);
+ "nl80211: Checking suitable BSS for the DFS event");
- switch (event_type) {
- case NL80211_RADAR_DETECTED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
- break;
- case NL80211_RADAR_CAC_FINISHED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
- break;
- case NL80211_RADAR_CAC_ABORTED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
- break;
- case NL80211_RADAR_NOP_FINISHED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
- break;
- case NL80211_RADAR_PRE_CAC_EXPIRED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_PRE_CAC_EXPIRED,
- &data);
- break;
- case NL80211_RADAR_CAC_STARTED:
- wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data);
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
- "received", event_type);
- break;
+ /* It is possible to have the event without ifidx and wdev_id, e.g.,
+ * with NL80211_RADAR_NOP_FINISHED and NL80211_RADAR_PRE_CAC_EXPIRED.
+ * Hence need to check on all BSSs. */
+ for (bss_iter = drv->first_bss; bss_iter; bss_iter = bss_iter->next) {
+ /* Find a link match based on the frequency. If
+ * NL80211_DRV_LINK_ID_NA is returned, either a match was not
+ * found or the BSS could be operating as a non-MLO. */
+ data.dfs_event.link_id = nl80211_get_link_id_by_freq(
+ bss_iter, data.dfs_event.freq);
+ /* If a link match is found, exit the loop after the handler is
+ * called */
+ if (data.dfs_event.link_id != NL80211_DRV_LINK_ID_NA)
+ return nl80211_process_radar_event(bss_iter, &data,
+ event_type);
+ if (data.dfs_event.link_id == NL80211_DRV_LINK_ID_NA) {
+ /* For non-MLO operation, frequency should still match
+ */
+ if (!bss_iter->valid_links &&
+ bss_iter->links[0].freq == data.dfs_event.freq)
+ return nl80211_process_radar_event(
+ bss_iter, &data, event_type);
+ }
+
+ /* For event like NL80211_RADAR_NOP_FINISHED, frequency
+ * information will not match exactly the link frequency. Hence,
+ * if the link frequency is 5 GHz, pass the event to it.
+ */
+ for_each_link_default(bss_iter->valid_links, i, 0) {
+ if (bss_iter->links[i].freq < 5180 ||
+ bss_iter->links[i].freq > 5900)
+ continue;
+
+ data.dfs_event.link_id = bss_iter->valid_links ?
+ i : NL80211_DRV_LINK_ID_NA;
+
+ /* Cannot just return after one match since if split
+ * hardware is participating in MLO, possibly the event
+ * is for 5 GHz upper band and this iteration has picked
+ * a 5 GHz low band link, but 5 GHz freq check will be
+ * true for both. Hence, iterate on all possible links.
+ * The handler should take care whether the event is
+ * actually for it. */
+ nl80211_process_radar_event(bss_iter, &data,
+ event_type);
+
+ hit = true;
+ }
}
+
+ if (hit)
+ return;
+
+ wpa_printf(MSG_DEBUG, "nl80211: DFS event on unknown freq on %s",
+ bss->ifname);
}
@@ -4119,7 +4177,7 @@
mlme_event_ft_event(drv, tb);
break;
case NL80211_CMD_RADAR_DETECT:
- nl80211_radar_event(drv, tb);
+ nl80211_radar_event(bss, tb);
break;
case NL80211_CMD_STOP_AP:
nl80211_stop_ap(bss, tb);
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index d0ed7ad..f0313c1 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -238,6 +238,11 @@
if (params->extra_ies) {
wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
params->extra_ies, params->extra_ies_len);
+ if (params->extra_ies_len > drv->capa.max_probe_req_ie_len)
+ wpa_printf(MSG_INFO,
+ "nl80211: Extra IEs for scan do not fit driver limit (%zu > %zu) - this is likely to fail",
+ params->extra_ies_len,
+ drv->capa.max_probe_req_ie_len);
if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
params->extra_ies))
goto fail;
@@ -739,7 +744,7 @@
return android_pno_stop(bss);
#endif /* ANDROID */
- msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
+ msg = nl80211_bss_msg(bss, 0, NL80211_CMD_STOP_SCHED_SCAN);
ret = send_and_recv_cmd(drv, msg);
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -1205,7 +1210,7 @@
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: vendor scan request");
drv->scan_for_auth = 0;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 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_TRIGGER_SCAN) )
@@ -1380,7 +1385,7 @@
if (!drv->set_wifi_conf_vendor_cmd_avail)
return -1;
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_VENDOR)) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION))
diff --git a/src/eap_common/eap_teap_common.c b/src/eap_common/eap_teap_common.c
index ffb9a62..aeb0e69 100644
--- a/src/eap_common/eap_teap_common.c
+++ b/src/eap_common/eap_teap_common.c
@@ -118,32 +118,7 @@
}
-int eap_teap_derive_cmk_basic_pw_auth(u16 tls_cs, const u8 *s_imck_msk, u8 *cmk)
-{
- u8 imsk[32], imck[EAP_TEAP_IMCK_LEN];
- int res;
-
- /* FIX: The Basic-Password-Auth (i.e., no inner EAP) case is
- * not fully defined in RFC 7170, so this CMK derivation may
- * need to be changed if a fixed definition is eventually
- * published. For now, derive CMK[0] based on S-IMCK[0] and
- * IMSK of 32 octets of zeros. */
- os_memset(imsk, 0, 32);
- res = eap_teap_tls_prf(tls_cs, s_imck_msk, EAP_TEAP_SIMCK_LEN,
- "Inner Methods Compound Keys",
- imsk, 32, imck, sizeof(imck));
- if (res < 0)
- return -1;
- os_memcpy(cmk, &imck[EAP_TEAP_SIMCK_LEN], EAP_TEAP_CMK_LEN);
- wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: CMK[no-inner-EAP]",
- cmk, EAP_TEAP_CMK_LEN);
- forced_memzero(imck, sizeof(imck));
- return 0;
-}
-
-
-int eap_teap_derive_imck(u16 tls_cs,
- const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
+int eap_teap_derive_imck(u16 tls_cs, const u8 *prev_s_imck,
const u8 *msk, size_t msk_len,
const u8 *emsk, size_t emsk_len,
u8 *s_imck_msk, u8 *cmk_msk,
@@ -186,7 +161,7 @@
imsk, 32);
res = eap_teap_tls_prf(tls_cs,
- prev_s_imck_emsk, EAP_TEAP_SIMCK_LEN,
+ prev_s_imck, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, EAP_TEAP_IMCK_LEN);
forced_memzero(imsk, sizeof(imsk));
@@ -216,7 +191,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Zero IMSK", imsk, 32);
}
- res = eap_teap_tls_prf(tls_cs, prev_s_imck_msk, EAP_TEAP_SIMCK_LEN,
+ res = eap_teap_tls_prf(tls_cs, prev_s_imck, EAP_TEAP_SIMCK_LEN,
"Inner Methods Compound Keys",
imsk, 32, imck, EAP_TEAP_IMCK_LEN);
forced_memzero(imsk, sizeof(imsk));
@@ -342,10 +317,6 @@
if (res < 0)
return res;
- /* FIX: RFC 7170 does not describe how to handle truncation of the
- * Compound MAC or if the fields are supposed to be of variable length
- * based on the negotiated TLS cipher suite (they are defined as having
- * fixed size of 20 octets in the TLV description) */
if (mac_len > sizeof(tmp))
mac_len = sizeof(tmp);
os_memcpy(mac, tmp, mac_len);
@@ -704,41 +675,3 @@
wpabuf_put_be16(buf, id);
return buf;
}
-
-
-int eap_teap_allowed_anon_prov_phase2_method(int vendor, enum eap_type type)
-{
- /* RFC 7170, Section 3.8.3: MUST provide mutual authentication,
- * provide key generation, and be resistant to dictionary attack.
- * Section 3.8 also mentions requirement for using EMSK Compound MAC. */
- return vendor == EAP_VENDOR_IETF &&
- (type == EAP_TYPE_PWD || type == EAP_TYPE_EKE);
-}
-
-
-int eap_teap_allowed_anon_prov_cipher_suite(u16 cs)
-{
- /* RFC 7170, Section 3.8.3: anonymous ciphersuites MAY be supported as
- * long as the TLS pre-master secret is generated form contribution from
- * both peers. Accept the recommended TLS_DH_anon_WITH_AES_128_CBC_SHA
- * cipher suite and other ciphersuites that use DH in some form, have
- * SHA-1 or stronger MAC function, and use reasonable strong cipher. */
- static const u16 ok_cs[] = {
- /* DH-anon */
- 0x0034, 0x003a, 0x006c, 0x006d, 0x00a6, 0x00a7,
- /* DHE-RSA */
- 0x0033, 0x0039, 0x0067, 0x006b, 0x009e, 0x009f,
- /* ECDH-anon */
- 0xc018, 0xc019,
- /* ECDH-RSA */
- 0xc003, 0xc00f, 0xc029, 0xc02a, 0xc031, 0xc032,
- /* ECDH-ECDSA */
- 0xc004, 0xc005, 0xc025, 0xc026, 0xc02d, 0xc02e,
- /* ECDHE-RSA */
- 0xc013, 0xc014, 0xc027, 0xc028, 0xc02f, 0xc030,
- /* ECDHE-ECDSA */
- 0xc009, 0xc00a, 0xc023, 0xc024, 0xc02b, 0xc02c,
- };
-
- return tls_cipher_suite_match(ok_cs, ARRAY_SIZE(ok_cs), cs);
-}
diff --git a/src/eap_common/eap_teap_common.h b/src/eap_common/eap_teap_common.h
index 3a25879..cbf1315 100644
--- a/src/eap_common/eap_teap_common.h
+++ b/src/eap_common/eap_teap_common.h
@@ -205,10 +205,7 @@
struct wpabuf * eap_teap_tlv_eap_payload(struct wpabuf *buf);
int eap_teap_derive_eap_msk(u16 tls_cs, const u8 *simck, u8 *msk);
int eap_teap_derive_eap_emsk(u16 tls_cs, const u8 *simck, u8 *emsk);
-int eap_teap_derive_cmk_basic_pw_auth(u16 tls_cs, const u8 *s_imck_msk,
- u8 *cmk);
-int eap_teap_derive_imck(u16 tls_cs,
- const u8 *prev_s_imck_msk, const u8 *prev_s_imck_emsk,
+int eap_teap_derive_imck(u16 tls_cs, const u8 *prev_s_imck,
const u8 *msk, size_t msk_len,
const u8 *emsk, size_t emsk_len,
u8 *s_imck_msk, u8 *cmk_msk,
@@ -224,7 +221,5 @@
struct wpabuf * eap_teap_tlv_error(enum teap_error_codes error);
struct wpabuf * eap_teap_tlv_identity_type(enum teap_identity_types id);
enum eap_type;
-int eap_teap_allowed_anon_prov_phase2_method(int vendor, enum eap_type type);
-int eap_teap_allowed_anon_prov_cipher_suite(u16 cs);
#endif /* EAP_TEAP_H */
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 1454447..43e100a 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -724,8 +724,6 @@
EXT_CERT_CHECK_GOOD,
EXT_CERT_CHECK_BAD,
} pending_ext_cert_check;
-
- int teap_anon_dh;
};
diff --git a/src/eap_peer/eap_teap.c b/src/eap_peer/eap_teap.c
index ced7b16..8ce7cb7 100644
--- a/src/eap_peer/eap_teap.c
+++ b/src/eap_peer/eap_teap.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TEAP (RFC 7170)
- * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2024, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,11 +14,6 @@
#include "eap_i.h"
#include "eap_tls_common.h"
#include "eap_config.h"
-#include "eap_teap_pac.h"
-
-#ifdef EAP_TEAP_DYNAMIC
-#include "eap_teap_pac.c"
-#endif /* EAP_TEAP_DYNAMIC */
static void eap_teap_deinit(struct eap_sm *sm, void *priv);
@@ -43,13 +38,6 @@
struct eap_method_type *phase2_types;
size_t num_phase2_types;
int resuming; /* starting a resumed session */
-#define EAP_TEAP_PROV_UNAUTH 1
-#define EAP_TEAP_PROV_AUTH 2
- int provisioning_allowed; /* Allowed PAC provisioning modes */
- int provisioning; /* doing PAC provisioning (not the normal auth) */
- int anon_provisioning; /* doing anonymous (unauthenticated)
- * provisioning */
- int session_ticket_used;
int test_outer_tlvs;
u8 key_data[EAP_TEAP_KEY_LEN];
@@ -58,96 +46,34 @@
u8 emsk[EAP_EMSK_LEN];
int success;
- struct eap_teap_pac *pac;
- struct eap_teap_pac *current_pac;
- size_t max_pac_list_len;
- int use_pac_binary_format;
-
+ u8 simck[EAP_TEAP_SIMCK_LEN];
u8 simck_msk[EAP_TEAP_SIMCK_LEN];
u8 simck_emsk[EAP_TEAP_SIMCK_LEN];
int simck_idx;
- int cmk_emsk_available;
+ bool cmk_emsk_available;
struct wpabuf *pending_phase2_req;
struct wpabuf *pending_resp;
struct wpabuf *server_outer_tlvs;
struct wpabuf *peer_outer_tlvs;
+
+ enum teap_compat {
+ TEAP_DEFAULT,
+ TEAP_FREERADIUS,
+ } teap_compat;
};
-static int eap_teap_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
- const u8 *client_random,
- const u8 *server_random,
- u8 *master_secret)
-{
- struct eap_teap_data *data = ctx;
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: SessionTicket callback");
-
- if (!master_secret) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: SessionTicket failed - fall back to full TLS handshake");
- data->session_ticket_used = 0;
- if (data->provisioning_allowed) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Try to provision a new PAC-Key");
- data->provisioning = 1;
- data->current_pac = NULL;
- }
- return 0;
- }
-
- wpa_hexdump(MSG_DEBUG, "EAP-TEAP: SessionTicket", ticket, len);
-
- if (!data->current_pac) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: No PAC-Key available for using SessionTicket");
- data->session_ticket_used = 0;
- return 0;
- }
-
- /* EAP-TEAP uses PAC-Key as the TLS master_secret */
- os_memcpy(master_secret, data->current_pac->pac_key,
- EAP_TEAP_PAC_KEY_LEN);
-
- data->session_ticket_used = 1;
-
- return 1;
-}
-
-
static void eap_teap_parse_phase1(struct eap_teap_data *data,
const char *phase1)
{
- const char *pos;
-
- pos = os_strstr(phase1, "teap_provisioning=");
- if (pos) {
- data->provisioning_allowed = atoi(pos + 18);
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Automatic PAC provisioning mode: %d",
- data->provisioning_allowed);
- }
-
- pos = os_strstr(phase1, "teap_max_pac_list_len=");
- if (pos) {
- data->max_pac_list_len = atoi(pos + 22);
- if (data->max_pac_list_len == 0)
- data->max_pac_list_len = 1;
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Maximum PAC list length: %lu",
- (unsigned long) data->max_pac_list_len);
- }
-
- if (os_strstr(phase1, "teap_pac_format=binary")) {
- data->use_pac_binary_format = 1;
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Using binary format for PAC list");
- }
-
#ifdef CONFIG_TESTING_OPTIONS
if (os_strstr(phase1, "teap_test_outer_tlvs=1"))
data->test_outer_tlvs = 1;
#endif /* CONFIG_TESTING_OPTIONS */
+
+ if (os_strstr(phase1, "teap_compat=freeradius"))
+ data->teap_compat = TEAP_FREERADIUS;
}
@@ -163,21 +89,10 @@
if (!data)
return NULL;
data->teap_version = EAP_TEAP_VERSION;
- data->max_pac_list_len = 10;
if (config->phase1)
eap_teap_parse_phase1(data, config->phase1);
- if ((data->provisioning_allowed & EAP_TEAP_PROV_AUTH) &&
- !config->cert.ca_cert && !config->cert.ca_path) {
- /* Prevent PAC provisioning without mutual authentication
- * (either by validating server certificate or by suitable
- * inner EAP method). */
- wpa_printf(MSG_INFO,
- "EAP-TEAP: Disable authenticated provisioning due to no ca_cert/ca_path");
- data->provisioning_allowed &= ~EAP_TEAP_PROV_AUTH;
- }
-
if (eap_peer_select_phase2_methods(config, "auth=",
&data->phase2_types,
&data->num_phase2_types, 0) < 0) {
@@ -188,44 +103,12 @@
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_NONE;
- config->teap_anon_dh = !!(data->provisioning_allowed &
- EAP_TEAP_PROV_UNAUTH);
if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TEAP)) {
wpa_printf(MSG_INFO, "EAP-TEAP: Failed to initialize SSL");
eap_teap_deinit(sm, data);
return NULL;
}
- if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
- eap_teap_session_ticket_cb,
- data) < 0) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: Failed to set SessionTicket callback");
- eap_teap_deinit(sm, data);
- return NULL;
- }
-
- if (!config->pac_file) {
- wpa_printf(MSG_INFO, "EAP-TEAP: No PAC file configured");
- eap_teap_deinit(sm, data);
- return NULL;
- }
-
- if (data->use_pac_binary_format &&
- eap_teap_load_pac_bin(sm, &data->pac, config->pac_file) < 0) {
- wpa_printf(MSG_INFO, "EAP-TEAP: Failed to load PAC file");
- eap_teap_deinit(sm, data);
- return NULL;
- }
-
- if (!data->use_pac_binary_format &&
- eap_teap_load_pac(sm, &data->pac, config->pac_file) < 0) {
- wpa_printf(MSG_INFO, "EAP-TEAP: Failed to load PAC file");
- eap_teap_deinit(sm, data);
- return NULL;
- }
- eap_teap_pac_list_truncate(data->pac, data->max_pac_list_len);
-
return data;
}
@@ -244,6 +127,7 @@
data->server_outer_tlvs = NULL;
wpabuf_free(data->peer_outer_tlvs);
data->peer_outer_tlvs = NULL;
+ forced_memzero(data->simck, EAP_TEAP_SIMCK_LEN);
forced_memzero(data->simck_msk, EAP_TEAP_SIMCK_LEN);
forced_memzero(data->simck_emsk, EAP_TEAP_SIMCK_LEN);
}
@@ -252,7 +136,6 @@
static void eap_teap_deinit(struct eap_sm *sm, void *priv)
{
struct eap_teap_data *data = priv;
- struct eap_teap_pac *pac, *prev;
if (!data)
return;
@@ -262,25 +145,20 @@
os_free(data->phase2_types);
eap_peer_tls_ssl_deinit(sm, &data->ssl);
- pac = data->pac;
- prev = NULL;
- while (pac) {
- prev = pac;
- pac = pac->next;
- eap_teap_free_pac(prev);
- }
-
os_free(data);
}
static int eap_teap_derive_msk(struct eap_teap_data *data)
{
- /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
- * is used in this derivation */
- if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Derive MSK/EMSK (n=%d)",
+ data->simck_idx);
+ wpa_hexdump(MSG_DEBUG, "EAP-TEAP: S-IMCK[n]", data->simck,
+ EAP_TEAP_SIMCK_LEN);
+
+ if (eap_teap_derive_eap_msk(data->tls_cs, data->simck,
data->key_data) < 0 ||
- eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
+ eap_teap_derive_eap_emsk(data->tls_cs, data->simck,
data->emsk) < 0)
return -1;
data->success = 1;
@@ -296,13 +174,14 @@
/* RFC 7170, Section 5.1 */
res = tls_connection_export_key(sm->ssl_ctx, data->ssl.conn,
TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0,
- data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ data->simck, EAP_TEAP_SIMCK_LEN);
if (res)
return res;
wpa_hexdump_key(MSG_DEBUG,
"EAP-TEAP: session_key_seed (S-IMCK[0])",
- data->simck_msk, EAP_TEAP_SIMCK_LEN);
- os_memcpy(data->simck_emsk, data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ data->simck, EAP_TEAP_SIMCK_LEN);
+ os_memcpy(data->simck_msk, data->simck, EAP_TEAP_SIMCK_LEN);
+ os_memcpy(data->simck_emsk, data->simck, EAP_TEAP_SIMCK_LEN);
data->simck_idx = 0;
return 0;
}
@@ -339,17 +218,6 @@
{
size_t i;
- /* TODO: TNC with anonymous provisioning; need to require both
- * completed inner EAP authentication (EAP-pwd or EAP-EKE) and TNC */
-
- if (data->anon_provisioning &&
- !eap_teap_allowed_anon_prov_phase2_method(vendor, type)) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: EAP type %u:%u not allowed during unauthenticated provisioning",
- vendor, type);
- return -1;
- }
-
#ifdef EAP_TNC
if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) {
data->phase2_type.vendor = EAP_VENDOR_IETF;
@@ -518,28 +386,6 @@
}
-static struct wpabuf * eap_teap_tlv_pac_ack(void)
-{
- struct wpabuf *buf;
- struct teap_tlv_result *res;
- struct teap_tlv_pac_ack *ack;
-
- buf = wpabuf_alloc(sizeof(*res) + sizeof(*ack));
- if (!buf)
- return NULL;
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV (ack)");
- ack = wpabuf_put(buf, sizeof(*ack));
- ack->tlv_type = host_to_be16(TEAP_TLV_PAC | TEAP_TLV_MANDATORY);
- ack->length = host_to_be16(sizeof(*ack) - sizeof(struct teap_tlv_hdr));
- ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT);
- ack->pac_len = host_to_be16(2);
- ack->result = host_to_be16(TEAP_STATUS_SUCCESS);
-
- return buf;
-}
-
-
static struct wpabuf * eap_teap_add_identity_type(struct eap_sm *sm,
struct wpabuf *msg)
{
@@ -693,18 +539,21 @@
sizeof(struct teap_tlv_hdr));
rbind->version = EAP_TEAP_VERSION;
rbind->received_version = data->received_version;
- /* FIX: RFC 7170 is not clear on which Flags value to use when
- * Crypto-Binding TLV is used with Basic-Password-Auth */
- flags = cmk_emsk ? TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC :
- TEAP_CRYPTO_BINDING_MSK_CMAC;
subtype = TEAP_CRYPTO_BINDING_SUBTYPE_RESPONSE;
+ if (cmk_emsk)
+ flags = TEAP_CRYPTO_BINDING_EMSK_CMAC;
+ else if (cmk_msk)
+ flags = TEAP_CRYPTO_BINDING_MSK_CMAC;
+ else
+ return -1;
rbind->subtype = (flags << 4) | subtype;
os_memcpy(rbind->nonce, cb->nonce, sizeof(cb->nonce));
inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
os_memset(rbind->emsk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
os_memset(rbind->msk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
- if (eap_teap_compound_mac(data->tls_cs, rbind, data->server_outer_tlvs,
+ if (cmk_msk &&
+ eap_teap_compound_mac(data->tls_cs, rbind, data->server_outer_tlvs,
data->peer_outer_tlvs, cmk_msk,
rbind->msk_compound_mac) < 0)
return -1;
@@ -740,9 +589,7 @@
data->simck_idx + 1);
if (!data->phase2_method)
- return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
- data->simck_msk,
- cmk_msk);
+ goto out; /* no MSK derived in Basic-Password-Auth */
if (!data->phase2_method || !data->phase2_priv) {
wpa_printf(MSG_INFO, "EAP-TEAP: Phase 2 method not available");
@@ -773,17 +620,34 @@
&emsk_len);
}
- res = eap_teap_derive_imck(data->tls_cs,
- data->simck_msk, data->simck_emsk,
- msk, msk_len, emsk, emsk_len,
- data->simck_msk, cmk_msk,
- data->simck_emsk, cmk_emsk);
+out:
+ if (data->teap_compat == TEAP_FREERADIUS) {
+ u8 tmp_simck[EAP_TEAP_SIMCK_LEN];
+ u8 tmp_cmk[EAP_TEAP_CMK_LEN];
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TEAP: FreeRADIUS compatibility: use S-IMCK_MSK[j-1] and S-IMCK_EMSK[j-1] based on MSK/EMSK derivations instead of a single selected S-IMCK[j-1]");
+ res = eap_teap_derive_imck(data->tls_cs, data->simck_msk,
+ msk, msk_len, emsk, emsk_len,
+ data->simck_msk, cmk_msk,
+ tmp_simck, tmp_cmk);
+ if (emsk)
+ res = eap_teap_derive_imck(data->tls_cs,
+ data->simck_emsk,
+ msk, msk_len, emsk, emsk_len,
+ tmp_simck, tmp_cmk,
+ data->simck_emsk, cmk_emsk);
+ } else {
+ res = eap_teap_derive_imck(data->tls_cs, data->simck,
+ msk, msk_len, emsk, emsk_len,
+ data->simck_msk, cmk_msk,
+ data->simck_emsk, cmk_emsk);
+ }
bin_clear_free(msk, msk_len);
bin_clear_free(emsk, emsk_len);
if (res == 0) {
data->simck_idx++;
- if (emsk)
- data->cmk_emsk_available = 1;
+ data->cmk_emsk_available = emsk != NULL;
}
return res;
}
@@ -825,10 +689,12 @@
u8 *pos;
u8 cmk_msk[EAP_TEAP_CMK_LEN];
u8 cmk_emsk[EAP_TEAP_CMK_LEN];
+ const u8 *cmk_msk_ptr = NULL;
const u8 *cmk_emsk_ptr = NULL;
int res;
size_t len;
u8 flags;
+ bool server_msk, server_emsk;
if (eap_teap_validate_crypto_binding(data, cb) < 0 ||
eap_teap_get_cmk(sm, data, cmk_msk, cmk_emsk) < 0)
@@ -836,9 +702,12 @@
/* Validate received MSK/EMSK Compound MAC */
flags = cb->subtype >> 4;
+ server_msk = flags == TEAP_CRYPTO_BINDING_MSK_CMAC ||
+ flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC;
+ server_emsk = flags == TEAP_CRYPTO_BINDING_EMSK_CMAC ||
+ flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC;
- if (flags == TEAP_CRYPTO_BINDING_MSK_CMAC ||
- flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) {
+ if (server_msk) {
u8 msk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
if (eap_teap_compound_mac(data->tls_cs, cb,
@@ -860,9 +729,7 @@
}
}
- if ((flags == TEAP_CRYPTO_BINDING_EMSK_CMAC ||
- flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) &&
- data->cmk_emsk_available) {
+ if (server_emsk && data->cmk_emsk_available) {
u8 emsk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
if (eap_teap_compound_mac(data->tls_cs, cb,
@@ -882,8 +749,6 @@
"EAP-TEAP: EMSK Compound MAC did not match");
return NULL;
}
-
- cmk_emsk_ptr = cmk_emsk;
}
if (flags == TEAP_CRYPTO_BINDING_EMSK_CMAC &&
@@ -898,6 +763,20 @@
* crypto binding to allow server to complete authentication.
*/
+ if (server_emsk && data->cmk_emsk_available) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Selected S-IMCK_EMSK");
+ os_memcpy(data->simck, data->simck_emsk, EAP_TEAP_SIMCK_LEN);
+ cmk_emsk_ptr = cmk_emsk;
+ } else if (server_msk) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Selected S-IMCK_MSK");
+ os_memcpy(data->simck, data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ cmk_msk_ptr = cmk_msk;
+ } else {
+ return NULL;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Selected S-IMCK[j]",
+ data->simck, EAP_TEAP_SIMCK_LEN);
+
len = sizeof(struct teap_tlv_crypto_binding);
resp = wpabuf_alloc(len);
if (!resp)
@@ -920,7 +799,7 @@
pos = wpabuf_put(resp, sizeof(struct teap_tlv_crypto_binding));
if (eap_teap_write_crypto_binding(
data, (struct teap_tlv_crypto_binding *) pos,
- cb, cmk_msk, cmk_emsk_ptr) < 0) {
+ cb, cmk_msk_ptr, cmk_emsk_ptr) < 0) {
wpabuf_free(resp);
return NULL;
}
@@ -929,231 +808,6 @@
}
-static void eap_teap_parse_pac_tlv(struct eap_teap_pac *entry, int type,
- u8 *pos, size_t len, int *pac_key_found)
-{
- switch (type & 0x7fff) {
- case PAC_TYPE_PAC_KEY:
- wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: PAC-Key", pos, len);
- if (len != EAP_TEAP_PAC_KEY_LEN) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Invalid PAC-Key length %lu",
- (unsigned long) len);
- break;
- }
- *pac_key_found = 1;
- os_memcpy(entry->pac_key, pos, len);
- break;
- case PAC_TYPE_PAC_OPAQUE:
- wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Opaque", pos, len);
- entry->pac_opaque = pos;
- entry->pac_opaque_len = len;
- break;
- case PAC_TYPE_PAC_INFO:
- wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Info", pos, len);
- entry->pac_info = pos;
- entry->pac_info_len = len;
- break;
- default:
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Ignored unknown PAC type %d",
- type);
- break;
- }
-}
-
-
-static int eap_teap_process_pac_tlv(struct eap_teap_pac *entry,
- u8 *pac, size_t pac_len)
-{
- struct pac_attr_hdr *hdr;
- u8 *pos;
- size_t left, len;
- int type, pac_key_found = 0;
-
- pos = pac;
- left = pac_len;
-
- while (left > sizeof(*hdr)) {
- hdr = (struct pac_attr_hdr *) pos;
- type = be_to_host16(hdr->type);
- len = be_to_host16(hdr->len);
- pos += sizeof(*hdr);
- left -= sizeof(*hdr);
- if (len > left) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC TLV overrun (type=%d len=%lu left=%lu)",
- type, (unsigned long) len,
- (unsigned long) left);
- return -1;
- }
-
- eap_teap_parse_pac_tlv(entry, type, pos, len, &pac_key_found);
-
- pos += len;
- left -= len;
- }
-
- if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC TLV does not include all the required fields");
- return -1;
- }
-
- return 0;
-}
-
-
-static int eap_teap_parse_pac_info(struct eap_teap_pac *entry, int type,
- u8 *pos, size_t len)
-{
- u16 pac_type;
- u32 lifetime;
- struct os_time now;
-
- switch (type & 0x7fff) {
- case PAC_TYPE_CRED_LIFETIME:
- if (len != 4) {
- wpa_hexdump(MSG_DEBUG,
- "EAP-TEAP: PAC-Info - Invalid CRED_LIFETIME length - ignored",
- pos, len);
- return 0;
- }
-
- /*
- * This is not currently saved separately in PAC files since
- * the server can automatically initiate PAC update when
- * needed. Anyway, the information is available from PAC-Info
- * dump if it is needed for something in the future.
- */
- lifetime = WPA_GET_BE32(pos);
- os_get_time(&now);
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC-Info - CRED_LIFETIME %d (%d days)",
- lifetime, (lifetime - (u32) now.sec) / 86400);
- break;
- case PAC_TYPE_A_ID:
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - A-ID",
- pos, len);
- entry->a_id = pos;
- entry->a_id_len = len;
- break;
- case PAC_TYPE_I_ID:
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - I-ID",
- pos, len);
- entry->i_id = pos;
- entry->i_id_len = len;
- break;
- case PAC_TYPE_A_ID_INFO:
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - A-ID-Info",
- pos, len);
- entry->a_id_info = pos;
- entry->a_id_info_len = len;
- break;
- case PAC_TYPE_PAC_TYPE:
- /* RFC 7170, Section 4.2.12.6 - PAC-Type TLV */
- if (len != 2) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: Invalid PAC-Type length %lu (expected 2)",
- (unsigned long) len);
- wpa_hexdump_ascii(MSG_DEBUG,
- "EAP-TEAP: PAC-Info - PAC-Type",
- pos, len);
- return -1;
- }
- pac_type = WPA_GET_BE16(pos);
- if (pac_type != PAC_TYPE_TUNNEL_PAC) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: Unsupported PAC Type %d",
- pac_type);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: PAC-Info - PAC-Type %d",
- pac_type);
- entry->pac_type = pac_type;
- break;
- default:
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Ignored unknown PAC-Info type %d", type);
- break;
- }
-
- return 0;
-}
-
-
-static int eap_teap_process_pac_info(struct eap_teap_pac *entry)
-{
- struct pac_attr_hdr *hdr;
- u8 *pos;
- size_t left, len;
- int type;
-
- /* RFC 7170, Section 4.2.12.4 */
-
- /* PAC-Type defaults to Tunnel PAC (Type 1) */
- entry->pac_type = PAC_TYPE_TUNNEL_PAC;
-
- pos = entry->pac_info;
- left = entry->pac_info_len;
- while (left > sizeof(*hdr)) {
- hdr = (struct pac_attr_hdr *) pos;
- type = be_to_host16(hdr->type);
- len = be_to_host16(hdr->len);
- pos += sizeof(*hdr);
- left -= sizeof(*hdr);
- if (len > left) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC-Info overrun (type=%d len=%lu left=%lu)",
- type, (unsigned long) len,
- (unsigned long) left);
- return -1;
- }
-
- if (eap_teap_parse_pac_info(entry, type, pos, len) < 0)
- return -1;
-
- pos += len;
- left -= len;
- }
-
- if (!entry->a_id || !entry->a_id_info) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC-Info does not include all the required fields");
- return -1;
- }
-
- return 0;
-}
-
-
-static struct wpabuf * eap_teap_process_pac(struct eap_sm *sm,
- struct eap_teap_data *data,
- struct eap_method_ret *ret,
- u8 *pac, size_t pac_len)
-{
- struct eap_peer_config *config = eap_get_config(sm);
- struct eap_teap_pac entry;
-
- os_memset(&entry, 0, sizeof(entry));
- if (eap_teap_process_pac_tlv(&entry, pac, pac_len) ||
- eap_teap_process_pac_info(&entry))
- return NULL;
-
- eap_teap_add_pac(&data->pac, &data->current_pac, &entry);
- eap_teap_pac_list_truncate(data->pac, data->max_pac_list_len);
- if (data->use_pac_binary_format)
- eap_teap_save_pac_bin(sm, data->pac, config->pac_file);
- else
- eap_teap_save_pac(sm, data->pac, config->pac_file);
-
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Send PAC-Acknowledgement - %s initiated provisioning completed successfully",
- data->provisioning ? "peer" : "server");
- return eap_teap_tlv_pac_ack();
-}
-
-
static int eap_teap_parse_decrypted(struct wpabuf *decrypted,
struct eap_teap_tlv_parse *tlv,
struct wpabuf **resp)
@@ -1208,38 +862,6 @@
}
-static struct wpabuf * eap_teap_pac_request(void)
-{
- struct wpabuf *req;
- struct teap_tlv_request_action *act;
- struct teap_tlv_hdr *pac;
- struct teap_attr_pac_type *type;
-
- req = wpabuf_alloc(sizeof(*act) + sizeof(*pac) + sizeof(*type));
- if (!req)
- return NULL;
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Request Action TLV (Process TLV)");
- act = wpabuf_put(req, sizeof(*act));
- act->tlv_type = host_to_be16(TEAP_TLV_REQUEST_ACTION);
- act->length = host_to_be16(2);
- act->status = TEAP_STATUS_SUCCESS;
- act->action = TEAP_REQUEST_ACTION_PROCESS_TLV;
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV (PAC-Type = Tunnel)");
- pac = wpabuf_put(req, sizeof(*pac));
- pac->tlv_type = host_to_be16(TEAP_TLV_PAC);
- pac->length = host_to_be16(sizeof(*type));
-
- type = wpabuf_put(req, sizeof(*type));
- type->type = host_to_be16(PAC_TYPE_PAC_TYPE);
- type->length = host_to_be16(2);
- type->pac_type = host_to_be16(PAC_TYPE_TUNNEL_PAC);
-
- return req;
-}
-
-
static int eap_teap_process_decrypted(struct eap_sm *sm,
struct eap_teap_data *data,
struct eap_method_ret *ret,
@@ -1387,58 +1009,17 @@
}
}
- if (data->result_success_done && data->session_ticket_used &&
+ if (data->result_success_done &&
+ tls_connection_get_own_cert_used(data->ssl.conn) &&
eap_teap_derive_msk(data) == 0) {
/* Assume the server might accept authentication without going
* through inner authentication. */
wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC used - server may decide to skip inner authentication");
- ret->methodState = METHOD_MAY_CONT;
- ret->decision = DECISION_COND_SUCC;
- } else if (data->result_success_done &&
- tls_connection_get_own_cert_used(data->ssl.conn) &&
- eap_teap_derive_msk(data) == 0) {
- /* Assume the server might accept authentication without going
- * through inner authentication. */
- wpa_printf(MSG_DEBUG,
"EAP-TEAP: Client certificate used - server may decide to skip inner authentication");
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_COND_SUCC;
}
- if (tlv.pac) {
- if (tlv.result == TEAP_STATUS_SUCCESS) {
- tmp = eap_teap_process_pac(sm, data, ret,
- tlv.pac, tlv.pac_len);
- resp = wpabuf_concat(resp, tmp);
- } else {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC TLV without Result TLV acknowledging success");
- failed = 1;
- error = TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED;
- }
- }
-
- if (!data->current_pac && data->provisioning && !failed && !tlv.pac &&
- tlv.crypto_binding &&
- (!data->anon_provisioning ||
- (data->phase2_success && data->phase2_method &&
- data->phase2_method->vendor == 0 &&
- eap_teap_allowed_anon_prov_cipher_suite(data->tls_cs) &&
- eap_teap_allowed_anon_prov_phase2_method(
- data->phase2_method->vendor,
- data->phase2_method->method))) &&
- (tlv.iresult == TEAP_STATUS_SUCCESS ||
- tlv.result == TEAP_STATUS_SUCCESS)) {
- /*
- * Need to request Tunnel PAC when using authenticated
- * provisioning.
- */
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Request Tunnel PAC");
- tmp = eap_teap_pac_request();
- resp = wpabuf_concat(resp, tmp);
- }
-
done:
if (failed) {
tmp = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0);
@@ -1470,8 +1051,7 @@
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Authentication completed successfully");
ret->methodState = METHOD_MAY_CONT;
- data->on_tx_completion = data->provisioning ?
- METHOD_MAY_CONT : METHOD_DONE;
+ data->on_tx_completion = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
}
@@ -1562,76 +1142,11 @@
}
-static void eap_teap_select_pac(struct eap_teap_data *data,
- const u8 *a_id, size_t a_id_len)
-{
- if (!a_id)
- return;
- data->current_pac = eap_teap_get_pac(data->pac, a_id, a_id_len,
- PAC_TYPE_TUNNEL_PAC);
- if (data->current_pac) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC found for this A-ID (PAC-Type %d)",
- data->current_pac->pac_type);
- wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TEAP: A-ID-Info",
- data->current_pac->a_id_info,
- data->current_pac->a_id_info_len);
- }
-}
-
-
-static int eap_teap_use_pac_opaque(struct eap_sm *sm,
- struct eap_teap_data *data,
- struct eap_teap_pac *pac)
-{
- u8 *tlv;
- size_t tlv_len, olen;
- struct teap_tlv_hdr *ehdr;
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC-Opaque TLS extension");
- olen = pac->pac_opaque_len;
- tlv_len = sizeof(*ehdr) + olen;
- tlv = os_malloc(tlv_len);
- if (tlv) {
- ehdr = (struct teap_tlv_hdr *) tlv;
- ehdr->tlv_type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
- ehdr->length = host_to_be16(olen);
- os_memcpy(ehdr + 1, pac->pac_opaque, olen);
- }
- if (!tlv ||
- tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
- TLS_EXT_PAC_OPAQUE,
- tlv, tlv_len) < 0) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Failed to add PAC-Opaque TLS extension");
- os_free(tlv);
- return -1;
- }
- os_free(tlv);
-
- return 0;
-}
-
-
-static int eap_teap_clear_pac_opaque_ext(struct eap_sm *sm,
- struct eap_teap_data *data)
-{
- if (tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
- TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Failed to remove PAC-Opaque TLS extension");
- return -1;
- }
- return 0;
-}
-
-
static int eap_teap_process_start(struct eap_sm *sm,
struct eap_teap_data *data, u8 flags,
const u8 *pos, size_t left)
{
const u8 *a_id = NULL;
- size_t a_id_len = 0;
/* TODO: Support (mostly theoretical) case of TEAP/Start request being
* fragmented */
@@ -1725,7 +1240,6 @@
return -1;
}
a_id = outer_pos;
- a_id_len = tlv_len;
} else {
wpa_printf(MSG_DEBUG,
"EAP-TEAP: Ignore unknown Outer TLV (Type %u)",
@@ -1740,28 +1254,6 @@
return -1;
}
- eap_teap_select_pac(data, a_id, a_id_len);
-
- if (data->resuming && data->current_pac) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Trying to resume session - do not add PAC-Opaque to TLS ClientHello");
- if (eap_teap_clear_pac_opaque_ext(sm, data) < 0)
- return -1;
- } else if (data->current_pac) {
- /*
- * PAC found for the A-ID and we are not resuming an old
- * session, so add PAC-Opaque extension to ClientHello.
- */
- if (eap_teap_use_pac_opaque(sm, data, data->current_pac) < 0)
- return -1;
- } else if (data->provisioning_allowed) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: No PAC found - starting provisioning");
- if (eap_teap_clear_pac_opaque_ext(sm, data) < 0)
- return -1;
- data->provisioning = 1;
- }
-
return 0;
}
@@ -1939,8 +1431,6 @@
}
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- char cipher[80];
-
wpa_printf(MSG_DEBUG,
"EAP-TEAP: TLS done, proceed to Phase 2");
data->tls_cs =
@@ -1949,19 +1439,6 @@
"EAP-TEAP: TLS cipher suite 0x%04x",
data->tls_cs);
- if (data->provisioning &&
- (!(data->provisioning_allowed &
- EAP_TEAP_PROV_AUTH) ||
- tls_get_cipher(sm->ssl_ctx, data->ssl.conn,
- cipher, sizeof(cipher)) < 0 ||
- os_strstr(cipher, "ADH-") ||
- os_strstr(cipher, "anon"))) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Using anonymous (unauthenticated) provisioning");
- data->anon_provisioning = 1;
- } else {
- data->anon_provisioning = 0;
- }
data->resuming = 0;
if (eap_teap_derive_key_auth(sm, data) < 0) {
wpa_printf(MSG_DEBUG,
@@ -2037,8 +1514,6 @@
data->iresult_verified = 0;
data->done_on_tx_completion = 0;
data->resuming = 1;
- data->provisioning = 0;
- data->anon_provisioning = 0;
data->simck_idx = 0;
return priv;
}
diff --git a/src/eap_peer/eap_teap_pac.c b/src/eap_peer/eap_teap_pac.c
deleted file mode 100644
index 34a2743..0000000
--- a/src/eap_peer/eap_teap_pac.c
+++ /dev/null
@@ -1,931 +0,0 @@
-/*
- * EAP peer method: EAP-TEAP PAC file processing
- * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eap_config.h"
-#include "eap_i.h"
-#include "eap_teap_pac.h"
-
-/* TODO: encrypt PAC-Key in the PAC file */
-
-
-/* Text data format */
-static const char *pac_file_hdr =
- "wpa_supplicant EAP-TEAP PAC file - version 1";
-
-/*
- * Binary data format
- * 4-octet magic value: 6A E4 92 1C
- * 2-octet version (big endian)
- * <version specific data>
- *
- * version=0:
- * Sequence of PAC entries:
- * 2-octet PAC-Type (big endian)
- * 32-octet PAC-Key
- * 2-octet PAC-Opaque length (big endian)
- * <variable len> PAC-Opaque data (length bytes)
- * 2-octet PAC-Info length (big endian)
- * <variable len> PAC-Info data (length bytes)
- */
-
-#define EAP_TEAP_PAC_BINARY_MAGIC 0x6ae4921c
-#define EAP_TEAP_PAC_BINARY_FORMAT_VERSION 0
-
-
-/**
- * eap_teap_free_pac - Free PAC data
- * @pac: Pointer to the PAC entry
- *
- * Note that the PAC entry must not be in a list since this function does not
- * remove the list links.
- */
-void eap_teap_free_pac(struct eap_teap_pac *pac)
-{
- os_free(pac->pac_opaque);
- os_free(pac->pac_info);
- os_free(pac->a_id);
- os_free(pac->i_id);
- os_free(pac->a_id_info);
- os_free(pac);
-}
-
-
-/**
- * eap_teap_get_pac - Get a PAC entry based on A-ID
- * @pac_root: Pointer to root of the PAC list
- * @a_id: A-ID to search for
- * @a_id_len: Length of A-ID
- * @pac_type: PAC-Type to search for
- * Returns: Pointer to the PAC entry, or %NULL if A-ID not found
- */
-struct eap_teap_pac * eap_teap_get_pac(struct eap_teap_pac *pac_root,
- const u8 *a_id, size_t a_id_len,
- u16 pac_type)
-{
- struct eap_teap_pac *pac = pac_root;
-
- while (pac) {
- if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
- os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
- return pac;
- }
- pac = pac->next;
- }
- return NULL;
-}
-
-
-static void eap_teap_remove_pac(struct eap_teap_pac **pac_root,
- struct eap_teap_pac **pac_current,
- const u8 *a_id, size_t a_id_len, u16 pac_type)
-{
- struct eap_teap_pac *pac, *prev;
-
- pac = *pac_root;
- prev = NULL;
-
- while (pac) {
- if (pac->pac_type == pac_type && pac->a_id_len == a_id_len &&
- os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
- if (!prev)
- *pac_root = pac->next;
- else
- prev->next = pac->next;
- if (*pac_current == pac)
- *pac_current = NULL;
- eap_teap_free_pac(pac);
- break;
- }
- prev = pac;
- pac = pac->next;
- }
-}
-
-
-static int eap_teap_copy_buf(u8 **dst, size_t *dst_len,
- const u8 *src, size_t src_len)
-{
- if (src) {
- *dst = os_memdup(src, src_len);
- if (!(*dst))
- return -1;
- *dst_len = src_len;
- }
- return 0;
-}
-
-
-/**
- * eap_teap_add_pac - Add a copy of a PAC entry to a list
- * @pac_root: Pointer to PAC list root pointer
- * @pac_current: Pointer to the current PAC pointer
- * @entry: New entry to clone and add to the list
- * Returns: 0 on success, -1 on failure
- *
- * This function makes a clone of the given PAC entry and adds this copied
- * entry to the list (pac_root). If an old entry for the same A-ID is found,
- * it will be removed from the PAC list and in this case, pac_current entry
- * is set to %NULL if it was the removed entry.
- */
-int eap_teap_add_pac(struct eap_teap_pac **pac_root,
- struct eap_teap_pac **pac_current,
- struct eap_teap_pac *entry)
-{
- struct eap_teap_pac *pac;
-
- if (!entry || !entry->a_id)
- return -1;
-
- /* Remove a possible old entry for the matching A-ID. */
- eap_teap_remove_pac(pac_root, pac_current,
- entry->a_id, entry->a_id_len, entry->pac_type);
-
- /* Allocate a new entry and add it to the list of PACs. */
- pac = os_zalloc(sizeof(*pac));
- if (!pac)
- return -1;
-
- pac->pac_type = entry->pac_type;
- os_memcpy(pac->pac_key, entry->pac_key, EAP_TEAP_PAC_KEY_LEN);
- if (eap_teap_copy_buf(&pac->pac_opaque, &pac->pac_opaque_len,
- entry->pac_opaque, entry->pac_opaque_len) < 0 ||
- eap_teap_copy_buf(&pac->pac_info, &pac->pac_info_len,
- entry->pac_info, entry->pac_info_len) < 0 ||
- eap_teap_copy_buf(&pac->a_id, &pac->a_id_len,
- entry->a_id, entry->a_id_len) < 0 ||
- eap_teap_copy_buf(&pac->i_id, &pac->i_id_len,
- entry->i_id, entry->i_id_len) < 0 ||
- eap_teap_copy_buf(&pac->a_id_info, &pac->a_id_info_len,
- entry->a_id_info, entry->a_id_info_len) < 0) {
- eap_teap_free_pac(pac);
- return -1;
- }
-
- pac->next = *pac_root;
- *pac_root = pac;
-
- return 0;
-}
-
-
-struct eap_teap_read_ctx {
- FILE *f;
- const char *pos;
- const char *end;
- int line;
- char *buf;
- size_t buf_len;
-};
-
-static int eap_teap_read_line(struct eap_teap_read_ctx *rc, char **value)
-{
- char *pos;
-
- rc->line++;
- if (rc->f) {
- if (fgets(rc->buf, rc->buf_len, rc->f) == NULL)
- return -1;
- } else {
- const char *l_end;
- size_t len;
-
- if (rc->pos >= rc->end)
- return -1;
- l_end = rc->pos;
- while (l_end < rc->end && *l_end != '\n')
- l_end++;
- len = l_end - rc->pos;
- if (len >= rc->buf_len)
- len = rc->buf_len - 1;
- os_memcpy(rc->buf, rc->pos, len);
- rc->buf[len] = '\0';
- rc->pos = l_end + 1;
- }
-
- rc->buf[rc->buf_len - 1] = '\0';
- pos = rc->buf;
- while (*pos != '\0') {
- if (*pos == '\n' || *pos == '\r') {
- *pos = '\0';
- break;
- }
- pos++;
- }
-
- pos = os_strchr(rc->buf, '=');
- if (pos)
- *pos++ = '\0';
- *value = pos;
-
- return 0;
-}
-
-
-static u8 * eap_teap_parse_hex(const char *value, size_t *len)
-{
- int hlen;
- u8 *buf;
-
- if (!value)
- return NULL;
- hlen = os_strlen(value);
- if (hlen & 1)
- return NULL;
- *len = hlen / 2;
- buf = os_malloc(*len);
- if (!buf)
- return NULL;
- if (hexstr2bin(value, buf, *len)) {
- os_free(buf);
- return NULL;
- }
- return buf;
-}
-
-
-static int eap_teap_init_pac_data(struct eap_sm *sm, const char *pac_file,
- struct eap_teap_read_ctx *rc)
-{
- os_memset(rc, 0, sizeof(*rc));
-
- rc->buf_len = 2048;
- rc->buf = os_malloc(rc->buf_len);
- if (!rc->buf)
- return -1;
-
- if (os_strncmp(pac_file, "blob://", 7) == 0) {
- const struct wpa_config_blob *blob;
-
- blob = eap_get_config_blob(sm, pac_file + 7);
- if (!blob) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: No PAC blob '%s' - assume no PAC entries have been provisioned",
- pac_file + 7);
- os_free(rc->buf);
- return -1;
- }
- rc->pos = (char *) blob->data;
- rc->end = (char *) blob->data + blob->len;
- } else {
- rc->f = fopen(pac_file, "rb");
- if (!rc->f) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: No PAC file '%s' - assume no PAC entries have been provisioned",
- pac_file);
- os_free(rc->buf);
- return -1;
- }
- }
-
- return 0;
-}
-
-
-static void eap_teap_deinit_pac_data(struct eap_teap_read_ctx *rc)
-{
- os_free(rc->buf);
- if (rc->f)
- fclose(rc->f);
-}
-
-
-static const char * eap_teap_parse_start(struct eap_teap_pac **pac)
-{
- if (*pac)
- return "START line without END";
-
- *pac = os_zalloc(sizeof(struct eap_teap_pac));
- if (!(*pac))
- return "No memory for PAC entry";
- (*pac)->pac_type = PAC_TYPE_TUNNEL_PAC;
- return NULL;
-}
-
-
-static const char * eap_teap_parse_end(struct eap_teap_pac **pac_root,
- struct eap_teap_pac **pac)
-{
- if (!(*pac))
- return "END line without START";
- if (*pac_root) {
- struct eap_teap_pac *end = *pac_root;
-
- while (end->next)
- end = end->next;
- end->next = *pac;
- } else
- *pac_root = *pac;
-
- *pac = NULL;
- return NULL;
-}
-
-
-static const char * eap_teap_parse_pac_type(struct eap_teap_pac *pac,
- char *pos)
-{
- if (!pos)
- return "Cannot parse pac type";
- pac->pac_type = atoi(pos);
- if (pac->pac_type != PAC_TYPE_TUNNEL_PAC)
- return "Unrecognized PAC-Type";
-
- return NULL;
-}
-
-
-static const char * eap_teap_parse_pac_key(struct eap_teap_pac *pac, char *pos)
-{
- u8 *key;
- size_t key_len;
-
- key = eap_teap_parse_hex(pos, &key_len);
- if (!key || key_len != EAP_TEAP_PAC_KEY_LEN) {
- os_free(key);
- return "Invalid PAC-Key";
- }
-
- os_memcpy(pac->pac_key, key, EAP_TEAP_PAC_KEY_LEN);
- os_free(key);
-
- return NULL;
-}
-
-
-static const char * eap_teap_parse_pac_opaque(struct eap_teap_pac *pac,
- char *pos)
-{
- os_free(pac->pac_opaque);
- pac->pac_opaque = eap_teap_parse_hex(pos, &pac->pac_opaque_len);
- if (!pac->pac_opaque)
- return "Invalid PAC-Opaque";
- return NULL;
-}
-
-
-static const char * eap_teap_parse_a_id(struct eap_teap_pac *pac, char *pos)
-{
- os_free(pac->a_id);
- pac->a_id = eap_teap_parse_hex(pos, &pac->a_id_len);
- if (!pac->a_id)
- return "Invalid A-ID";
- return NULL;
-}
-
-
-static const char * eap_teap_parse_i_id(struct eap_teap_pac *pac, char *pos)
-{
- os_free(pac->i_id);
- pac->i_id = eap_teap_parse_hex(pos, &pac->i_id_len);
- if (!pac->i_id)
- return "Invalid I-ID";
- return NULL;
-}
-
-
-static const char * eap_teap_parse_a_id_info(struct eap_teap_pac *pac,
- char *pos)
-{
- os_free(pac->a_id_info);
- pac->a_id_info = eap_teap_parse_hex(pos, &pac->a_id_info_len);
- if (!pac->a_id_info)
- return "Invalid A-ID-Info";
- return NULL;
-}
-
-
-/**
- * eap_teap_load_pac - Load PAC entries (text format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Pointer to root of the PAC list (to be filled)
- * @pac_file: Name of the PAC file/blob to load
- * Returns: 0 on success, -1 on failure
- */
-int eap_teap_load_pac(struct eap_sm *sm, struct eap_teap_pac **pac_root,
- const char *pac_file)
-{
- struct eap_teap_read_ctx rc;
- struct eap_teap_pac *pac = NULL;
- int count = 0;
- char *pos;
- const char *err = NULL;
-
- if (!pac_file)
- return -1;
-
- if (eap_teap_init_pac_data(sm, pac_file, &rc) < 0)
- return 0;
-
- if (eap_teap_read_line(&rc, &pos) < 0) {
- /* empty file - assume it is fine to overwrite */
- eap_teap_deinit_pac_data(&rc);
- return 0;
- }
- if (os_strcmp(pac_file_hdr, rc.buf) != 0)
- err = "Unrecognized header line";
-
- while (!err && eap_teap_read_line(&rc, &pos) == 0) {
- if (os_strcmp(rc.buf, "START") == 0)
- err = eap_teap_parse_start(&pac);
- else if (os_strcmp(rc.buf, "END") == 0) {
- err = eap_teap_parse_end(pac_root, &pac);
- count++;
- } else if (!pac)
- err = "Unexpected line outside START/END block";
- else if (os_strcmp(rc.buf, "PAC-Type") == 0)
- err = eap_teap_parse_pac_type(pac, pos);
- else if (os_strcmp(rc.buf, "PAC-Key") == 0)
- err = eap_teap_parse_pac_key(pac, pos);
- else if (os_strcmp(rc.buf, "PAC-Opaque") == 0)
- err = eap_teap_parse_pac_opaque(pac, pos);
- else if (os_strcmp(rc.buf, "A-ID") == 0)
- err = eap_teap_parse_a_id(pac, pos);
- else if (os_strcmp(rc.buf, "I-ID") == 0)
- err = eap_teap_parse_i_id(pac, pos);
- else if (os_strcmp(rc.buf, "A-ID-Info") == 0)
- err = eap_teap_parse_a_id_info(pac, pos);
- }
-
- if (pac) {
- if (!err)
- err = "PAC block not terminated with END";
- eap_teap_free_pac(pac);
- }
-
- eap_teap_deinit_pac_data(&rc);
-
- if (err) {
- wpa_printf(MSG_INFO, "EAP-TEAP: %s in '%s:%d'",
- err, pac_file, rc.line);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Read %d PAC entries from '%s'",
- count, pac_file);
-
- return 0;
-}
-
-
-static void eap_teap_write(char **buf, char **pos, size_t *buf_len,
- const char *field, const u8 *data,
- size_t len, int txt)
-{
- size_t i, need;
- int ret;
- char *end;
-
- if (!data || !buf || !(*buf) || !pos || !(*pos) || *pos < *buf)
- return;
-
- need = os_strlen(field) + len * 2 + 30;
- if (txt)
- need += os_strlen(field) + len + 20;
-
- if (*pos - *buf + need > *buf_len) {
- char *nbuf = os_realloc(*buf, *buf_len + need);
-
- if (!nbuf) {
- os_free(*buf);
- *buf = NULL;
- return;
- }
- *pos = nbuf + (*pos - *buf);
- *buf = nbuf;
- *buf_len += need;
- }
- end = *buf + *buf_len;
-
- ret = os_snprintf(*pos, end - *pos, "%s=", field);
- if (os_snprintf_error(end - *pos, ret))
- return;
- *pos += ret;
- *pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
- ret = os_snprintf(*pos, end - *pos, "\n");
- if (os_snprintf_error(end - *pos, ret))
- return;
- *pos += ret;
-
- if (txt) {
- ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
- if (os_snprintf_error(end - *pos, ret))
- return;
- *pos += ret;
- for (i = 0; i < len; i++) {
- ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
- if (os_snprintf_error(end - *pos, ret))
- return;
- *pos += ret;
- }
- ret = os_snprintf(*pos, end - *pos, "\n");
- if (os_snprintf_error(end - *pos, ret))
- return;
- *pos += ret;
- }
-}
-
-
-static int eap_teap_write_pac(struct eap_sm *sm, const char *pac_file,
- char *buf, size_t len)
-{
- if (os_strncmp(pac_file, "blob://", 7) == 0) {
- struct wpa_config_blob *blob;
-
- blob = os_zalloc(sizeof(*blob));
- if (!blob)
- return -1;
- blob->data = (u8 *) buf;
- blob->len = len;
- buf = NULL;
- blob->name = os_strdup(pac_file + 7);
- if (!blob->name) {
- os_free(blob);
- return -1;
- }
- eap_set_config_blob(sm, blob);
- } else {
- FILE *f;
-
- f = fopen(pac_file, "wb");
- if (!f) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: Failed to open PAC file '%s' for writing",
- pac_file);
- return -1;
- }
- if (fwrite(buf, 1, len, f) != len) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: Failed to write all PACs into '%s'",
- pac_file);
- fclose(f);
- return -1;
- }
- os_free(buf);
- fclose(f);
- }
-
- return 0;
-}
-
-
-static int eap_teap_add_pac_data(struct eap_teap_pac *pac, char **buf,
- char **pos, size_t *buf_len)
-{
- int ret;
-
- ret = os_snprintf(*pos, *buf + *buf_len - *pos,
- "START\nPAC-Type=%d\n", pac->pac_type);
- if (os_snprintf_error(*buf + *buf_len - *pos, ret))
- return -1;
-
- *pos += ret;
- eap_teap_write(buf, pos, buf_len, "PAC-Key",
- pac->pac_key, EAP_TEAP_PAC_KEY_LEN, 0);
- eap_teap_write(buf, pos, buf_len, "PAC-Opaque",
- pac->pac_opaque, pac->pac_opaque_len, 0);
- eap_teap_write(buf, pos, buf_len, "PAC-Info",
- pac->pac_info, pac->pac_info_len, 0);
- eap_teap_write(buf, pos, buf_len, "A-ID",
- pac->a_id, pac->a_id_len, 0);
- eap_teap_write(buf, pos, buf_len, "I-ID",
- pac->i_id, pac->i_id_len, 1);
- eap_teap_write(buf, pos, buf_len, "A-ID-Info",
- pac->a_id_info, pac->a_id_info_len, 1);
- if (!(*buf)) {
- wpa_printf(MSG_DEBUG, "EAP-TEAP: No memory for PAC data");
- return -1;
- }
- ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
- if (os_snprintf_error(*buf + *buf_len - *pos, ret))
- return -1;
- *pos += ret;
-
- return 0;
-}
-
-
-/**
- * eap_teap_save_pac - Save PAC entries (text format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Root of the PAC list
- * @pac_file: Name of the PAC file/blob
- * Returns: 0 on success, -1 on failure
- */
-int eap_teap_save_pac(struct eap_sm *sm, struct eap_teap_pac *pac_root,
- const char *pac_file)
-{
- struct eap_teap_pac *pac;
- int ret, count = 0;
- char *buf, *pos;
- size_t buf_len;
-
- if (!pac_file)
- return -1;
-
- buf_len = 1024;
- pos = buf = os_malloc(buf_len);
- if (!buf)
- return -1;
-
- ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
- if (os_snprintf_error(buf + buf_len - pos, ret)) {
- os_free(buf);
- return -1;
- }
- pos += ret;
-
- pac = pac_root;
- while (pac) {
- if (eap_teap_add_pac_data(pac, &buf, &pos, &buf_len)) {
- os_free(buf);
- return -1;
- }
- count++;
- pac = pac->next;
- }
-
- if (eap_teap_write_pac(sm, pac_file, buf, pos - buf)) {
- os_free(buf);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Wrote %d PAC entries into '%s'",
- count, pac_file);
-
- return 0;
-}
-
-
-/**
- * eap_teap_pac_list_truncate - Truncate a PAC list to the given length
- * @pac_root: Root of the PAC list
- * @max_len: Maximum length of the list (>= 1)
- * Returns: Number of PAC entries removed
- */
-size_t eap_teap_pac_list_truncate(struct eap_teap_pac *pac_root,
- size_t max_len)
-{
- struct eap_teap_pac *pac, *prev;
- size_t count;
-
- pac = pac_root;
- prev = NULL;
- count = 0;
-
- while (pac) {
- count++;
- if (count > max_len)
- break;
- prev = pac;
- pac = pac->next;
- }
-
- if (count <= max_len || !prev)
- return 0;
-
- count = 0;
- prev->next = NULL;
-
- while (pac) {
- prev = pac;
- pac = pac->next;
- eap_teap_free_pac(prev);
- count++;
- }
-
- return count;
-}
-
-
-static void eap_teap_pac_get_a_id(struct eap_teap_pac *pac)
-{
- u8 *pos, *end;
- u16 type, len;
-
- pos = pac->pac_info;
- end = pos + pac->pac_info_len;
-
- while (end - pos > 4) {
- type = WPA_GET_BE16(pos);
- pos += 2;
- len = WPA_GET_BE16(pos);
- pos += 2;
- if (len > (unsigned int) (end - pos))
- break;
-
- if (type == PAC_TYPE_A_ID) {
- os_free(pac->a_id);
- pac->a_id = os_memdup(pos, len);
- if (!pac->a_id)
- break;
- pac->a_id_len = len;
- }
-
- if (type == PAC_TYPE_A_ID_INFO) {
- os_free(pac->a_id_info);
- pac->a_id_info = os_memdup(pos, len);
- if (!pac->a_id_info)
- break;
- pac->a_id_info_len = len;
- }
-
- pos += len;
- }
-}
-
-
-/**
- * eap_teap_load_pac_bin - Load PAC entries (binary format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Pointer to root of the PAC list (to be filled)
- * @pac_file: Name of the PAC file/blob to load
- * Returns: 0 on success, -1 on failure
- */
-int eap_teap_load_pac_bin(struct eap_sm *sm, struct eap_teap_pac **pac_root,
- const char *pac_file)
-{
- const struct wpa_config_blob *blob = NULL;
- u8 *buf, *end, *pos;
- size_t len, count = 0;
- struct eap_teap_pac *pac, *prev;
-
- *pac_root = NULL;
-
- if (!pac_file)
- return -1;
-
- if (os_strncmp(pac_file, "blob://", 7) == 0) {
- blob = eap_get_config_blob(sm, pac_file + 7);
- if (!blob) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: No PAC blob '%s' - assume no PAC entries have been provisioned",
- pac_file + 7);
- return 0;
- }
- buf = blob->data;
- len = blob->len;
- } else {
- buf = (u8 *) os_readfile(pac_file, &len);
- if (!buf) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: No PAC file '%s' - assume no PAC entries have been provisioned",
- pac_file);
- return 0;
- }
- }
-
- if (len == 0) {
- if (!blob)
- os_free(buf);
- return 0;
- }
-
- if (len < 6 || WPA_GET_BE32(buf) != EAP_TEAP_PAC_BINARY_MAGIC ||
- WPA_GET_BE16(buf + 4) != EAP_TEAP_PAC_BINARY_FORMAT_VERSION) {
- wpa_printf(MSG_INFO, "EAP-TEAP: Invalid PAC file '%s' (bin)",
- pac_file);
- if (!blob)
- os_free(buf);
- return -1;
- }
-
- pac = prev = NULL;
- pos = buf + 6;
- end = buf + len;
- while (pos < end) {
- u16 val;
-
- if (end - pos < 2 + EAP_TEAP_PAC_KEY_LEN + 2 + 2) {
- pac = NULL;
- goto parse_fail;
- }
-
- pac = os_zalloc(sizeof(*pac));
- if (!pac)
- goto parse_fail;
-
- pac->pac_type = WPA_GET_BE16(pos);
- pos += 2;
- os_memcpy(pac->pac_key, pos, EAP_TEAP_PAC_KEY_LEN);
- pos += EAP_TEAP_PAC_KEY_LEN;
- val = WPA_GET_BE16(pos);
- pos += 2;
- if (val > end - pos)
- goto parse_fail;
- pac->pac_opaque_len = val;
- pac->pac_opaque = os_memdup(pos, pac->pac_opaque_len);
- if (!pac->pac_opaque)
- goto parse_fail;
- pos += pac->pac_opaque_len;
- if (end - pos < 2)
- goto parse_fail;
- val = WPA_GET_BE16(pos);
- pos += 2;
- if (val > end - pos)
- goto parse_fail;
- pac->pac_info_len = val;
- pac->pac_info = os_memdup(pos, pac->pac_info_len);
- if (!pac->pac_info)
- goto parse_fail;
- pos += pac->pac_info_len;
- eap_teap_pac_get_a_id(pac);
-
- count++;
- if (prev)
- prev->next = pac;
- else
- *pac_root = pac;
- prev = pac;
- }
-
- if (!blob)
- os_free(buf);
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Read %lu PAC entries from '%s' (bin)",
- (unsigned long) count, pac_file);
-
- return 0;
-
-parse_fail:
- wpa_printf(MSG_INFO, "EAP-TEAP: Failed to parse PAC file '%s' (bin)",
- pac_file);
- if (!blob)
- os_free(buf);
- if (pac)
- eap_teap_free_pac(pac);
- return -1;
-}
-
-
-/**
- * eap_teap_save_pac_bin - Save PAC entries (binary format)
- * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
- * @pac_root: Root of the PAC list
- * @pac_file: Name of the PAC file/blob
- * Returns: 0 on success, -1 on failure
- */
-int eap_teap_save_pac_bin(struct eap_sm *sm, struct eap_teap_pac *pac_root,
- const char *pac_file)
-{
- size_t len, count = 0;
- struct eap_teap_pac *pac;
- u8 *buf, *pos;
-
- len = 6;
- pac = pac_root;
- while (pac) {
- if (pac->pac_opaque_len > 65535 ||
- pac->pac_info_len > 65535)
- return -1;
- len += 2 + EAP_TEAP_PAC_KEY_LEN + 2 + pac->pac_opaque_len +
- 2 + pac->pac_info_len;
- pac = pac->next;
- }
-
- buf = os_malloc(len);
- if (!buf)
- return -1;
-
- pos = buf;
- WPA_PUT_BE32(pos, EAP_TEAP_PAC_BINARY_MAGIC);
- pos += 4;
- WPA_PUT_BE16(pos, EAP_TEAP_PAC_BINARY_FORMAT_VERSION);
- pos += 2;
-
- pac = pac_root;
- while (pac) {
- WPA_PUT_BE16(pos, pac->pac_type);
- pos += 2;
- os_memcpy(pos, pac->pac_key, EAP_TEAP_PAC_KEY_LEN);
- pos += EAP_TEAP_PAC_KEY_LEN;
- WPA_PUT_BE16(pos, pac->pac_opaque_len);
- pos += 2;
- os_memcpy(pos, pac->pac_opaque, pac->pac_opaque_len);
- pos += pac->pac_opaque_len;
- WPA_PUT_BE16(pos, pac->pac_info_len);
- pos += 2;
- os_memcpy(pos, pac->pac_info, pac->pac_info_len);
- pos += pac->pac_info_len;
-
- pac = pac->next;
- count++;
- }
-
- if (eap_teap_write_pac(sm, pac_file, (char *) buf, len)) {
- os_free(buf);
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Wrote %lu PAC entries into '%s' (bin)",
- (unsigned long) count, pac_file);
-
- return 0;
-}
diff --git a/src/eap_peer/eap_teap_pac.h b/src/eap_peer/eap_teap_pac.h
deleted file mode 100644
index edf4c57..0000000
--- a/src/eap_peer/eap_teap_pac.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * EAP peer method: EAP-TEAP PAC file processing
- * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#ifndef EAP_TEAP_PAC_H
-#define EAP_TEAP_PAC_H
-
-#include "eap_common/eap_teap_common.h"
-
-struct eap_teap_pac {
- struct eap_teap_pac *next;
-
- u8 pac_key[EAP_TEAP_PAC_KEY_LEN];
- u8 *pac_opaque;
- size_t pac_opaque_len;
- u8 *pac_info;
- size_t pac_info_len;
- u8 *a_id;
- size_t a_id_len;
- u8 *i_id;
- size_t i_id_len;
- u8 *a_id_info;
- size_t a_id_info_len;
- u16 pac_type;
-};
-
-
-void eap_teap_free_pac(struct eap_teap_pac *pac);
-struct eap_teap_pac * eap_teap_get_pac(struct eap_teap_pac *pac_root,
- const u8 *a_id, size_t a_id_len,
- u16 pac_type);
-int eap_teap_add_pac(struct eap_teap_pac **pac_root,
- struct eap_teap_pac **pac_current,
- struct eap_teap_pac *entry);
-int eap_teap_load_pac(struct eap_sm *sm, struct eap_teap_pac **pac_root,
- const char *pac_file);
-int eap_teap_save_pac(struct eap_sm *sm, struct eap_teap_pac *pac_root,
- const char *pac_file);
-size_t eap_teap_pac_list_truncate(struct eap_teap_pac *pac_root,
- size_t max_len);
-int eap_teap_load_pac_bin(struct eap_sm *sm, struct eap_teap_pac **pac_root,
- const char *pac_file);
-int eap_teap_save_pac_bin(struct eap_sm *sm, struct eap_teap_pac *pac_root,
- const char *pac_file);
-
-#endif /* EAP_TEAP_PAC_H */
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 5594216..c539738 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -184,8 +184,6 @@
/* RFC 7170 requires TLS v1.2 or newer to be used with TEAP */
params->flags |= TLS_CONN_DISABLE_TLSv1_0 |
TLS_CONN_DISABLE_TLSv1_1;
- if (config->teap_anon_dh)
- params->flags |= TLS_CONN_TEAP_ANON_DH;
}
if (data->eap_type == EAP_TYPE_FAST ||
data->eap_type == EAP_TYPE_TEAP ||
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index d965a25..0a987e6 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -199,7 +199,6 @@
*/
int pac_key_refresh_time;
int eap_teap_auth;
- int eap_teap_pac_no_inner;
int eap_teap_separate_result;
enum eap_teap_id {
EAP_TEAP_ID_ALLOW_ANY = 0,
diff --git a/src/eap_server/eap_server_teap.c b/src/eap_server/eap_server_teap.c
index e32c6e4..d624523 100644
--- a/src/eap_server/eap_server_teap.c
+++ b/src/eap_server/eap_server_teap.c
@@ -1,6 +1,6 @@
/*
* EAP-TEAP server (RFC 7170)
- * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2024, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,7 +9,6 @@
#include "includes.h"
#include "common.h"
-#include "crypto/aes_wrap.h"
#include "crypto/tls.h"
#include "crypto/random.h"
#include "eap_common/eap_teap_common.h"
@@ -20,17 +19,11 @@
static void eap_teap_reset(struct eap_sm *sm, void *priv);
-/* Private PAC-Opaque TLV types */
-#define PAC_OPAQUE_TYPE_PAD 0
-#define PAC_OPAQUE_TYPE_KEY 1
-#define PAC_OPAQUE_TYPE_LIFETIME 2
-#define PAC_OPAQUE_TYPE_IDENTITY 3
-
struct eap_teap_data {
struct eap_ssl_data ssl;
enum {
START, PHASE1, PHASE1B, PHASE2_START, PHASE2_ID,
- PHASE2_BASIC_AUTH, PHASE2_METHOD, CRYPTO_BINDING, REQUEST_PAC,
+ PHASE2_BASIC_AUTH, PHASE2_METHOD, CRYPTO_BINDING,
FAILURE_SEND_RESULT, SUCCESS_SEND_RESULT, SUCCESS, FAILURE
} state;
@@ -44,34 +37,29 @@
u8 crypto_binding_nonce[32];
int final_result;
+ u8 simck[EAP_TEAP_SIMCK_LEN];
u8 simck_msk[EAP_TEAP_SIMCK_LEN];
u8 cmk_msk[EAP_TEAP_CMK_LEN];
u8 simck_emsk[EAP_TEAP_SIMCK_LEN];
u8 cmk_emsk[EAP_TEAP_CMK_LEN];
int simck_idx;
- int cmk_emsk_available;
+ bool cmk_emsk_available;
- u8 pac_opaque_encr[16];
u8 *srv_id;
size_t srv_id_len;
char *srv_id_info;
unsigned int basic_auth_not_done:1;
unsigned int inner_eap_not_done:1;
- int anon_provisioning;
int skipped_inner_auth;
- int send_new_pac; /* server triggered re-keying of Tunnel PAC */
struct wpabuf *pending_phase2_resp;
struct wpabuf *server_outer_tlvs;
struct wpabuf *peer_outer_tlvs;
- u8 *identity; /* from PAC-Opaque or client certificate */
+ u8 *identity; /* from client certificate */
size_t identity_len;
int eap_seq;
int tnc_started;
- int pac_key_lifetime;
- int pac_key_refresh_time;
-
enum teap_error_codes error_code;
enum teap_identity_types cur_id_type;
@@ -104,8 +92,6 @@
return "PHASE2_METHOD";
case CRYPTO_BINDING:
return "CRYPTO_BINDING";
- case REQUEST_PAC:
- return "REQUEST_PAC";
case FAILURE_SEND_RESULT:
return "FAILURE_SEND_RESULT";
case SUCCESS_SEND_RESULT:
@@ -137,158 +123,6 @@
}
-static int eap_teap_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
- const u8 *client_random,
- const u8 *server_random,
- u8 *master_secret)
-{
- struct eap_teap_data *data = ctx;
- const u8 *pac_opaque;
- size_t pac_opaque_len;
- u8 *buf, *pos, *end, *pac_key = NULL;
- os_time_t lifetime = 0;
- struct os_time now;
- u8 *identity = NULL;
- size_t identity_len = 0;
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: SessionTicket callback");
- wpa_hexdump(MSG_DEBUG, "EAP-TEAP: SessionTicket (PAC-Opaque)",
- ticket, len);
-
- if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) {
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Ignore invalid SessionTicket");
- return 0;
- }
-
- pac_opaque_len = WPA_GET_BE16(ticket + 2);
- pac_opaque = ticket + 4;
- if (pac_opaque_len < 8 || pac_opaque_len % 8 ||
- pac_opaque_len > len - 4) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Ignore invalid PAC-Opaque (len=%lu left=%lu)",
- (unsigned long) pac_opaque_len,
- (unsigned long) len);
- return 0;
- }
- wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Received PAC-Opaque",
- pac_opaque, pac_opaque_len);
-
- buf = os_malloc(pac_opaque_len - 8);
- if (!buf) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Failed to allocate memory for decrypting PAC-Opaque");
- return 0;
- }
-
- if (aes_unwrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
- (pac_opaque_len - 8) / 8, pac_opaque, buf) < 0) {
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Failed to decrypt PAC-Opaque");
- os_free(buf);
- /*
- * This may have been caused by server changing the PAC-Opaque
- * encryption key, so just ignore this PAC-Opaque instead of
- * failing the authentication completely. Provisioning can now
- * be used to provision a new PAC.
- */
- return 0;
- }
-
- end = buf + pac_opaque_len - 8;
- wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Decrypted PAC-Opaque",
- buf, end - buf);
-
- pos = buf;
- while (end - pos > 1) {
- u8 id, elen;
-
- id = *pos++;
- elen = *pos++;
- if (elen > end - pos)
- break;
-
- switch (id) {
- case PAC_OPAQUE_TYPE_PAD:
- goto done;
- case PAC_OPAQUE_TYPE_KEY:
- if (elen != EAP_TEAP_PAC_KEY_LEN) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Invalid PAC-Key length %d",
- elen);
- os_free(buf);
- return -1;
- }
- pac_key = pos;
- wpa_hexdump_key(MSG_DEBUG,
- "EAP-TEAP: PAC-Key from decrypted PAC-Opaque",
- pac_key, EAP_TEAP_PAC_KEY_LEN);
- break;
- case PAC_OPAQUE_TYPE_LIFETIME:
- if (elen != 4) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Invalid PAC-Key lifetime length %d",
- elen);
- os_free(buf);
- return -1;
- }
- lifetime = WPA_GET_BE32(pos);
- break;
- case PAC_OPAQUE_TYPE_IDENTITY:
- identity = pos;
- identity_len = elen;
- break;
- }
-
- pos += elen;
- }
-done:
-
- if (!pac_key) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: No PAC-Key included in PAC-Opaque");
- os_free(buf);
- return -1;
- }
-
- if (identity) {
- wpa_hexdump_ascii(MSG_DEBUG,
- "EAP-TEAP: Identity from PAC-Opaque",
- identity, identity_len);
- os_free(data->identity);
- data->identity = os_malloc(identity_len);
- if (data->identity) {
- os_memcpy(data->identity, identity, identity_len);
- data->identity_len = identity_len;
- }
- }
-
- if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC-Key not valid anymore (lifetime=%ld now=%ld)",
- lifetime, now.sec);
- data->send_new_pac = 2;
- /*
- * Allow PAC to be used to allow a PAC update with some level
- * of server authentication (i.e., do not fall back to full TLS
- * handshake since we cannot be sure that the peer would be
- * able to validate server certificate now). However, reject
- * the authentication since the PAC was not valid anymore. Peer
- * can connect again with the newly provisioned PAC after this.
- */
- } else if (lifetime - now.sec < data->pac_key_refresh_time) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC-Key soft timeout; send an update if authentication succeeds");
- data->send_new_pac = 1;
- }
-
- /* EAP-TEAP uses PAC-Key as the TLS master_secret */
- os_memcpy(master_secret, pac_key, EAP_TEAP_PAC_KEY_LEN);
-
- os_free(buf);
-
- return 1;
-}
-
-
static int eap_teap_derive_key_auth(struct eap_sm *sm,
struct eap_teap_data *data)
{
@@ -297,13 +131,14 @@
/* RFC 7170, Section 5.1 */
res = tls_connection_export_key(sm->cfg->ssl_ctx, data->ssl.conn,
TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0,
- data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ data->simck, EAP_TEAP_SIMCK_LEN);
if (res)
return res;
wpa_hexdump_key(MSG_DEBUG,
"EAP-TEAP: session_key_seed (S-IMCK[0])",
- data->simck_msk, EAP_TEAP_SIMCK_LEN);
- os_memcpy(data->simck_emsk, data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ data->simck, EAP_TEAP_SIMCK_LEN);
+ os_memcpy(data->simck_msk, data->simck, EAP_TEAP_SIMCK_LEN);
+ os_memcpy(data->simck_emsk, data->simck, EAP_TEAP_SIMCK_LEN);
data->simck_idx = 0;
return 0;
}
@@ -319,9 +154,7 @@
data->simck_idx + 1);
if (sm->cfg->eap_teap_auth == 1)
- return eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
- data->simck_msk,
- data->cmk_msk);
+ goto out; /* no MSK derived in Basic-Password-Auth */
if (!data->phase2_method || !data->phase2_priv) {
wpa_printf(MSG_INFO, "EAP-TEAP: Phase 2 method not available");
@@ -343,8 +176,8 @@
&emsk_len);
}
- res = eap_teap_derive_imck(data->tls_cs,
- data->simck_msk, data->simck_emsk,
+out:
+ res = eap_teap_derive_imck(data->tls_cs, data->simck,
msk, msk_len, emsk, emsk_len,
data->simck_msk, data->cmk_msk,
data->simck_emsk, data->cmk_emsk);
@@ -352,8 +185,7 @@
bin_clear_free(emsk, emsk_len);
if (res == 0) {
data->simck_idx++;
- if (emsk)
- data->cmk_emsk_available = 1;
+ data->cmk_emsk_available = emsk != NULL;
}
return 0;
}
@@ -377,28 +209,6 @@
return NULL;
}
- /* TODO: Add anon-DH TLS cipher suites (and if one is negotiated,
- * enforce inner EAP with mutual authentication to be used) */
-
- if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx,
- data->ssl.conn,
- eap_teap_session_ticket_cb,
- data) < 0) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: Failed to set SessionTicket callback");
- eap_teap_reset(sm, data);
- return NULL;
- }
-
- if (!sm->cfg->pac_opaque_encr_key) {
- wpa_printf(MSG_INFO,
- "EAP-TEAP: No PAC-Opaque encryption key configured");
- eap_teap_reset(sm, data);
- return NULL;
- }
- os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key,
- sizeof(data->pac_opaque_encr));
-
if (!sm->cfg->eap_fast_a_id) {
wpa_printf(MSG_INFO, "EAP-TEAP: No A-ID configured");
eap_teap_reset(sm, data);
@@ -424,16 +234,6 @@
return NULL;
}
- /* PAC-Key lifetime in seconds (hard limit) */
- data->pac_key_lifetime = sm->cfg->pac_key_lifetime;
-
- /*
- * PAC-Key refresh time in seconds (soft limit on remaining hard
- * limit). The server will generate a new PAC-Key when this number of
- * seconds (or fewer) of the lifetime remains.
- */
- data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time;
-
return data;
}
@@ -457,7 +257,6 @@
forced_memzero(data->simck_emsk, EAP_TEAP_SIMCK_LEN);
forced_memzero(data->cmk_msk, EAP_TEAP_CMK_LEN);
forced_memzero(data->cmk_emsk, EAP_TEAP_CMK_LEN);
- forced_memzero(data->pac_opaque_encr, sizeof(data->pac_opaque_encr));
bin_clear_free(data, sizeof(*data));
}
@@ -504,8 +303,6 @@
static int eap_teap_phase1_done(struct eap_sm *sm, struct eap_teap_data *data)
{
- char cipher[64];
-
wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 1 done, starting Phase 2");
if (!data->identity && sm->cfg->eap_teap_auth == 2) {
@@ -525,18 +322,6 @@
wpa_printf(MSG_DEBUG, "EAP-TEAP: TLS cipher suite 0x%04x",
data->tls_cs);
- if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn,
- cipher, sizeof(cipher)) < 0) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Failed to get cipher information");
- eap_teap_state(data, FAILURE);
- return -1;
- }
- data->anon_provisioning = os_strstr(cipher, "ADH") != NULL;
-
- if (data->anon_provisioning)
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Anonymous provisioning");
-
if (eap_teap_derive_key_auth(sm, data) < 0) {
eap_teap_state(data, FAILURE);
return -1;
@@ -626,8 +411,7 @@
if (!buf)
return NULL;
- if (data->send_new_pac || data->anon_provisioning ||
- data->basic_auth_not_done || data->inner_eap_not_done ||
+ if (data->basic_auth_not_done || data->inner_eap_not_done ||
data->phase2_method || sm->cfg->eap_teap_separate_result)
data->final_result = 0;
else
@@ -663,8 +447,6 @@
cb->length = host_to_be16(sizeof(*cb) - sizeof(struct teap_tlv_hdr));
cb->version = EAP_TEAP_VERSION;
cb->received_version = data->peer_version;
- /* FIX: RFC 7170 is not clear on which Flags value to use when
- * Crypto-Binding TLV is used with Basic-Password-Auth */
flags = data->cmk_emsk_available ?
TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC :
TEAP_CRYPTO_BINDING_MSK_CMAC;
@@ -714,144 +496,6 @@
}
-static struct wpabuf * eap_teap_build_pac(struct eap_sm *sm,
- struct eap_teap_data *data)
-{
- u8 pac_key[EAP_TEAP_PAC_KEY_LEN];
- u8 *pac_buf, *pac_opaque;
- struct wpabuf *buf;
- u8 *pos;
- size_t buf_len, srv_id_info_len, pac_len;
- struct teap_tlv_hdr *pac_tlv;
- struct pac_attr_hdr *pac_info;
- struct teap_tlv_result *result;
- struct os_time now;
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Build a new PAC");
-
- if (random_get_bytes(pac_key, EAP_TEAP_PAC_KEY_LEN) < 0 ||
- os_get_time(&now) < 0)
- return NULL;
- wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Generated PAC-Key",
- pac_key, EAP_TEAP_PAC_KEY_LEN);
-
- pac_len = (2 + EAP_TEAP_PAC_KEY_LEN) + (2 + 4) +
- (2 + sm->identity_len) + 8;
- pac_buf = os_malloc(pac_len);
- if (!pac_buf)
- return NULL;
-
- srv_id_info_len = os_strlen(data->srv_id_info);
-
- pos = pac_buf;
- *pos++ = PAC_OPAQUE_TYPE_KEY;
- *pos++ = EAP_TEAP_PAC_KEY_LEN;
- os_memcpy(pos, pac_key, EAP_TEAP_PAC_KEY_LEN);
- pos += EAP_TEAP_PAC_KEY_LEN;
-
- wpa_printf(MSG_DEBUG, "EAP-TEAP: PAC-Key lifetime: %u seconds",
- data->pac_key_lifetime);
- *pos++ = PAC_OPAQUE_TYPE_LIFETIME;
- *pos++ = 4;
- WPA_PUT_BE32(pos, now.sec + data->pac_key_lifetime);
- pos += 4;
-
- if (sm->identity) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Opaque Identity",
- sm->identity, sm->identity_len);
- *pos++ = PAC_OPAQUE_TYPE_IDENTITY;
- *pos++ = sm->identity_len;
- os_memcpy(pos, sm->identity, sm->identity_len);
- pos += sm->identity_len;
- }
-
- pac_len = pos - pac_buf;
- while (pac_len % 8) {
- *pos++ = PAC_OPAQUE_TYPE_PAD;
- pac_len++;
- }
-
- pac_opaque = os_malloc(pac_len + 8);
- if (!pac_opaque) {
- os_free(pac_buf);
- return NULL;
- }
- if (aes_wrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr),
- pac_len / 8, pac_buf, pac_opaque) < 0) {
- os_free(pac_buf);
- os_free(pac_opaque);
- return NULL;
- }
- os_free(pac_buf);
-
- pac_len += 8;
- wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Opaque", pac_opaque, pac_len);
-
- buf_len = sizeof(*pac_tlv) +
- sizeof(struct pac_attr_hdr) + EAP_TEAP_PAC_KEY_LEN +
- sizeof(struct pac_attr_hdr) + pac_len +
- data->srv_id_len + srv_id_info_len + 100 + sizeof(*result);
- buf = wpabuf_alloc(buf_len);
- if (!buf) {
- os_free(pac_opaque);
- return NULL;
- }
-
- /* Result TLV */
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Result TLV (status=SUCCESS)");
- result = wpabuf_put(buf, sizeof(*result));
- WPA_PUT_BE16((u8 *) &result->tlv_type,
- TEAP_TLV_MANDATORY | TEAP_TLV_RESULT);
- WPA_PUT_BE16((u8 *) &result->length, 2);
- WPA_PUT_BE16((u8 *) &result->status, TEAP_STATUS_SUCCESS);
-
- /* PAC TLV */
- wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV");
- pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv));
- pac_tlv->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | TEAP_TLV_PAC);
-
- /* PAC-Key */
- eap_teap_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_TEAP_PAC_KEY_LEN);
-
- /* PAC-Opaque */
- eap_teap_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len);
- os_free(pac_opaque);
-
- /* PAC-Info */
- pac_info = wpabuf_put(buf, sizeof(*pac_info));
- pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO);
-
- /* PAC-Lifetime (inside PAC-Info) */
- eap_teap_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4);
- wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime);
-
- /* A-ID (inside PAC-Info) */
- eap_teap_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len);
-
- /* Note: headers may be misaligned after A-ID */
-
- if (sm->identity) {
- eap_teap_put_tlv(buf, PAC_TYPE_I_ID, sm->identity,
- sm->identity_len);
- }
-
- /* A-ID-Info (inside PAC-Info) */
- eap_teap_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info,
- srv_id_info_len);
-
- /* PAC-Type (inside PAC-Info) */
- eap_teap_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2);
- wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC);
-
- /* Update PAC-Info and PAC TLV Length fields */
- pos = wpabuf_put(buf, 0);
- pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1));
- pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1));
-
- return buf;
-}
-
-
static int eap_teap_encrypt_phase2(struct eap_sm *sm,
struct eap_teap_data *data,
struct wpabuf *plain, int piggyback)
@@ -976,9 +620,6 @@
eap_teap_state(data, PHASE2_METHOD);
}
break;
- case REQUEST_PAC:
- req = eap_teap_build_pac(sm, data);
- break;
case FAILURE_SEND_RESULT:
req = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0);
if (data->error_code)
@@ -1166,18 +807,9 @@
}
eap_teap_state(data, PHASE2_METHOD);
- if (data->anon_provisioning) {
- /* TODO: Allow any inner EAP method that provides
- * mutual authentication and EMSK derivation (i.e.,
- * EAP-pwd or EAP-EKE). */
- next_vendor = EAP_VENDOR_IETF;
- next_type = EAP_TYPE_PWD;
- sm->user_eap_method_index = 0;
- } else {
- next_vendor = sm->user->methods[0].vendor;
- next_type = sm->user->methods[0].method;
- sm->user_eap_method_index = 1;
- }
+ next_vendor = sm->user->methods[0].vendor;
+ next_type = sm->user->methods[0].method;
+ sm->user_eap_method_index = 1;
wpa_printf(MSG_DEBUG, "EAP-TEAP: Try EAP type %u:%u",
next_vendor, next_type);
break;
@@ -1509,25 +1141,23 @@
return -1;
}
+ if (data->cmk_emsk_available &&
+ (flags == TEAP_CRYPTO_BINDING_EMSK_CMAC ||
+ flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC)) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Selected S-IMCK_EMSK");
+ os_memcpy(data->simck, data->simck_emsk, EAP_TEAP_SIMCK_LEN);
+ } else if (flags == TEAP_CRYPTO_BINDING_MSK_CMAC ||
+ flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) {
+ wpa_printf(MSG_DEBUG, "EAP-TEAP: Selected S-IMCK_EMSK");
+ os_memcpy(data->simck, data->simck_msk, EAP_TEAP_SIMCK_LEN);
+ }
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: Selected S-IMCK[j]",
+ data->simck, EAP_TEAP_SIMCK_LEN);
+
return 0;
}
-static int eap_teap_pac_type(u8 *pac, size_t len, u16 type)
-{
- struct teap_attr_pac_type *tlv;
-
- if (!pac || len != sizeof(*tlv))
- return 0;
-
- tlv = (struct teap_attr_pac_type *) pac;
-
- return be_to_host16(tlv->type) == PAC_TYPE_PAC_TYPE &&
- be_to_host16(tlv->length) == 2 &&
- be_to_host16(tlv->pac_type) == type;
-}
-
-
static void eap_teap_process_phase2_tlvs(struct eap_sm *sm,
struct eap_teap_data *data,
struct wpabuf *in_data)
@@ -1556,34 +1186,6 @@
return;
}
- if (data->state == REQUEST_PAC) {
- u16 type, len, res;
-
- if (!tlv.pac || tlv.pac_len < 6) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: No PAC Acknowledgement received");
- eap_teap_state(data, FAILURE);
- return;
- }
-
- type = WPA_GET_BE16(tlv.pac);
- len = WPA_GET_BE16(tlv.pac + 2);
- res = WPA_GET_BE16(tlv.pac + 4);
-
- if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 ||
- res != TEAP_STATUS_SUCCESS) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC TLV did not contain acknowledgement");
- eap_teap_state(data, FAILURE);
- return;
- }
-
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: PAC-Acknowledgement received - PAC provisioning succeeded");
- eap_teap_state(data, SUCCESS);
- return;
- }
-
if (check_crypto_binding) {
if (!tlv.crypto_binding) {
wpa_printf(MSG_DEBUG,
@@ -1623,42 +1225,10 @@
"EAP-TEAP: Authentication completed successfully");
}
- if (data->anon_provisioning &&
- sm->cfg->eap_fast_prov != ANON_PROV &&
- sm->cfg->eap_fast_prov != BOTH_PROV) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Client is trying to use unauthenticated provisioning which is disabled");
- eap_teap_state(data, FAILURE);
- return;
- }
-
- if (sm->cfg->eap_fast_prov != AUTH_PROV &&
- sm->cfg->eap_fast_prov != BOTH_PROV &&
- tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV &&
- eap_teap_pac_type(tlv.pac, tlv.pac_len,
- PAC_TYPE_TUNNEL_PAC)) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Client is trying to use authenticated provisioning which is disabled");
- eap_teap_state(data, FAILURE);
- return;
- }
-
- if (data->anon_provisioning ||
- (tlv.request_action == TEAP_REQUEST_ACTION_PROCESS_TLV &&
- eap_teap_pac_type(tlv.pac, tlv.pac_len,
- PAC_TYPE_TUNNEL_PAC))) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Requested a new Tunnel PAC");
- eap_teap_state(data, REQUEST_PAC);
- } else if (data->send_new_pac) {
- wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Server triggered re-keying of Tunnel PAC");
- eap_teap_state(data, REQUEST_PAC);
- } else if (data->final_result) {
+ if (data->final_result)
eap_teap_state(data, SUCCESS);
- } else if (sm->cfg->eap_teap_separate_result) {
+ else if (sm->cfg->eap_teap_separate_result)
eap_teap_state(data, SUCCESS_SEND_RESULT);
- }
}
if (tlv.basic_auth_resp) {
@@ -1810,7 +1380,7 @@
enum eap_type next_type;
if (data->identity) {
- /* Used PAC and identity is from PAC-Opaque */
+ /* Identity is from client certificate */
os_free(sm->identity);
sm->identity = data->identity;
data->identity = NULL;
@@ -1823,17 +1393,16 @@
next_vendor = EAP_VENDOR_IETF;
next_type = EAP_TYPE_NONE;
eap_teap_state(data, PHASE2_METHOD);
- } else if (sm->cfg->eap_teap_pac_no_inner ||
- sm->cfg->eap_teap_auth == 2) {
+ } else if (sm->cfg->eap_teap_auth == 2) {
wpa_printf(MSG_DEBUG,
- "EAP-TEAP: Used PAC or client certificate and identity already known - skip inner auth");
+ "EAP-TEAP: Used client certificate and identity already known - skip inner auth");
data->skipped_inner_auth = 1;
- /* FIX: Need to derive CMK here. However, how is that
- * supposed to be done? RFC 7170 does not tell that for
- * the no-inner-auth case. */
- eap_teap_derive_cmk_basic_pw_auth(data->tls_cs,
- data->simck_msk,
- data->cmk_msk);
+ if (eap_teap_derive_imck(data->tls_cs, data->simck,
+ NULL, 0, NULL, 0,
+ data->simck_msk, data->cmk_msk,
+ data->simck_emsk,
+ data->cmk_emsk))
+ return -1;
eap_teap_state(data, CRYPTO_BINDING);
return 1;
} else if (sm->cfg->eap_teap_auth == 1) {
@@ -1880,7 +1449,6 @@
case PHASE2_BASIC_AUTH:
case PHASE2_METHOD:
case CRYPTO_BINDING:
- case REQUEST_PAC:
case SUCCESS_SEND_RESULT:
eap_teap_process_phase2(sm, data, data->ssl.tls_in);
break;
@@ -2043,9 +1611,7 @@
if (!eapKeyData)
return NULL;
- /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
- * is used in this derivation */
- if (eap_teap_derive_eap_msk(data->tls_cs, data->simck_msk,
+ if (eap_teap_derive_eap_msk(data->tls_cs, data->simck,
eapKeyData) < 0) {
os_free(eapKeyData);
return NULL;
@@ -2068,9 +1634,7 @@
if (!eapKeyData)
return NULL;
- /* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
- * is used in this derivation */
- if (eap_teap_derive_eap_emsk(data->tls_cs, data->simck_msk,
+ if (eap_teap_derive_eap_emsk(data->tls_cs, data->simck,
eapKeyData) < 0) {
os_free(eapKeyData);
return NULL;
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index f3742ea..0bc6f0d 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -247,8 +247,16 @@
peer->go_neg_conf = NULL;
p2p->go_neg_peer = NULL;
+#ifdef CONFIG_PASN
+ if (peer->p2p2 && peer->pasn)
+ wpa_pasn_reset(peer->pasn);
+ os_memset(p2p->dev_sae_password, 0, sizeof(p2p->dev_sae_password));
+ os_memset(p2p->peer_sae_password, 0, sizeof(p2p->peer_sae_password));
+#endif /* CONFIG_PASN */
+
os_memset(&res, 0, sizeof(res));
res.status = status;
+ res.p2p2 = peer->p2p2;
os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
@@ -962,6 +970,16 @@
}
os_free(dev->bootstrap_params);
+
+ wpabuf_free(dev->action_frame_wrapper);
+
+#ifdef CONFIG_PASN
+ if (dev->pasn) {
+ wpa_pasn_reset(dev->pasn);
+ pasn_data_deinit(dev->pasn);
+ }
+#endif /* CONFIG_PASN */
+
wpabuf_free(dev->info.wfd_subelems);
wpabuf_free(dev->info.vendor_elems);
wpabuf_free(dev->go_neg_conf);
@@ -1850,10 +1868,27 @@
params->passphrase[p2p->cfg->passphrase_len] = '\0';
}
p2p->passphrase_set = 0;
+ params->cipher = WPA_CIPHER_CCMP;
+ if (p2p->cfg->pairing_config.pasn_type & 0xc)
+ params->cipher |= WPA_CIPHER_GCMP_256;
+
+ if (params->p2p2) {
+ os_strlcpy(p2p->dev_sae_password, params->passphrase,
+ sizeof(p2p->dev_sae_password));
+ os_strlcpy(params->sae_password, p2p->dev_sae_password,
+ sizeof(params->sae_password));
+ }
+
return 0;
}
+void p2p_set_go_role(struct p2p_data *p2p, bool val)
+{
+ p2p->go_role = val;
+}
+
+
void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
{
struct p2p_go_neg_results res;
@@ -1915,8 +1950,57 @@
wpabuf_free(peer->go_neg_conf);
peer->go_neg_conf = NULL;
- p2p_set_state(p2p, P2P_PROVISIONING);
- p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
+#ifdef CONFIG_PASN
+ if (peer->p2p2 && peer->pasn) {
+ res.p2p2 = peer->p2p2;
+ res.akmp = peer->pasn->akmp;
+ res.cipher = peer->pasn->cipher;
+
+ if (res.akmp == WPA_KEY_MGMT_PASN) {
+ if (go) {
+ os_strlcpy(res.sae_password,
+ p2p->dev_sae_password,
+ sizeof(res.sae_password));
+ } else {
+ if (!os_strlen(p2p->peer_sae_password)) {
+ p2p_dbg(p2p, "No password from peer GO for P2P2 group formation");
+ return;
+ }
+ os_strlcpy(res.sae_password,
+ p2p->peer_sae_password,
+ sizeof(res.sae_password));
+ }
+ } else if (res.akmp == WPA_KEY_MGMT_SAE) {
+ if (peer->role == P2P_ROLE_PAIRING_INITIATOR) {
+ pasn_initiator_pmksa_cache_get(
+ peer->pasn->pmksa,
+ peer->pasn->peer_addr,
+ res.pmkid, res.pmk, &res.pmk_len);
+ } else {
+ pasn_responder_pmksa_cache_get(
+ peer->pasn->pmksa,
+ peer->pasn->peer_addr,
+ res.pmkid, res.pmk, &res.pmk_len);
+ }
+ }
+
+ os_memset(p2p->dev_sae_password, 0,
+ sizeof(p2p->dev_sae_password));
+ os_memset(p2p->peer_sae_password, 0,
+ sizeof(p2p->peer_sae_password));
+ wpa_pasn_reset(peer->pasn);
+ }
+#endif /* CONFIG_PASN */
+
+ if (p2p->go_role && peer->p2p2) {
+ p2p->cfg->set_go_security_config(p2p->cfg->cb_ctx, &res);
+ p2p->go_role = false;
+ } else {
+ p2p_set_state(p2p, P2P_PROVISIONING);
+ p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
+ }
+
+ forced_memzero(&res, sizeof(res));
}
@@ -2998,6 +3082,13 @@
}
+void p2p_set_dev_addr(struct p2p_data *p2p, const u8 *addr)
+{
+ if (p2p && addr)
+ os_memcpy(p2p->cfg->dev_addr, addr, ETH_ALEN);
+}
+
+
static void p2p_pairing_info_deinit(struct p2p_data *p2p)
{
#ifdef CONFIG_PASN
@@ -3032,8 +3123,10 @@
os_memcpy(pairing_info->dev_ik.dik_data,
p2p->cfg->pairing_config.dik_data,
p2p->cfg->pairing_config.dik_len);
+ pairing_info->dev_ik.expiration = 24; /* hours */
p2p_pairing_info_deinit(p2p);
+
p2p->pairing_info = pairing_info;
#ifdef CONFIG_PASN
p2p->initiator_pmksa = pasn_initiator_pmksa_cache_init();
@@ -3928,7 +4021,7 @@
p2p_invitation_req_cb(p2p, success);
break;
case P2P_PENDING_INVITATION_RESPONSE:
- p2p_invitation_resp_cb(p2p, success);
+ p2p_invitation_resp_cb(p2p, dst, success);
break;
case P2P_PENDING_DEV_DISC_REQUEST:
p2p_dev_disc_req_cb(p2p, success);
@@ -4228,7 +4321,7 @@
p2p->cfg->invitation_result(
p2p->cfg->cb_ctx, -1, NULL, NULL,
p2p->invite_peer->info.p2p_device_addr,
- 0, 0);
+ 0, 0, NULL, NULL, 0);
}
p2p_set_state(p2p, P2P_IDLE);
}
@@ -4868,6 +4961,108 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+
+void p2p_set_pairing_setup(struct p2p_data *p2p, int pairing_setup)
+{
+ p2p_dbg(p2p, "Pairing Setup %s",
+ pairing_setup ? "Enabled" : "Disabled");
+ if (pairing_setup) {
+ p2p->cfg->pairing_config.pairing_capable = true;
+ p2p->cfg->pairing_config.enable_pairing_setup = true;
+ if (p2p->pairing_info)
+ p2p->pairing_info->enable_pairing_setup = true;
+ } else {
+ p2p->cfg->pairing_config.pairing_capable = false;
+ p2p->cfg->pairing_config.enable_pairing_setup = false;
+ if (p2p->pairing_info)
+ p2p->pairing_info->enable_pairing_setup = false;
+ }
+}
+
+
+void p2p_set_pairing_cache(struct p2p_data *p2p, int pairing_cache)
+{
+ p2p_dbg(p2p, "Pairing Cache %s",
+ pairing_cache ? "Enabled" : "Disabled");
+ if (pairing_cache) {
+ p2p->cfg->pairing_config.enable_pairing_cache = true;
+ if (p2p->pairing_info)
+ p2p->pairing_info->enable_pairing_cache = true;
+ } else {
+ p2p->cfg->pairing_config.enable_pairing_cache = false;
+ if (p2p->pairing_info)
+ p2p->pairing_info->enable_pairing_cache = false;
+ }
+}
+
+
+void p2p_set_bootstrapmethods(struct p2p_data *p2p, int bootstrap_methods)
+{
+ p2p_dbg(p2p, "Bootstraping methods: 0x%x", bootstrap_methods);
+ p2p->cfg->pairing_config.bootstrap_methods = bootstrap_methods;
+ if (p2p->pairing_info)
+ p2p->pairing_info->supported_bootstrap = bootstrap_methods;
+}
+
+
+void p2p_set_pasn_type(struct p2p_data *p2p, u8 pasn_type)
+{
+ p2p_dbg(p2p, "PASN type: 0x%x", pasn_type);
+ p2p->cfg->pairing_config.pasn_type = pasn_type;
+}
+
+
+void p2p_set_comeback_after(struct p2p_data *p2p, int comeback_after)
+{
+ p2p_dbg(p2p, "Comeback after: %d", comeback_after);
+ p2p->cfg->comeback_after = comeback_after;
+}
+
+
+void p2p_set_reg_info(struct p2p_data *p2p, u8 val)
+{
+ p2p->cfg->reg_info = val;
+}
+
+
+void p2p_set_twt_power_mgmt(struct p2p_data *p2p, int val)
+{
+ p2p_dbg(p2p, "TWT-based P2P Power Mgmt: %s",
+ val ? "Enabled" : "Disabled");
+ if (val)
+ p2p->cfg->twt_power_mgmt = true;
+ else
+ p2p->cfg->twt_power_mgmt = false;
+}
+
+
+void p2p_set_chan_switch_req_enable(struct p2p_data *p2p, bool val)
+{
+ p2p->cfg->chan_switch_req_enable = val;
+}
+
+
+void p2p_set_invitation_op_freq(struct p2p_data *p2p, int freq)
+{
+ u8 op_class, channel;
+
+ if (freq == -1) {
+ p2p->cfg->inv_op_class = 0;
+ p2p->cfg->inv_op_channel = 0;
+ return;
+ }
+
+ if (p2p_freq_to_channel(freq, &op_class, &channel) < 0)
+ return;
+
+ p2p->cfg->inv_op_class = op_class;
+ p2p->cfg->inv_op_channel = channel;
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class,
u8 *op_channel,
struct wpa_freq_range_list *avoid_list,
@@ -5026,6 +5221,28 @@
}
+int p2p_get_dev_identity_key(struct p2p_data *p2p, const u8 *dev_addr,
+ const u8 **dik_data, size_t *dik_len, u8 *cipher)
+{
+ if (!p2p || !p2p->peer_dik_len) {
+ wpa_printf(MSG_DEBUG,
+ "P2P2: Failed to get device identity key for "
+ MACSTR, MAC2STR(dev_addr));
+ return -1;
+ }
+
+ *dik_data = p2p->peer_dik_data;
+ *dik_len = p2p->peer_dik_len;
+ *cipher = p2p->dik_cipher_version;
+
+ /* Reset DIK length to invalidate DIK for successive iteration of a new
+ * peer. */
+ p2p->peer_dik_len = 0;
+
+ return 0;
+}
+
+
void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr)
{
os_memcpy(p2p->peer_filter, addr, ETH_ALEN);
@@ -5839,6 +6056,16 @@
}
+static void p2p_validate_dira(struct p2p_data *p2p, struct p2p_device *dev,
+ const u8 *dira, u16 dira_len)
+{
+ if (p2p->cfg->validate_dira)
+ p2p->cfg->validate_dira(p2p->cfg->cb_ctx,
+ dev->info.p2p_device_addr,
+ dira, dira_len);
+}
+
+
struct wpabuf * p2p_usd_elems(struct p2p_data *p2p)
{
struct wpabuf *buf;
@@ -5884,7 +6111,6 @@
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);
@@ -5950,6 +6176,9 @@
if (!ether_addr_equal(peer_addr, p2p_dev_addr))
os_memcpy(dev->interface_addr, peer_addr, ETH_ALEN);
+ if (msg.dira && msg.dira_len)
+ p2p_validate_dira(p2p, dev, msg.dira, msg.dira_len);
+
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,
@@ -5957,6 +6186,973 @@
p2p->cfg->dev_found(p2p->cfg->cb_ctx, dev->info.p2p_device_addr,
&dev->info, !(dev->flags & P2P_DEV_REPORTED_ONCE));
+ dev->flags |= P2P_DEV_REPORTED | P2P_DEV_REPORTED_ONCE;
p2p_parse_free(&msg);
}
+
+
+#ifdef CONFIG_PASN
+
+int p2p_config_sae_password(struct p2p_data *p2p, const char *pw)
+{
+ os_memset(p2p->dev_sae_password, 0, sizeof(p2p->dev_sae_password));
+ if (os_strlen(pw) >= sizeof(p2p->dev_sae_password))
+ return -1;
+
+ os_strlcpy(p2p->dev_sae_password, pw, sizeof(p2p->dev_sae_password));
+ return 0;
+}
+
+
+static int p2p_prepare_pasn_extra_ie(struct p2p_data *p2p,
+ struct wpabuf *extra_ies,
+ const struct wpabuf *frame)
+{
+ struct wpabuf *buf, *buf2;
+ size_t len;
+
+ len = 100;
+ if (frame)
+ len += wpabuf_len(frame);
+ buf = wpabuf_alloc(len);
+ if (!buf)
+ return -1;
+
+ /* P2P Capability Extension attribute */
+ p2p_buf_add_pcea(buf, p2p);
+
+ if (frame) {
+ p2p_dbg(p2p, "Add Action frame wrapper for PASN");
+ wpabuf_put_u8(buf, P2P_ATTR_ACTION_FRAME_WRAPPER);
+ wpabuf_put_le16(buf, wpabuf_len(frame));
+ wpabuf_put_buf(buf, frame);
+ }
+
+ buf2 = p2p_encaps_ie(buf, P2P2_IE_VENDOR_TYPE);
+ wpabuf_free(buf);
+
+ if (wpabuf_tailroom(extra_ies) < wpabuf_len(buf2)) {
+ p2p_err(p2p, "Not enough room for P2P2 IE in PASN extra IEs");
+ wpabuf_free(buf2);
+ return -1;
+ }
+ wpabuf_put_buf(extra_ies, buf2);
+ wpabuf_free(buf2);
+
+ return 0;
+}
+
+
+static struct wpabuf * p2p_pairing_generate_rsnxe(struct p2p_data *p2p,
+ int akmp)
+{
+ u32 capab;
+ size_t flen = 0;
+ struct wpabuf *buf;
+
+ capab = BIT(WLAN_RSNX_CAPAB_KEK_IN_PASN);
+
+ if (wpa_key_mgmt_sae(akmp))
+ capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+ while (capab >> flen * 8)
+ flen++;
+
+ buf = wpabuf_alloc(2 + flen);
+ if (!buf)
+ return NULL;
+
+ if (wpabuf_tailroom(buf) < 2 + flen) {
+ p2p_dbg(p2p, "wpabuf tail room too small");
+ wpabuf_free(buf);
+ return NULL;
+ }
+ capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
+
+ p2p_dbg(p2p, "RSNXE capabilities: %04x", capab);
+ wpabuf_put_u8(buf, WLAN_EID_RSNX);
+ wpabuf_put_u8(buf, flen);
+ while (flen--) {
+ wpabuf_put_u8(buf, (capab & 0xff));
+ capab = capab >> 8;
+ }
+ return buf;
+}
+
+
+/* SSID used for deriving SAE pt for pairing */
+#define P2P_PAIRING_SSID "516F9A020000"
+
+static void p2p_pairing_set_password(struct pasn_data *pasn, u8 pasn_type,
+ const char *passphrase)
+{
+ int pasn_groups[4] = { 0 };
+ size_t len;
+
+ if (!passphrase)
+ return;
+
+ len = os_strlen(passphrase);
+
+ if (pasn_type & 0xc && pasn_type & 0x3) {
+ pasn_groups[0] = 20;
+ pasn_groups[1] = 19;
+ } else if (pasn_type & 0xc) {
+ pasn_groups[0] = 20;
+ } else {
+ pasn_groups[0] = 19;
+ }
+ pasn->pt = sae_derive_pt(pasn_groups, (const u8 *) P2P_PAIRING_SSID,
+ os_strlen(P2P_PAIRING_SSID),
+ (const u8 *) passphrase, len, NULL);
+ /* Set passphrase for pairing responder to validate PASN auth 1 frame */
+ pasn->password = passphrase;
+}
+
+
+void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev,
+ const u8 *addr, int freq, bool verify, bool derive_kek)
+{
+ struct pasn_data *pasn;
+ struct wpabuf *rsnxe;
+
+ if (!p2p || !dev)
+ return;
+
+ if (dev->pasn) {
+ wpa_pasn_reset(dev->pasn);
+ } else {
+ dev->pasn = pasn_data_init();
+ if (!dev->pasn)
+ return;
+ }
+
+ pasn = dev->pasn;
+
+ os_memcpy(pasn->own_addr, p2p->cfg->dev_addr, ETH_ALEN);
+ os_memcpy(pasn->peer_addr, addr, ETH_ALEN);
+
+ os_memcpy(pasn->bssid, dev->role == P2P_ROLE_PAIRING_INITIATOR ?
+ pasn->peer_addr : pasn->own_addr, ETH_ALEN);
+
+ pasn->noauth = 1;
+
+ if ((p2p->cfg->pairing_config.pasn_type & 0xc) &&
+ (dev->info.pairing_config.pasn_type & 0xc)) {
+ pasn->group = 20;
+ pasn->cipher = WPA_CIPHER_GCMP_256;
+ pasn->kek_len = 32;
+ pasn->derive_kek = true;
+ } else {
+ pasn->group = 19;
+ pasn->cipher = WPA_CIPHER_CCMP;
+ pasn->kek_len = 16;
+ pasn->derive_kek = true;
+ }
+
+ if (!derive_kek) {
+ pasn->derive_kek = false;
+ pasn->kek_len = 0;
+ }
+
+ if (dev->password[0]) {
+ pasn->akmp = WPA_KEY_MGMT_SAE;
+ p2p_pairing_set_password(pasn,
+ p2p->cfg->pairing_config.pasn_type,
+ dev->password);
+ } else if (verify) {
+ pasn->akmp = WPA_KEY_MGMT_SAE;
+ } else {
+ pasn->akmp = WPA_KEY_MGMT_PASN;
+ }
+
+ pasn->rsn_pairwise = pasn->cipher;
+ pasn->wpa_key_mgmt = pasn->akmp;
+
+ rsnxe = p2p_pairing_generate_rsnxe(p2p, pasn->akmp);
+ if (rsnxe) {
+ os_free(pasn->rsnxe_ie);
+ pasn->rsnxe_ie = os_memdup(wpabuf_head_u8(rsnxe),
+ wpabuf_len(rsnxe));
+ if (!pasn->rsnxe_ie) {
+ wpabuf_free(rsnxe);
+ return;
+ }
+ wpabuf_free(rsnxe);
+ }
+
+ if (dev->role == P2P_ROLE_PAIRING_INITIATOR)
+ pasn->pmksa = p2p->initiator_pmksa;
+ else
+ pasn->pmksa = p2p->responder_pmksa;
+
+ pasn->cb_ctx = p2p->cfg->cb_ctx;
+ pasn->send_mgmt = p2p->cfg->pasn_send_mgmt;
+ pasn->prepare_data_element = p2p->cfg->prepare_data_element;
+ pasn->parse_data_element = p2p->cfg->parse_data_element;
+
+ pasn->freq = freq;
+}
+
+
+int p2p_get_listen_freq(struct p2p_data *p2p, const u8 *peer_addr)
+{
+ int freq;
+ struct p2p_device *dev;
+
+ if (!peer_addr) {
+ p2p_dbg(p2p, "Peer address NULL");
+ return -1;
+ }
+
+ dev = p2p_get_device(p2p, peer_addr);
+ if (!dev) {
+ p2p_dbg(p2p, "Peer not known");
+ return -1;
+ }
+
+ freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
+ if (freq <= 0)
+ freq = dev->oob_go_neg_freq;
+ if (freq <= 0) {
+ p2p_dbg(p2p, "No listen/operating frequency known for the peer "
+ MACSTR, MAC2STR(dev->info.p2p_device_addr));
+ return -1;
+ }
+ return freq;
+}
+
+
+int p2p_initiate_pasn_verify(struct p2p_data *p2p, const u8 *peer_addr,
+ int freq, enum p2p_invite_role role,
+ const u8 *bssid, const u8 *ssid, size_t ssid_len,
+ unsigned int force_freq, const u8 *go_dev_addr,
+ unsigned int pref_freq)
+{
+ struct pasn_data *pasn;
+ struct p2p_device *dev;
+ struct wpabuf *extra_ies, *req;
+ int ret = 0;
+ u8 *pasn_extra_ies = NULL;
+
+ if (!peer_addr) {
+ p2p_dbg(p2p, "Peer address NULL");
+ return -1;
+ }
+
+ dev = p2p_get_device(p2p, peer_addr);
+ if (!dev) {
+ p2p_dbg(p2p, "Peer not known");
+ return -1;
+ }
+
+ if (p2p_invite(p2p, peer_addr, role, bssid, ssid, ssid_len, force_freq,
+ go_dev_addr, 1, pref_freq, -1, 1)) {
+ p2p_dbg(p2p, "p2p_invite() failed");
+ return -1;
+ }
+
+ dev->role = P2P_ROLE_PAIRING_INITIATOR;
+ p2p_pasn_initialize(p2p, dev, peer_addr, freq, true, true);
+ pasn = dev->pasn;
+
+ req = p2p_build_invitation_req(p2p, dev, go_dev_addr, -1);
+ if (!req)
+ return -1;
+
+ p2p_set_state(p2p, P2P_INVITE);
+ p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST;
+ p2p->invite_peer = dev;
+ dev->invitation_reqs++;
+
+ extra_ies = wpabuf_alloc(1500);
+ if (!extra_ies) {
+ wpabuf_free(req);
+ p2p_dbg(p2p, "Memory allocation failed for extra_ies");
+ return -1;
+ }
+
+ if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req)) {
+ p2p_dbg(p2p, "Prepare PASN extra IEs failed");
+ ret = -1;
+ goto out;
+ }
+
+ pasn_extra_ies = os_memdup(wpabuf_head_u8(extra_ies),
+ wpabuf_len(extra_ies));
+ if (!pasn_extra_ies) {
+ p2p_dbg(p2p, "Memory allocation failed for PASN extra IEs");
+ ret = -1;
+ goto out;
+ }
+
+ pasn->extra_ies = pasn_extra_ies;
+ pasn->extra_ies_len = wpabuf_len(extra_ies);
+
+ /* Start PASN verify */
+ if (wpa_pasn_verify(pasn, pasn->own_addr, pasn->peer_addr, pasn->bssid,
+ pasn->akmp, pasn->cipher, pasn->group, pasn->freq,
+ NULL, 0, NULL, 0, NULL)) {
+ p2p_dbg(p2p, "PASN verify failed");
+ ret = -1;
+ } else {
+ dev->flags |= P2P_DEV_WAIT_INV_REQ_ACK;
+ }
+out:
+ pasn->extra_ies = NULL;
+ pasn->extra_ies_len = 0;
+ os_free(pasn_extra_ies);
+ wpabuf_free(req);
+ wpabuf_free(extra_ies);
+ return ret;
+}
+
+
+int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq)
+{
+ struct pasn_data *pasn;
+ struct p2p_device *dev;
+ struct wpabuf *extra_ies, *req;
+ u8 *ies = NULL;
+ int ret = 0;
+ size_t ies_len;
+
+ if (!addr) {
+ p2p_dbg(p2p, "Peer address NULL");
+ return -1;
+ }
+
+ dev = p2p_get_device(p2p, addr);
+ if (!dev) {
+ p2p_dbg(p2p, "Peer not known");
+ return -1;
+ }
+
+ dev->role = P2P_ROLE_PAIRING_INITIATOR;
+ p2p_pasn_initialize(p2p, dev, addr, freq, false, true);
+ pasn = dev->pasn;
+
+ pasn_initiator_pmksa_cache_remove(pasn->pmksa, (u8 *)addr);
+
+ req = p2p_build_go_neg_req(p2p, dev);
+ if (!req)
+ return -1;
+
+ p2p->go_neg_peer = dev;
+ dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
+
+ extra_ies = wpabuf_alloc(1500);
+ if (!extra_ies) {
+ wpabuf_free(req);
+ return -1;
+ }
+
+ if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req)) {
+ p2p_dbg(p2p, "Failed to prepare PASN extra elements");
+ ret = -1;
+ goto out;
+ }
+
+ ies_len = wpabuf_len(extra_ies);
+ ies = os_memdup(wpabuf_head_u8(extra_ies), ies_len);
+ if (!ies) {
+ ret = -1;
+ goto out;
+ }
+
+ pasn->extra_ies = ies;
+ pasn->extra_ies_len = ies_len;
+
+ /* Start PASN authentication */
+ if (wpas_pasn_start(pasn, pasn->own_addr, pasn->peer_addr, pasn->bssid,
+ pasn->akmp, pasn->cipher, pasn->group, pasn->freq,
+ NULL, 0, NULL, 0, NULL)) {
+ p2p_dbg(p2p, "Failed to start PASN");
+ ret = -1;
+ }
+out:
+ os_free(ies);
+ pasn->extra_ies = NULL;
+ pasn->extra_ies_len = 0;
+ wpabuf_free(req);
+ wpabuf_free(extra_ies);
+ return ret;
+}
+
+
+static int p2p_pasn_handle_action_wrapper(struct p2p_data *p2p,
+ struct p2p_device *dev,
+ const struct ieee80211_mgmt *mgmt,
+ size_t len, int freq, int trans_seq)
+{
+ const u8 *ies;
+ size_t ies_len;
+ size_t data_len = 0;
+ bool derive_kek;
+ const u8 *data = NULL;
+ struct p2p_message msg;
+ struct ieee802_11_elems elems;
+
+ ies = mgmt->u.auth.variable;
+ ies_len = len - offsetof(struct ieee80211_mgmt, u.auth.variable);
+
+ os_memset(&msg, 0, sizeof(msg));
+ if (p2p_parse_ies(ies, ies_len, &msg)) {
+ p2p_dbg(p2p,
+ "Failed to parse P2P IE from PASN Authentication frame");
+ p2p_parse_free(&msg);
+ return -1;
+ }
+
+ if (msg.action_frame_wrapper && msg.action_frame_wrapper_len) {
+ data = msg.action_frame_wrapper;
+ data_len = msg.action_frame_wrapper_len;
+ if (data_len >= 2 &&
+ data[0] == WLAN_ACTION_PUBLIC &&
+ data[1] == WLAN_PA_VENDOR_SPECIFIC) {
+ data += 2;
+ data_len -= 2;
+ if (data_len < 4 ||
+ WPA_GET_BE32(data) != P2P_IE_VENDOR_TYPE) {
+ p2p_parse_free(&msg);
+ return -1;
+ }
+ data += 4;
+ data_len -= 4;
+ } else {
+ p2p_dbg(p2p,
+ "Invalid category in Action frame wrapper in Authentication frame seq %d",
+ trans_seq);
+ p2p_parse_free(&msg);
+ return -1;
+ }
+ }
+
+ if (trans_seq == 1) {
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ return -1;
+ }
+ derive_kek = ieee802_11_rsnx_capab_len(
+ elems.rsnxe, elems.rsnxe_len,
+ WLAN_RSNX_CAPAB_KEK_IN_PASN);
+ if (data && data_len >= 1 && data[0] == P2P_INVITATION_REQ) {
+ struct wpabuf *resp;
+
+ resp = p2p_process_invitation_req(p2p, mgmt->sa,
+ data + 1,
+ data_len - 1, freq,
+ true);
+ if (!resp)
+ p2p_dbg(p2p, "No Invitation Response found");
+
+ dev->role = P2P_ROLE_PAIRING_RESPONDER;
+ p2p_pasn_initialize(p2p, dev, mgmt->sa, freq, true,
+ derive_kek);
+ wpabuf_free(dev->action_frame_wrapper);
+ dev->action_frame_wrapper = resp;
+ } else if (data && data_len >= 1 && data[0] == P2P_GO_NEG_REQ) {
+ struct wpabuf *resp;
+
+ if (!derive_kek) {
+ p2p_dbg(p2p, "KEK-in-PASN not set in RSNXE");
+ return -1;
+ }
+ resp = p2p_process_go_neg_req(p2p, mgmt->sa, data + 1,
+ data_len - 1, freq, true);
+ if (!resp)
+ p2p_dbg(p2p,
+ "No GO Negotiation Response found");
+ wpabuf_free(dev->action_frame_wrapper);
+ dev->action_frame_wrapper = resp;
+ } else {
+ p2p_dbg(p2p, "Invalid action frame wrapper in Auth1");
+ }
+ } else if (trans_seq == 2) {
+ if (data && data_len >= 1 && data[0] == P2P_INVITATION_RESP) {
+ p2p_process_invitation_resp(p2p, mgmt->sa, data + 1,
+ data_len - 1);
+ wpabuf_free(dev->action_frame_wrapper);
+ dev->action_frame_wrapper = NULL;
+ } else if (data && data_len >= 1 &&
+ data[0] == P2P_GO_NEG_RESP) {
+ struct wpabuf *conf;
+
+ conf = p2p_process_go_neg_resp(p2p, mgmt->sa, data + 1,
+ data_len - 1, freq,
+ true);
+ if (!conf)
+ p2p_dbg(p2p, "No GO Negotiation Confirm found");
+ wpabuf_free(dev->action_frame_wrapper);
+ dev->action_frame_wrapper = conf;
+ } else {
+ p2p_dbg(p2p, "Invalid action frame wrapper in Auth2");
+ }
+ } else if (trans_seq == 3) {
+ if (data && data_len >= 1 && data[0] == P2P_GO_NEG_CONF)
+ p2p_handle_go_neg_conf(p2p, mgmt->sa, data + 1,
+ data_len - 1, true);
+ else
+ p2p_invitation_resp_cb(p2p, mgmt->sa,
+ P2P_SEND_ACTION_SUCCESS);
+ }
+ p2p_parse_free(&msg);
+ return 0;
+}
+
+
+static int p2p_pasn_add_encrypted_data(struct p2p_data *p2p,
+ struct p2p_device *dev,
+ struct wpabuf *buf)
+{
+ struct pasn_data *pasn;
+ struct wpabuf *p2p2_ie;
+ u8 *dika_len, *p2p2_ie_len;
+ int ret;
+
+ if (!p2p || !dev || !dev->pasn)
+ return 0;
+
+ pasn = dev->pasn;
+
+ if (dev->req_bootstrap_method != P2P_PBMA_OPPORTUNISTIC &&
+ !p2p->pairing_info->enable_pairing_cache)
+ return 0;
+
+ p2p2_ie = wpabuf_alloc(100);
+ if (!p2p2_ie)
+ return -1;
+
+ p2p2_ie_len = p2p_buf_add_p2p2_ie_hdr(p2p2_ie);
+
+ if (p2p->pairing_info->enable_pairing_cache) {
+ wpabuf_put_u8(p2p2_ie, P2P_ATTR_DEVICE_IDENTITY_KEY);
+ dika_len = wpabuf_put(p2p2_ie, 2);
+
+ wpabuf_put_u8(p2p2_ie,
+ p2p->pairing_info->dev_ik.cipher_version);
+ wpabuf_put_data(p2p2_ie, p2p->pairing_info->dev_ik.dik_data,
+ p2p->pairing_info->dev_ik.dik_len);
+ wpabuf_put_be32(p2p2_ie, p2p->pairing_info->dev_ik.expiration);
+
+ WPA_PUT_LE16(dika_len,
+ (u8 *) wpabuf_put(p2p2_ie, 0) - dika_len - 2);
+ }
+
+ if (dev->req_bootstrap_method == P2P_PBMA_OPPORTUNISTIC) {
+ if (!p2p->dev_sae_password[0]) {
+ int password_len;
+
+ /* SAE password is not available as the request is not
+ * for an existing GO. Pick a random SAE password of
+ * length between 10 and 20. */
+ password_len = 10 + os_random() % 10;
+ if (p2p_random(p2p->dev_sae_password,
+ password_len) < 0) {
+ wpabuf_free(p2p2_ie);
+ return -1;
+ }
+ p2p->dev_sae_password[password_len] = '\0';
+ }
+
+ wpabuf_put_u8(p2p2_ie, P2P_ATTR_PASSWORD);
+ wpabuf_put_le16(p2p2_ie, os_strlen(p2p->dev_sae_password));
+ wpabuf_put_str(p2p2_ie, p2p->dev_sae_password);
+ }
+
+ p2p_buf_update_ie_hdr(p2p2_ie, p2p2_ie_len);
+
+ ret = pasn_add_encrypted_data(pasn, buf, wpabuf_mhead_u8(p2p2_ie),
+ wpabuf_len(p2p2_ie));
+ wpabuf_free(p2p2_ie);
+ return ret;
+}
+
+
+int p2p_prepare_data_element(struct p2p_data *p2p, const u8 *peer_addr)
+{
+ int ret = -1;
+ struct p2p_device *dev;
+ struct pasn_data *pasn;
+ struct wpabuf *extra_ies;
+
+ if (!p2p)
+ return -1;
+
+ dev = p2p_get_device(p2p, peer_addr);
+ if (!dev || !dev->pasn) {
+ p2p_dbg(p2p, "PASN: Peer not found " MACSTR,
+ MAC2STR(peer_addr));
+ return -1;
+ }
+ pasn = dev->pasn;
+
+ extra_ies = wpabuf_alloc(1500);
+ if (!extra_ies ||
+ p2p_prepare_pasn_extra_ie(p2p, extra_ies,
+ dev->action_frame_wrapper)) {
+ p2p_dbg(p2p, "Failed to prepare PASN extra elements");
+ goto out;
+ }
+
+ if (p2p_pasn_add_encrypted_data(p2p, dev, extra_ies) < 0)
+ p2p_dbg(p2p, "Failed to add PASN encrypted elements");
+
+ pasn->extra_ies = os_memdup(wpabuf_head_u8(extra_ies),
+ wpabuf_len(extra_ies));
+ if (!pasn->extra_ies)
+ goto out;
+ pasn->extra_ies_len = wpabuf_len(extra_ies);
+ ret = 0;
+
+out:
+ wpabuf_free(extra_ies);
+ wpabuf_free(dev->action_frame_wrapper);
+ dev->action_frame_wrapper = NULL;
+
+ return ret;
+}
+
+
+int p2p_parse_data_element(struct p2p_data *p2p, const u8 *data, size_t len)
+{
+ u8 attr_id;
+ const u8 *pos, *next;
+ u16 rem_len, attr_len;
+
+ if (!p2p || !data || !len)
+ return -1;
+
+ pos = data;
+ rem_len = len;
+
+ if (rem_len < 6 ||
+ pos[0] != WLAN_EID_VENDOR_SPECIFIC ||
+ pos[1] < 4 ||
+ rem_len < 2 + pos[1] ||
+ WPA_GET_BE32(&pos[2]) != P2P2_IE_VENDOR_TYPE) {
+ p2p_dbg(p2p,
+ "P2P: P2P2 IE not present in PASN Encrypted Data element");
+ return -1;
+ }
+
+ pos += 6;
+ rem_len -= 6;
+
+ while (rem_len >= 3) {
+ attr_id = *pos++;
+ attr_len = WPA_GET_LE16(pos);
+ pos += 2;
+ rem_len -= 3;
+ if (rem_len < attr_len)
+ return -1;
+ next = pos + attr_len;
+ rem_len -= attr_len;
+
+ switch (attr_id) {
+ case P2P_ATTR_DEVICE_IDENTITY_KEY:
+ if (attr_len < 1) {
+ p2p_dbg(p2p,
+ "Too short Device Identity Key attribute");
+ return -1;
+ }
+ p2p->dik_cipher_version = *pos++;
+ attr_len--;
+ if (p2p->dik_cipher_version ==
+ DIRA_CIPHER_VERSION_128) {
+ if (attr_len < DEVICE_IDENTITY_KEY_LEN) {
+ p2p_dbg(p2p, "Too short DevIK");
+ return -1;
+ }
+ os_memcpy(p2p->peer_dik_data, pos,
+ DEVICE_IDENTITY_KEY_LEN);
+ p2p->peer_dik_len = DEVICE_IDENTITY_KEY_LEN;
+ pos += DEVICE_IDENTITY_KEY_LEN;
+ attr_len -= DEVICE_IDENTITY_KEY_LEN;
+ } else {
+ p2p_dbg(p2p,
+ "Unsupported cipher version %u in Device Identity Key attribute",
+ p2p->dik_cipher_version);
+ return -1;
+ }
+ if (attr_len < 4) {
+ p2p_dbg(p2p,
+ "Not enough room for DevIK lifetime");
+ return -1;
+ }
+ p2p->peer_dik_lifetime = WPA_GET_BE32(pos);
+ p2p_dbg(p2p,
+ "Received peer DevIK of length %zu octets and lifetime %u",
+ p2p->peer_dik_len, p2p->peer_dik_lifetime);
+ break;
+ case P2P_ATTR_PASSWORD:
+ if (attr_len < 1 ||
+ attr_len > sizeof(p2p->peer_sae_password) - 1) {
+ p2p_dbg(p2p,
+ "P2P: Invalid password length %d",
+ attr_len);
+ return -1;
+ }
+ os_memset(p2p->peer_sae_password, 0,
+ sizeof(p2p->peer_sae_password));
+ os_memcpy(p2p->peer_sae_password, pos, attr_len);
+ break;
+ default:
+ p2p_dbg(p2p,
+ "Unsupported Attribute ID %u in P2P2 IE in PASN Encrypted Data element",
+ attr_id);
+ break;
+ }
+ pos = next;
+ }
+
+ return 0;
+}
+
+
+int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
+ size_t data_len, bool acked, bool verify)
+{
+ int ret = 0;
+ struct p2p_device *dev;
+ struct pasn_data *pasn;
+ const struct ieee80211_mgmt *mgmt =
+ (const struct ieee80211_mgmt *) data;
+
+ if (!p2p)
+ return -1;
+
+ dev = p2p_get_device(p2p, mgmt->da);
+ if (!dev || !dev->pasn) {
+ p2p_dbg(p2p, "P2P PASN: Peer not found " MACSTR,
+ MAC2STR(mgmt->da));
+ return -1;
+ }
+
+ pasn = dev->pasn;
+
+ ret = wpa_pasn_auth_tx_status(pasn, data, data_len, acked);
+ if (ret != 1 && !acked && pasn->frame)
+ return pasn->send_mgmt(pasn->cb_ctx, wpabuf_head(pasn->frame),
+ wpabuf_len(pasn->frame), 0, pasn->freq,
+ 1000);
+
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+
+ if (ret != 1)
+ return ret;
+
+ if (verify && dev == p2p->invite_peer)
+ p2p_start_invitation_connect(p2p, dev);
+ else if (dev == p2p->go_neg_peer)
+ p2p_go_complete(p2p, dev);
+
+ return 0;
+}
+
+
+static int p2p_handle_pasn_auth(struct p2p_data *p2p, struct p2p_device *dev,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int freq)
+{
+ struct pasn_data *pasn;
+ u8 pasn_type;
+ int pasn_groups[4] = { 0 };
+ u16 auth_alg, auth_transaction, status_code;
+
+ if (!p2p || !dev || !dev->pasn)
+ return -1;
+
+ if (os_memcmp(mgmt->da, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
+ p2p_dbg(p2p, "PASN Responder: Not our frame");
+ return -1;
+ }
+
+ if (len < offsetof(struct ieee80211_mgmt, u.auth.variable))
+ return -1;
+
+ pasn = dev->pasn;
+ auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+ status_code = le_to_host16(mgmt->u.auth.status_code);
+
+ auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+
+ if (status_code != WLAN_STATUS_SUCCESS &&
+ status_code != WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
+ p2p_dbg(p2p, "PASN: Authentication rejected - status=%u",
+ status_code);
+ return -1;
+ }
+
+ if (auth_alg != WLAN_AUTH_PASN || auth_transaction == 2) {
+ p2p_dbg(p2p,
+ "PASN Responder: Not a PASN frame or unexpected Authentication frame, auth_alg=%d",
+ auth_alg);
+ return -1;
+ }
+ if (auth_transaction == 1) {
+ pasn_type = p2p->cfg->pairing_config.pasn_type;
+ if (pasn_type & 0xc && pasn_type & 0x3) {
+ pasn_groups[0] = 20;
+ pasn_groups[1] = 19;
+ } else if (pasn_type & 0xc) {
+ pasn_groups[0] = 20;
+ } else {
+ pasn_groups[0] = 19;
+ }
+ pasn->pasn_groups = pasn_groups;
+
+ if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq,
+ auth_transaction)) {
+ p2p_dbg(p2p,
+ "PASN Responder: Handle Auth 1 action wrapper failed");
+ return -1;
+ }
+ if (handle_auth_pasn_1(pasn, p2p->cfg->dev_addr, mgmt->sa, mgmt,
+ len, false) < 0) {
+ p2p_dbg(p2p,
+ "PASN Responder: Handle Auth 1 failed");
+ return -1;
+ }
+ } else if (auth_transaction == 3) {
+ if (handle_auth_pasn_3(pasn, p2p->cfg->dev_addr, mgmt->sa, mgmt,
+ len) < 0) {
+ p2p_dbg(p2p,
+ "PASN Responder: Handle Auth 3 failed");
+ return -1;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+ p2p_pasn_store_ptk(p2p, &pasn->ptk);
+#endif /* CONFIG_TESTING_OPTIONS */
+ if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq,
+ auth_transaction)) {
+ p2p_dbg(p2p,
+ "PASN Responder: Handle Auth 3 action wrapper failed");
+ /* Drop keying material from a failed pairing attempt */
+ os_memset(p2p->peer_dik_data, 0,
+ sizeof(p2p->peer_dik_data));
+ os_memset(p2p->peer_sae_password, 0,
+ sizeof(p2p->peer_sae_password));
+ return -1;
+ }
+ forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
+ }
+ return 0;
+}
+
+
+int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt,
+ size_t len, int freq)
+{
+ int ret = 0;
+ u8 auth_transaction;
+ struct p2p_device *dev;
+ struct pasn_data *pasn;
+ struct wpa_pasn_params_data pasn_data;
+
+ dev = p2p_get_device(p2p, mgmt->sa);
+ if (!dev) {
+ p2p_dbg(p2p, "PASN: Peer not found " MACSTR,
+ MAC2STR(mgmt->sa));
+ return -1;
+ }
+
+ if (!dev->pasn) {
+ p2p_dbg(p2p, "PASN: Uninitialized");
+ return -1;
+ }
+
+ pasn = dev->pasn;
+
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+
+ pasn_register_callbacks(pasn, p2p->cfg->cb_ctx,
+ p2p->cfg->pasn_send_mgmt, NULL);
+ auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+
+ if (dev->role == P2P_ROLE_PAIRING_INITIATOR && auth_transaction == 2) {
+ if (p2p_pasn_handle_action_wrapper(p2p, dev, mgmt, len, freq,
+ auth_transaction)) {
+ p2p_dbg(p2p,
+ "PASN Initiator: Handle Auth 2 action wrapper failed");
+ return -1;
+ }
+ ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len,
+ &pasn_data);
+ if (ret < 0) {
+ p2p_dbg(p2p, "PASN: wpa_pasn_auth_rx() failed");
+ dev->role = P2P_ROLE_IDLE;
+ }
+#ifdef CONFIG_TESTING_OPTIONS
+ p2p_pasn_store_ptk(p2p, &pasn->ptk);
+#endif /* CONFIG_TESTING_OPTIONS */
+ forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
+ } else {
+ ret = p2p_handle_pasn_auth(p2p, dev, mgmt, len, freq);
+ }
+ return ret;
+}
+
+
+void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst,
+ const u8 *pmk, size_t pmk_len, const u8 *pmkid)
+{
+ pasn_initiator_pmksa_cache_add(p2p->initiator_pmksa, src, dst, pmk,
+ pmk_len, pmkid);
+ pasn_responder_pmksa_cache_add(p2p->responder_pmksa, src, dst, pmk,
+ pmk_len, pmkid);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+
+void p2p_pasn_store_ptk(struct p2p_data *p2p, struct wpa_ptk *ptk)
+{
+ u8 *pos;
+
+ if (ptk->ptk_len > sizeof(p2p->pasn_ptk)) {
+ p2p_dbg(p2p, "P2P PASN PTK exceeds: (len=%ld)", ptk->ptk_len);
+ return;
+ }
+
+ pos = p2p->pasn_ptk;
+ p2p->pasn_ptk_len = ptk->ptk_len;
+ if (ptk->kck_len) {
+ os_memcpy(pos, ptk->kck, ptk->kck_len);
+ pos += ptk->kck_len;
+ }
+ if (ptk->kek_len) {
+ os_memcpy(pos, ptk->kek, ptk->kek_len);
+ pos += ptk->kek_len;
+ }
+ if (ptk->tk_len) {
+ os_memcpy(pos, ptk->tk, ptk->tk_len);
+ pos += ptk->tk_len;
+ }
+ if (ptk->kdk_len) {
+ os_memcpy(pos, ptk->kdk, ptk->kdk_len);
+ pos += ptk->kdk_len;
+ }
+}
+
+
+int p2p_pasn_get_ptk(struct p2p_data *p2p, const u8 **buf, size_t *buf_len)
+{
+ if (!p2p || !p2p->pasn_ptk_len)
+ return -1;
+
+ *buf_len = p2p->pasn_ptk_len;
+ *buf = p2p->pasn_ptk;
+ return 0;
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#endif /* CONFIG_PASN */
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 5b5c7dd..60a4a34 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -11,6 +11,7 @@
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
+#include "common/wpa_common.h"
#define DEVICE_IDENTITY_KEY_MAX_LEN 64
#define DEVICE_IDENTITY_KEY_LEN 16
@@ -181,6 +182,41 @@
* peer_config_timeout - Peer configuration timeout (in 10 msec units)
*/
unsigned int peer_config_timeout;
+
+ /**
+ * p2p2 - Whether this group uses P2P2
+ */
+ bool p2p2;
+
+ /**
+ * akmp - The negotiated PASN AKMP for P2P2
+ */
+ int akmp;
+
+ /**
+ * cipher - Pairwise cipher(s) for the group for P2P2
+ */
+ int cipher;
+
+ /**
+ * pmkid - PMKID for P2P2 when PMK is derived as part of pairing
+ */
+ u8 pmkid[PMKID_LEN];
+
+ /**
+ * pmk - PMK for P2P2 when PMK is derived as part of pairing
+ */
+ u8 pmk[PMK_LEN_MAX];
+
+ /**
+ * pmk_len - Length of @pmk in octets
+ */
+ size_t pmk_len;
+
+ /**
+ * sae_password - SAE password for the group (P2P2)
+ */
+ char sae_password[100];
};
struct p2ps_provision {
@@ -350,11 +386,6 @@
bool enable_pairing_cache;
/**
- * Enable P2P pairing verification with cached NIK/NPK
- */
- bool enable_pairing_verification;
-
- /**
* P2P bootstrapping methods supported
*/
u16 bootstrap_methods;
@@ -691,6 +722,23 @@
u16 comeback_after;
/**
+ * chan_switch_req_enable - Enable P2P client channel switch request
+ */
+ bool chan_switch_req_enable;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ /**
+ * Operating class for own operational channel in Invitation Response
+ */
+ u8 inv_op_class;
+
+ /**
+ * inv_op_channel - Own operational channel in Invitation Response
+ */
+ u8 inv_op_channel;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ /**
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
@@ -918,6 +966,20 @@
void (*go_neg_completed)(void *ctx, struct p2p_go_neg_results *res);
/**
+ * set_go_security_config - Set security configuration for P2P GO
+ * @ctx: Callback context from cb_ctx
+ * @res: GO Negotiation results
+ *
+ * This callback is used to set PMK/passphrase derived during PASN
+ * authentication with a P2P client. This will fetch an active P2P group
+ * owner instance and configure PMKSA in case of password based PASN, or
+ * configures the passphrase and derive PT in case of unauthenticated
+ * PASN.
+ */
+ void (*set_go_security_config)(void *ctx,
+ struct p2p_go_neg_results *res);
+
+ /**
* sd_request - Callback on Service Discovery Request
* @ctx: Callback context from cb_ctx
* @freq: Frequency (in MHz) of the channel
@@ -1027,6 +1089,8 @@
* @channels: Available operating channels for the group
* @dev_pw_id: Device Password ID for NFC static handover or -1 if not
* used
+ * @p2p2: Whether invitation request was wrapped in PASN authentication
+ * received from a P2P2 device
* Returns: Status code (P2P_SC_*)
*
* This optional callback can be used to implement persistent reconnect
@@ -1049,7 +1113,7 @@
size_t ssid_len, int *go, u8 *group_bssid,
int *force_freq, int persistent_group,
const struct p2p_channels *channels,
- int dev_pw_id);
+ int dev_pw_id, bool p2p2);
/**
* invitation_received - Callback on Invitation Request RX
@@ -1071,7 +1135,8 @@
void (*invitation_received)(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *ssid, size_t ssid_len,
const u8 *go_dev_addr, u8 status,
- int op_freq);
+ int op_freq, const u8 *pmkid, const u8 *pmk,
+ size_t pmk_len);
/**
* invitation_result - Callback on Invitation result
@@ -1092,7 +1157,9 @@
*/
void (*invitation_result)(void *ctx, int status, const u8 *bssid,
const struct p2p_channels *channels,
- const u8 *addr, int freq, int peer_oper_freq);
+ const u8 *addr, int freq, int peer_oper_freq,
+ const u8 *pmkid, const u8 *pmk,
+ size_t pmk_len);
/**
* go_connected - Check whether we are connected to a GO
@@ -1276,6 +1343,53 @@
*/
void (*bootstrap_completed)(void *ctx, const u8 *addr,
enum p2p_status_code status, int freq);
+
+ /**
+ * validate_dira - Indicate reception of DIRA to be validated against a
+ * list of available device identity keys
+ * @ctx: Callback context from cb_ctx
+ * @peer_addr: P2P Device address of the peer
+ * @dira: DIRA attribute present in the USD frames
+ * @dira_len: Length of DIRA
+ *
+ * This function can be used to validate DIRA and configure PMK of a
+ * paired/persistent peer from configuration. The handler function is
+ * expected to call p2p_pasn_pmksa_set_pmk() to set the PMK/PMKID in
+ * case a matching entry is found.
+ */
+ void (*validate_dira)(void *ctx, const u8 *peer_addr,
+ const u8 *dira, size_t dira_len);
+
+ /**
+ * pasn_send_mgmt - Function handler to transmit a Management frame
+ * @ctx: Callback context from cb_ctx
+ * @data: Frame to transmit
+ * @data_len: Length of frame to transmit
+ * @noack: No ack flag
+ * @freq: Frequency in MHz for the channel on which to transmit
+ * @wait: How many milliseconds to wait for a response frame
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*pasn_send_mgmt)(void *ctx, const u8 *data, size_t data_len,
+ int noack, unsigned int freq, unsigned int wait);
+
+ /**
+ * prepare_data_element - Function handler to update protocol specific
+ * elements in PASN authentication frames
+ * @ctx: Callback context from cb_ctx
+ * @peer_addr: Peer MAC address
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*prepare_data_element)(void *ctx, const u8 *peer_addr);
+
+ /**
+ * parse_data_element - Function handler to parse P2P data element
+ * @ctx: Callback context from cb_ctx
+ * @data: Data to be parsed
+ * @len: Length of data
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*parse_data_element)(void *ctx, const u8 *data, size_t len);
};
@@ -1609,12 +1723,14 @@
* force_freq == 0)
* @dev_pw_id: Device Password ID from OOB Device Password (NFC) static handover
* case or -1 if not used
+ * @p2p2: Operating in P2P2 mode
* Returns: 0 on success, -1 on failure
*/
int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
const u8 *bssid, const u8 *ssid, size_t ssid_len,
unsigned int force_freq, const u8 *go_dev_addr,
- int persistent_group, unsigned int pref_freq, int dev_pw_id);
+ int persistent_group, unsigned int pref_freq, int dev_pw_id,
+ bool p2p2);
/**
* p2p_presence_req - Request GO presence
@@ -1855,6 +1971,11 @@
*/
struct p2p_group_config {
/**
+ * p2p2 - Whether the group was formed using P2P2
+ */
+ bool p2p2;
+
+ /**
* persistent_group - Whether the group is persistent
* 0 = not a persistent group
* 1 = persistent group without persistent reconnect
@@ -2101,6 +2222,18 @@
int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params);
/**
+ * p2p_set_go_role - Set the current role of P2P device
+ * @p2p: P2P module context from p2p_init()
+ * @val: 1 if P2P GO, 0 to reset the role variable
+ *
+ * This role is configured as P2P GO when authorizing a P2P Client to join the
+ * group. Once PASN authentication with GO negotiation with predefined GO intent
+ * values (15 for P2P GO) is completed, the role helps to configure PMK derived
+ * during the PASN authentication.
+ */
+void p2p_set_go_role(struct p2p_data *p2p, bool val);
+
+/**
* p2p_get_group_capab - Get Group Capability from P2P IE data
* @p2p_ie: P2P IE(s) contents
* Returns: Group Capability
@@ -2200,6 +2333,8 @@
u8 *iface_addr);
int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr,
u8 *dev_addr);
+int p2p_get_dev_identity_key(struct p2p_data *p2p, const u8 *dev_addr,
+ const u8 **dik_data, size_t *dik_len, u8 *cipher);
void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr);
@@ -2583,4 +2718,35 @@
void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
const u8 *peer_addr, unsigned int freq);
+void p2p_set_pairing_setup(struct p2p_data *p2p, int pairing_setup);
+void p2p_set_pairing_cache(struct p2p_data *p2p, int pairing_cache);
+void p2p_set_bootstrapmethods(struct p2p_data *p2p, int bootstrap_methods);
+void p2p_set_pasn_type(struct p2p_data *p2p, u8 pasn_type);
+void p2p_set_comeback_after(struct p2p_data *p2p, int comeback_after);
+void p2p_set_reg_info(struct p2p_data *p2p, u8 val);
+void p2p_set_twt_power_mgmt(struct p2p_data *p2p, int val);
+void p2p_set_dev_addr(struct p2p_data *p2p, const u8 *addr);
+void p2p_set_chan_switch_req_enable(struct p2p_data *p2p, bool val);
+void p2p_set_invitation_op_freq(struct p2p_data *p2p, int freq);
+
+int p2p_get_listen_freq(struct p2p_data *p2p, const u8 *peer_addr);
+int p2p_initiate_pasn_auth(struct p2p_data *p2p, const u8 *addr, int freq);
+int p2p_initiate_pasn_verify(struct p2p_data *p2p, const u8 *peer_addr,
+ int freq, enum p2p_invite_role role,
+ const u8 *bssid, const u8 *ssid, size_t ssid_len,
+ unsigned int force_freq, const u8 *go_dev_addr,
+ unsigned int pref_freq);
+int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt,
+ size_t len, int freq);
+int p2p_prepare_data_element(struct p2p_data *p2p, const u8 *peer_addr);
+int p2p_parse_data_element(struct p2p_data *p2p, const u8 *data, size_t len);
+int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
+ size_t data_len, bool acked, bool verify);
+int p2p_config_sae_password(struct p2p_data *p2p, const char *pw);
+void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst,
+ const u8 *pmk, size_t pmk_len, const u8 *pmkid);
+void p2p_set_store_pasn_ptk(struct p2p_data *p2p, u8 val);
+void p2p_pasn_store_ptk(struct p2p_data *p2p, struct wpa_ptk *ptk);
+int p2p_pasn_get_ptk(struct p2p_data *p2p, const u8 **buf, size_t *buf_len);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index ddadd34..343566d 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -741,6 +741,9 @@
if (p2p->cfg->dfs_owner)
capability_info |= P2P_PCEA_DFS_OWNER;
+ if (p2p->cfg->chan_switch_req_enable)
+ capability_info |= P2P_PCEA_CLI_REQ_CS;
+
if (p2p->cfg->pairing_config.pairing_capable)
capability_info |= P2P_PCEA_PAIRING_CAPABLE;
@@ -806,8 +809,7 @@
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)
+ !p2p->cfg->pairing_config.enable_pairing_cache)
return;
dev_ik = &p2p->pairing_info->dev_ik;
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index c036f92..2659787 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -205,11 +205,28 @@
}
+struct wpabuf * p2p_group_build_p2p2_ie(struct p2p_data *p2p,
+ struct wpabuf *p2p2_ie, int freq)
+{
+ u8 *len;
+
+ wpabuf_put_u8(p2p2_ie, WLAN_EID_VENDOR_SPECIFIC);
+ len = wpabuf_put(p2p2_ie, 1);
+ wpabuf_put_be32(p2p2_ie, P2P2_IE_VENDOR_TYPE);
+ wpa_printf(MSG_DEBUG, "P2P: * P2P2 IE header");
+ p2p_buf_add_pcea(p2p2_ie, p2p);
+ *len = (u8 *) wpabuf_put(p2p2_ie, 0) - len - 1;
+
+ return p2p2_ie;
+}
+
+
static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
{
struct wpabuf *ie;
u8 *len;
size_t extra = 0;
+ struct wpabuf *p2p2_ie;
#ifdef CONFIG_WIFI_DISPLAY
if (group->p2p->wfd_ie_beacon)
@@ -220,7 +237,7 @@
group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO])
extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]);
- ie = wpabuf_alloc(257 + extra);
+ ie = wpabuf_alloc(500 + extra);
if (ie == NULL)
return NULL;
@@ -240,6 +257,17 @@
p2p_group_add_noa(ie, group->noa);
p2p_buf_update_ie_hdr(ie, len);
+ if (group->cfg->p2p2) {
+ p2p2_ie = wpabuf_alloc(255);
+ if (!p2p2_ie) {
+ wpabuf_free(ie);
+ return NULL;
+ }
+
+ p2p_group_build_p2p2_ie(group->p2p, p2p2_ie, group->cfg->freq);
+ ie = wpabuf_concat(p2p2_ie, ie);
+ }
+
return ie;
}
@@ -443,6 +471,7 @@
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
{
struct wpabuf *p2p_subelems, *ie;
+ struct wpabuf *p2p2_ie;
p2p_subelems = wpabuf_alloc(500);
if (p2p_subelems == NULL)
@@ -474,7 +503,16 @@
ie = wpabuf_concat(wfd, ie);
}
#endif /* CONFIG_WIFI_DISPLAY */
+ if (group->cfg->p2p2) {
+ p2p2_ie = wpabuf_alloc(255);
+ if (!p2p2_ie) {
+ wpabuf_free(ie);
+ return NULL;
+ }
+ p2p_group_build_p2p2_ie(group->p2p, p2p2_ie, group->cfg->freq);
+ ie = wpabuf_concat(p2p2_ie, ie);
+ }
return ie;
}
@@ -648,6 +686,7 @@
struct wpabuf *resp;
u8 *rlen;
size_t extra = 0;
+ struct wpabuf *p2p2_ie;
#ifdef CONFIG_WIFI_DISPLAY
if (group->wfd_ie)
@@ -683,6 +722,17 @@
p2p_buf_add_status(resp, status);
p2p_buf_update_ie_hdr(resp, rlen);
+ if (group->cfg->p2p2) {
+ p2p2_ie = wpabuf_alloc(255);
+ if (!p2p2_ie) {
+ wpabuf_free(resp);
+ return NULL;
+ }
+
+ p2p_group_build_p2p2_ie(group->p2p, p2p2_ie, group->cfg->freq);
+ resp = wpabuf_concat(p2p2_ie, resp);
+ }
+
return resp;
}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 808bb96..a54e375 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -37,6 +37,13 @@
REMOTE_GO
};
+/* Enumeration for P2P device current role */
+enum p2p_role {
+ P2P_ROLE_IDLE = 0,
+ P2P_ROLE_PAIRING_INITIATOR,
+ P2P_ROLE_PAIRING_RESPONDER,
+};
+
/**
* struct bootstrap_params - P2P Device bootstrap request parameters
*/
@@ -183,6 +190,21 @@
/* Password for P2P2 GO negotiation */
char password[100];
+
+ /* PASN data structure */
+ struct pasn_data *pasn;
+ struct wpabuf *action_frame_wrapper;
+
+ /* Device role */
+ enum p2p_role role;
+
+ /* Invitation parameters for P2P2 */
+ bool inv_reject;
+ u8 inv_status;
+ int inv_freq;
+ int inv_peer_oper_freq;
+ u8 inv_bssid[ETH_ALEN];
+ bool inv_all_channels;
};
struct p2p_sd_query {
@@ -199,6 +221,8 @@
int akmp;
/* Cipher version type */
int cipher_version;
+ /* DevIK expiration time in hours */
+ u32 expiration;
/* Buffer to hold the DevIK */
u8 dik_data[DEVICE_IDENTITY_KEY_MAX_LEN];
/* Length of DevIK */
@@ -637,6 +661,46 @@
struct rsn_pmksa_cache *initiator_pmksa;
/* Pairing responder PMKSA cache */
struct rsn_pmksa_cache *responder_pmksa;
+
+ /* DevIK variables: Cipher version, DevIK, and its lifetime
+ * These are fetched from the P2P2 included in the PASN Encrypted Data
+ * element during P2P2 group negotiation with PASN Authentication
+ * frames. These values are stored in struct p2p_data for an ongoing GO
+ * negotiation or join-a-group operation with the assumption that these
+ * operations cannot happen in parallel with multiple peers. After
+ * successful group formation and connection, these are moved to
+ * wpa_supplicant configuration if the connection is persistent. */
+ u8 dik_cipher_version;
+ u8 peer_dik_data[DEVICE_IDENTITY_KEY_MAX_LEN];
+ size_t peer_dik_len;
+ unsigned int peer_dik_lifetime;
+
+ /* Password used during an ongoing group formation after opportunistic
+ * PASN authentication or while joining an existing group. This will be
+ * moved to a more permanent location from struct p2p_data at the
+ * conclusion of a successful pairing. */
+ char dev_sae_password[100];
+ char peer_sae_password[100];
+
+ /* Variable used to know the role of the device in a given instance.
+ * go_role variable is set while authorizing a P2P Client for PASN
+ * authentication with predefined GO intent value for GO (15 for
+ * P2P-GO). Once the authentication is completed and security
+ * configuration is done, this variable is reset to false.
+ */
+ bool go_role;
+
+#ifdef CONFIG_TESTING_OPTIONS
+ /**
+ * PASN PTK of recent auth
+ */
+ u8 pasn_ptk[128];
+
+ /**
+ * PASN PTK length
+ */
+ size_t pasn_ptk_len;
+#endif /* CONFIG_TESTING_OPTIONS */
};
/**
@@ -898,6 +962,8 @@
const struct weighted_pcl *pref_freq_list,
unsigned int size);
struct wpabuf * p2p_encaps_ie(const struct wpabuf *subelems, u32 ie_type);
+struct wpabuf * p2p_group_build_p2p2_ie(struct p2p_data *p2p,
+ struct wpabuf *p2p2_ie, int freq);
/* p2p_sd.c */
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
@@ -951,19 +1017,23 @@
struct p2p_device *dev);
/* p2p_invitation.c */
+struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
+ struct p2p_device *peer,
+ const u8 *go_dev_addr, int dev_pw_id);
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);
+ int rx_freq, bool p2p2);
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,
const u8 *go_dev_addr, int dev_pw_id);
void p2p_invitation_req_cb(struct p2p_data *p2p, int success);
-void p2p_invitation_resp_cb(struct p2p_data *p2p, int success);
+void p2p_invitation_resp_cb(struct p2p_data *p2p, const u8 *dst, int success);
+void p2p_start_invitation_connect(struct p2p_data *p2p, struct p2p_device *dev);
/* p2p_dev_disc.c */
void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
@@ -1021,6 +1091,9 @@
struct p2p_channels *res, bool go);
void p2p_sd_query_cb(struct p2p_data *p2p, int success);
+void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev,
+ const u8 *addr, int freq, bool verify,
+ bool derive_kek);
void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 3fd66c2..766b63e 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -11,14 +11,17 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "common/wpa_ctrl.h"
+#include "common/sae.h"
+#include "crypto/sha384.h"
+#include "common/wpa_common.h"
+#include "pasn/pasn_common.h"
#include "p2p_i.h"
#include "p2p.h"
-static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
- struct p2p_device *peer,
- const u8 *go_dev_addr,
- int dev_pw_id)
+struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
+ struct p2p_device *peer,
+ const u8 *go_dev_addr, int dev_pw_id)
{
struct wpabuf *buf;
u8 *len;
@@ -100,7 +103,7 @@
if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ])
wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]);
- if (dev_pw_id >= 0) {
+ if (dev_pw_id >= 0 && !peer->p2p2) {
/* WSC IE in Invitation Request for NFC static handover */
p2p_build_wps_ie(p2p, buf, dev_pw_id, 0);
}
@@ -183,7 +186,7 @@
struct wpabuf * p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
const u8 *data, size_t len,
- int rx_freq)
+ int rx_freq, bool p2p2)
{
struct p2p_device *dev;
struct p2p_message msg;
@@ -268,7 +271,8 @@
p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id,
msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN,
&go, group_bssid, &op_freq, persistent, &intersection,
- msg.dev_password_id_present ? msg.dev_password_id : -1);
+ msg.dev_password_id_present ? msg.dev_password_id : -1,
+ p2p2);
}
if (go) {
@@ -311,6 +315,17 @@
p2p_dbg(p2p, "Own default op_class %d channel %d",
p2p->op_reg_class, p2p->op_channel);
+#ifdef CONFIG_TESTING_OPTIONS
+ if (p2p->cfg->inv_op_class) {
+ /* Override configuration as a starting point */
+ p2p->op_reg_class = p2p->cfg->inv_op_class;
+ p2p->op_channel = p2p->cfg->inv_op_channel;
+ p2p_dbg(p2p,
+ "Override Invitation op_class %d channel %d",
+ p2p->op_reg_class, p2p->op_channel);
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
/* Use peer preference if specified and compatible */
if (msg.operating_channel) {
int req_freq;
@@ -422,7 +437,7 @@
int freq;
struct wpabuf *resp;
- resp = p2p_process_invitation_req(p2p, sa, data, len, rx_freq);
+ resp = p2p_process_invitation_req(p2p, sa, data, len, rx_freq, false);
if (!resp)
return;
@@ -451,6 +466,7 @@
struct p2p_device *dev;
struct p2p_message msg;
struct p2p_channels intersection, *channels = NULL;
+ bool all_channels = false;
p2p_dbg(p2p, "Received Invitation Response from " MACSTR,
MAC2STR(sa));
@@ -530,14 +546,17 @@
#endif /* CONFIG_P2P_STRICT */
/* Try to survive without peer channel list */
channels = &p2p->channels;
+ all_channels = true;
} else if (!msg.channel_list) {
/* Non-success cases are not required to include Channel List */
channels = &p2p->channels;
+ all_channels = true;
} else if (p2p_peer_channels_check(p2p, &p2p->channels, dev,
msg.channel_list,
msg.channel_list_len) < 0) {
p2p_dbg(p2p, "No common channels found");
p2p_parse_free(&msg);
+ dev->inv_reject = true;
return;
} else {
p2p_channels_intersect(&p2p->channels, &dev->channels,
@@ -566,17 +585,74 @@
*/
p2p_check_pref_chan(p2p, 0, dev, &msg);
+ if (dev->p2p2) {
+ dev->inv_freq = freq;
+ dev->inv_status = *msg.status;
+ dev->inv_all_channels = all_channels;
+ dev->inv_peer_oper_freq = peer_oper_freq;
+ if (msg.group_bssid)
+ os_memcpy(dev->inv_bssid, msg.group_bssid,
+ ETH_ALEN);
+ goto out;
+ }
+
p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status,
msg.group_bssid, channels, sa,
- freq, peer_oper_freq);
+ freq, peer_oper_freq, NULL, NULL,
+ 0);
}
+ p2p_clear_timeout(p2p);
+ p2p_set_state(p2p, P2P_IDLE);
+ p2p->invite_peer = NULL;
+
+out:
p2p_parse_free(&msg);
+}
+
+
+#ifdef CONFIG_PASN
+void p2p_start_invitation_connect(struct p2p_data *p2p, struct p2p_device *dev)
+{
+ size_t pmk_len = 0;
+ u8 pmkid[PMKID_LEN];
+ u8 pmk[PMK_LEN_MAX];
+ struct p2p_channels intersection;
+ const struct p2p_channels *inv_channels;
+
+ if (!p2p || !dev || dev->inv_reject || !dev->pasn)
+ return;
+
+ if (dev->inv_all_channels) {
+ inv_channels = &p2p->channels;
+ } else {
+ p2p_channels_intersect(&p2p->channels, &dev->channels,
+ &intersection);
+ inv_channels = &intersection;
+ }
+
+ pasn_initiator_pmksa_cache_get(dev->pasn->pmksa, dev->pasn->peer_addr,
+ pmkid, pmk, &pmk_len);
+
+ wpa_pasn_reset(dev->pasn);
+ p2p_dbg(p2p, "Invitation connect: msg status %d", dev->inv_status);
+ if (p2p->cfg->invitation_result)
+ p2p->cfg->invitation_result(p2p->cfg->cb_ctx, dev->inv_status,
+ dev->inv_bssid, inv_channels,
+ dev->info.p2p_device_addr,
+ dev->inv_freq,
+ dev->inv_peer_oper_freq, pmkid,
+ pmk, pmk_len);
+
+ /* Reset PMK and PMKID from stack */
+ forced_memzero(pmkid, sizeof(pmkid));
+ forced_memzero(pmk, sizeof(pmk));
p2p_clear_timeout(p2p);
p2p_set_state(p2p, P2P_IDLE);
p2p->invite_peer = NULL;
}
+#endif /* CONFIG_PASN */
int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev,
@@ -647,8 +723,26 @@
}
-void p2p_invitation_resp_cb(struct p2p_data *p2p, int success)
+void p2p_invitation_resp_cb(struct p2p_data *p2p, const u8 *peer, int success)
{
+ size_t pmk_len = 0;
+ const u8 *pmkid = NULL, *pmk = NULL;
+
+#ifdef CONFIG_PASN
+ u8 _pmkid[PMKID_LEN];
+ u8 _pmk[PMK_LEN_MAX];
+ struct p2p_device *dev;
+
+ dev = p2p_get_device(p2p, peer);
+ if (dev && dev->pasn) {
+ pasn_responder_pmksa_cache_get(dev->pasn->pmksa,
+ dev->pasn->peer_addr, _pmkid,
+ _pmk, &pmk_len);
+ pmkid = _pmkid;
+ pmk = _pmk;
+ }
+#endif /* CONFIG_PASN */
+
p2p_dbg(p2p, "Invitation Response TX callback: success=%d", success);
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
@@ -662,15 +756,23 @@
p2p->inv_ssid, p2p->inv_ssid_len,
p2p->inv_go_dev_addr,
p2p->inv_status,
- p2p->inv_op_freq);
+ p2p->inv_op_freq, pmkid, pmk,
+ pmk_len);
}
+
+#ifdef CONFIG_PASN
+ /* Reset PMK and PMKID from stack */
+ forced_memzero(_pmkid, sizeof(_pmkid));
+ forced_memzero(_pmk, sizeof(_pmk));
+#endif /* CONFIG_PASN */
}
int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
const u8 *bssid, const u8 *ssid, size_t ssid_len,
unsigned int force_freq, const u8 *go_dev_addr,
- int persistent_group, unsigned int pref_freq, int dev_pw_id)
+ int persistent_group, unsigned int pref_freq, int dev_pw_id,
+ bool p2p2)
{
struct p2p_device *dev;
@@ -738,5 +840,8 @@
os_memcpy(p2p->inv_ssid, ssid, ssid_len);
p2p->inv_ssid_len = ssid_len;
p2p->inv_persistent = persistent_group;
+ if (p2p2)
+ return 0;
+
return p2p_invite_send(p2p, dev, go_dev_addr, dev_pw_id);
}
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index fb20313..a55e7e6 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -703,7 +703,6 @@
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;
}
}
@@ -849,6 +848,12 @@
wpa_printf(MSG_ERROR, "Bootstrap received %d", bootstrap);
+ if (status == P2P_SC_SUCCESS) {
+ dev->role = P2P_ROLE_PAIRING_RESPONDER;
+#ifdef CONFIG_PASN
+ p2p_pasn_initialize(p2p, dev, sa, rx_freq, false, true);
+#endif /* CONFIG_PASN */
+ }
out:
/* Send PD Bootstrapping Response for the PD Request */
resp = p2p_build_prov_disc_bootstrap_resp(p2p, dev, msg->dialog_token,
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index bc33a25..be7293f 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -3161,9 +3161,9 @@
be_to_host16(eth_hdr->ethertype));
/* the destination address shall not be an individual address */
- if (!ether_addr_equal(eth_hdr->dest, pae_group_addr)) {
+ if (!is_multicast_ether_addr(eth_hdr->dest)) {
wpa_printf(MSG_DEBUG,
- "KaY: ethernet destination address is not PAE group address");
+ "KaY: ethernet destination address is not a multicast adddress");
return -1;
}
diff --git a/src/pasn/pasn_common.c b/src/pasn/pasn_common.c
index 25e44a1..654656e 100644
--- a/src/pasn/pasn_common.c
+++ b/src/pasn/pasn_common.c
@@ -15,6 +15,8 @@
#include "crypto/sha384.h"
#include "crypto/crypto.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/aes_wrap.h"
#include "pasn_common.h"
@@ -31,6 +33,7 @@
if (!pasn)
return;
os_free(pasn->rsnxe_ie);
+ wpabuf_free(pasn->frame);
bin_clear_free(pasn, sizeof(struct pasn_data));
}
@@ -241,3 +244,107 @@
return NULL;
return &pasn->ptk;
}
+
+
+int pasn_add_encrypted_data(struct pasn_data *pasn, struct wpabuf *buf,
+ const u8 *data, size_t data_len)
+{
+ int ret;
+ u8 *encrypted_data, *padded_data = NULL;
+ u8 *len;
+ size_t pad_len = 0;
+
+ if (!pasn->ptk.kek_len) {
+ wpa_printf(MSG_DEBUG, "PASN: KEK not available");
+ return -2;
+ }
+
+ pad_len = data_len % 8;
+ if (pad_len) {
+ pad_len = 8 - pad_len;
+ padded_data = os_zalloc(data_len + pad_len);
+ if (!padded_data)
+ return -1;
+ os_memcpy(padded_data, data, data_len);
+ data = padded_data;
+ padded_data[data_len] = 0xdd;
+ }
+ data_len += pad_len + 8;
+
+ encrypted_data = os_malloc(data_len);
+ if (!encrypted_data) {
+ os_free(padded_data);
+ return -1;
+ }
+
+ ret = aes_wrap(pasn->ptk.kek, pasn->ptk.kek_len,
+ (data_len - 8) / 8, data, encrypted_data);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "PASN: AES wrap failed, ret=%d", ret);
+ goto out;
+ }
+
+ if (wpabuf_tailroom(buf) < 1 + 1 + 1 + data_len) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Not enough room in the buffer for PASN Encrypred Data element");
+ ret = -1;
+ goto out;
+ }
+
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ len = wpabuf_put(buf, 1);
+
+ wpabuf_put_u8(buf, WLAN_EID_EXT_PASN_ENCRYPTED_DATA);
+
+ wpabuf_put_data(buf, encrypted_data, data_len);
+ *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
+
+out:
+ os_free(padded_data);
+ os_free(encrypted_data);
+ return ret;
+}
+
+
+int pasn_parse_encrypted_data(struct pasn_data *pasn, const u8 *data,
+ size_t len)
+{
+ int ret = -1;
+ u8 *buf;
+ u16 buf_len;
+ struct ieee802_11_elems elems;
+ const struct ieee80211_mgmt *mgmt =
+ (const struct ieee80211_mgmt *) data;
+
+ if (len < 24 + 6 ||
+ ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 0) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ return -1;
+ }
+
+ if (!elems.pasn_encrypted_data || elems.pasn_encrypted_data_len < 8 ||
+ elems.pasn_encrypted_data_len % 8) {
+ wpa_printf(MSG_DEBUG, "PASN: No encrypted elements");
+ return 0;
+ }
+
+ buf_len = elems.pasn_encrypted_data_len - 8;
+
+ buf = os_malloc(buf_len);
+ if (!buf)
+ return -1;
+
+ ret = aes_unwrap(pasn->ptk.kek, pasn->ptk.kek_len, buf_len / 8,
+ elems.pasn_encrypted_data, buf);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "PASN: AES unwrap failed, ret=%d", ret);
+ else if (pasn->parse_data_element && pasn->cb_ctx)
+ ret = pasn->parse_data_element(pasn->cb_ctx, buf, buf_len);
+
+ os_free(buf);
+ return ret;
+}
diff --git a/src/pasn/pasn_common.h b/src/pasn/pasn_common.h
index 7b7c737..cc3abf6 100644
--- a/src/pasn/pasn_common.h
+++ b/src/pasn/pasn_common.h
@@ -66,6 +66,7 @@
size_t extra_ies_len;
/* External modules do not access below variables */
+ bool derive_kek;
size_t kek_len;
u16 group;
bool secure_ltf;
@@ -130,6 +131,7 @@
struct os_reltime last_comeback_key_update;
u16 comeback_idx;
u16 *comeback_pending_idx;
+ struct wpabuf *frame;
/**
* send_mgmt - Function handler to transmit a Management frame
@@ -151,6 +153,10 @@
*/
int (*validate_custom_pmkid)(void *ctx, const u8 *addr,
const u8 *pmkid);
+
+ int (*prepare_data_element)(void *ctx, const u8 *peer_addr);
+
+ int (*parse_data_element)(void *ctx, const u8 *data, size_t len);
};
/* Initiator */
@@ -210,8 +216,9 @@
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);
+ const u8 *own_addr, const u8 *bssid,
+ const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid);
int pasn_initiator_pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *bssid, u8 *pmkid, u8 *pmk,
size_t *pmk_len);
@@ -232,8 +239,9 @@
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);
+ const u8 *own_addr, const u8 *bssid,
+ const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid);
int pasn_responder_pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
const u8 *bssid, u8 *pmkid, u8 *pmk,
size_t *pmk_len);
@@ -246,6 +254,10 @@
size_t pasn_get_pmk_len(struct pasn_data *pasn);
u8 * pasn_get_pmk(struct pasn_data *pasn);
struct wpa_ptk * pasn_get_ptk(struct pasn_data *pasn);
+int pasn_add_encrypted_data(struct pasn_data *pasn, struct wpabuf *buf,
+ const u8 *data, size_t data_len);
+int pasn_parse_encrypted_data(struct pasn_data *pasn, const u8 *data,
+ size_t len);
#ifdef __cplusplus
}
diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c
index ce1055b..035ae81 100644
--- a/src/pasn/pasn_initiator.c
+++ b/src/pasn/pasn_initiator.c
@@ -39,8 +39,9 @@
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)
+ const u8 *own_addr, const u8 *bssid,
+ const u8 *pmk,
+ size_t pmk_len, const u8 *pmkid)
{
if (pmksa_cache_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, bssid,
own_addr, NULL, WPA_KEY_MGMT_SAE, 0))
@@ -682,7 +683,8 @@
{
struct wpabuf *buf, *wrapped_data_buf = NULL;
u8 mic[WPA_PASN_MAX_MIC_LEN];
- u8 mic_len, data_len;
+ u8 mic_len;
+ size_t data_len;
const u8 *data;
u8 *ptr;
u8 wrapped_data;
@@ -716,6 +718,11 @@
wpabuf_free(wrapped_data_buf);
wrapped_data_buf = NULL;
+ if (pasn->prepare_data_element && pasn->cb_ctx)
+ pasn->prepare_data_element(pasn->cb_ctx, pasn->peer_addr);
+
+ wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
+
/* Add the MIC */
mic_len = pasn_mic_len(pasn->akmp, pasn->cipher);
wpabuf_put_u8(buf, WLAN_EID_MIC);
@@ -817,6 +824,9 @@
os_free((u8 *) pasn->extra_ies);
pasn->extra_ies = NULL;
}
+
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
}
@@ -987,16 +997,20 @@
goto fail;
}
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+
ret = pasn->send_mgmt(pasn->cb_ctx,
wpabuf_head(frame), wpabuf_len(frame), 0,
pasn->freq, 1000);
- wpabuf_free(frame);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed sending 1st auth frame");
+ wpabuf_free(frame);
goto fail;
}
+ pasn->frame = frame;
return 0;
fail:
@@ -1386,21 +1400,30 @@
wpa_printf(MSG_DEBUG, "PASN: Success verifying Authentication frame");
+ if (pasn_parse_encrypted_data(pasn, data, len) < 0) {
+ wpa_printf(MSG_DEBUG, "PASN: Encrypted data processing failed");
+ goto fail;
+ }
+
frame = wpas_pasn_build_auth_3(pasn);
if (!frame) {
wpa_printf(MSG_DEBUG, "PASN: Failed building 3rd auth frame");
goto fail;
}
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+
ret = pasn->send_mgmt(pasn->cb_ctx,
wpabuf_head(frame), wpabuf_len(frame), 0,
pasn->freq, 100);
- wpabuf_free(frame);
if (ret) {
wpa_printf(MSG_DEBUG, "PASN: Failed sending 3st auth frame");
+ wpabuf_free(frame);
goto fail;
}
+ pasn->frame = frame;
wpa_printf(MSG_DEBUG, "PASN: Success sending last frame. Store PTK");
pasn->status = WLAN_STATUS_SUCCESS;
diff --git a/src/pasn/pasn_responder.c b/src/pasn/pasn_responder.c
index e344898..11f27e1 100644
--- a/src/pasn/pasn_responder.c
+++ b/src/pasn/pasn_responder.c
@@ -39,8 +39,9 @@
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)
+ const u8 *own_addr, const u8 *bssid,
+ const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid)
{
if (pmksa_cache_auth_add(pmksa, pmk, pmk_len, pmkid, NULL, 0, own_addr,
bssid, 0, NULL, WPA_KEY_MGMT_SAE))
@@ -561,6 +562,9 @@
if (rsnxe_ie)
wpabuf_put_data(buf, rsnxe_ie, 2 + rsnxe_ie[1]);
+ if (pasn->prepare_data_element && pasn->cb_ctx)
+ pasn->prepare_data_element(pasn->cb_ctx, peer_addr);
+
wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
/* Add the mic */
@@ -636,6 +640,8 @@
wpa_printf(MSG_DEBUG,
"PASN: Building frame 2: success; resp STA=" MACSTR,
MAC2STR(peer_addr));
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
ret = pasn->send_mgmt(pasn->cb_ctx, wpabuf_head_u8(buf),
wpabuf_len(buf), 0, pasn->freq, 0);
@@ -643,7 +649,7 @@
wpa_printf(MSG_INFO, "send_auth_reply: Send failed");
wpabuf_free(rsn_buf);
- wpabuf_free(buf);
+ pasn->frame = buf;
return ret;
fail:
wpabuf_free(wrapped_data_buf);
@@ -735,6 +741,14 @@
wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
+ if (!ieee802_11_rsnx_capab_len(elems.rsnxe, elems.rsnxe_len,
+ WLAN_RSNX_CAPAB_KEK_IN_PASN)) {
+ pasn->kek_len = 0;
+ pasn->derive_kek = false;
+ }
+
+ wpa_printf(MSG_DEBUG, "PASN: kek_len=%zu", pasn->kek_len);
+
if (!elems.pasn_params || !elems.pasn_params_len) {
wpa_printf(MSG_DEBUG,
"PASN: No PASN Parameters element found");
@@ -1086,6 +1100,11 @@
wpabuf_free(wrapped_data);
}
+ if (pasn_parse_encrypted_data(pasn, (const u8 *) mgmt, len) < 0) {
+ wpa_printf(MSG_DEBUG, "PASN: Encrypted data processing failed");
+ goto fail;
+ }
+
wpa_printf(MSG_INFO,
"PASN: Success handling transaction == 3. Store PTK");
return 0;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index d145da0..d8cdebb 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -650,6 +650,8 @@
#ifdef CONFIG_TESTING_OPTIONS
if (sm->encrypt_eapol_m2)
key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
+ if (sm->eapol_2_key_info_set_mask)
+ key_info |= sm->eapol_2_key_info_set_mask;
#endif /* CONFIG_TESTING_OPTIONS */
WPA_PUT_BE16(reply->key_info, key_info);
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
@@ -3816,7 +3818,8 @@
* @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
* @len: Length of the EAPOL frame
* @encrypted: Whether the frame was encrypted
- * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure
+ * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure,
+ * -2 = reply counter did not increase.
*
* This function is called for each received EAPOL frame. Other than EAPOL-Key
* frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is
@@ -3925,6 +3928,7 @@
WPA_REPLAY_COUNTER_LEN) <= 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: EAPOL-Key Replay Counter did not increase - dropping packet");
+ ret = -2;
goto out;
}
@@ -4374,6 +4378,8 @@
wpabuf_free(sm->test_assoc_ie);
wpabuf_free(sm->test_eapol_m2_elems);
wpabuf_free(sm->test_eapol_m4_elems);
+ wpabuf_free(sm->test_rsnxe_data);
+ wpabuf_free(sm->test_rsnxe_mask);
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FILS_SK_PFS
crypto_ecdh_deinit(sm->fils_ecdh);
@@ -4973,6 +4979,9 @@
case WPA_PARAM_ENCRYPT_EAPOL_M4:
sm->encrypt_eapol_m4 = value;
break;
+ case WPA_PARAM_EAPOL_2_KEY_INFO_SET_MASK:
+ sm->eapol_2_key_info_set_mask = value;
+ break;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_DPP2
case WPA_PARAM_DPP_PFS:
@@ -5230,6 +5239,76 @@
}
+#ifdef CONFIG_TESTING_OPTIONS
+
+int wpa_sm_set_test_rsnxe_data(struct wpa_sm *sm, struct wpabuf *data,
+ struct wpabuf *mask)
+{
+ size_t data_len = 0, mask_len = 0;
+
+ wpabuf_free(sm->test_rsnxe_data);
+ sm->test_rsnxe_data = NULL;
+ wpabuf_free(sm->test_rsnxe_mask);
+ sm->test_rsnxe_mask = NULL;
+
+ if (!data && !mask)
+ return 0;
+
+ if (data)
+ data_len = wpabuf_len(data);
+ if (mask)
+ mask_len = wpabuf_len(mask);
+
+ if (data_len != mask_len || data_len > 255)
+ return -1;
+
+ sm->test_rsnxe_data = data;
+ sm->test_rsnxe_mask = mask;
+
+ return 0;
+}
+
+
+static int wpa_set_test_rsnxe_data(struct wpa_sm *sm, u8 *rsnxe,
+ size_t orig_len, size_t max_len)
+{
+ const u8 *data, *mask;
+ size_t i, data_len;
+
+ if (!sm->test_rsnxe_data || !sm->test_rsnxe_mask)
+ return orig_len;
+
+ mask = wpabuf_head(sm->test_rsnxe_mask);
+ data = wpabuf_head(sm->test_rsnxe_data);
+ data_len = wpabuf_len(sm->test_rsnxe_data);
+ if (max_len < data_len + 2) {
+ wpa_printf(MSG_ERROR, "Couldn't fit RSNXE test data");
+ return -1;
+ }
+
+ /* Set data after original RSNXE to zero */
+ if (orig_len < data_len + 2)
+ os_memset(&rsnxe[orig_len], 0, data_len + 2 - orig_len);
+
+ /* Set EID and length fields */
+ *rsnxe++ = WLAN_EID_RSNX;
+ *rsnxe++ = data_len;
+
+ /* Preserve original RSNXE bit value when mask bit is zero */
+ for (i = 0; i < data_len; i++) {
+ if (!mask[i])
+ continue;
+
+ rsnxe[i] &= ~mask[i];
+ rsnxe[i] |= data[i] & mask[i];
+ }
+
+ return data_len + 2;
+}
+
+#endif /* CONFIG_TESTING_OPTIONS */
+
+
/**
* wpa_sm_set_assoc_rsnxe_default - Generate own RSNXE from configuration
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -5248,6 +5327,11 @@
res = wpa_gen_rsnxe(sm, rsnxe, *rsnxe_len);
if (res < 0)
return -1;
+#ifdef CONFIG_TESTING_OPTIONS
+ res = wpa_set_test_rsnxe_data(sm, rsnxe, res, *rsnxe_len);
+ if (res < 0)
+ return -1;
+#endif /* CONFIG_TESTING_OPTIONS */
*rsnxe_len = res;
wpa_hexdump(MSG_DEBUG, "RSN: Set own RSNXE default", rsnxe, *rsnxe_len);
@@ -5565,6 +5649,25 @@
}
+int wpa_sm_pmksa_get_pmk(struct wpa_sm *sm, const u8 *aa, const u8 **pmk,
+ size_t *pmk_len, const u8 **pmkid)
+{
+ struct rsn_pmksa_cache_entry *pmksa;
+
+ pmksa = wpa_sm_pmksa_cache_get(sm, aa, NULL, NULL, 0);
+ if (!pmksa) {
+ wpa_printf(MSG_DEBUG, "RSN: Failed to get PMKSA for " MACSTR,
+ MAC2STR(aa));
+ return -1;
+ }
+
+ *pmk = pmksa->pmk;
+ *pmk_len = pmksa->pmk_len;
+ *pmkid = pmksa->pmkid;
+ return 0;
+}
+
+
void wpa_sm_pmksa_cache_remove(struct wpa_sm *sm,
struct rsn_pmksa_cache_entry *entry)
{
@@ -6670,6 +6773,29 @@
goto fail;
}
+ if ((sm->ap_rsnxe && !elems.rsnxe) ||
+ (!sm->ap_rsnxe && elems.rsnxe) ||
+ (sm->ap_rsnxe && elems.rsnxe && sm->ap_rsnxe_len >= 2 &&
+ (sm->ap_rsnxe_len != 2U + elems.rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe + 2, elems.rsnxe, sm->ap_rsnxe_len - 2) !=
+ 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "FILS: RSNXE mismatch between Beacon/Probe Response and (Re)Association Response");
+ wpa_hexdump(MSG_INFO, "FILS: RSNXE in Beacon/Probe Response",
+ sm->ap_rsnxe, sm->ap_rsnxe_len);
+ wpa_hexdump(MSG_INFO, "RSNXE in (Re)Association Response",
+ elems.rsnxe, elems.rsnxe_len);
+ /* As an interop workaround, allow this for now if we did not
+ * include the RSNXE in (Re)Association Request frame since
+ * IEEE Std 802.11-2020 does not say anything about verifying
+ * the RSNXE in FILS cases and there have been hostapd releases
+ * that might omit the RSNXE in cases where the STA did not
+ * include it in the Association Request frame. This workaround
+ * might eventually be removed. */
+ if (sm->assoc_rsnxe && sm->assoc_rsnxe_len)
+ goto fail;
+ }
+
/* TODO: FILS Public Key */
if (!elems.fils_key_confirm) {
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index ca64d8f..39a1e93 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -139,6 +139,7 @@
WPA_PARAM_SSID_PROTECTION,
WPA_PARAM_RSN_OVERRIDE,
WPA_PARAM_RSN_OVERRIDE_SUPPORT,
+ WPA_PARAM_EAPOL_2_KEY_INFO_SET_MASK,
};
enum wpa_rsn_override {
@@ -255,6 +256,8 @@
const u8 *pmkid,
const void *network_ctx,
int akmp);
+int wpa_sm_pmksa_get_pmk(struct wpa_sm *sm, const u8 *aa, const u8 **pmk,
+ size_t *pmk_len, const u8 **pmkid);
void wpa_sm_pmksa_cache_remove(struct wpa_sm *sm,
struct rsn_pmksa_cache_entry *entry);
bool wpa_sm_has_ft_keys(struct wpa_sm *sm, const u8 *md);
@@ -279,6 +282,8 @@
int wpa_fils_is_completed(struct wpa_sm *sm);
void wpa_sm_pmksa_cache_reconfig(struct wpa_sm *sm);
int wpa_sm_set_mlo_params(struct wpa_sm *sm, const struct wpa_sm_mlo *mlo);
+void wpa_sm_set_driver_bss_selection(struct wpa_sm *sm,
+ bool driver_bss_selection);
#else /* CONFIG_NO_WPA */
@@ -322,6 +327,11 @@
{
}
+static inline void wpa_sm_set_ssid(struct wpa_sm *sm, const u8 *ssid,
+ size_t ssid_len)
+{
+}
+
static inline void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
{
}
@@ -471,7 +481,7 @@
return NULL;
}
-static inline int wpa_sm_has_ptk(struct wpa_sm *sm)
+static inline int wpa_sm_has_ptk_installed(struct wpa_sm *sm)
{
return 0;
}
@@ -517,6 +527,11 @@
return 0;
}
+static inline void wpa_sm_set_driver_bss_selection(struct wpa_sm *sm,
+ bool driver_bss_selection)
+{
+}
+
#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_IEEE80211R
@@ -645,6 +660,8 @@
void wpa_sm_set_test_eapol_m2_elems(struct wpa_sm *sm, struct wpabuf *buf);
void wpa_sm_set_test_eapol_m4_elems(struct wpa_sm *sm, struct wpabuf *buf);
const u8 * wpa_sm_get_anonce(struct wpa_sm *sm);
+int wpa_sm_set_test_rsnxe_data(struct wpa_sm *sm, struct wpabuf *data,
+ struct wpabuf *mask);
unsigned int wpa_sm_get_key_mgmt(struct wpa_sm *sm);
struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md);
@@ -670,7 +687,5 @@
void wpa_sm_set_cur_pmksa(struct wpa_sm *sm,
struct rsn_pmksa_cache_entry *entry);
const u8 * wpa_sm_get_auth_addr(struct wpa_sm *sm);
-void wpa_sm_set_driver_bss_selection(struct wpa_sm *sm,
- bool driver_bss_selection);
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 9a39749..544e349 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -215,7 +215,7 @@
struct rsn_mdie *mdie;
struct rsn_ie_hdr *rsnie;
int mdie_len;
- u8 rsnxe[10];
+ u8 rsnxe[257];
size_t rsnxe_len;
int rsnxe_used;
int res;
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index ef26b24..2fd08b0 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -188,12 +188,15 @@
struct wpabuf *test_assoc_ie;
struct wpabuf *test_eapol_m2_elems;
struct wpabuf *test_eapol_m4_elems;
+ struct wpabuf *test_rsnxe_data;
+ struct wpabuf *test_rsnxe_mask;
int ft_rsnxe_used;
unsigned int oci_freq_override_eapol;
unsigned int oci_freq_override_eapol_g2;
unsigned int oci_freq_override_ft_assoc;
unsigned int oci_freq_override_fils_assoc;
unsigned int disable_eapol_g2_tx;
+ unsigned int eapol_2_key_info_set_mask;
bool encrypt_eapol_m2;
bool encrypt_eapol_m4;
#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/utils/common.h b/src/utils/common.h
index aed93fb..3deb204 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -283,6 +283,23 @@
a[0] = val & 0xff;
}
+static inline u64 WPA_GET_LE48(const u8 *a)
+{
+ return (((u64) a[5]) << 40) | (((u64) a[4]) << 32) |
+ (((u64) a[3]) << 24) | (((u64) a[2]) << 16) |
+ (((u64) a[1]) << 8) | ((u64) a[0]);
+}
+
+static inline void WPA_PUT_LE48(u8 *a, u64 val)
+{
+ a[5] = val >> 40;
+ a[4] = val >> 32;
+ a[3] = val >> 24;
+ a[2] = val >> 16;
+ a[1] = val >> 8;
+ a[0] = val & 0xff;
+}
+
static inline u64 WPA_GET_BE64(const u8 *a)
{
return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) |
diff --git a/src/utils/ext_password_file.c b/src/utils/ext_password_file.c
index 4bb0095..3122512 100644
--- a/src/utils/ext_password_file.c
+++ b/src/utils/ext_password_file.c
@@ -9,7 +9,6 @@
#include "includes.h"
#include "utils/common.h"
-#include "utils/config.h"
#include "ext_password_i.h"
@@ -97,9 +96,19 @@
wpa_printf(MSG_DEBUG, "EXT PW FILE: get(%s)", name);
- while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
- char *sep = os_strchr(pos, '=');
+ while ((pos = fgets(buf, sizeof(buf), f))) {
+ char *sep;
+ line++;
+
+ /* Strip newline characters */
+ pos[strcspn(pos, "\r\n")] = 0;
+
+ /* Skip comments and empty lines */
+ if (*pos == '#' || *pos == '\0')
+ continue;
+
+ sep = os_strchr(pos, '=');
if (!sep) {
wpa_printf(MSG_ERROR, "Invalid password line %d.",
line);
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index e190645..0b8612a 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -569,7 +569,7 @@
struct wpa_trace_test_fail {
unsigned int fail_after;
char pattern[256];
-} wpa_trace_test_fail[5][2];
+} wpa_trace_test_fail[5][4];
int testing_test_fail(const char *tag, bool is_alloc)
{
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 291aa07..b3876c5 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -36,6 +36,7 @@
#define wpa_debug_open_file(p) do { } while (0)
#define wpa_debug_close_file() do { } while (0)
#define wpa_debug_setup_stdout() do { } while (0)
+#define wpa_debug_stop_log() do { } while (0)
#define wpa_dbg(args...) do { } while (0)
static inline int wpa_debug_reopen_file(void)
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index 5361289..380fe47 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -12,6 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// The wpa_supplicant related modules are split into 2 sections:
+// 1. For cuttlefish series products, start from `wpa_supplicant_headers` to `libpasn`.
+// 2. For non-cuttlefish series products, ex: physical devices created by oems,
+// the section starts from `wpa_supplicant_driver_srcs_default` to the end of this file.
+
package {
default_applicable_licenses: [
// Inherits SPDX-license-identifier-BSD-3-Clause
@@ -36,6 +41,9 @@
],
}
+// The section below is for cuttlefish series products. For non-cuttlefish
+// products please update the section starting at `wpa_supplicant_driver_srcs_default`.
+// Start of cuttlefish section
cc_library_headers {
name: "wpa_supplicant_headers",
export_include_dirs: [
@@ -150,6 +158,7 @@
"-DCONFIG_IPV6",
"-DCONFIG_JSON",
"-DCONFIG_MBO",
+ "-DCONFIG_NAN_USD",
"-DCONFIG_NO_ACCOUNTING",
"-DCONFIG_NO_RADIUS",
"-DCONFIG_NO_RADIUS",
@@ -290,6 +299,7 @@
"interworking.c",
"main.c",
"mbo.c",
+ "nan_usd.c",
"notify.c",
"offchannel.c",
"op_classes.c",
@@ -326,6 +336,7 @@
"src/ap/ieee802_11_vht.c",
"src/ap/ieee802_1x.c",
"src/ap/mbo_ap.c",
+ "src/ap/nan_usd_ap.c",
"src/ap/neighbor_db.c",
"src/ap/p2p_hostapd.c",
"src/ap/pmksa_cache_auth.c",
@@ -351,6 +362,7 @@
"src/common/gas_server.c",
"src/common/hw_features_common.c",
"src/common/ieee802_11_common.c",
+ "src/common/nan_de.c",
"src/common/sae.c",
"src/common/sae_pk.c",
"src/common/wpa_common.c",
@@ -702,7 +714,29 @@
},
}
-// For converting the default to soong
+// End of cuttlefish section
+
+// The section starting below is for non-cuttlefish products.
+// For cuttlefish series please update the section starting from `wpa_supplicant_headers`.
+
+// If you need to add a new build setting based on a product config, ex:
+// ifeq ($(WIFI_PRIV_CMD_UPDATE_MBO_CELL_STATUS), enabled)
+// L_CFLAGS += -DENABLE_PRIV_CMD_UPDATE_MBO_CELL_STATUS
+// endif
+
+// In order to export the Makefile variable to soong, you will need to use a `soong_config_set` method
+// under `build/core/board_config_wpa_supplicant.mk`. Ex:
+// ifeq ($(WIFI_PRIV_CMD_UPDATE_MBO_CELL_STATUS), enabled)
+// $(call soong_config_set_bool,wpa_supplicant_8,wifi_priv_cmd_update_mbo_cell_status,true)
+// endif
+
+// And then use the select statement in Android.bp to reflect the condition you need, ex:
+// select(soong_config_variable("wpa_supplicant_8", "wifi_priv_cmd_update_mbo_cell_status"), {
+// true: ["-DENABLE_PRIV_CMD_UPDATE_MBO_CELL_STATUS"],
+// default: [],
+// })
+
+// Start of non-cuttlefish section
cc_defaults {
name: "wpa_supplicant_driver_srcs_default",
srcs: [
@@ -870,21 +904,21 @@
] + 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: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "wpa_supplicant_11ax"), {
+ true: ["-DCONFIG_IEEE80211AX"],
+ default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "wpa_supplicant_11be"), {
+ true: ["-DCONFIG_IEEE80211BE"],
+ default: [],
}),
arch: {
arm: {
@@ -1157,9 +1191,12 @@
"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"), {
+ ] + select(soong_config_variable("wpa_supplicant_8", "wpa_supplicant_11ax"), {
true: ["src/ap/ieee802_11_he.c"],
default: [],
+ }) + select(soong_config_variable("wpa_supplicant_8", "wpa_supplicant_11be"), {
+ true: ["src/ap/ieee802_11_eht.c"],
+ default: [],
}),
defaults: [
"wpa_supplicant_driver_srcs_default",
@@ -1222,6 +1259,18 @@
],
}
+cc_defaults {
+ name: "wpa_supplicant_usd_defaults",
+ cflags: [
+ "-DCONFIG_NAN_USD",
+ ],
+ srcs: [
+ "nan_usd.c",
+ "src/ap/nan_usd_ap.c",
+ "src/common/nan_de.c",
+ ],
+}
+
cc_binary {
name: "wpa_cli",
proprietary: true,
@@ -1295,6 +1344,7 @@
"wpa_supplicant_srcs_default",
"wpa_supplicant_cflags_default",
"wpa_supplicant_includes_default",
+ "wpa_supplicant_usd_defaults",
],
soong_config_variables: {
board_wpa_supplicant_private_lib: {
@@ -1448,6 +1498,7 @@
name: "libwpa_aidl",
vendor: true,
cppflags: [
+ "-DCONFIG_NAN_USD",
"-Wall",
"-Werror",
"-Wno-unused-parameter",
@@ -1480,3 +1531,18 @@
"wpa_supplicant_includes_default",
],
}
+
+// End of non-cuttlefish section
+
+genrule {
+ name: "com.android.hardware.wpa_supplicant.rc-gen",
+ srcs: ["aidl/vendor/android.hardware.wifi.supplicant-service.rc"],
+ out: ["com.android.hardware.wpa_supplicant.rc"],
+ cmd: "sed -E 's@/vendor/bin@/apex/com.android.hardware.wpa_supplicant/bin@' $(in) > $(out)",
+}
+
+prebuilt_etc {
+ name: "com.android.hardware.wpa_supplicant.rc",
+ src: ":com.android.hardware.wpa_supplicant.rc-gen",
+ installable: false,
+}
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 581d907..1b5ea81 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -329,6 +329,7 @@
ifdef CONFIG_NAN_USD
OBJS += src/common/nan_de.c
OBJS += nan_usd.c
+NEED_OFFCHANNEL=y
L_CFLAGS += -DCONFIG_NAN_USD
endif
@@ -763,7 +764,7 @@
EAPDYN += src/eap_common/eap_teap_common.c
else
L_CFLAGS += -DEAP_TEAP
-OBJS += src/eap_peer/eap_teap.c src/eap_peer/eap_teap_pac.c
+OBJS += src/eap_peer/eap_teap.c
OBJS += src/eap_common/eap_teap_common.c
endif
TLS_FUNCS=y
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 8bec178..49c1793 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -320,6 +320,7 @@
ifdef CONFIG_NAN_USD
OBJS += ../src/common/nan_de.o
OBJS += nan_usd.o
+NEED_OFFCHANNEL=y
CFLAGS += -DCONFIG_NAN_USD
endif
@@ -763,7 +764,7 @@
ifdef CONFIG_EAP_TEAP
# EAP-TEAP
-SRC_EAP_TEAP = ../src/eap_peer/eap_teap.c ../src/eap_peer/eap_teap_pac.c
+SRC_EAP_TEAP = ../src/eap_peer/eap_teap.c
SRC_EAP_TEAP += ../src/eap_common/eap_teap_common.c
ifeq ($(CONFIG_EAP_TEAP), dyn)
CFLAGS += -DEAP_TEAP_DYNAMIC
diff --git a/wpa_supplicant/aidl/mainline/config/mainline_supplicant.rc b/wpa_supplicant/aidl/mainline/config/mainline_supplicant.rc
index 8c436c6..018df1c 100644
--- a/wpa_supplicant/aidl/mainline/config/mainline_supplicant.rc
+++ b/wpa_supplicant/aidl/mainline/config/mainline_supplicant.rc
@@ -3,7 +3,9 @@
-g@android:wpa_wlan0
interface aidl wifi_mainline_supplicant
class main
- user root
+ user wifi
+ group wifi net_raw net_admin
+ capabilities NET_RAW NET_ADMIN
socket wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
diff --git a/wpa_supplicant/aidl/mainline/usd_iface.cpp b/wpa_supplicant/aidl/mainline/usd_iface.cpp
new file mode 100644
index 0000000..b514f77
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/usd_iface.cpp
@@ -0,0 +1,43 @@
+/*
+ * WPA Supplicant - Interface for USD operations
+ * 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 "usd_iface.h"
+
+UsdIface::UsdIface(struct wpa_global* wpa_global, std::string iface_name)
+ : wpa_global_(wpa_global), iface_name_(iface_name) {}
+
+::ndk::ScopedAStatus UsdIface::getUsdCapabilities(UsdCapabilities* _aidl_return) {
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus UsdIface::startUsdPublish(int32_t in_cmdId,
+ const PublishConfig& in_usdPublishConfig) {
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus UsdIface::startUsdSubscribe(int32_t in_cmdId,
+ const SubscribeConfig& in_usdSubscribeConfig) {
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus UsdIface::updateUsdPublish(int32_t in_publishId,
+ const std::vector<uint8_t>& in_serviceSpecificInfo) {
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus UsdIface::cancelUsdPublish(int32_t in_publishId) {
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus UsdIface::cancelUsdSubscribe(int32_t in_subscribeId) {
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus UsdIface::sendUsdMessage(const UsdMessageInfo& in_messageInfo) {
+ return ndk::ScopedAStatus::ok();
+}
diff --git a/wpa_supplicant/aidl/mainline/usd_iface.h b/wpa_supplicant/aidl/mainline/usd_iface.h
new file mode 100644
index 0000000..32b86cc
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/usd_iface.h
@@ -0,0 +1,36 @@
+/*
+ * WPA Supplicant - Interface for USD operations
+ * 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_USD_IFACE_H
+#define MAINLINE_SUPPLICANT_USD_IFACE_H
+
+#include <aidl/android/system/wifi/mainline_supplicant/BnUsdInterface.h>
+
+using ::aidl::android::system::wifi::mainline_supplicant::BnUsdInterface;
+using ::aidl::android::system::wifi::mainline_supplicant::UsdMessageInfo;
+
+class UsdIface : public BnUsdInterface {
+ public:
+ UsdIface(struct wpa_global* wpa_global, std::string iface_name);
+ ::ndk::ScopedAStatus getUsdCapabilities(UsdCapabilities* _aidl_return) override;
+ ::ndk::ScopedAStatus startUsdPublish(int32_t in_cmdId,
+ const PublishConfig& in_usdPublishConfig) override;
+ ::ndk::ScopedAStatus startUsdSubscribe(int32_t in_cmdId,
+ const SubscribeConfig& in_usdSubscribeConfig) override;
+ ::ndk::ScopedAStatus updateUsdPublish(int32_t in_publishId,
+ const std::vector<uint8_t>& in_serviceSpecificInfo) override;
+ ::ndk::ScopedAStatus cancelUsdPublish(int32_t in_publishId) override;
+ ::ndk::ScopedAStatus cancelUsdSubscribe(int32_t in_subscribeId) override;
+ ::ndk::ScopedAStatus sendUsdMessage(const UsdMessageInfo& in_messageInfo) override;
+
+ private:
+ wpa_global* wpa_global_;
+ std::string iface_name_;
+};
+
+#endif // MAINLINE_SUPPLICANT_USD_IFACE_H
diff --git a/wpa_supplicant/aidl/vendor/aidl.cpp b/wpa_supplicant/aidl/vendor/aidl.cpp
index a0446fe..afda33f 100644
--- a/wpa_supplicant/aidl/vendor/aidl.cpp
+++ b/wpa_supplicant/aidl/vendor/aidl.cpp
@@ -1116,3 +1116,81 @@
wpa_printf(MSG_DEBUG, "Notifying Qos Policy SCS Response");
aidl_manager->notifyQosPolicyScsResponse(wpa_s, count, scs_resp);
}
+
+void wpas_aidl_notify_usd_service_discovered(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, const u8 *ssi, size_t ssi_len)
+{
+ if (!wpa_s || !peer_addr || !ssi)
+ return;
+
+ AidlManager *aidl_manager = AidlManager::getInstance();
+ if (!aidl_manager)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying USD service discovered");
+ aidl_manager->notifyUsdServiceDiscovered(wpa_s, srv_proto_type,
+ subscribe_id, peer_publish_id, peer_addr, fsd, ssi, ssi_len);
+}
+
+void wpas_aidl_notify_usd_publish_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)
+{
+ if (!wpa_s || !peer_addr || !ssi)
+ return;
+
+ AidlManager *aidl_manager = AidlManager::getInstance();
+ if (!aidl_manager)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying USD publish replied");
+ aidl_manager->notifyUsdPublishReplied(wpa_s, srv_proto_type,
+ publish_id, peer_subscribe_id, peer_addr, ssi, ssi_len);
+}
+
+void wpas_aidl_notify_usd_message_received(struct wpa_supplicant *wpa_s,
+ int id, int peer_instance_id, const u8 *peer_addr,
+ const u8 *message, size_t message_len)
+{
+ if (!wpa_s || !peer_addr || !message)
+ return;
+
+ AidlManager *aidl_manager = AidlManager::getInstance();
+ if (!aidl_manager)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying USD message received");
+ aidl_manager->notifyUsdMessageReceived(wpa_s, id, peer_instance_id,
+ peer_addr, message, message_len);
+}
+
+void wpas_aidl_notify_usd_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id, enum nan_de_reason reason)
+{
+ if (!wpa_s)
+ return;
+
+ AidlManager *aidl_manager = AidlManager::getInstance();
+ if (!aidl_manager)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying USD publish terminated");
+ aidl_manager->notifyUsdPublishTerminated(wpa_s, publish_id, reason);
+}
+
+void wpas_aidl_notify_usd_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id, enum nan_de_reason reason)
+{
+ if (!wpa_s)
+ return;
+
+ AidlManager *aidl_manager = AidlManager::getInstance();
+ if (!aidl_manager)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Notifying USD subscribe terminated");
+ aidl_manager->notifyUsdSubscribeTerminated(wpa_s, subscribe_id, reason);
+}
diff --git a/wpa_supplicant/aidl/vendor/aidl.h b/wpa_supplicant/aidl/vendor/aidl.h
index 71620f4..a8f38cb 100644
--- a/wpa_supplicant/aidl/vendor/aidl.h
+++ b/wpa_supplicant/aidl/vendor/aidl.h
@@ -157,6 +157,21 @@
ssize_t wpas_aidl_list_aliases(const char *prefix, char ***aliases);
void wpas_aidl_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s,
unsigned int count, int **scs_resp);
+ void wpas_aidl_notify_usd_service_discovered(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, const u8 *ssi, size_t ssi_len);
+ void wpas_aidl_notify_usd_publish_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_aidl_notify_usd_message_received(struct wpa_supplicant *wpa_s, int id,
+ int peer_instance_id, const u8 *peer_addr,
+ const u8 *message, size_t message_len);
+ void wpas_aidl_notify_usd_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id, enum nan_de_reason reason);
+ void wpas_aidl_notify_usd_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id, enum nan_de_reason reason);
#else // CONFIG_CTRL_IFACE_AIDL
static inline int wpas_aidl_register_interface(struct wpa_supplicant *wpa_s)
{
@@ -357,6 +372,21 @@
}
static void wpas_aidl_notify_qos_policy_scs_response(struct wpa_supplicant *wpa_s,
unsigned int count, int **scs_resp) {}
+static void wpas_aidl_notify_usd_service_discovered(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, const u8 *ssi, size_t ssi_len) {}
+static void wpas_aidl_notify_usd_publish_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) {}
+static void wpas_aidl_notify_usd_message_received(struct wpa_supplicant *wpa_s, int id,
+ int peer_instance_id, const u8 *peer_addr,
+ const u8 *message, size_t message_len) {}
+static void wpas_aidl_notify_usd_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id, enum nan_de_reason reason) {}
+static void wpas_aidl_notify_usd_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id, enum nan_de_reason reason) {}
#endif // CONFIG_CTRL_IFACE_AIDL
#ifdef _cplusplus
diff --git a/wpa_supplicant/aidl/vendor/aidl_manager.cpp b/wpa_supplicant/aidl/vendor/aidl_manager.cpp
index 177f478..60ce800 100644
--- a/wpa_supplicant/aidl/vendor/aidl_manager.cpp
+++ b/wpa_supplicant/aidl/vendor/aidl_manager.cpp
@@ -1313,6 +1313,33 @@
std::placeholders::_1));
}
+int32_t convertP2pPairingBootstrappingMethodsToAidl(u16 bootstrap_methods)
+{
+ int32_t pairingBootstrappingMethods = 0;
+
+ if (bootstrap_methods & P2P_PBMA_OPPORTUNISTIC) {
+ pairingBootstrappingMethods |=
+ P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_OPPORTUNISTIC;
+ }
+ if (bootstrap_methods & P2P_PBMA_PIN_CODE_DISPLAY) {
+ pairingBootstrappingMethods |=
+ P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_DISPLAY_PINCODE;
+ }
+ if (bootstrap_methods & P2P_PBMA_PASSPHRASE_DISPLAY) {
+ pairingBootstrappingMethods |=
+ P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_DISPLAY_PASSPHRASE;
+ }
+ if (bootstrap_methods & P2P_PBMA_PIN_CODE_KEYPAD) {
+ pairingBootstrappingMethods |=
+ P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_KEYPAD_PINCODE;
+ }
+ if (bootstrap_methods & P2P_PBMA_PASSPHRASE_KEYPAD) {
+ pairingBootstrappingMethods |=
+ P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_KEYPAD_PASSPHRASE;
+ }
+
+ return pairingBootstrappingMethods;
+}
void AidlManager::notifyP2pDeviceFound(
struct wpa_supplicant *wpa_s, const u8 *addr,
const struct p2p_peer_info *info, const u8 *peer_wfd_device_info,
@@ -1375,8 +1402,9 @@
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;
+ // TODO Fill the DIRA info when supplicant implementation is ready
+ params.pairingBootstrappingMethods = convertP2pPairingBootstrappingMethodsToAidl(
+ info->pairing_config.bootstrap_methods);
}
callWithEachP2pIfaceCallback(
misc_utils::charBufToString(wpa_s->ifname),
@@ -1485,6 +1513,18 @@
std::placeholders::_1, reason));
}
+uint32_t convertSupplicantKeyMgmtForP2pGroupConnectionToAidl(int supp_key_mgmt)
+{
+ uint32_t aidl_key_mgmt = 0;
+ if (supp_key_mgmt & WPA_KEY_MGMT_PSK) {
+ aidl_key_mgmt |= static_cast<uint32_t>(KeyMgmtMask::WPA_PSK);
+ }
+ if (supp_key_mgmt & WPA_KEY_MGMT_SAE) {
+ aidl_key_mgmt |= static_cast<uint32_t>(KeyMgmtMask::SAE);
+ }
+ return aidl_key_mgmt;
+}
+
void AidlManager::notifyP2pGroupStarted(
struct wpa_supplicant *wpa_group_s, const struct wpa_ssid *ssid,
int persistent, int client, const u8 *ip)
@@ -1538,10 +1578,10 @@
params.p2pClientIpInfo.ipAddressClient,
params.p2pClientIpInfo.ipAddressMask,
params.p2pClientIpInfo.ipAddressGo);
- }
+ }
if (areAidlServiceAndClientAtLeastVersion(4)) {
- // TODO Fill the field when supplicant implementation is ready
- params.keyMgmtMask = 0;
+ params.keyMgmtMask = convertSupplicantKeyMgmtForP2pGroupConnectionToAidl(
+ wpa_group_s->key_mgmt);
}
callWithEachP2pIfaceCallback(
misc_utils::charBufToString(wpa_s->ifname),
@@ -1679,75 +1719,6 @@
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)
@@ -2976,6 +2947,210 @@
std::placeholders::_1, scsResponses));
}
+void AidlManager::notifyUsdPublishStarted(struct wpa_supplicant *wpa_s,
+ int cmd_id, int publish_id)
+{
+ if (!wpa_s) return;
+ if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+ callWithEachStaIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname), std::bind(
+ &ISupplicantStaIfaceCallback::onUsdPublishStarted,
+ std::placeholders::_1, cmd_id, publish_id));
+}
+void AidlManager::notifyUsdSubscribeStarted(struct wpa_supplicant *wpa_s,
+ int cmd_id, int subscribe_id)
+{
+ if (!wpa_s) return;
+ if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+ callWithEachStaIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname), std::bind(
+ &ISupplicantStaIfaceCallback::onUsdSubscribeStarted,
+ std::placeholders::_1, cmd_id, subscribe_id));
+}
+void AidlManager::notifyUsdPublishConfigFailed(struct wpa_supplicant *wpa_s,
+ int cmd_id, ISupplicantStaIfaceCallback::UsdConfigErrorCode error_code)
+{
+ if (!wpa_s) return;
+ if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+ callWithEachStaIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname), std::bind(
+ &ISupplicantStaIfaceCallback::onUsdPublishConfigFailed,
+ std::placeholders::_1, cmd_id, error_code));
+}
+
+void AidlManager::notifyUsdSubscribeConfigFailed(struct wpa_supplicant *wpa_s,
+ int cmd_id, ISupplicantStaIfaceCallback::UsdConfigErrorCode error_code)
+{
+ if (!wpa_s) return;
+ if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+ callWithEachStaIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname), std::bind(
+ &ISupplicantStaIfaceCallback::onUsdSubscribeConfigFailed,
+ std::placeholders::_1, cmd_id, error_code));
+}
+
+UsdServiceProtoType convertUsdServiceProtoTypeToAidl(nan_service_protocol_type type) {
+ switch (type) {
+ case NAN_SRV_PROTO_GENERIC:
+ return UsdServiceProtoType::GENERIC;
+ case NAN_SRV_PROTO_CSA_MATTER:
+ return UsdServiceProtoType::CSA_MATTER;
+ default:
+ // Should not reach here
+ wpa_printf(MSG_ERROR, "Received invalid USD proto type %d from internal",
+ static_cast<int>(type));
+ return UsdServiceProtoType::GENERIC;
+ }
+}
+
+P2pUsdBasedServiceDiscoveryResultParams createP2pUsdBasedServiceDiscoveryResult(
+ enum nan_service_protocol_type srv_proto_type,
+ int own_id, int peer_id, const u8 *peer_addr,
+ const u8 *ssi, size_t ssi_len) {
+ P2pUsdBasedServiceDiscoveryResultParams p2pServiceDiscoveryInfo;
+ p2pServiceDiscoveryInfo.peerMacAddress = macAddrToArray(peer_addr);
+ p2pServiceDiscoveryInfo.sessionId = own_id;
+ p2pServiceDiscoveryInfo.peerSessionId = peer_id;
+ p2pServiceDiscoveryInfo.serviceProtocolType = static_cast<int>(srv_proto_type);
+ if (ssi != NULL) {
+ p2pServiceDiscoveryInfo.serviceSpecificInfo = byteArrToVec(ssi, ssi_len);
+ }
+ return p2pServiceDiscoveryInfo;
+}
+
+UsdServiceDiscoveryInfo createUsdServiceDiscoveryInfo(
+ enum nan_service_protocol_type srv_proto_type,
+ int own_id, int peer_id, const u8 *peer_addr,
+ bool fsd, const u8 *ssi, size_t ssi_len) {
+ // TODO: Fill the matchFilter field in the AIDL struct
+ UsdServiceDiscoveryInfo discoveryInfo;
+ discoveryInfo.ownId = own_id;
+ discoveryInfo.peerId = peer_id;
+ discoveryInfo.peerMacAddress = macAddrToArray(peer_addr);
+ discoveryInfo.protoType = convertUsdServiceProtoTypeToAidl(srv_proto_type);
+ discoveryInfo.serviceSpecificInfo = byteArrToVec(ssi, ssi_len);
+ discoveryInfo.isFsd = fsd;
+ return discoveryInfo;
+}
+
+void AidlManager::notifyUsdServiceDiscovered(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, const u8 *ssi, size_t ssi_len)
+{
+ if (!wpa_s || !peer_addr) return;
+ if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+ if (p2p_iface_object_map_.find(wpa_s->ifname) != p2p_iface_object_map_.end()) {
+ // Notify service discovered event on P2P device interface.
+ P2pUsdBasedServiceDiscoveryResultParams p2pServiceDiscoveryInfo =
+ createP2pUsdBasedServiceDiscoveryResult(srv_proto_type, subscribe_id,
+ peer_publish_id, peer_addr, ssi, ssi_len);
+ callWithEachP2pIfaceCallback(misc_utils::charBufToString(wpa_s->ifname),
+ std::bind(&ISupplicantP2pIfaceCallback::onUsdBasedServiceDiscoveryResult,
+ std::placeholders::_1, p2pServiceDiscoveryInfo));
+ } else {
+ // Notify service discovered event on STA interface.
+ UsdServiceDiscoveryInfo discoveryInfo = createUsdServiceDiscoveryInfo(
+ srv_proto_type, subscribe_id, peer_publish_id, peer_addr, fsd, ssi, ssi_len);
+ callWithEachStaIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname), std::bind(
+ &ISupplicantStaIfaceCallback::onUsdServiceDiscovered,
+ std::placeholders::_1, discoveryInfo));
+ }
+}
+
+void AidlManager::notifyUsdPublishReplied(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)
+{
+ if (!wpa_s || !peer_addr || !ssi) return;
+ if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+ UsdServiceDiscoveryInfo discoveryInfo = createUsdServiceDiscoveryInfo(
+ srv_proto_type, publish_id, peer_subscribe_id, peer_addr, false /* fsd */,
+ ssi, ssi_len);
+ callWithEachStaIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname), std::bind(
+ &ISupplicantStaIfaceCallback::onUsdPublishReplied,
+ std::placeholders::_1, discoveryInfo));
+}
+
+void AidlManager::notifyUsdMessageReceived(struct wpa_supplicant *wpa_s, int id,
+ int peer_instance_id, const u8 *peer_addr,
+ const u8 *message, size_t message_len)
+{
+ if (!wpa_s || !peer_addr || !message) return;
+ if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+
+ UsdMessageInfo messageInfo;
+ messageInfo.ownId = id;
+ messageInfo.peerId = peer_instance_id;
+ messageInfo.peerMacAddress = macAddrToArray(peer_addr);
+ messageInfo.message = byteArrToVec(message, message_len);
+
+ callWithEachStaIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname), std::bind(
+ &ISupplicantStaIfaceCallback::onUsdMessageReceived,
+ std::placeholders::_1, messageInfo));
+}
+
+UsdTerminateReasonCode convertUsdTerminateReasonCodeToAidl(nan_de_reason reason) {
+ switch (reason) {
+ case NAN_DE_REASON_TIMEOUT:
+ return UsdTerminateReasonCode::TIMEOUT;
+ case NAN_DE_REASON_USER_REQUEST:
+ return UsdTerminateReasonCode::USER_REQUEST;
+ case NAN_DE_REASON_FAILURE:
+ return UsdTerminateReasonCode::FAILURE;
+ default:
+ return UsdTerminateReasonCode::UNKNOWN;
+ }
+}
+
+void AidlManager::notifyUsdPublishTerminated(struct wpa_supplicant *wpa_s,
+ int publish_id, enum nan_de_reason reason)
+{
+ if (!wpa_s) return;
+ if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+ UsdTerminateReasonCode aidlReasonCode = convertUsdTerminateReasonCodeToAidl(reason);
+ if (p2p_iface_object_map_.find(wpa_s->ifname) != p2p_iface_object_map_.end()) {
+ // Notify publish terminated event on P2P device interface.
+ callWithEachP2pIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname),
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onUsdBasedServiceAdvertisementTerminated,
+ std::placeholders::_1, publish_id, aidlReasonCode));
+ } else {
+ // Notify publish terminated event on STA interface.
+ callWithEachStaIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname), std::bind(
+ &ISupplicantStaIfaceCallback::onUsdPublishTerminated,
+ std::placeholders::_1, publish_id, aidlReasonCode));
+ }
+}
+
+void AidlManager::notifyUsdSubscribeTerminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id, enum nan_de_reason reason)
+{
+ if (!wpa_s) return;
+ if (!areAidlServiceAndClientAtLeastVersion(4)) return;
+ UsdTerminateReasonCode aidlReasonCode = convertUsdTerminateReasonCodeToAidl(reason);
+ if (p2p_iface_object_map_.find(wpa_s->ifname) != p2p_iface_object_map_.end()) {
+ // Notify subscribe terminated event on P2P device interface.
+ callWithEachP2pIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname),
+ std::bind(
+ &ISupplicantP2pIfaceCallback::onUsdBasedServiceDiscoveryTerminated,
+ std::placeholders::_1, subscribe_id, aidlReasonCode));
+ } else {
+ // Notify subscribe terminated event on STA interface.
+ callWithEachStaIfaceCallback(
+ misc_utils::charBufToString(wpa_s->ifname), std::bind(
+ &ISupplicantStaIfaceCallback::onUsdSubscribeTerminated,
+ std::placeholders::_1, subscribe_id, aidlReasonCode));
+ }
+}
+
} // namespace supplicant
} // namespace wifi
} // namespace hardware
diff --git a/wpa_supplicant/aidl/vendor/aidl_manager.h b/wpa_supplicant/aidl/vendor/aidl_manager.h
index 46a40aa..667422f 100644
--- a/wpa_supplicant/aidl/vendor/aidl_manager.h
+++ b/wpa_supplicant/aidl/vendor/aidl_manager.h
@@ -120,15 +120,6 @@
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);
@@ -178,6 +169,29 @@
unsigned int count, int **scs_resp);
void notifyMloLinksInfoChanged(struct wpa_supplicant *wpa_s,
enum mlo_info_change_reason reason);
+ void notifyUsdPublishStarted(struct wpa_supplicant *wpa_s,
+ int cmd_id, int publish_id);
+ void notifyUsdSubscribeStarted(struct wpa_supplicant *wpa_s,
+ int cmd_id, int subscribe_id);
+ void notifyUsdPublishConfigFailed(struct wpa_supplicant *wpa_s,
+ int cmd_id, ISupplicantStaIfaceCallback::UsdConfigErrorCode error_code);
+ void notifyUsdSubscribeConfigFailed(struct wpa_supplicant *wpa_s,
+ int cmd_id, ISupplicantStaIfaceCallback::UsdConfigErrorCode error_code);
+ void notifyUsdServiceDiscovered(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, const u8 *ssi, size_t ssi_len);
+ void notifyUsdPublishReplied(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 notifyUsdMessageReceived(struct wpa_supplicant *wpa_s, int id,
+ int peer_instance_id, const u8 *peer_addr,
+ const u8 *message, size_t message_len);
+ void notifyUsdPublishTerminated(struct wpa_supplicant *wpa_s,
+ int publish_id, enum nan_de_reason reason);
+ void notifyUsdSubscribeTerminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id, enum nan_de_reason reason);
// Methods called from aidl objects.
int32_t isAidlServiceVersionAtLeast(int32_t expected_version);
diff --git a/wpa_supplicant/aidl/vendor/p2p_iface.cpp b/wpa_supplicant/aidl/vendor/p2p_iface.cpp
index b1cd1cd..16c5536 100644
--- a/wpa_supplicant/aidl/vendor/p2p_iface.cpp
+++ b/wpa_supplicant/aidl/vendor/p2p_iface.cpp
@@ -24,6 +24,10 @@
}
#define P2P_JOIN_LIMIT 3
+#define WPA_KEY_MGMT_P2P_MODE_WFD_PCC (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_PSK)
+#define IS_P2P_MODE_WFD_PCC_KEY_MGMT(key_mgmt_mask) \
+ ((key_mgmt_mask & WPA_KEY_MGMT_P2P_MODE_WFD_PCC) == WPA_KEY_MGMT_P2P_MODE_WFD_PCC)
+#define DEFAULT_QUERY_PERIOD_MS 40
namespace {
const char kConfigMethodStrPbc[] = "pbc";
@@ -40,9 +44,14 @@
using aidl::android::hardware::wifi::supplicant::ISupplicantP2pIface;
using aidl::android::hardware::wifi::supplicant::ISupplicantStaNetwork;
+using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
using aidl::android::hardware::wifi::supplicant::MiracastMode;
using aidl::android::hardware::wifi::supplicant::P2pFrameTypeMask;
+constexpr uint32_t kAllowedKeyMgmtMask =
+ (static_cast<uint32_t>(KeyMgmtMask::WPA_PSK) |
+ static_cast<uint32_t>(KeyMgmtMask::SAE));
+
uint8_t convertAidlMiracastModeToInternal(
MiracastMode mode)
{
@@ -168,13 +177,23 @@
const uint8_t *group_owner_bssid,
const std::vector<uint8_t>& ssid,
const std::string& passphrase,
- uint32_t freq)
+ uint32_t freq,
+ uint32_t key_mgmt_mask)
{
int ret = 0;
int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
+ if (key_mgmt_mask != 0 && key_mgmt_mask & ~kAllowedKeyMgmtMask) {
+ return -1;
+ }
+
+ if (key_mgmt_mask == WPA_KEY_MGMT_SAE) {
+ wpa_s->p2p2 = true;
+ wpa_s->p2p_mode = WPA_P2P_MODE_WFD_R2;
+ }
+
// Construct a network for adding group.
// Group client follows the persistent attribute of Group Owner.
// If joined group is persistent, it adds a persistent network on GroupStarted.
@@ -191,7 +210,8 @@
if (wpas_p2p_group_add_persistent(
wpa_s, wpa_network, 0, 0, freq, 0, ht40, vht,
CONF_OPER_CHWIDTH_USE_HT, he, 0, NULL, 0, 0, is6GhzAllowed(wpa_s),
- P2P_JOIN_LIMIT, isAnyEtherAddr(group_owner_bssid) ? NULL : group_owner_bssid)) {
+ P2P_JOIN_LIMIT, isAnyEtherAddr(group_owner_bssid) ? NULL : group_owner_bssid,
+ NULL, NULL, NULL, 0)) {
ret = -1;
}
@@ -400,7 +420,7 @@
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&P2pIface::connectInternal, _aidl_return, in_peerAddress,
in_provisionMethod, in_preSelectedPin, in_joinExistingGroup,
- in_persistent, in_goIntent);
+ in_persistent, in_goIntent, 0, "", 0, false, "");
}
::ndk::ScopedAStatus P2pIface::cancelConnect()
@@ -417,7 +437,7 @@
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&P2pIface::provisionDiscoveryInternal, in_peerAddress,
- in_provisionMethod);
+ in_provisionMethod, 0);
}
ndk::ScopedAStatus P2pIface::addGroup(
@@ -426,7 +446,7 @@
return validateAndCall(
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&P2pIface::addGroupInternal, in_persistent,
- in_persistentNetworkId);
+ in_persistentNetworkId, false);
}
::ndk::ScopedAStatus P2pIface::addGroupWithConfig(
@@ -439,7 +459,8 @@
this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
&P2pIface::addGroupWithConfigInternal, in_ssid,
in_pskPassphrase, in_persistent, in_freq,
- in_peerAddress, in_joinExistingGroup);
+ in_peerAddress, in_joinExistingGroup,
+ static_cast<uint32_t>(KeyMgmtMask::WPA_PSK));
}
::ndk::ScopedAStatus P2pIface::removeGroup(
@@ -1098,13 +1119,38 @@
return ndk::ScopedAStatus::ok();
}
+u16 convertAidlPairingBootstrappingMethodToWpa(uint32_t pairing_bootstrapping_method)
+{
+ switch (pairing_bootstrapping_method) {
+ case P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_OPPORTUNISTIC:
+ return P2P_PBMA_OPPORTUNISTIC;
+ case P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_DISPLAY_PINCODE:
+ return P2P_PBMA_PIN_CODE_DISPLAY;
+ case P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_DISPLAY_PASSPHRASE:
+ return P2P_PBMA_PASSPHRASE_DISPLAY;
+ case P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_KEYPAD_PINCODE:
+ return P2P_PBMA_PIN_CODE_KEYPAD;
+ case P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_KEYPAD_PASSPHRASE:
+ return P2P_PBMA_PASSPHRASE_KEYPAD;
+ case P2pPairingBootstrappingMethodMask::BOOTSTRAPPING_OUT_OF_BAND:
+ return P2P_PBMA_HANDSHAKE_SKIP;
+ default:
+ return 0;
+ }
+}
+
// This method only implements support for subset (needed by Android framework)
// of parameters that can be specified for connect.
std::pair<std::string, ndk::ScopedAStatus> P2pIface::connectInternal(
const std::vector<uint8_t>& peer_address,
WpsProvisionMethod provision_method,
const std::string& pre_selected_pin, bool join_existing_group,
- bool persistent, uint32_t go_intent)
+ bool persistent, uint32_t go_intent,
+ uint32_t pairing_bootstrapping_method,
+ const std::string& password,
+ uint32_t frequency,
+ bool authorize,
+ const std::string& group_ifname)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
if (go_intent > 15) {
@@ -1129,6 +1175,28 @@
wps_method = WPS_NOT_READY;
break;
}
+
+ bool p2p2 = false;
+ u16 bootstrap = 0;
+ const char* pairing_password = nullptr;
+ bool skip_prov = false;
+ int auto_join = 0;
+ if (wps_method == WPS_NOT_READY) {
+ bootstrap = convertAidlPairingBootstrappingMethodToWpa(
+ pairing_bootstrapping_method);
+ if (bootstrap == 0) {
+ return {"", createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+ }
+ if (bootstrap == P2P_PBMA_HANDSHAKE_SKIP) {
+ skip_prov = true;
+ }
+ p2p2 = true;
+ pairing_password = password.length() > 0 ? password.data() : nullptr;
+ if (authorize) {
+ auto_join = 1;
+ }
+ }
+
int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
@@ -1136,10 +1204,10 @@
const char* pin =
pre_selected_pin.length() > 0 ? pre_selected_pin.data() : nullptr;
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,
+ wpa_s, peer_address.data(), pin, wps_method, persistent, auto_join,
+ join_existing_group, authorize, go_intent_signed, 0, 0, -1, false, ht40,
vht, CONF_OPER_CHWIDTH_USE_HT, he, edmg, nullptr, 0, is6GhzAllowed(wpa_s),
- false, 0, NULL);
+ p2p2, bootstrap, pairing_password, skip_prov);
if (new_pin < 0) {
return {"", createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
}
@@ -1167,7 +1235,8 @@
ndk::ScopedAStatus P2pIface::provisionDiscoveryInternal(
const std::vector<uint8_t>& peer_address,
- WpsProvisionMethod provision_method)
+ WpsProvisionMethod provision_method,
+ uint32_t pairingBootstrappingMethod)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
p2ps_provision* prov_param;
@@ -1185,11 +1254,11 @@
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;
}
+ // TODO Handle pairing bootstrapping method when supplicant implementation is ready
if (wpas_p2p_prov_disc(
wpa_s, peer_address.data(), config_method_str,
WPAS_P2P_PD_FOR_GO_NEG, nullptr)) {
@@ -1263,7 +1332,7 @@
}
if (wpas_p2p_invite(
wpa_s, peer_address.data(), ssid, NULL, 0, 0, ht40, vht,
- CONF_OPER_CHWIDTH_USE_HT, 0, he, edmg, is6GhzAllowed(wpa_s))) {
+ CONF_OPER_CHWIDTH_USE_HT, 0, he, edmg, is6GhzAllowed(wpa_s), false)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
@@ -1714,19 +1783,21 @@
}
ndk::ScopedAStatus P2pIface::addGroupInternal(
- bool persistent, int32_t persistent_network_id)
+ bool persistent, int32_t persistent_network_id, bool p2p2)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
int he = wpa_s->conf->p2p_go_he;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
int edmg = wpa_s->conf->p2p_go_edmg;
+ enum wpa_p2p_mode p2p_mode = p2p2 ? WPA_P2P_MODE_WFD_R2 : WPA_P2P_MODE_WFD_R1;
struct wpa_ssid* ssid =
wpa_config_get_network(wpa_s->conf, persistent_network_id);
if (ssid == NULL) {
if (wpas_p2p_group_add(
wpa_s, persistent, 0, 0, ht40, vht,
- CONF_OPER_CHWIDTH_USE_HT, he, edmg, is6GhzAllowed(wpa_s))) {
+ CONF_OPER_CHWIDTH_USE_HT, he, edmg, is6GhzAllowed(wpa_s),
+ p2p2, p2p_mode)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
} else {
return ndk::ScopedAStatus::ok();
@@ -1735,7 +1806,8 @@
if (wpas_p2p_group_add_persistent(
wpa_s, ssid, 0, 0, 0, 0, ht40, vht,
CONF_OPER_CHWIDTH_USE_HT, he, edmg, NULL, 0, 0,
- is6GhzAllowed(wpa_s), 0, NULL)) {
+ is6GhzAllowed(wpa_s), 0, NULL,
+ NULL, NULL, NULL, 0)) {
return createStatus(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN);
} else {
return ndk::ScopedAStatus::ok();
@@ -1744,10 +1816,21 @@
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
+enum wpa_p2p_mode convertAidlKeyMgmtMaskToWpaP2pMode(uint32_t key_mgmt_mask)
+{
+ if (IS_P2P_MODE_WFD_PCC_KEY_MGMT(key_mgmt_mask)) {
+ return WPA_P2P_MODE_WFD_PCC;
+ } else if (wpa_key_mgmt_sae(key_mgmt_mask)) {
+ return WPA_P2P_MODE_WFD_R2;
+ } else {
+ return WPA_P2P_MODE_WFD_R1;
+ }
+}
+
ndk::ScopedAStatus P2pIface::addGroupWithConfigInternal(
const std::vector<uint8_t>& ssid, const std::string& passphrase,
bool persistent, uint32_t freq, const std::vector<uint8_t>& peer_address,
- bool joinExistingGroup)
+ bool joinExistingGroup, uint32_t key_mgmt_mask)
{
struct wpa_supplicant* wpa_s = retrieveIfacePtr();
int he = wpa_s->conf->p2p_go_he;
@@ -1769,10 +1852,17 @@
"Passphrase is invalid.");
}
+ if (key_mgmt_mask != 0 && key_mgmt_mask & ~kAllowedKeyMgmtMask) {
+ return createStatusWithMsg(SupplicantStatusCode::FAILURE_ARGS_INVALID,
+ "Unknown key_mgmt_mask");
+ }
+
+ enum wpa_p2p_mode p2p_mode = convertAidlKeyMgmtMaskToWpaP2pMode(key_mgmt_mask);
+
wpa_printf(MSG_DEBUG,
- "P2P: Add group with config Role: %s network name: %s freq: %d",
+ "P2P: Add group with config Role: %s network name: %s freq: %d p2p_mode: %d",
joinExistingGroup ? "CLIENT" : "GO",
- wpa_ssid_txt(ssid.data(), ssid.size()), freq);
+ wpa_ssid_txt(ssid.data(), ssid.size()), freq, p2p_mode);
if (!joinExistingGroup) {
struct p2p_data *p2p = wpa_s->global->p2p;
os_memcpy(p2p->ssid, ssid.data(), ssid.size());
@@ -1785,7 +1875,8 @@
if (wpas_p2p_group_add(
wpa_s, persistent, freq, 0, ht40, vht,
- CONF_OPER_CHWIDTH_USE_HT, he, edmg, is6GhzAllowed(wpa_s))) {
+ CONF_OPER_CHWIDTH_USE_HT, he, edmg, is6GhzAllowed(wpa_s),
+ false, p2p_mode)) {
return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
@@ -1798,7 +1889,7 @@
return createStatusWithMsg(SupplicantStatusCode::FAILURE_ARGS_INVALID,
"Peer address is invalid.");
}
- if (joinGroup(wpa_s, peer_address.data(), ssid, passphrase, freq)) {
+ if (joinGroup(wpa_s, peer_address.data(), ssid, passphrase, freq, key_mgmt_mask)) {
return createStatusWithMsg(SupplicantStatusCode::FAILURE_UNKNOWN,
"Failed to start scan.");
}
@@ -1979,7 +2070,12 @@
connectInfo.peerAddress.begin(), connectInfo.peerAddress.end()};
return connectInternal(peerAddressVec, connectInfo.provisionMethod,
connectInfo.preSelectedPin, connectInfo.joinExistingGroup,
- connectInfo.persistent, connectInfo.goIntent);
+ connectInfo.persistent, connectInfo.goIntent,
+ connectInfo.pairingBootstrappingMethod,
+ connectInfo.password.has_value() ? connectInfo.password.value() : "",
+ connectInfo.frequencyMHz, connectInfo.authorizeConnectionFromPeer,
+ connectInfo.groupInterfaceName.has_value() ?
+ connectInfo.groupInterfaceName.value() : "");
}
ndk::ScopedAStatus P2pIface::findWithParamsInternal(const P2pDiscoveryInfo& discoveryInfo)
@@ -2015,14 +2111,16 @@
groupConfigurationParams.ssid, groupConfigurationParams.passphrase,
groupConfigurationParams.isPersistent, groupConfigurationParams.frequencyMHzOrBand,
goInterfaceAddressVec,
- groupConfigurationParams.joinExistingGroup);
+ groupConfigurationParams.joinExistingGroup,
+ groupConfigurationParams.keyMgmtMask);
}
ndk::ScopedAStatus P2pIface::createGroupOwnerInternal(
const P2pCreateGroupOwnerInfo& groupOwnerInfo)
{
return addGroupInternal(
- groupOwnerInfo.persistent, groupOwnerInfo.persistentNetworkId);
+ groupOwnerInfo.persistent, groupOwnerInfo.persistentNetworkId,
+ groupOwnerInfo.isP2pV2);
}
std::pair<int64_t, ndk::ScopedAStatus> P2pIface::getFeatureSetInternal()
@@ -2035,37 +2133,119 @@
P2pIface::startUsdBasedServiceDiscoveryInternal(
const P2pUsdBasedServiceDiscoveryConfig& serviceDiscoveryConfig)
{
- // TODO Fill the field when supplicant implementation is ready
- return {0, ndk::ScopedAStatus::ok()};
+#ifdef CONFIG_NAN_USD
+ int sessionId;
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ struct nan_subscribe_params params;
+ struct wpabuf *service_specific_info = NULL;
+
+ os_memset(¶ms, 0, sizeof(params));
+
+ if (serviceDiscoveryConfig.serviceSpecificInfo.size() > 0) {
+ auto ssiBuffer = misc_utils::convertVectorToWpaBuf(
+ serviceDiscoveryConfig.serviceSpecificInfo);
+ if (ssiBuffer && ssiBuffer.get() != nullptr) {
+ service_specific_info = ssiBuffer.get();
+ }
+ }
+
+ params.active = true;
+ params.ttl = serviceDiscoveryConfig.timeoutInSeconds;
+ params.query_period = DEFAULT_QUERY_PERIOD_MS;
+ if (serviceDiscoveryConfig.bandMask != 0) {
+ // TODO convert band to channel instead of scanning all channel frequencies.
+ params.freq_list = wpas_nan_usd_all_freqs(wpa_s);
+ } else {
+ if (serviceDiscoveryConfig.frequencyListMhz.size() != 0) {
+ params.freq_list = serviceDiscoveryConfig.frequencyListMhz.data();
+ } else {
+ params.freq = NAN_USD_DEFAULT_FREQ;
+ }
+ }
+ sessionId = wpas_nan_usd_subscribe(wpa_s, serviceDiscoveryConfig.serviceName.c_str(),
+ (enum nan_service_protocol_type)
+ serviceDiscoveryConfig.serviceProtocolType,
+ service_specific_info, ¶ms, true);
+ if (service_specific_info != NULL) {
+ freeWpaBuf(service_specific_info);
+ }
+ if (sessionId > 0) {
+ return {sessionId, ndk::ScopedAStatus::ok()};
+ }
+ return {-1, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+#else
+ return {-1, createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED)};
+#endif
}
ndk::ScopedAStatus P2pIface::stopUsdBasedServiceDiscoveryInternal(
uint32_t sessionId)
{
- // TODO Fill the field when supplicant implementation is ready
+#ifdef CONFIG_NAN_USD
+ wpas_nan_usd_cancel_subscribe(retrieveIfacePtr(), sessionId);
return ndk::ScopedAStatus::ok();
+#else
+ return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+#endif
}
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()};
+#ifdef CONFIG_NAN_USD
+ int sessionId;
+ struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+ struct nan_publish_params params;
+ struct wpabuf *service_specific_info = NULL;
+ os_memset(¶ms, 0, sizeof(params));
+
+ if (serviceAdvertisementConfig.serviceSpecificInfo.size() > 0) {
+ auto ssiBuffer = misc_utils::convertVectorToWpaBuf(
+ serviceAdvertisementConfig.serviceSpecificInfo);
+ if (ssiBuffer && ssiBuffer.get() != nullptr) {
+ service_specific_info = ssiBuffer.get();
+ }
+ }
+
+ params.solicited = true;
+ params.ttl = serviceAdvertisementConfig.timeoutInSeconds;
+ params.freq = serviceAdvertisementConfig.frequencyMHz;
+ sessionId = wpas_nan_usd_publish(wpa_s, serviceAdvertisementConfig.serviceName.c_str(),
+ (enum nan_service_protocol_type)
+ serviceAdvertisementConfig.serviceProtocolType,
+ service_specific_info, ¶ms, true);
+ if (service_specific_info != NULL) {
+ freeWpaBuf(service_specific_info);
+ }
+ if (sessionId > 0) {
+ return {sessionId, ndk::ScopedAStatus::ok()};
+ }
+ return {-1, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+#else
+ return {-1, createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED)};
+#endif
}
ndk::ScopedAStatus P2pIface::stopUsdBasedServiceAdvertisementInternal(
uint32_t sessionId)
{
- // TODO Fill the field when supplicant implementation is ready
+#ifdef CONFIG_NAN_USD
+ wpas_nan_usd_cancel_publish(retrieveIfacePtr(), sessionId);
return ndk::ScopedAStatus::ok();
+#else
+ return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+#endif
}
ndk::ScopedAStatus P2pIface::provisionDiscoveryWithParamsInternal(
const P2pProvisionDiscoveryParams& params)
{
- // TODO Fill the field when supplicant implementation is ready
- return ndk::ScopedAStatus::ok();
+ std::vector<uint8_t> peerMacAddressVec {
+ params.peerMacAddress.begin(),
+ params.peerMacAddress.end()};
+ return provisionDiscoveryInternal(peerMacAddressVec, params.provisionMethod,
+ params.pairingBootstrappingMethod);
}
std::pair<P2pDirInfo, ndk::ScopedAStatus> P2pIface::getDirInfoInternal()
diff --git a/wpa_supplicant/aidl/vendor/p2p_iface.h b/wpa_supplicant/aidl/vendor/p2p_iface.h
index 545a6c9..1c38437 100644
--- a/wpa_supplicant/aidl/vendor/p2p_iface.h
+++ b/wpa_supplicant/aidl/vendor/p2p_iface.h
@@ -19,6 +19,7 @@
#include <aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.h>
#include <aidl/android/hardware/wifi/supplicant/ISupplicantP2pNetwork.h>
#include <aidl/android/hardware/wifi/supplicant/MiracastMode.h>
+#include <aidl/android/hardware/wifi/supplicant/P2pPairingBootstrappingMethodMask.h>
#include <aidl/android/hardware/wifi/supplicant/WpsProvisionMethod.h>
extern "C"
@@ -230,16 +231,20 @@
const std::vector<uint8_t>& peer_address,
WpsProvisionMethod provision_method,
const std::string& pre_selected_pin, bool join_existing_group,
- bool persistent, uint32_t go_intent);
+ bool persistent, uint32_t go_intent,
+ uint32_t pairing_bootstrapping_method, const std::string& password,
+ uint32_t frequency, bool authorize, const std::string& group_ifname);
ndk::ScopedAStatus cancelConnectInternal();
ndk::ScopedAStatus provisionDiscoveryInternal(
const std::vector<uint8_t>& peer_address,
- WpsProvisionMethod provision_method);
- ndk::ScopedAStatus addGroupInternal(bool in_persistent, int32_t in_persistentNetworkId);
+ WpsProvisionMethod provision_method,
+ uint32_t pairingBootstrappingMethod);
+ ndk::ScopedAStatus addGroupInternal(bool in_persistent, int32_t in_persistentNetworkId,
+ bool isP2pV2);
ndk::ScopedAStatus addGroupWithConfigInternal(
const std::vector<uint8_t>& ssid, const std::string& passphrase,
bool persistent, uint32_t freq, const std::vector<uint8_t>& peer_address,
- bool joinExistingGroup);
+ bool joinExistingGroup, uint32_t key_mgmt_mask);
ndk::ScopedAStatus removeGroupInternal(const std::string& group_ifname);
ndk::ScopedAStatus rejectInternal(
const std::vector<uint8_t>& peer_address);
diff --git a/wpa_supplicant/aidl/vendor/sta_iface.cpp b/wpa_supplicant/aidl/vendor/sta_iface.cpp
index 1a6ae08..fe6738c 100644
--- a/wpa_supplicant/aidl/vendor/sta_iface.cpp
+++ b/wpa_supplicant/aidl/vendor/sta_iface.cpp
@@ -38,6 +38,12 @@
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::UsdBaseConfig;
+using aidl::android::hardware::wifi::supplicant::UsdCapabilities;
+using aidl::android::hardware::wifi::supplicant::UsdPublishConfig;
+using aidl::android::hardware::wifi::supplicant::UsdPublishTransmissionType;
+using aidl::android::hardware::wifi::supplicant::UsdServiceProtoType;
+using aidl::android::hardware::wifi::supplicant::UsdSubscribeConfig;
using aidl::android::hardware::wifi::supplicant::WifiChannelWidthInMhz;
using aidl::android::hardware::wifi::supplicant::WifiTechnology;
using aidl::android::hardware::wifi::supplicant::misc_utils::createStatus;
@@ -58,6 +64,14 @@
static_cast<uint32_t>(ISupplicant::EXT_RADIO_WORK_TIMEOUT_IN_SECS);
constexpr char kExtRadioWorkNamePrefix[] = "ext:";
+constexpr bool kIsUsdPublisherSupported = false;
+constexpr bool kIsUsdSubscriberSupported = false;
+constexpr int32_t kMaxUsdLocalSsiLengthBytes = 1400;
+constexpr int32_t kMaxUsdServiceNameLengthBytes = 255;
+constexpr int32_t kMaxUsdMatchFilterLengthBytes = 255;
+constexpr int32_t kMaxNumUsdPublishSessions = 1;
+constexpr int32_t kMaxNumUsdSubscribeSessions = 1;
+
uint8_t convertAidlRxFilterTypeToInternal(
RxFilterType type)
{
@@ -84,6 +98,21 @@
WPA_ASSERT(false);
}
+nan_service_protocol_type convertAidlServiceProtoTypeToInternal(
+ UsdServiceProtoType type)
+{
+ switch (type) {
+ case UsdServiceProtoType::GENERIC:
+ return NAN_SRV_PROTO_GENERIC;
+ case UsdServiceProtoType::CSA_MATTER:
+ return NAN_SRV_PROTO_CSA_MATTER;
+ default:
+ // Default case is not expected, due
+ // to the USD validation method
+ return NAN_SRV_PROTO_GENERIC;
+ };
+}
+
ndk::ScopedAStatus doZeroArgDriverCommand(
struct wpa_supplicant *wpa_s, const char *cmd)
{
@@ -284,6 +313,120 @@
return arr;
}
+template <typename T>
+inline bool checkContainerSize(const T& container, int maxSize) {
+ return container.size() <= maxSize;
+}
+
+template <typename T>
+inline bool isValidEnumValue(T value, T enumRangeMin, T enumRangeMax) {
+ return static_cast<uint32_t>(value) >= static_cast<uint32_t>(enumRangeMin)
+ && static_cast<uint32_t>(value) <= static_cast<uint32_t>(enumRangeMax);
+}
+
+bool validateUsdBaseConfig(UsdBaseConfig baseConfig) {
+ if (!isValidEnumValue(baseConfig.serviceProtoType,
+ UsdServiceProtoType::GENERIC, UsdServiceProtoType::CSA_MATTER)) {
+ wpa_printf(MSG_ERROR, "Unknown protocol type received: %d",
+ static_cast<int>(baseConfig.serviceProtoType));
+ return false;
+ }
+ if (!checkContainerSize(baseConfig.serviceName, kMaxUsdServiceNameLengthBytes)) {
+ wpa_printf(MSG_ERROR, "Service name of size %zu exceeds the supported size of %d",
+ baseConfig.serviceName.size(), kMaxUsdServiceNameLengthBytes);
+ return false;
+ }
+ if (!checkContainerSize(baseConfig.serviceSpecificInfo, kMaxUsdLocalSsiLengthBytes)) {
+ wpa_printf(MSG_ERROR, "Service specific info of size %zu exceeds"
+ " the supported size of %d", baseConfig.serviceSpecificInfo.size(),
+ kMaxUsdLocalSsiLengthBytes);
+ return false;
+ }
+ if (baseConfig.txMatchFilter.has_value() && !checkContainerSize(
+ baseConfig.txMatchFilter.value(), kMaxUsdMatchFilterLengthBytes)) {
+ wpa_printf(MSG_ERROR, "TX match filter of size %zu exceeds"
+ " the supported size of %d", baseConfig.txMatchFilter.value().size(),
+ kMaxUsdMatchFilterLengthBytes);
+ return false;
+ }
+ if (baseConfig.rxMatchFilter.has_value() && !checkContainerSize(
+ baseConfig.rxMatchFilter.value(), kMaxUsdMatchFilterLengthBytes)) {
+ wpa_printf(MSG_ERROR, "RX match filter of size %zu exceeds"
+ " the supported size of %d", baseConfig.rxMatchFilter.value().size(),
+ kMaxUsdMatchFilterLengthBytes);
+ return false;
+ }
+ return true;
+}
+
+bool validateUsdPublishConfig(UsdPublishConfig publishConfig) {
+ if (!validateUsdBaseConfig(publishConfig.usdBaseConfig)) {
+ return false;
+ }
+ if (!isValidEnumValue(publishConfig.publishType,
+ UsdPublishConfig::PublishType::SOLICITED_ONLY,
+ UsdPublishConfig::PublishType::SOLICITED_AND_UNSOLICITED)) {
+ wpa_printf(MSG_ERROR, "Unknown publish type received: %d",
+ static_cast<int>(publishConfig.publishType));
+ return false;
+ }
+ if (!isValidEnumValue(publishConfig.transmissionType,
+ UsdPublishTransmissionType::UNICAST,
+ UsdPublishTransmissionType::MULTICAST)) {
+ wpa_printf(MSG_ERROR, "Unknown transmission type received: %d",
+ static_cast<int>(publishConfig.transmissionType));
+ return false;
+ }
+ return true;
+}
+
+bool validateUsdSubscribeConfig(UsdSubscribeConfig subscribeConfig) {
+ if (!validateUsdBaseConfig(subscribeConfig.usdBaseConfig)) {
+ return false;
+ }
+ if (!isValidEnumValue(subscribeConfig.subscribeType,
+ UsdSubscribeConfig::SubscribeType::PASSIVE_MODE,
+ UsdSubscribeConfig::SubscribeType::ACTIVE_MODE)) {
+ wpa_printf(MSG_ERROR, "Unknown subscribe type received: %d",
+ static_cast<int>(subscribeConfig.subscribeType));
+ return false;
+ }
+ return true;
+}
+
+struct nan_publish_params convertAidlNanPublishParamsToInternal(UsdPublishConfig publishConfig) {
+ struct nan_publish_params nanPublishParams;
+ nanPublishParams.unsolicited =
+ publishConfig.publishType == UsdPublishConfig::PublishType::UNSOLICITED_ONLY
+ || publishConfig.publishType == UsdPublishConfig::PublishType::SOLICITED_AND_UNSOLICITED;
+ nanPublishParams.solicited =
+ publishConfig.publishType == UsdPublishConfig::PublishType::SOLICITED_ONLY
+ || publishConfig.publishType == UsdPublishConfig::PublishType::SOLICITED_AND_UNSOLICITED;
+ nanPublishParams.solicited_multicast = nanPublishParams.solicited &&
+ publishConfig.transmissionType == UsdPublishTransmissionType::MULTICAST;
+ nanPublishParams.ttl = publishConfig.usdBaseConfig.ttlSec;
+ nanPublishParams.fsd = publishConfig.isFsd;
+ nanPublishParams.freq = publishConfig.usdBaseConfig.defaultFreqMhz;
+ nanPublishParams.announcement_period = publishConfig.announcementPeriodMillis;
+ nanPublishParams.disable_events = !publishConfig.eventsEnabled;
+ // Pass the original pointer to the freq list, since the receiver will memcpy the data
+ nanPublishParams.freq_list = publishConfig.usdBaseConfig.freqsMhz.data();
+ return nanPublishParams;
+}
+
+struct nan_subscribe_params convertAidlNanSubscribeParamsToInternal(
+ UsdSubscribeConfig subscribeConfig) {
+ struct nan_subscribe_params nanSubscribeParams;
+ nanSubscribeParams.active =
+ subscribeConfig.subscribeType == UsdSubscribeConfig::SubscribeType::ACTIVE_MODE;
+ nanSubscribeParams.ttl = subscribeConfig.usdBaseConfig.ttlSec;
+ nanSubscribeParams.freq = subscribeConfig.usdBaseConfig.defaultFreqMhz;
+ nanSubscribeParams.query_period = subscribeConfig.queryPeriodMillis;
+ // Pass the original pointer to the freq list, since the receiver will memcpy the data
+ nanSubscribeParams.freq_list = subscribeConfig.usdBaseConfig.freqsMhz.data();
+ return nanSubscribeParams;
+}
+
} // namespace
namespace aidl {
@@ -855,7 +998,7 @@
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
- &StaIface::startUsdPublishInternal, in_usdPublishConfig);
+ &StaIface::startUsdPublishInternal, in_cmdId, in_usdPublishConfig);
}
::ndk::ScopedAStatus StaIface::startUsdSubscribe(int32_t in_cmdId,
@@ -863,7 +1006,7 @@
{
return validateAndCall(
this, SupplicantStatusCode::FAILURE_UNKNOWN,
- &StaIface::startUsdSubscribeInternal, in_usdSubscribeConfig);
+ &StaIface::startUsdSubscribeInternal, in_cmdId, in_usdSubscribeConfig);
}
::ndk::ScopedAStatus StaIface::updateUsdPublish(int32_t in_publishId,
@@ -1961,7 +2104,7 @@
#endif
AidlManager *aidl_manager = AidlManager::getInstance();
WPA_ASSERT(aidl_manager);
- if (aidl_manager->isAidlServiceVersionAtLeast(4) && wpas_rsn_overriding(wpa_s)) {
+ if (aidl_manager->isAidlServiceVersionAtLeast(4) && wpas_rsn_overriding(wpa_s, NULL)) {
mask |= static_cast<uint32_t>(WpaDriverCapabilitiesMask::RSN_OVERRIDING);
}
@@ -2608,35 +2751,145 @@
}
std::pair<UsdCapabilities, ndk::ScopedAStatus> StaIface::getUsdCapabilitiesInternal() {
+ // TODO (b/382756996): Retrieve the capabilities dynamically
UsdCapabilities capabilities;
+ capabilities.isUsdPublisherSupported = kIsUsdPublisherSupported;
+ capabilities.isUsdSubscriberSupported = kIsUsdSubscriberSupported;
+ capabilities.maxLocalSsiLengthBytes = kMaxUsdLocalSsiLengthBytes;
+ capabilities.maxServiceNameLengthBytes = kMaxUsdServiceNameLengthBytes;
+ capabilities.maxMatchFilterLengthBytes = kMaxUsdMatchFilterLengthBytes;
+ capabilities.maxNumPublishSessions = kMaxNumUsdPublishSessions;
+ capabilities.maxNumSubscribeSessions = kMaxNumUsdSubscribeSessions;
return {capabilities, ndk::ScopedAStatus::ok()};
}
ndk::ScopedAStatus StaIface::startUsdPublishInternal(
- const UsdPublishConfig& usdPublishConfig) {
- return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+ int32_t cmdId, const UsdPublishConfig& usdPublishConfig) {
+ if (!validateUsdPublishConfig(usdPublishConfig)) {
+ return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+ }
+ auto ssiBuffer = misc_utils::convertVectorToWpaBuf(
+ usdPublishConfig.usdBaseConfig.serviceSpecificInfo);
+ if (ssiBuffer.get() == nullptr) {
+ wpa_printf(MSG_INFO, "Unable to convert USD publish SSI to buffer");
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct nan_publish_params nanPublishParams =
+ convertAidlNanPublishParamsToInternal(usdPublishConfig);
+
+ int publishId = wpas_nan_usd_publish(
+ wpa_s, usdPublishConfig.usdBaseConfig.serviceName.c_str(),
+ convertAidlServiceProtoTypeToInternal(
+ usdPublishConfig.usdBaseConfig.serviceProtoType),
+ ssiBuffer.get(), &nanPublishParams, false /* p2p */);
+
+ // Core supplicant does not have an internal callback for USD publish, but some
+ // implementations may decide to offload and return the result in a callback.
+ // In our case (core supplicant), the AIDL callback will be invoked directly here.
+ AidlManager *aidl_manager = AidlManager::getInstance();
+ WPA_ASSERT(aidl_manager);
+ if (publishId < 0) {
+ wpa_printf(MSG_INFO, "Failed to configure USD publish");
+ aidl_manager->notifyUsdPublishConfigFailed(
+ wpa_s, cmdId, ISupplicantStaIfaceCallback::UsdConfigErrorCode::FAILURE_UNKNOWN);
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+ aidl_manager->notifyUsdPublishStarted(wpa_s, cmdId, publishId);
+ return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus StaIface::startUsdSubscribeInternal(
- const UsdSubscribeConfig& usdSubscribeConfig) {
- return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+ int32_t cmdId, const UsdSubscribeConfig& usdSubscribeConfig) {
+ if (!validateUsdSubscribeConfig(usdSubscribeConfig)) {
+ return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+ }
+ auto ssiBuffer = misc_utils::convertVectorToWpaBuf(
+ usdSubscribeConfig.usdBaseConfig.serviceSpecificInfo);
+ if (ssiBuffer.get() == nullptr) {
+ wpa_printf(MSG_INFO, "Unable to convert USD subscribe SSI to buffer");
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+
+ struct wpa_supplicant *wpa_s = retrieveIfacePtr();
+ struct nan_subscribe_params nanSubscribeParams =
+ convertAidlNanSubscribeParamsToInternal(usdSubscribeConfig);
+
+ int subscribeId = wpas_nan_usd_subscribe(
+ wpa_s, usdSubscribeConfig.usdBaseConfig.serviceName.c_str(),
+ convertAidlServiceProtoTypeToInternal(
+ usdSubscribeConfig.usdBaseConfig.serviceProtoType),
+ ssiBuffer.get(), &nanSubscribeParams, false /* p2p */);
+
+ // See comment in startUsdPublishInternal regarding callbacks
+ AidlManager *aidl_manager = AidlManager::getInstance();
+ WPA_ASSERT(aidl_manager);
+ if (subscribeId < 0) {
+ wpa_printf(MSG_INFO, "Failed to configure USD subscribe");
+ aidl_manager->notifyUsdSubscribeConfigFailed(
+ wpa_s, cmdId, ISupplicantStaIfaceCallback::UsdConfigErrorCode::FAILURE_UNKNOWN);
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+ aidl_manager->notifyUsdSubscribeStarted(wpa_s, cmdId, subscribeId);
+ return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus StaIface::updateUsdPublishInternal(int32_t publishId,
const std::vector<uint8_t>& serviceSpecificInfo) {
- return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+ if (!checkContainerSize(serviceSpecificInfo, kMaxUsdLocalSsiLengthBytes)) {
+ wpa_printf(MSG_ERROR, "Service specific info of size %zu exceeds the"
+ " supported size of %d", serviceSpecificInfo.size(),
+ kMaxUsdLocalSsiLengthBytes);
+ return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+ }
+ auto ssiBuffer = misc_utils::convertVectorToWpaBuf(serviceSpecificInfo);
+ if (ssiBuffer.get() == nullptr) {
+ wpa_printf(MSG_INFO, "Unable to convert USD update SSI to buffer");
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+ int status = wpas_nan_usd_update_publish(
+ retrieveIfacePtr(), publishId, ssiBuffer.get());
+ if (status < 0) {
+ wpa_printf(MSG_INFO, "Failed to update USD publish");
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+ return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus StaIface::cancelUsdPublishInternal(int32_t publishId) {
- return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+ // Status code is returned by the callback
+ wpas_nan_usd_cancel_publish(retrieveIfacePtr(), publishId);
+ return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus StaIface::cancelUsdSubscribeInternal(int32_t subscribeId) {
- return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+ // Status code is returned by the callback
+ wpas_nan_usd_cancel_subscribe(retrieveIfacePtr(), subscribeId);
+ return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus StaIface::sendUsdMessageInternal(const UsdMessageInfo& messageInfo) {
- return createStatus(SupplicantStatusCode::FAILURE_UNSUPPORTED);
+ if (!checkContainerSize(messageInfo.message, kMaxUsdLocalSsiLengthBytes)) {
+ wpa_printf(MSG_ERROR, "Message of size %zu exceeds the supported size of %d",
+ messageInfo.message.size(), kMaxUsdLocalSsiLengthBytes);
+ return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
+ }
+ auto msgBuffer = misc_utils::convertVectorToWpaBuf(messageInfo.message);
+ if (msgBuffer.get() == nullptr) {
+ wpa_printf(MSG_INFO, "Unable to convert message contents to buffer");
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+ int handle = messageInfo.ownId;
+ int reqInstanceId = messageInfo.peerId;
+ int status = wpas_nan_usd_transmit(
+ retrieveIfacePtr(), handle, msgBuffer.get(), nullptr /* elems */,
+ messageInfo.peerMacAddress.data(), reqInstanceId);
+ if (status < 0) {
+ wpa_printf(MSG_INFO, "Failed to send USD message");
+ return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+ }
+ return ndk::ScopedAStatus::ok();
}
/**
diff --git a/wpa_supplicant/aidl/vendor/sta_iface.h b/wpa_supplicant/aidl/vendor/sta_iface.h
index 6c6cfb9..8703aaf 100644
--- a/wpa_supplicant/aidl/vendor/sta_iface.h
+++ b/wpa_supplicant/aidl/vendor/sta_iface.h
@@ -31,6 +31,7 @@
#include "wpa_supplicant_i.h"
#include "config.h"
#include "driver_i.h"
+#include "nan_usd.h"
#include "wpa.h"
}
@@ -292,8 +293,10 @@
::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 startUsdPublishInternal(
+ int32_t cmdId, const UsdPublishConfig& usdPublishConfig);
+ ::ndk::ScopedAStatus startUsdSubscribeInternal(
+ int32_t cmdId, const UsdSubscribeConfig& usdSubscribeConfig);
::ndk::ScopedAStatus updateUsdPublishInternal(int32_t publishId,
const std::vector<uint8_t>& serviceSpecificInfo);
::ndk::ScopedAStatus cancelUsdPublishInternal(int32_t publishId);
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 69a0e5e..de18a68 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -540,12 +540,6 @@
conf->supported_rates = list;
}
-#ifdef CONFIG_IEEE80211AX
- if (ssid->mode == WPAS_MODE_P2P_GO ||
- ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
- conf->ieee80211ax = ssid->he;
-#endif /* CONFIG_IEEE80211AX */
-
bss->isolate = !wpa_s->conf->p2p_intra_bss;
bss->extended_key_id = wpa_s->conf->extended_key_id;
bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk;
@@ -582,6 +576,18 @@
else
bss->wpa_key_mgmt = ssid->key_mgmt;
bss->wpa_pairwise = ssid->pairwise_cipher;
+
+#ifdef CONFIG_P2P
+ if (ssid->p2p_mode == WPA_P2P_MODE_WFD_PCC) {
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ bss->rsn_override_key_mgmt = WPA_KEY_MGMT_SAE |
+ WPA_KEY_MGMT_PASN;
+ bss->wpa_pairwise = WPA_CIPHER_CCMP;
+ bss->rsn_override_pairwise = WPA_CIPHER_CCMP;
+ bss->rsn_override_mfp = 2;
+ }
+#endif /* CONFIG_P2P */
+
if (wpa_key_mgmt_sae(bss->wpa_key_mgmt) && ssid->passphrase) {
bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase);
} else if (ssid->psk_set) {
@@ -638,10 +644,7 @@
bss->sae_passwords = pw;
}
- if (ssid->sae_pwe != DEFAULT_SAE_PWE)
- bss->sae_pwe = ssid->sae_pwe;
- else
- bss->sae_pwe = wpa_s->conf->sae_pwe;
+ bss->sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
#endif /* CONFIG_SAE */
if (wpa_s->conf->go_interworking) {
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 39de8ba..10ebab0 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -316,7 +316,8 @@
&owe_ssid_len))
continue;
- if (owe_ssid_len == ssid_len &&
+ if (bss->ssid_len &&
+ owe_ssid_len == ssid_len &&
os_memcmp(owe_ssid, ssid, ssid_len) == 0)
return bss;
#endif /* CONFIG_OWE */
@@ -1083,6 +1084,7 @@
if (wpa_s->reassoc_same_ess &&
wpa_s->wpa_state != WPA_COMPLETED &&
wpa_s->last_ssid &&
+ wpa_s->last_ssid->ssid &&
bss->ssid_len == wpa_s->last_ssid->ssid_len &&
os_memcmp(bss->ssid, wpa_s->last_ssid->ssid,
bss->ssid_len) == 0)
@@ -1588,7 +1590,7 @@
end = pos + len;
pos += sizeof(*ap_info);
- for (i = 0; i < count; i++) {
+ for (i = 0; i < count; i++, pos += ap_info->tbtt_info_len) {
u8 bss_params;
if (end - pos < ap_info->tbtt_info_len)
@@ -1599,7 +1601,7 @@
link_id = *(mld_params + 1) & EHT_ML_LINK_ID_MSK;
if (link_id >= MAX_NUM_MLD_LINKS)
- return;
+ continue;
if (*mld_params != mbssid_idx) {
wpa_printf(MSG_DEBUG,
@@ -1637,8 +1639,6 @@
RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
}
}
-
- pos += ap_info->tbtt_info_len;
}
}
@@ -1711,11 +1711,11 @@
const u8 *rsne;
size_t rsne_len;
- if (elems.rsne_override_2 && wpas_rsn_overriding(wpa_s)) {
+ if (elems.rsne_override_2 && wpas_rsn_overriding(wpa_s, ssid)) {
rsne = elems.rsne_override_2;
rsne_len = elems.rsne_override_2_len;
} else if (elems.rsne_override &&
- wpas_rsn_overriding(wpa_s)) {
+ wpas_rsn_overriding(wpa_s, ssid)) {
rsne = elems.rsne_override;
rsne_len = elems.rsne_override_len;
} else {
@@ -1822,8 +1822,8 @@
goto out;
wpa_bss_parse_ml_rnr_ap_info(wpa_s, bss, mbssid_idx,
- ap_info, len, &seen,
- &missing, ssid);
+ ap_info, ap_info_len,
+ &seen, &missing, ssid);
pos += ap_info_len;
len -= ap_info_len;
@@ -1931,6 +1931,8 @@
}
+#ifndef CONFIG_NO_WPA
+
static bool wpa_bss_supported_cipher(struct wpa_supplicant *wpa_s,
int pairwise_cipher)
{
@@ -2056,14 +2058,17 @@
return true;
}
+#endif /* CONFIG_NO_WPA */
+
const u8 * wpa_bss_get_rsne(struct wpa_supplicant *wpa_s,
const struct wpa_bss *bss, struct wpa_ssid *ssid,
bool mlo)
{
+#ifndef CONFIG_NO_WPA
const u8 *ie;
- if (wpas_rsn_overriding(wpa_s)) {
+ if (wpas_rsn_overriding(wpa_s, ssid)) {
if (!ssid)
ssid = wpa_s->current_ssid;
@@ -2087,6 +2092,7 @@
return ie;
}
}
+#endif /* CONFIG_NO_WPA */
return wpa_bss_get_ie(bss, WLAN_EID_RSN);
}
@@ -2098,7 +2104,7 @@
{
const u8 *ie;
- if (wpas_rsn_overriding(wpa_s)) {
+ if (wpas_rsn_overriding(wpa_s, ssid)) {
ie = wpa_bss_get_vendor_ie(bss, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
if (ie) {
const u8 *tmp;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 5b08478..9fe83a5 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2529,6 +2529,7 @@
{ INT(mem_only_psk) },
{ STR_KEY(sae_password) },
{ STR(sae_password_id) },
+ { INT(sae_pwe) },
{ FUNC(proto) },
{ FUNC(key_mgmt) },
{ INT(bg_scan_period) },
@@ -2543,7 +2544,7 @@
{ INT_RANGE(he, 0, 1) },
{ INT_RANGE(ht40, -1, 1) },
{ INT_RANGE(max_oper_chwidth, CONF_OPER_CHWIDTH_USE_HT,
- CONF_OPER_CHWIDTH_80P80MHZ) },
+ CONF_OPER_CHWIDTH_320MHZ) },
{ INT(vht_center_freq1) },
{ INT(vht_center_freq2) },
#ifdef IEEE8021X_EAPOL
@@ -2757,6 +2758,7 @@
{ INT_RANGE(enable_4addr_mode, 0, 1)},
{ INT_RANGE(max_idle, 0, 65535)},
{ INT_RANGE(ssid_protection, 0, 1)},
+ { INT_RANGE(rsn_overriding, 0, 2)},
};
#undef OFFSET
@@ -3028,6 +3030,7 @@
{
struct wpa_ssid *ssid, *prev = NULL;
struct wpa_cred *cred, *cprev;
+ struct wpa_dev_ik *identity, *iprev;
int i;
ssid = config->ssid;
@@ -3044,6 +3047,13 @@
wpa_config_free_cred(cprev);
}
+ identity = config->identity;
+ while (identity) {
+ iprev = identity;
+ identity = identity->next;
+ wpa_config_free_identity(iprev);
+ }
+
wpa_config_flush_blobs(config);
wpabuf_free(config->wps_vendor_ext_m1);
@@ -3097,6 +3107,8 @@
os_free(config->dpp_extra_conf_req_name);
os_free(config->dpp_extra_conf_req_value);
wpabuf_free(config->dik);
+ wpabuf_free(config->wfa_gen_capa_supp);
+ wpabuf_free(config->wfa_gen_capa_cert);
os_free(config);
}
@@ -3282,6 +3294,7 @@
#endif /* CONFIG_MACSEC */
ssid->mac_addr = WPAS_MAC_ADDR_STYLE_NOT_SET;
ssid->max_oper_chwidth = DEFAULT_MAX_OPER_CHWIDTH;
+ ssid->rsn_overriding = RSN_OVERRIDING_NOT_SET;
}
@@ -5497,6 +5510,14 @@
{ INT(p2p_interface_random_mac_addr), 0 },
{ INT(p2p_6ghz_disable), 0 },
{ INT(p2p_dfs_chan_enable), 0 },
+ { INT_RANGE(p2p_pairing_setup, 0, 1), 0 },
+ { INT_RANGE(p2p_pairing_cache, 0, 1), 0 },
+ { INT(p2p_bootstrap_methods), 0 },
+ { INT(p2p_pasn_type), 0 },
+ { INT(p2p_comeback_after), 0 },
+ { INT_RANGE(p2p_twt_power_mgmt, 0, 1), 0 },
+ { INT_RANGE(p2p_chan_switch_req_enable, 0, 1), 0 },
+ { INT(p2p_reg_info), 0 },
{ INT(dik_cipher), 0},
{ BIN(dik), 0 },
#endif /* CONFIG_P2P */
@@ -5577,6 +5598,7 @@
{ INT(gas_address3), 0 },
{ INT_RANGE(ftm_responder, 0, 1), 0 },
{ INT_RANGE(ftm_initiator, 0, 1), 0 },
+ { INT_RANGE(twt_requester, 0, 1), 0 },
{ INT(gas_rand_addr_lifetime), 0 },
{ INT_RANGE(gas_rand_mac_addr, 0, 2), 0 },
#ifdef CONFIG_DPP
@@ -5607,6 +5629,9 @@
{ FUNC(mld_connect_bssid_pref), 0 },
#endif /* CONFIG_TESTING_OPTIONS */
{ INT_RANGE(ft_prepend_pmkid, 0, 1), CFG_CHANGED_FT_PREPEND_PMKID },
+ { INT_RANGE(wfa_gen_capa, 0, 2), 0},
+ { BIN(wfa_gen_capa_supp), 0 },
+ { BIN(wfa_gen_capa_cert), 0 },
/* NOTE: When adding new parameters here, add_interface() in
* wpa_supplicant/dbus_new_introspect.c may need to be modified to
* increase the size of the iface->xml buffer. */
@@ -5774,3 +5799,129 @@
return ret;
}
+
+
+int wpa_config_set_identity(struct wpa_dev_ik *identity, const char *var,
+ const char *value, int line)
+{
+ char *val;
+ size_t len;
+ int ret = 0;
+
+ if (os_strcmp(var, "dik_cipher") == 0) {
+ identity->dik_cipher = atoi(value);
+ return 0;
+ }
+
+ val = wpa_config_parse_string(value, &len);
+ if (!val) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid field '%s' string value '%s'.",
+ line, var, value);
+ return -1;
+ }
+
+ if (os_strcmp(var, "dik") == 0) {
+ wpabuf_free(identity->dik);
+ identity->dik = wpabuf_alloc_copy(val, len);
+ if (!identity->dik)
+ ret = -1;
+ } else if (os_strcmp(var, "pmk") == 0) {
+ wpabuf_free(identity->pmk);
+ identity->pmk = wpabuf_alloc_copy(val, len);
+ if (!identity->pmk)
+ ret = -1;
+ } else if (os_strcmp(var, "pmkid") == 0) {
+ if (len == PMKID_LEN) {
+ wpabuf_free(identity->pmkid);
+ identity->pmkid = wpabuf_alloc_copy(val, len);
+ if (!identity->pmkid)
+ ret = -1;
+ } else {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid field '%s' string value '%s'.",
+ line, var, value);
+ ret = -1;
+ }
+ } else if (line) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown identity field '%s'.",
+ line, var);
+ ret = -1;
+ }
+
+ os_free(val);
+ return ret;
+}
+
+
+void wpa_config_free_identity(struct wpa_dev_ik *identity)
+{
+ wpabuf_clear_free(identity->dik);
+ wpabuf_clear_free(identity->pmk);
+ wpabuf_free(identity->pmkid);
+ os_free(identity);
+}
+
+
+/**
+ * wpa_config_add_identity - Add a new device identity with empty configuration
+ * @config: Configuration data from wpa_config_read()
+ * Returns: The new device identity or %NULL if operation failed
+ */
+struct wpa_dev_ik * wpa_config_add_identity(struct wpa_config *config)
+{
+ int id;
+ struct wpa_dev_ik *identity, *last = NULL;
+
+ id = -1;
+ identity = config->identity;
+ while (identity) {
+ if (identity->id > id)
+ id = identity->id;
+ last = identity;
+ identity = identity->next;
+ }
+ id++;
+
+ identity = os_zalloc(sizeof(*identity));
+ if (!identity)
+ return NULL;
+ identity->id = id;
+ if (last)
+ last->next = identity;
+ else
+ config->identity = identity;
+
+ return identity;
+}
+
+
+/**
+ * wpa_config_remove_identity - Remove a configured identity based on id
+ * @config: Configuration data from wpa_config_read()
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found
+ */
+int wpa_config_remove_identity(struct wpa_config *config, int id)
+{
+ struct wpa_dev_ik *identity, *prev = NULL;
+
+ identity = config->identity;
+ while (identity) {
+ if (id == identity->id)
+ break;
+ prev = identity;
+ identity = identity->next;
+ }
+
+ if (!identity)
+ return -1;
+
+ if (prev)
+ prev->next = identity->next;
+ else
+ config->identity = identity->next;
+
+ wpa_config_free_identity(identity);
+ return 0;
+}
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 1281786..0643114 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -430,6 +430,47 @@
int sim_num;
};
+struct wpa_dev_ik {
+ /**
+ * next - Next device identity in the list
+ *
+ * This pointer can be used to iterate over all device identity keys.
+ * The head of this list is stored in the dev_ik field of struct
+ * wpa_config.
+ */
+ struct wpa_dev_ik *next;
+
+ /**
+ * id - Unique id for the identity
+ *
+ * This identifier is used as a unique identifier for each identity
+ * block when using the control interface. Each identity is allocated
+ * an id when it is being created, either when reading the
+ * configuration file or when a new identity is added.
+ */
+ int id;
+
+ /**
+ * dik_cipher - Device identity key cipher version
+ */
+ int dik_cipher;
+
+ /**
+ * dik - Device identity key which is unique for the device
+ */
+ struct wpabuf *dik;
+
+ /**
+ * pmk - PMK associated with the previous connection with the device
+ */
+ struct wpabuf *pmk;
+
+ /**
+ * pmkid - PMKID used in the previous connection with the device
+ */
+ struct wpabuf *pmkid;
+};
+
#define CFG_CHANGED_DEVICE_NAME BIT(0)
#define CFG_CHANGED_CONFIG_METHODS BIT(1)
@@ -872,6 +913,14 @@
int p2p_optimize_listen_chan;
int p2p_6ghz_disable;
int p2p_dfs_chan_enable;
+ bool p2p_pairing_setup;
+ bool p2p_pairing_cache;
+ int p2p_bootstrap_methods;
+ int p2p_pasn_type;
+ int p2p_comeback_after;
+ bool p2p_twt_power_mgmt;
+ bool p2p_chan_switch_req_enable;
+ int p2p_reg_info;
struct wpabuf *wps_vendor_ext_m1;
@@ -1804,17 +1853,9 @@
int wowlan_disconnect_on_deinit;
/**
- * rsn_overriding - RSN overriding
- *
- * 0 = Disabled
- * 1 = Enabled automatically if the driver indicates support
- * 2 = Forced to be enabled even without driver capability indication
+ * rsn_overriding - RSN overriding (default behavior)
*/
- enum rsn_overriding {
- RSN_OVERRIDING_DISABLED = 0,
- RSN_OVERRIDING_AUTO = 1,
- RSN_OVERRIDING_ENABLED = 2,
- } rsn_overriding;
+ enum wpas_rsn_overriding rsn_overriding;
#ifdef CONFIG_PASN
#ifdef CONFIG_TESTING_OPTIONS
@@ -1849,6 +1890,55 @@
/* DevIK */
struct wpabuf *dik;
+
+ /**
+ * identity - P2P2 peer device identities
+ *
+ * This is the head for the list of all the paired devices.
+ */
+ struct wpa_dev_ik *identity;
+
+ /**
+ * twt_requester - Whether TWT Requester Support is enabled
+ *
+ * This is for setting the bit 77 of the Extended Capabilities element.
+ */
+ bool twt_requester;
+
+ /**
+ * wfa_gen_capa: Whether to indicate Wi-Fi generational capability to
+ * the AP
+ *
+ * 0 = do not indicate (default)
+ * 1 = indicate in protected Action frame
+ * 2 = indicate in unprotected (Re)Association Request frame
+ */
+ enum {
+ WFA_GEN_CAPA_DISABLED = 0,
+ WFA_GEN_CAPA_PROTECTED = 1,
+ WFA_GEN_CAPA_UNPROTECTED = 2,
+ } wfa_gen_capa;
+
+ /**
+ * wfa_gen_capa_supp: Supported Generations (hexdump of a bit field)
+ *
+ * A bit field of supported Wi-Fi generations. This is encoded as an
+ * little endian octt string.
+ * bit 0: Wi-Fi 4
+ * bit 1: Wi-Fi 5
+ * bit 2: Wi-Fi 6
+ * bit 3: Wi-Fi 7
+ */
+ struct wpabuf *wfa_gen_capa_supp;
+
+ /**
+ * wfa_gen_capa_cert: Certified Generations (hexdump of a bit field)
+ *
+ * This has the same format as wfa_gen_capa_supp. This is an optional
+ * field, but if included, shall have the same length as
+ * wfa_gen_capa_supp.
+ */
+ struct wpabuf *wfa_gen_capa_cert;
};
@@ -1895,6 +1985,12 @@
const char *value, int line);
char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var);
+int wpa_config_set_identity(struct wpa_dev_ik *identity, const char *var,
+ const char *value, int line);
+void wpa_config_free_identity(struct wpa_dev_ik *identity);
+struct wpa_dev_ik * wpa_config_add_identity(struct wpa_config *config);
+int wpa_config_remove_identity(struct wpa_config *config, int id);
+
struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param);
#ifndef CONFIG_NO_STDOUT_DEBUG
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 53614ae..4029d49 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -296,6 +296,65 @@
#endif /* CONFIG_NO_CONFIG_BLOBS */
+static struct wpa_dev_ik * wpa_config_read_identity(FILE *f, int *line, int id)
+{
+ struct wpa_dev_ik *identity;
+ int errors = 0, end = 0;
+ char buf[256], *pos, *pos2;
+
+ wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new identity block",
+ *line);
+ identity = os_zalloc(sizeof(*identity));
+ if (!identity)
+ return NULL;
+ identity->id = id;
+
+ while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
+ if (os_strcmp(pos, "}") == 0) {
+ end = 1;
+ break;
+ }
+
+ pos2 = os_strchr(pos, '=');
+ if (!pos2) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid identity line '%s'.",
+ *line, pos);
+ errors++;
+ continue;
+ }
+
+ *pos2++ = '\0';
+ if (*pos2 == '"') {
+ if (os_strchr(pos2 + 1, '"') == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid quotation '%s'.",
+ *line, pos2);
+ errors++;
+ continue;
+ }
+ }
+
+ if (wpa_config_set_identity(identity, pos, pos2, *line) < 0)
+ errors++;
+ }
+
+ if (!end) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: identity block was not terminated properly.",
+ *line);
+ errors++;
+ }
+
+ if (errors) {
+ wpa_config_free_identity(identity);
+ identity = NULL;
+ }
+
+ return identity;
+}
+
+
struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp,
bool ro)
{
@@ -304,9 +363,11 @@
int errors = 0, line = 0;
struct wpa_ssid *ssid, *tail, *head;
struct wpa_cred *cred, *cred_tail, *cred_head;
+ struct wpa_dev_ik *identity, *identity_tail, *identity_head;
struct wpa_config *config;
static int id = 0;
static int cred_id = 0;
+ static int identity_id = 0;
if (name == NULL)
return NULL;
@@ -325,6 +386,9 @@
cred_tail = cred_head = config->cred;
while (cred_tail && cred_tail->next)
cred_tail = cred_tail->next;
+ identity_tail = identity_head = config->identity;
+ while (identity_tail && identity_tail->next)
+ identity_tail = identity_tail->next;
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
f = fopen(name, "r");
@@ -383,6 +447,22 @@
continue;
}
#endif /* CONFIG_NO_CONFIG_BLOBS */
+ } else if (os_strcmp(pos, "identity={") == 0) {
+ identity = wpa_config_read_identity(f, &line,
+ identity_id++);
+ if (!identity) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: failed to parse identity block.",
+ line);
+ errors++;
+ continue;
+ }
+ if (!identity_head) {
+ identity_head = identity_tail = identity;
+ } else {
+ identity_tail->next = identity;
+ identity_tail = identity;
+ }
} else if (wpa_config_process_global(config, pos, line) < 0) {
wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
"line '%s'.", line, pos);
@@ -396,6 +476,7 @@
config->ssid = head;
wpa_config_debug_dump_networks(config);
config->cred = cred_head;
+ config->identity = identity_head;
#ifndef WPA_IGNORE_CONFIG_ERRORS
if (errors) {
@@ -895,6 +976,7 @@
INT(enable_4addr_mode);
INT(max_idle);
INT(ssid_protection);
+ INT_DEF(rsn_overriding, RSN_OVERRIDING_NOT_SET);
#undef STR
#undef INT
@@ -1298,6 +1380,27 @@
if (config->p2p_6ghz_disable)
fprintf(f, "p2p_6ghz_disable=%d\n", config->p2p_6ghz_disable);
+ if (config->p2p_pairing_setup)
+ fprintf(f, "p2p_pairing_setup=%d\n", config->p2p_pairing_setup);
+ if (config->p2p_pairing_cache)
+ fprintf(f, "p2p_pairing_cache=%d\n", config->p2p_pairing_cache);
+ if (config->p2p_bootstrap_methods)
+ fprintf(f, "p2p_bootstrap_methods=%d\n",
+ config->p2p_bootstrap_methods);
+ if (config->p2p_pasn_type)
+ fprintf(f, "p2p_pasn_type=%d\n", config->p2p_pasn_type);
+ if (config->p2p_comeback_after)
+ fprintf(f, "p2p_comeback_after=%d\n",
+ config->p2p_comeback_after);
+ if (config->p2p_twt_power_mgmt)
+ fprintf(f, "p2p_twt_power_mgmt=%d\n",
+ config->p2p_twt_power_mgmt);
+ if (config->p2p_chan_switch_req_enable)
+ fprintf(f, "p2p_chan_switch_req_enable=%d\n",
+ config->p2p_chan_switch_req_enable);
+ if (config->p2p_reg_info)
+ fprintf(f, "p2p_reg_info=%d\n", config->p2p_reg_info);
+
if (WPA_GET_BE32(config->ip_addr_go))
fprintf(f, "ip_addr_go=%u.%u.%u.%u\n",
config->ip_addr_go[0], config->ip_addr_go[1],
@@ -1567,6 +1670,9 @@
if (config->ftm_initiator)
fprintf(f, "ftm_initiator=%d\n", config->ftm_initiator);
+ if (config->twt_requester)
+ fprintf(f, "twt_requester=%d\n", config->twt_requester);
+
if (config->osu_dir)
fprintf(f, "osu_dir=%s\n", config->osu_dir);
@@ -1639,6 +1745,24 @@
fprintf(f, "dik_cipher=%d\n", config->dik_cipher);
write_global_bin(f, "dik", config->dik);
}
+ if (config->wfa_gen_capa)
+ fprintf(f, "wfa_gen_capa=%d\n", config->wfa_gen_capa);
+ write_global_bin(f, "wfa_gen_capa_supp", config->wfa_gen_capa_supp);
+ write_global_bin(f, "wfa_gen_capa_cert", config->wfa_gen_capa_cert);
+}
+
+static void wpa_config_write_identity(FILE *f, struct wpa_dev_ik *dev_ik)
+{
+ fprintf(f, "\tdik_cipher=%d\n", dev_ik->dik_cipher);
+
+ if (dev_ik->dik)
+ write_global_bin(f, "\tdik", dev_ik->dik);
+
+ if (dev_ik->pmk)
+ write_global_bin(f, "\tpmk", dev_ik->pmk);
+
+ if (dev_ik->pmkid)
+ write_global_bin(f, "\tpmkid", dev_ik->pmkid);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
@@ -1650,6 +1774,7 @@
FILE *f;
struct wpa_ssid *ssid;
struct wpa_cred *cred;
+ struct wpa_dev_ik *dev_ik;
#ifndef CONFIG_NO_CONFIG_BLOBS
struct wpa_config_blob *blob;
#endif /* CONFIG_NO_CONFIG_BLOBS */
@@ -1697,13 +1822,20 @@
!ssid->psk_set && !ssid->passphrase)
continue; /* do not save invalid network */
if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
- !ssid->passphrase && !ssid->sae_password)
+ !ssid->passphrase && !ssid->sae_password &&
+ !ssid->pmk_valid)
continue; /* do not save invalid network */
fprintf(f, "\nnetwork={\n");
wpa_config_write_network(f, ssid);
fprintf(f, "}\n");
}
+ for (dev_ik = config->identity; dev_ik; dev_ik = dev_ik->next) {
+ fprintf(f, "\nidentity={\n");
+ wpa_config_write_identity(f, dev_ik);
+ fprintf(f, "}\n");
+ }
+
#ifndef CONFIG_NO_CONFIG_BLOBS
for (blob = config->blobs; blob; blob = blob->next) {
ret = wpa_config_write_blob(f, blob);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 3d1bc5e..92ee234 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -79,6 +79,20 @@
};
/**
+ * rsn_overriding - RSN overriding
+ *
+ * 0 = Disabled
+ * 1 = Enabled automatically if the driver indicates support
+ * 2 = Forced to be enabled even without driver capability indication
+ */
+enum wpas_rsn_overriding {
+ RSN_OVERRIDING_NOT_SET = -1,
+ RSN_OVERRIDING_DISABLED = 0,
+ RSN_OVERRIDING_AUTO = 1,
+ RSN_OVERRIDING_ENABLED = 2,
+};
+
+/**
* struct wpa_ssid - Network configuration data
*
* This structure includes all the configuration variables for a network. This
@@ -232,6 +246,11 @@
char *passphrase;
/**
+ * pmk_valid - Whether PMK is valid in case of P2P2 derived from PASN
+ */
+ bool pmk_valid;
+
+ /**
* sae_password - SAE password
*
* This parameter can be used to set a password for SAE. By default, the
@@ -1282,6 +1301,17 @@
* ssid_protection - Whether to use SSID protection in 4-way handshake
*/
bool ssid_protection;
+
+ /**
+ * rsn_overriding - RSN overriding (per-network override for the global
+ * parameter with the same name)
+ */
+ enum wpas_rsn_overriding rsn_overriding;
+
+ /**
+ * p2p_mode - P2P R1 only, P2P R2 only, or PCC mode
+ */
+ enum wpa_p2p_mode p2p_mode;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index a8fc962..43d1a66 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -881,6 +881,8 @@
} else if (os_strcasecmp(cmd, "dpp_test") == 0) {
dpp_test = atoi(value);
#endif /* CONFIG_DPP */
+ } else if (os_strcasecmp(cmd, "eapol_2_key_info_set_mask") == 0) {
+ wpa_s->eapol_2_key_info_set_mask = strtoul(value, NULL, 0x10);
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_FILS
} else if (os_strcasecmp(cmd, "disable_fils") == 0) {
@@ -6354,6 +6356,29 @@
}
+static bool bootstrap_pwd_required(u16 bootstrap)
+{
+ switch (bootstrap) {
+ case P2P_PBMA_OPPORTUNISTIC:
+ return false;
+ case P2P_PBMA_PIN_CODE_DISPLAY:
+ case P2P_PBMA_PASSPHRASE_DISPLAY:
+ case P2P_PBMA_QR_DISPLAY:
+ case P2P_PBMA_NFC_TAG:
+ case P2P_PBMA_PIN_CODE_KEYPAD:
+ case P2P_PBMA_PASSPHRASE_KEYPAD:
+ case P2P_PBMA_QR_SCAN:
+ case P2P_PBMA_NFC_READER:
+ return true;
+ case P2P_PBMA_SERVICE_MANAGED:
+ case P2P_PBMA_HANDSHAKE_SKIP:
+ return false;
+ }
+
+ return false;
+}
+
+
static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
char *buf, size_t buflen)
{
@@ -6376,7 +6401,7 @@
size_t group_ssid_len = 0;
int he;
bool allow_6ghz;
- bool p2p2;
+ bool p2p2, skip_prov;
u16 bootstrap = 0;
const char *password = NULL;
char *token, *context = NULL;
@@ -6393,7 +6418,7 @@
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
* [ht40] [vht] [he] [edmg] [auto] [ssid=<hexdump>]
- * [p2p2] [bstrapmethod=<value>] [password=<string>]
+ * [p2p2] [skip_prov] [bstrapmethod=<value>] [password=<string>]
*/
if (hwaddr_aton(cmd, addr))
@@ -6429,6 +6454,7 @@
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;
+ skip_prov = os_strstr(pos, " skip_prov") != NULL;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -6515,12 +6541,18 @@
}
}
+ if (bootstrap_pwd_required(bootstrap) && !password) {
+ wpa_printf(MSG_DEBUG,
+ "CTRL_IFACE: This P2P2 bootstrap method requires password");
+ return -1;
+ }
+
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, p2p2,
- bootstrap, password);
+ bootstrap, password, skip_prov);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -7073,6 +7105,7 @@
int ht40, vht, he, max_oper_chwidth, chwidth = 0, freq2 = 0;
int edmg;
bool allow_6ghz;
+ bool p2p2;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -7129,9 +7162,11 @@
if (allow_6ghz && chwidth == 40)
max_oper_chwidth = CONF_OPER_CHWIDTH_40MHZ_6GHZ;
+ p2p2 = os_strstr(cmd, " p2p2") != NULL;
+
return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, freq2, ht40, vht,
max_oper_chwidth, pref_freq, he, edmg,
- allow_6ghz);
+ allow_6ghz, p2p2);
}
@@ -7200,13 +7235,15 @@
vht_center_freq2, ht40, vht,
vht_chwidth, he, edmg,
NULL, 0, 0, allow_6ghz, 0,
- go_bssid);
+ go_bssid, NULL, NULL, NULL, 0);
}
static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
{
int freq = 0, persistent = 0, group_id = -1;
+ bool p2p2 = false;
+ int p2pmode = WPA_P2P_MODE_WFD_R1;
bool allow_6ghz = false;
int vht = wpa_s->conf->p2p_go_vht;
int ht40 = wpa_s->conf->p2p_go_ht40 || vht;
@@ -7222,7 +7259,8 @@
while ((token = str_token(cmd, " ", &context))) {
if (sscanf(token, "freq2=%d", &freq2) == 1 ||
sscanf(token, "persistent=%d", &group_id) == 1 ||
- sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1) {
+ sscanf(token, "max_oper_chwidth=%d", &chwidth) == 1 ||
+ sscanf(token, "p2pmode=%d", &p2pmode) == 1) {
continue;
#ifdef CONFIG_ACS
} else if (os_strcmp(token, "freq=acs") == 0) {
@@ -7243,6 +7281,8 @@
persistent = 1;
} else if (os_strcmp(token, "allow_6ghz") == 0) {
allow_6ghz = true;
+ } else if (os_strcmp(token, "p2p2") == 0) {
+ p2p2 = true;
} else if (os_strncmp(token, "go_bssid=", 9) == 0) {
if (hwaddr_aton(token + 9, go_bssid_buf))
return -1;
@@ -7293,8 +7333,12 @@
edmg, allow_6ghz,
go_bssid);
+ if (p2pmode < WPA_P2P_MODE_WFD_R1 || p2pmode > WPA_P2P_MODE_WFD_PCC)
+ return -1;
+
return wpas_p2p_group_add(wpa_s, persistent, freq, freq2, ht40, vht,
- max_oper_chwidth, he, edmg, allow_6ghz);
+ max_oper_chwidth, he, edmg, allow_6ghz, p2p2,
+ (enum wpa_p2p_mode) p2pmode);
}
@@ -7697,6 +7741,53 @@
return 0;
}
+#ifdef CONFIG_TESTING_OPTIONS
+ if (os_strcmp(cmd, "pairing_setup") == 0) {
+ p2p_set_pairing_setup(wpa_s->global->p2p, atoi(param));
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "pairing_cache") == 0) {
+ p2p_set_pairing_cache(wpa_s->global->p2p, atoi(param));
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "supported_bootstrapmethods") == 0) {
+ p2p_set_bootstrapmethods(wpa_s->global->p2p, atoi(param));
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "pasn_type") == 0) {
+ p2p_set_pasn_type(wpa_s->global->p2p, atoi(param));
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "comeback_after") == 0) {
+ p2p_set_comeback_after(wpa_s->global->p2p, atoi(param));
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "reginfo") == 0) {
+ p2p_set_reg_info(wpa_s->global->p2p, atoi(param));
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "twt_power_mgmt") == 0) {
+ p2p_set_twt_power_mgmt(wpa_s->global->p2p, atoi(param));
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "chan_switch_req_enable") == 0) {
+ p2p_set_chan_switch_req_enable(wpa_s->global->p2p, atoi(param));
+ return 0;
+ }
+
+ if (os_strcmp(cmd, "inv_oper_freq") == 0) {
+ p2p_set_invitation_op_freq(wpa_s->global->p2p, atoi(param));
+ return 0;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
cmd);
@@ -7712,12 +7803,15 @@
#ifdef CONFIG_TESTING_OPTIONS
os_free(wpa_s->get_pref_freq_list_override);
wpa_s->get_pref_freq_list_override = NULL;
+ p2p_set_invitation_op_freq(wpa_s->global->p2p, -1);
#endif /* CONFIG_TESTING_OPTIONS */
wpas_p2p_stop_find(wpa_s);
wpa_s->parent->p2ps_method_config_any = 0;
if (wpa_s->global->p2p)
p2p_flush(wpa_s->global->p2p);
+
+ wpa_s->p2p2 = false;
}
@@ -7804,6 +7898,26 @@
return wpas_p2p_lo_start(wpa_s, freq, period, interval, count);
}
+
+#ifdef CONFIG_TESTING_OPTIONS
+static int p2p_ctrl_pmk_get(struct wpa_supplicant *wpa_s, char *buf,
+ size_t buflen)
+{
+ const u8 *pmk;
+ size_t pmk_len;
+
+ /* Return the PMK from the first identity entry. This assumes test
+ * cases to remove all indentities at the beginning so that only one
+ * entry is available. */
+ if (!wpa_s->conf->identity || !wpa_s->conf->identity->pmk)
+ return -1;
+
+ pmk_len = wpabuf_len(wpa_s->conf->identity->pmk);
+ pmk = wpabuf_head(wpa_s->conf->identity->pmk);
+
+ return wpa_snprintf_hex(buf, buflen, pmk, pmk_len);
+}
+#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_P2P */
@@ -8676,6 +8790,7 @@
ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
#ifdef CONFIG_P2P
if (ret == 0) {
+#ifdef CONFIG_P2P
if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
struct p2p_data *p2p = wpa_s->global->p2p;
if (p2p) {
@@ -8686,6 +8801,7 @@
p2p_set_country(p2p, country);
}
}
+#endif /* CONFIG_P2P */
ret = os_snprintf(buf, buflen, "%s\n", "OK");
if (os_snprintf_error(buflen, ret))
ret = -1;
@@ -8931,6 +9047,7 @@
wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
wpa_sm_set_test_eapol_m2_elems(wpa_s->wpa, NULL);
wpa_sm_set_test_eapol_m4_elems(wpa_s->wpa, NULL);
+ wpa_sm_set_test_rsnxe_data(wpa_s->wpa, NULL, NULL);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_ENCRYPT_EAPOL_M2, 0);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_ENCRYPT_EAPOL_M4, 0);
os_free(wpa_s->get_pref_freq_list_override);
@@ -8959,6 +9076,7 @@
wpa_s->oci_freq_override_fils_assoc = 0;
wpa_s->oci_freq_override_wnm_sleep = 0;
wpa_s->disable_eapol_g2_tx = 0;
+ wpa_s->eapol_2_key_info_set_mask = 0;
wpa_s->test_assoc_comeback_type = -1;
#ifdef CONFIG_DPP
os_free(wpa_s->dpp_config_obj_override);
@@ -10302,6 +10420,29 @@
}
+static int wpas_ctrl_test_rsnxe_data(struct wpa_supplicant *wpa_s,
+ const char *cmd)
+{
+ struct wpabuf *data = NULL, *mask = NULL;
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (!pos)
+ return -1;
+ *pos++ = '\0';
+
+ if (wpas_get_hex_buf(cmd, &data) < 0 ||
+ wpas_get_hex_buf(pos, &mask) < 0 ||
+ wpa_sm_set_test_rsnxe_data(wpa_s->wpa, data, mask) < 0) {
+ wpabuf_free(data);
+ wpabuf_free(mask);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s)
{
u8 zero[WPA_TK_MAX_LEN];
@@ -10856,6 +10997,24 @@
#endif /* CONFIG_AP */
}
+#ifdef CONFIG_P2P
+#ifdef CONFIG_PASN
+
+#ifdef CONFIG_TESTING_OPTIONS
+static int p2p_ctrl_get_pasn_ptk(struct wpa_supplicant *wpa_s, char *buf,
+ size_t buflen)
+{
+ const u8 *ptk;
+ size_t ptk_len;
+
+ if (wpas_p2p_get_pasn_ptk(wpa_s, &ptk, &ptk_len))
+ return -1;
+ return wpa_snprintf_hex(buf, buflen, ptk, ptk_len);
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#endif /* CONFIG_PASN */
+#endif /* CONFIG_P2P */
#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
@@ -12870,6 +13029,12 @@
reply_len = -1;
} else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
+#ifdef CONFIG_PASN
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strcmp(buf, "P2P_GET_PASNPTK") == 0) {
+ reply_len = p2p_ctrl_get_pasn_ptk(wpa_s, reply, reply_size);
+#endif /* CONFIG_TESTING_OPTIONS */
+#endif /* CONFIG_PASN */
} else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
reply_size);
@@ -12936,6 +13101,13 @@
} else if (os_strcmp(buf, "P2P_LO_STOP") == 0) {
if (wpas_p2p_lo_stop(wpa_s))
reply_len = -1;
+ } else if (os_strcmp(buf, "P2P_REMOVE_IDENTITY") == 0) {
+ if (wpas_p2p_remove_all_identity(wpa_s))
+ reply_len = -1;
+#ifdef CONFIG_TESTING_OPTIONS
+ } else if (os_strncmp(buf, "P2P_PMK_GET", 12) == 0) {
+ reply_len = p2p_ctrl_pmk_get(wpa_s, reply, reply_size);
+#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_P2P */
#ifdef CONFIG_WIFI_DISPLAY
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
@@ -13387,6 +13559,9 @@
} else if (os_strncmp(buf, "ML_PROBE_REQ ", 13) == 0) {
if (wpas_ctrl_ml_probe(wpa_s, buf + 13))
reply_len = -1;
+ } else if (os_strncmp(buf, "TEST_RSNXE_DATA ", 16) == 0) {
+ if (wpas_ctrl_test_rsnxe_data(wpa_s, buf + 16) < 0)
+ reply_len = -1;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
@@ -13593,6 +13768,8 @@
} else if (os_strncmp(buf, "NAN_TRANSMIT ", 13) == 0) {
if (wpas_ctrl_nan_transmit(wpa_s, buf + 13) < 0)
reply_len = -1;
+ } else if (os_strcmp(buf, "NAN_FLUSH") == 0) {
+ wpas_nan_usd_flush(wpa_s);
#endif /* CONFIG_NAN_USD */
#ifdef CONFIG_PASN
} else if (os_strncmp(buf, "PASN_START ", 11) == 0) {
@@ -13631,6 +13808,14 @@
} else if (os_strcmp(buf, "MLO_SIGNAL_POLL") == 0) {
reply_len = wpas_ctrl_iface_mlo_signal_poll(wpa_s, reply,
reply_size);
+ } else if (os_strcmp(buf, "NEW_RANDOM_MAC_ADDRESS") == 0) {
+ enum wpas_mac_addr_style mac_addr_style =
+ wpa_s->conf->preassoc_mac_addr;
+
+ wpa_s->conf->preassoc_mac_addr = WPAS_MAC_ADDR_STYLE_RANDOM;
+ if (wpas_update_random_addr_disassoc(wpa_s) != 1)
+ reply_len = -1;
+ wpa_s->conf->preassoc_mac_addr = mac_addr_style;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -13986,6 +14171,7 @@
"NFC_REPORT_HANDOVER ",
"P2P_ASP_PROVISION ",
"P2P_ASP_PROVISION_RESP ",
+ "NAN_",
#ifdef CONFIG_AP
"STA ",
"STA-NEXT ",
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index 27003eb..a3f32c3 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -1159,3 +1159,38 @@
os_memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
}
+
+
+dbus_bool_t wpa_dbus_dict_entry_is_int(const struct wpa_dbus_dict_entry *entry)
+{
+ return entry->type == DBUS_TYPE_BYTE ||
+ entry->type == DBUS_TYPE_INT16 ||
+ entry->type == DBUS_TYPE_UINT16 ||
+ entry->type == DBUS_TYPE_INT32 ||
+ entry->type == DBUS_TYPE_UINT32 ||
+ entry->type == DBUS_TYPE_INT64 ||
+ entry->type == DBUS_TYPE_UINT64;
+}
+
+
+int wpa_dbus_dict_entry_get_int(const struct wpa_dbus_dict_entry *entry)
+{
+ switch (entry->type) {
+ case DBUS_TYPE_BYTE:
+ return entry->byte_value;
+ case DBUS_TYPE_INT16:
+ return entry->int16_value;
+ case DBUS_TYPE_UINT16:
+ return entry->uint16_value;
+ case DBUS_TYPE_INT32:
+ return entry->int32_value;
+ case DBUS_TYPE_UINT32:
+ return entry->uint32_value;
+ case DBUS_TYPE_INT64:
+ return entry->int64_value;
+ case DBUS_TYPE_UINT64:
+ return entry->uint64_value;
+ }
+
+ return -1;
+}
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index 1d33689..15c8aba 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -158,4 +158,7 @@
void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry);
+dbus_bool_t wpa_dbus_dict_entry_is_int(const struct wpa_dbus_dict_entry *entry);
+int wpa_dbus_dict_entry_get_int(const struct wpa_dbus_dict_entry *entry);
+
#endif /* DBUS_DICT_HELPERS_H */
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 5ad5bcd..ff7e003 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -2332,6 +2332,113 @@
}
+/**
+ * wpas_dbus_signal_p2p_bootstrap_req - Signals BootstrappingRequest event
+ * @wpa_s: %wpa_supplicant network interface data
+ * @src: Source address of the message triggering this notification
+ * @bootstrap_method: Peer's bootstrap method
+ *
+ * Sends a signal to notify that a peer P2P Device is requesting bootstrapping
+ * negotiation with us.
+ */
+void wpas_dbus_signal_p2p_bootstrap_req(struct wpa_supplicant *wpa_s,
+ const u8 *src, u16 bootstrap_method)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ struct wpas_dbus_priv *iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!iface)
+ return;
+
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+ if (!wpa_s->dbus_new_path)
+ return;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(src));
+ path = peer_obj_path;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "BootstrappingRequest");
+ if (!msg)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT16,
+ &bootstrap_method))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_p2p_bootstrap_completed - Signals BootstrappingCompleted event
+ * event
+ * @wpa_s: %wpa_supplicant network interface data
+ * @src: Source address of the peer with which bootstrapping is done
+ * @status: Status of Bootstrapping handshake
+ *
+ * Sends a signal to notify that a peer P2P Device is requesting bootstrapping
+ * negotiation with us.
+ */
+void wpas_dbus_signal_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s,
+ const u8 *src, int status)
+{
+ DBusMessage *msg;
+ DBusMessageIter iter;
+ struct wpas_dbus_priv *iface;
+ char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
+ iface = wpa_s->global->dbus;
+
+ /* Do nothing if the control interface is not turned on */
+ if (!iface)
+ return;
+
+ if (wpa_s->p2p_mgmt)
+ wpa_s = wpa_s->parent;
+ if (!wpa_s->dbus_new_path)
+ return;
+
+ os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
+ wpa_s->dbus_new_path, MAC2STR(src));
+ path = peer_obj_path;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ "BootstrappingCompleted");
+ if (!msg)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path) ||
+ !dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,
+ &status))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+
+ dbus_message_unref(msg);
+}
+
+
#endif /* CONFIG_P2P */
@@ -3771,6 +3878,52 @@
},
},
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_NAN_USD
+ { "NANPublish", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_nan_publish,
+ {
+ { "args", "a{sv}", ARG_IN },
+ { "publish_id", "u", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "NANCancelPublish", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_nan_cancel_publish,
+ {
+ { "publish_id", "u", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "NANUpdatePublish", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_nan_update_publish,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "NANSubscribe", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_nan_subscribe,
+ {
+ { "args", "a{sv}", ARG_IN },
+ { "subscribe_id", "u", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "NANCancelSubscribe", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_nan_cancel_subscribe,
+ {
+ { "subscribe_id", "u", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "NANTransmit", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_nan_transmit,
+ {
+ { "args", "a{sv}", ARG_IN },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_NAN_USD */
{ NULL, NULL, NULL, { END_ARGS } }
};
@@ -4273,6 +4426,20 @@
END_ARGS
}
},
+ { "BootstrappingRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "bootstrap_method", "q", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "BootstrappingCompleted", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+ {
+ { "path", "o", ARG_OUT },
+ { "status", "i", ARG_OUT },
+ END_ARGS
+ }
+ },
#endif /* CONFIG_P2P */
#ifdef CONFIG_AP
{ "ProbeRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
@@ -4384,6 +4551,40 @@
}
},
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_NAN_USD
+ { "NANDiscoveryResult", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "NANReplied", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "NANReceive", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "args", "a{sv}", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "NANPublishTerminated", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "publish_id", "u", ARG_OUT },
+ { "reason", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "NANSubscribeTerminated", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ {
+ { "subscribe_id", "u", ARG_OUT },
+ { "reason", "s", ARG_OUT },
+ END_ARGS
+ }
+ },
+#endif /* CONFIG_NAN_USD */
{ NULL, NULL, { END_ARGS } }
};
@@ -5253,3 +5454,259 @@
dbus_message_unref(msg);
}
#endif /* CONFIG_HS20 */
+
+
+#ifdef CONFIG_NAN_USD
+
+/**
+ * wpas_dbus_signal_nan_discovery_result - Send NANDiscoveryResult signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @srv_proto_type: Service Protocol Type
+ * @subscribe_id: Subscribe ID of the session
+ * @peer_publish_id: Publish ID of the sender
+ * @peer_addr: MAC address of the peer device
+ * @ssi: Service specific information payload
+ * @ssi_len: Length of the SSI field
+ *
+ * This is used to indicate the NAN DE DiscoveryResult event.
+ */
+void wpas_dbus_signal_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)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ char addr_str[20];
+
+ iface = wpa_s->global->dbus;
+ /* Do nothing if the interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "NANDiscoveryResult");
+ if (!msg)
+ return;
+
+ snprintf(addr_str, sizeof(addr_str), MACSTR, MAC2STR(peer_addr));
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "subscribe_id",
+ subscribe_id) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "publish_id",
+ peer_publish_id) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "peer_addr", addr_str) ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "fsd", fsd) ||
+ !wpa_dbus_dict_append_bool(&dict_iter, "fsd_gas", fsd_gas) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "srv_proto_type",
+ srv_proto_type) ||
+ (ssi &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter,
+ "ssi",
+ (const char *) ssi,
+ ssi_len)) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_nan_replied - Send NANReplied signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @srv_proto_type: Service Protocol Type
+ * @publish_id: Publish id of the session
+ * @peer_subscribe_id: Subscribe id of the sender
+ * @peer_addr: MAC address of the peer device
+ * @ssi: Service specific information payload
+ * @ssi_len: Length of the SSI field
+ *
+ * This is used to indicate the NAN DE Replied event.
+ */
+void wpas_dbus_signal_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)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ char addr_str[20];
+
+ iface = wpa_s->global->dbus;
+ /* Do nothing if the interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "NANReplied");
+ if (!msg)
+ return;
+
+ snprintf(addr_str, sizeof(addr_str), MACSTR, MAC2STR(peer_addr));
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "publish_id",
+ publish_id) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "subscribe_id",
+ peer_subscribe_id) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "peer_addr", addr_str) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "srv_proto_type",
+ srv_proto_type) ||
+ (ssi &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "ssi",
+ (const char *) ssi,
+ ssi_len)) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_nan_receive - Send NANReceive signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @id: The original publish_id or subscribe_id
+ * @peer_id: Peer instance identifier
+ * @peer_addr: Address of the sender
+ * @ssi: Service specific information payload
+ * @ssi_len: Length of the SSI
+ *
+ * This is used to indicate the NAN DE Receive event to notify reception of a
+ * follow-up frame.
+ */
+void wpas_dbus_signal_nan_receive(struct wpa_supplicant *wpa_s,
+ int id, int peer_id, const u8 *peer_addr,
+ const u8 *ssi, size_t ssi_len)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ DBusMessageIter iter, dict_iter;
+ char addr_str[20];
+
+ iface = wpa_s->global->dbus;
+ /* Do nothing if the interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "NANReceive");
+ if (!msg)
+ return;
+
+ snprintf(addr_str, sizeof(addr_str), MACSTR, MAC2STR(peer_addr));
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "id", id) ||
+ !wpa_dbus_dict_append_uint32(&dict_iter, "peer_id", peer_id) ||
+ !wpa_dbus_dict_append_string(&dict_iter, "peer_addr", addr_str) ||
+ (ssi &&
+ !wpa_dbus_dict_append_byte_array(&dict_iter, "ssi",
+ (const char *) ssi,
+ ssi_len)) ||
+ !wpa_dbus_dict_close_write(&iter, &dict_iter))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_nan_publish_terminated - Send NANPublishTerminated signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @publish_id: The publish_id of the session
+ * @reason: The reason of the termination
+ *
+ * This is used to indicate the NAN DE PublishTerminated event to notify when
+ * the session has expired.
+ */
+void wpas_dbus_signal_nan_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id,
+ const char *reason)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ dbus_uint32_t pub_id = publish_id;
+
+ iface = wpa_s->global->dbus;
+ /* Do nothing if the interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "NANPublishTerminated");
+ if (!msg)
+ return;
+
+ if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &pub_id,
+ DBUS_TYPE_INVALID) ||
+ !dbus_message_append_args(msg, DBUS_TYPE_STRING, &reason,
+ DBUS_TYPE_INVALID))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+
+/**
+ * wpas_dbus_signal_nan_subscribe_terminated - Send NANSubscribeTerminated signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @subscribe_id: The subscribe_id of the session
+ * @reason: The reason of the termination
+ *
+ * This is used to indicate the NAN DE SubscribeTerminated event to notify when
+ * the session has expired.
+ */
+void wpas_dbus_signal_nan_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id,
+ const char *reason)
+{
+ struct wpas_dbus_priv *iface;
+ DBusMessage *msg;
+ dbus_uint32_t sub_id = subscribe_id;
+
+ iface = wpa_s->global->dbus;
+ /* Do nothing if the interface is not turned on */
+ if (!iface || !wpa_s->dbus_new_path)
+ return;
+
+ msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+ WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "NANSubscribeTerminated");
+ if (!msg)
+ return;
+
+ if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &sub_id,
+ DBUS_TYPE_INVALID) ||
+ !dbus_message_append_args(msg, DBUS_TYPE_STRING, &reason,
+ DBUS_TYPE_INVALID))
+ wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+ else
+ dbus_connection_send(iface->con, msg, NULL);
+ dbus_message_unref(msg);
+}
+
+#endif /* CONFIG_NAN_USD */
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 1db5fe8..f9ff636 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -21,6 +21,7 @@
struct wps_event_m2d;
struct wps_event_fail;
struct wps_credential;
+enum nan_service_protocol_type;
enum wpas_dbus_prop {
WPAS_DBUS_PROP_AP_SCAN,
@@ -265,6 +266,10 @@
const u8 *sa, const u8 *dev_addr,
const u8 *bssid, int id,
int op_freq);
+void wpas_dbus_signal_p2p_bootstrap_req(struct wpa_supplicant *wpa_s,
+ const u8 *src, u16 bootstrap_method);
+void wpas_dbus_signal_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s,
+ const u8 *src, int status);
void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_dbus_signal_mesh_group_removed(struct wpa_supplicant *wpa_s,
@@ -285,6 +290,28 @@
const u8 *dst, const char *result);
void wpas_dbus_signal_hs20_t_c_acceptance(struct wpa_supplicant *wpa_s,
const char *url);
+void wpas_dbus_signal_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_dbus_signal_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_dbus_signal_nan_receive(struct wpa_supplicant *wpa_s, int id,
+ int peer_id, const u8 *peer_addr,
+ const u8 *ssi, size_t ssi_len);
+void wpas_dbus_signal_nan_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id,
+ const char *reason);
+void wpas_dbus_signal_nan_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id,
+ const char *reason);
#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
@@ -617,6 +644,18 @@
}
static inline
+void wpas_dbus_signal_p2p_bootstrap_req(struct wpa_supplicant *wpa_s,
+ const u8 *src, u16 bootstrap_method)
+{
+}
+
+static inline
+void wpas_dbus_signal_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s,
+ const u8 *src, int status)
+{
+}
+
+static inline
void wpas_dbus_signal_mesh_group_started(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -668,6 +707,45 @@
{
}
+static inline void
+wpas_dbus_signal_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)
+{
+}
+
+static inline void
+wpas_dbus_signal_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)
+{
+}
+
+
+static inline void
+wpas_dbus_signal_nan_receive(struct wpa_supplicant *wpa_s,
+ int id, int peer_id, const u8 *peer_addr,
+ const u8 *ssi, size_t ssi_len)
+{
+}
+
+static inline void
+wpas_dbus_signal_nan_publish_terminated(struct wpa_supplicant *wpa_s,
+ int publish_id, const char *reason)
+{
+}
+
+static inline void
+wpas_dbus_signal_nan_subscribe_terminated(struct wpa_supplicant *wpa_s,
+ int subscribe_id, const char *reason)
+{
+}
+
#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
#endif /* CTRL_IFACE_DBUS_H_NEW */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 52e35a7..2fad8dd 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -12,6 +12,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "common/nan_de.h"
#include "eap_peer/eap_methods.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
@@ -27,6 +28,7 @@
#include "../autoscan.h"
#include "../ap.h"
#include "../interworking.h"
+#include "../nan_usd.h"
#include "dbus_new_helpers.h"
#include "dbus_new.h"
#include "dbus_new_handlers.h"
@@ -6485,3 +6487,514 @@
}
return TRUE;
}
+
+
+#ifdef CONFIG_NAN_USD
+
+/*
+ * wpas_dbus_handler_nan_publish - Send out NAN publish messages
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "NANPublish" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_nan_publish(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter, iter_dict;
+ struct wpa_dbus_dict_entry entry;
+ DBusMessage *reply = NULL;
+ int publish_id;
+ char *srv_name = NULL;
+ enum nan_service_protocol_type srv_proto_type = 0;
+ bool p2p = false;
+ struct nan_publish_params params;
+ int *freq_list = NULL;
+ struct wpabuf *ssi = NULL;
+ dbus_uint32_t id;
+
+ wpa_printf(MSG_DEBUG, "dbus: NANPublish");
+ if (!wpa_s->nan_de)
+ return NULL;
+
+ os_memset(¶ms, 0, sizeof(params));
+ /* USD shall use both solicited and unsolicited transmissions */
+ params.unsolicited = true;
+ params.solicited = true;
+ /* USD shall require FSD without GAS */
+ params.fsd = true;
+ params.freq = NAN_USD_DEFAULT_FREQ;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+ goto fail;
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto fail;
+ if (os_strcmp(entry.key, "srv_name") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ os_free(srv_name);
+ srv_name = os_strdup(entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
+ if (!srv_name)
+ goto oom;
+ } else if (os_strcmp(entry.key, "srv_proto_type") == 0 &&
+ wpa_dbus_dict_entry_is_int(&entry)) {
+ srv_proto_type = wpa_dbus_dict_entry_get_int(&entry);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "solicited") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ params.solicited = entry.bool_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "unsolicited") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ params.unsolicited = entry.bool_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "solicited_multicast") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ params.solicited_multicast = entry.bool_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "ttl") == 0 &&
+ wpa_dbus_dict_entry_is_int(&entry)) {
+ params.ttl = wpa_dbus_dict_entry_get_int(&entry);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "disable_events") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ params.disable_events = entry.bool_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "fsd") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ params.fsd = entry.bool_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "fsd_gas") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ params.fsd_gas = entry.bool_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "p2p") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ p2p = entry.bool_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "freq") == 0 &&
+ wpa_dbus_dict_entry_is_int(&entry)) {
+ params.freq = wpa_dbus_dict_entry_get_int(&entry);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "announcement_period") == 0 &&
+ wpa_dbus_dict_entry_is_int(&entry)) {
+ params.announcement_period =
+ wpa_dbus_dict_entry_get_int(&entry);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "ssi") == 0 &&
+ entry.type == DBUS_TYPE_ARRAY &&
+ entry.array_type == DBUS_TYPE_BYTE) {
+ wpabuf_free(ssi);
+ ssi = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ wpa_dbus_dict_entry_clear(&entry);
+ if (!ssi)
+ goto oom;
+ } else if (os_strcmp(entry.key, "freq_list") == 0 &&
+ entry.type == DBUS_TYPE_ARRAY &&
+ entry.array_type == DBUS_TYPE_UINT16) {
+ unsigned int i;
+
+ for (i = 0; i < entry.array_len; i++)
+ int_array_add_unique(
+ &freq_list, entry.uint16array_value[i]);
+ params.freq_list = freq_list;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "dbus: NANPublish - unsupported dict entry '%s'",
+ entry.key);
+ reply = wpas_dbus_error_invalid_args(message,
+ entry.key);
+ wpa_dbus_dict_entry_clear(&entry);
+ goto fail;
+ }
+ }
+
+ if (!srv_name)
+ goto fail;
+
+ publish_id = wpas_nan_usd_publish(wpa_s, srv_name, srv_proto_type, ssi,
+ ¶ms, p2p);
+ if (publish_id < 0) {
+ reply = wpas_dbus_error_unknown_error(
+ message, "error publishing NAN USD");
+ goto out;
+ }
+
+ id = publish_id;
+ reply = dbus_message_new_method_return(message);
+ if (!reply) {
+ reply = wpas_dbus_error_no_memory(message);
+ goto out;
+ }
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32,
+ &id, DBUS_TYPE_INVALID);
+
+out:
+ wpabuf_free(ssi);
+ os_free(freq_list);
+ os_free(srv_name);
+ return reply;
+fail:
+ reply = wpas_dbus_error_invalid_args(message,
+ "failed to parse NANPublish");
+ goto out;
+oom:
+ reply = wpas_dbus_error_no_memory(message);
+ goto out;
+}
+
+
+/*
+ * wpas_dbus_handler_nan_cancel_publish - Cancel a NAN publish
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "NANCancelPublish" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_nan_cancel_publish(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ dbus_uint32_t publish_id;
+
+ if (!wpa_s->nan_de)
+ return NULL;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_UINT32, &publish_id,
+ DBUS_TYPE_INVALID)) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: NANCancelPublish failed to get args");
+ return wpas_dbus_error_invalid_args(message, NULL);
+ }
+
+ wpa_printf(MSG_DEBUG, "dbus: NANCancelPublish: id=%u", publish_id);
+ nan_de_cancel_publish(wpa_s->nan_de, publish_id);
+ return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_nan_update_publish - Update the SSI for a NAN publish
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "NANUpdatePublish" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_nan_update_publish(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter, iter_dict;
+ struct wpa_dbus_dict_entry entry;
+ DBusMessage *reply = NULL;
+ int publish_id = -1;
+ struct wpabuf *ssi = NULL;
+
+ wpa_printf(MSG_DEBUG, "dbus: NANUpdatePublish");
+ if (!wpa_s->nan_de)
+ return NULL;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+ goto fail;
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto fail;
+ if (os_strcmp(entry.key, "publish_id") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
+ publish_id = entry.uint32_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ wpa_printf(MSG_DEBUG, "dbus: publish_id=%d",
+ publish_id);
+ } else if (os_strcmp(entry.key, "ssi") == 0 &&
+ entry.type == DBUS_TYPE_ARRAY &&
+ entry.array_type == DBUS_TYPE_BYTE) {
+ wpabuf_free(ssi);
+ ssi = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ wpa_dbus_dict_entry_clear(&entry);
+ if (!ssi) {
+ reply = wpas_dbus_error_no_memory(message);
+ goto out;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "dbus: NANTransmit - unsupported dict entry '%s'",
+ entry.key);
+ reply = wpas_dbus_error_invalid_args(message,
+ entry.key);
+ wpa_dbus_dict_entry_clear(&entry);
+ goto out;
+ }
+ }
+
+ if (publish_id < 0)
+ goto fail;
+
+ if (nan_de_update_publish(wpa_s->nan_de, publish_id, ssi) < 0)
+ reply = wpas_dbus_error_unknown_error(
+ message, "error updating NAN USD publish ssi");
+
+out:
+ wpabuf_free(ssi);
+ return reply;
+fail:
+ reply = wpas_dbus_error_invalid_args(
+ message,
+ "failed to parse NANUpdatePublish");
+ goto out;
+}
+
+
+/*
+ * wpas_dbus_handler_nan_subscribe - Send out NAN USD subscribe messages
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "NANSubscribe" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_nan_subscribe(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter, iter_dict;
+ struct wpa_dbus_dict_entry entry;
+ DBusMessage *reply = NULL;
+ int subscribe_id;
+ char *srv_name = NULL;
+ struct nan_subscribe_params params;
+ enum nan_service_protocol_type srv_proto_type = 0;
+ bool p2p = false;
+ struct wpabuf *ssi = NULL;
+ int *freq_list = NULL;
+
+ wpa_printf(MSG_DEBUG, "dbus: NANSubscribe");
+ if (!wpa_s->nan_de)
+ return NULL;
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.freq = NAN_USD_DEFAULT_FREQ;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+ goto fail;
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto fail;
+ if (os_strcmp(entry.key, "srv_name") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ os_free(srv_name);
+ srv_name = os_strdup(entry.str_value);
+ wpa_dbus_dict_entry_clear(&entry);
+ if (!srv_name)
+ goto oom;
+ } else if (os_strcmp(entry.key, "srv_proto_type") == 0 &&
+ wpa_dbus_dict_entry_is_int(&entry)) {
+ srv_proto_type = wpa_dbus_dict_entry_get_int(&entry);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "active") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ params.active = entry.bool_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "p2p") == 0 &&
+ entry.type == DBUS_TYPE_BOOLEAN) {
+ p2p = entry.bool_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "ttl") == 0 &&
+ wpa_dbus_dict_entry_is_int(&entry)) {
+ params.ttl = wpa_dbus_dict_entry_get_int(&entry);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "freq") == 0 &&
+ wpa_dbus_dict_entry_is_int(&entry)) {
+ params.freq = wpa_dbus_dict_entry_get_int(&entry);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "query_period") == 0 &&
+ wpa_dbus_dict_entry_is_int(&entry)) {
+ params.query_period =
+ wpa_dbus_dict_entry_get_int(&entry);
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "ssi") == 0 &&
+ entry.type == DBUS_TYPE_ARRAY &&
+ entry.array_type == DBUS_TYPE_BYTE) {
+ wpabuf_free(ssi);
+ ssi = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ wpa_dbus_dict_entry_clear(&entry);
+ if (!ssi)
+ goto oom;
+ } else if (os_strcmp(entry.key, "freq_list") == 0 &&
+ entry.type == DBUS_TYPE_ARRAY &&
+ entry.array_type == DBUS_TYPE_UINT16) {
+ unsigned int i;
+
+ for (i = 0; i < entry.array_len; i++)
+ int_array_add_unique(
+ &freq_list, entry.uint16array_value[i]);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "dbus: NANSubscribe - unsupported dict entry '%s'",
+ entry.key);
+ reply = wpas_dbus_error_invalid_args(message,
+ entry.key);
+ wpa_dbus_dict_entry_clear(&entry);
+ goto fail;
+ }
+ }
+
+ if (!srv_name)
+ goto fail;
+
+ subscribe_id = wpas_nan_usd_subscribe(wpa_s, srv_name, srv_proto_type,
+ ssi, ¶ms, p2p);
+ if (subscribe_id < 0) {
+ reply = wpas_dbus_error_unknown_error(
+ message, "error subscribing NAN USD");
+ goto out;
+ }
+
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32,
+ &subscribe_id, DBUS_TYPE_INVALID);
+out:
+ wpabuf_free(ssi);
+ os_free(freq_list);
+ os_free(srv_name);
+ return reply;
+fail:
+ reply = wpas_dbus_error_invalid_args(message,
+ "failed to parse NANSubscribe");
+ goto out;
+oom:
+ reply = wpas_dbus_error_no_memory(message);
+ goto out;
+}
+
+
+/*
+ * wpas_dbus_handler_nan_cancel_subscribe - Cancel a NAN subscription
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "NANCancelSubscribe" method call of network interface.
+ */
+DBusMessage *
+wpas_dbus_handler_nan_cancel_subscribe(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ dbus_uint32_t subscribe_id;
+
+ if (!wpa_s->nan_de)
+ return NULL;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_UINT32, &subscribe_id,
+ DBUS_TYPE_INVALID)) {
+ wpa_printf(MSG_DEBUG,
+ "dbus: NANCancelSubscribe failed to get args");
+ return wpas_dbus_error_invalid_args(message, NULL);
+ }
+
+ wpa_printf(MSG_DEBUG, "dbus: NANCancelSubscribe: id=%u", subscribe_id);
+ nan_de_cancel_subscribe(wpa_s->nan_de, subscribe_id);
+ return NULL;
+}
+
+
+/*
+ * wpas_dbus_handler_nan_transmit - Send out NAN followup frames
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "NANTransmit" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_nan_transmit(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessageIter iter, iter_dict;
+ struct wpa_dbus_dict_entry entry;
+ DBusMessage *reply = NULL;
+ int handle = -1;
+ int req_instance_id = -1;
+ u8 peer_addr[ETH_ALEN];
+ bool peer_addr_set = false;
+ struct wpabuf *ssi = NULL;
+
+ wpa_printf(MSG_DEBUG, "dbus: NANTransmit");
+ if (!wpa_s->nan_de)
+ return NULL;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
+ goto fail;
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto fail;
+ if (os_strcmp(entry.key, "handle") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
+ handle = entry.uint32_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ wpa_printf(MSG_DEBUG, "dbus: handle=%d", handle);
+ } else if (os_strcmp(entry.key, "req_instance_id") == 0 &&
+ entry.type == DBUS_TYPE_UINT32) {
+ req_instance_id = entry.uint32_value;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "peer_addr") == 0 &&
+ entry.type == DBUS_TYPE_STRING) {
+ if (hwaddr_aton(entry.str_value, peer_addr) < 0) {
+ wpa_dbus_dict_entry_clear(&entry);
+ goto fail;
+ }
+ peer_addr_set = true;
+ wpa_dbus_dict_entry_clear(&entry);
+ } else if (os_strcmp(entry.key, "ssi") == 0 &&
+ entry.type == DBUS_TYPE_ARRAY &&
+ entry.array_type == DBUS_TYPE_BYTE) {
+ wpabuf_free(ssi);
+ ssi = wpabuf_alloc_copy(entry.bytearray_value,
+ entry.array_len);
+ wpa_dbus_dict_entry_clear(&entry);
+ if (!ssi) {
+ reply = wpas_dbus_error_no_memory(message);
+ goto out;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "dbus: NANTransmit - unsupported dict entry '%s'",
+ entry.key);
+ reply = wpas_dbus_error_invalid_args(message,
+ entry.key);
+ wpa_dbus_dict_entry_clear(&entry);
+ goto fail;
+ }
+ }
+
+ if (handle < 0 || req_instance_id < 0 || !peer_addr_set || !ssi)
+ goto fail;
+
+ if (wpas_nan_usd_transmit(wpa_s, handle, ssi, NULL, peer_addr,
+ req_instance_id) < 0)
+ reply = wpas_dbus_error_unknown_error(
+ message, "failed to transmit follow-up");
+out:
+ wpabuf_free(ssi);
+ return reply;
+
+fail:
+ reply = wpas_dbus_error_invalid_args(message,
+ "failed to parse NANTransmit");
+ goto out;
+}
+
+#endif /* CONFIG_NAN_USD */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 7faf70a..a526090 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -290,4 +290,18 @@
DBusMessage * wpas_dbus_handler_unsubscribe_preq(
DBusMessage *message, struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_nan_publish(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_nan_cancel_publish(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_nan_update_publish(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_nan_subscribe(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage *
+wpas_dbus_handler_nan_cancel_subscribe(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_nan_transmit(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
#endif /* CTRL_IFACE_DBUS_HANDLERS_NEW_H */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 65bd478..ce49bce 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -477,7 +477,8 @@
freq2, ht40, vht,
max_oper_chwidth, he, edmg,
NULL, 0, 0, allow_6ghz,
- retry_limit, go_bssid)) {
+ retry_limit, go_bssid, NULL,
+ NULL, NULL, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -485,7 +486,7 @@
}
} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, freq2,
ht40, vht, max_oper_chwidth, he, edmg,
- allow_6ghz))
+ allow_6ghz, wpa_s->p2p2, wpa_s->p2p_mode))
goto inv_args;
out:
@@ -706,7 +707,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, 0, 0, NULL);
+ NULL, 0, false, 0, 0, NULL, false);
if (new_pin >= 0) {
char npin[9];
@@ -866,7 +867,7 @@
goto err;
if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0, 0,
- 0, 0, 0, false) < 0) {
+ 0, 0, 0, false, false) < 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
index a8c0d28..bfdc3e2 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -38,7 +38,7 @@
if (!iface)
return NULL;
iface->dbus_interface = os_strdup(dbus_interface);
- iface->xml = wpabuf_alloc(16000);
+ iface->xml = wpabuf_alloc(18000);
if (iface->dbus_interface == NULL || iface->xml == NULL) {
os_free(iface->dbus_interface);
wpabuf_free(iface->xml);
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 1b2c756..70f7a3b 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -59,6 +59,9 @@
struct dpp_authentication *auth);
static bool wpas_dpp_tcp_msg_sent(void *ctx, struct dpp_authentication *auth);
#endif /* CONFIG_DPP2 */
+#ifdef CONFIG_DPP3
+static void wpas_dpp_pb_next(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_DPP3 */
static const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -1347,6 +1350,16 @@
struct dpp_authentication *auth = wpa_s->dpp_auth;
int freq;
+#ifdef CONFIG_DPP3
+ if (wpa_s->dpp_pb_announcement && wpa_s->dpp_pb_discovery_done) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Failed to send push button announcement");
+ if (eloop_register_timeout(0, 0, wpas_dpp_pb_next,
+ wpa_s, NULL) < 0)
+ wpas_dpp_push_button_stop(wpa_s);
+ }
+#endif /* CONFIG_DPP3 */
+
if (wpa_s->dpp_listen_on_tx_expire && auth && auth->neg_freq) {
wpa_printf(MSG_DEBUG,
"DPP: Start listen on neg_freq %u MHz based on TX wait expiration on the previous channel",
@@ -5545,7 +5558,6 @@
#define DPP_PB_ANNOUNCE_PER_CHAN 3
static int wpas_dpp_pb_announce(struct wpa_supplicant *wpa_s, int freq);
-static void wpas_dpp_pb_next(void *eloop_ctx, void *timeout_ctx);
static void wpas_dpp_pb_tx_status(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index b6c7f50..43847cf 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -16,9 +16,17 @@
static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s,
const char *ifname)
{
- if (wpa_s->driver->init2)
+ if (wpa_s->driver->init2) {
+ enum wpa_p2p_mode p2p_mode = WPA_P2P_MODE_WFD_R1;
+
+#ifdef CONFIG_P2P
+ p2p_mode = wpa_s->p2p_mode;
+#endif /* CONFIG_P2P */
+
return wpa_s->driver->init2(wpa_s, ifname,
- wpa_s->global_drv_priv);
+ wpa_s->global_drv_priv,
+ p2p_mode);
+ }
if (wpa_s->driver->init) {
return wpa_s->driver->init(wpa_s, ifname);
}
@@ -104,6 +112,8 @@
static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
struct wpa_driver_scan_params *params)
{
+ params->link_id = -1;
+
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->test_failure == WPAS_TEST_FAILURE_SCAN_TRIGGER)
return -EBUSY;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 2a665d7..30176a0 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -437,6 +437,9 @@
wpa_s->ssid_verified = false;
wpa_s->bigtk_set = false;
+
+ wpabuf_free(wpa_s->pending_eapol_rx);
+ wpa_s->pending_eapol_rx = NULL;
}
@@ -1045,7 +1048,7 @@
#ifdef CONFIG_SAE
if (flagged && ((rate_ie[j] & 0x7f) ==
BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) {
- if (wpa_s->conf->sae_pwe ==
+ if (wpas_get_ssid_sae_pwe(wpa_s, ssid) ==
SAE_PWE_HUNT_AND_PECK &&
!ssid->sae_password_id &&
!is_6ghz_freq(bss->freq) &&
@@ -1163,7 +1166,8 @@
if (wpas_network_disabled(wpa_s, ssid))
continue;
if (ssid->ssid_len == *ret_ssid_len &&
- os_memcmp(ssid->ssid, ret_ssid, *ret_ssid_len) == 0) {
+ 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,
@@ -1267,12 +1271,15 @@
{
int res;
bool wpa, check_ssid, osen, rsn_osen = false;
+#ifndef CONFIG_NO_WPA
struct wpa_ie_data data;
+#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_MBO
const u8 *assoc_disallow;
#endif /* CONFIG_MBO */
#ifdef CONFIG_SAE
u8 rsnxe_capa = 0;
+ enum sae_pwe sae_pwe;
#endif /* CONFIG_SAE */
const u8 *ie;
@@ -1280,9 +1287,11 @@
wpa = ie && ie[1];
ie = wpa_bss_get_rsne(wpa_s, bss, ssid, false);
wpa |= ie && ie[1];
+#ifndef CONFIG_NO_WPA
if (ie && wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) == 0 &&
(data.key_mgmt & WPA_KEY_MGMT_OSEN))
rsn_osen = true;
+#endif /* CONFIG_NO_WPA */
ie = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
osen = ie != NULL;
@@ -1449,9 +1458,10 @@
#ifdef CONFIG_SAE
/* When using SAE Password Identifier and when operationg on the 6 GHz
* band, only H2E is allowed. */
- if ((wpa_s->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
+ sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
+ if ((sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
is_6ghz_freq(bss->freq) || ssid->sae_password_id) &&
- wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
+ sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
wpa_key_mgmt_sae(ssid->key_mgmt) &&
#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
!(wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt)) &&
@@ -1737,7 +1747,7 @@
}
-static struct wpa_bss *
+struct wpa_bss *
wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
struct wpa_ssid *group,
struct wpa_ssid **selected_ssid,
@@ -2167,7 +2177,8 @@
int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
struct wpa_bss *current_bss,
- struct wpa_bss *selected)
+ struct wpa_bss *selected,
+ bool poll_current)
{
int min_diff, diff;
int cur_band_score, sel_band_score;
@@ -2222,7 +2233,7 @@
* scan results may be a bit old, since we can very quickly get fresh
* information about our currently associated AP.
*/
- if (wpa_drv_signal_poll(wpa_s, &si) == 0 &&
+ if (poll_current && wpa_drv_signal_poll(wpa_s, &si) == 0 &&
(si.data.avg_beacon_signal || si.data.avg_signal)) {
/*
* Normalize avg_signal to the RSSI over 20 MHz, as the
@@ -2395,7 +2406,7 @@
#ifndef CONFIG_NO_ROAMING
return wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss,
- selected);
+ selected, true);
#else /* CONFIG_NO_ROAMING */
return 0;
#endif /* CONFIG_NO_ROAMING */
@@ -2557,7 +2568,27 @@
}
#endif /* CONFIG_NO_RANDOM_POOL */
- wpa_s->last_scan_external = data && data->scan_info.external_scan;
+ if (data) {
+ size_t idx;
+
+ wpa_s->last_scan_external = data->scan_info.external_scan;
+ wpa_s->last_scan_num_ssids = data->scan_info.num_ssids;
+ for (idx = 0; idx < wpa_s->last_scan_num_ssids; idx++) {
+ /* Copy the SSID and its length */
+ if (idx >= WPAS_MAX_SCAN_SSIDS ||
+ data->scan_info.ssids[idx].ssid_len > SSID_MAX_LEN)
+ continue;
+
+ os_memcpy(wpa_s->last_scan_ssids[idx].ssid,
+ data->scan_info.ssids[idx].ssid,
+ data->scan_info.ssids[idx].ssid_len);
+ wpa_s->last_scan_ssids[idx].ssid_len =
+ data->scan_info.ssids[idx].ssid_len;
+ }
+ } else {
+ wpa_s->last_scan_external = false;
+ wpa_s->last_scan_num_ssids = 0;
+ }
if (update_only) {
ret = 1;
@@ -3470,7 +3501,7 @@
#endif /* CONFIG_WNM */
interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len);
- if (wpa_s->hw_capab == CAPAB_VHT &&
+ if ((wpa_s->hw_capab & BIT(CAPAB_VHT)) &&
get_ie(data->assoc_info.resp_ies,
data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP))
wpa_s->ieee80211ac = 1;
@@ -5698,7 +5729,8 @@
WPA_GET_BE32(&payload[1]) == NAN_SDF_VENDOR_TYPE) {
payload += 5;
plen -= 5;
- wpas_nan_usd_rx_sdf(wpa_s, mgmt->sa, freq, payload, plen);
+ wpas_nan_usd_rx_sdf(wpa_s, mgmt->sa, mgmt->bssid, freq,
+ payload, plen);
return;
}
#endif /* CONFIG_NAN_USD */
@@ -6271,6 +6303,37 @@
#endif /* MAINLINE_SUPPLICANT */
+#ifdef CONFIG_PASN
+static int wpas_pasn_auth(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int freq)
+{
+#ifdef CONFIG_P2P
+ struct ieee802_11_elems elems;
+
+ if (len < 24) {
+ wpa_printf(MSG_DEBUG, "nl80211: Too short Management frame");
+ return -2;
+ }
+
+ if (ieee802_11_parse_elems(mgmt->u.auth.variable,
+ len - offsetof(struct ieee80211_mgmt,
+ u.auth.variable),
+ &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG,
+ "PASN: Failed parsing Authentication frame");
+ return -2;
+ }
+
+ if (elems.p2p2_ie && elems.p2p2_ie_len)
+ return wpas_p2p_pasn_auth_rx(wpa_s, mgmt, len, freq);
+#endif /* CONFIG_P2P */
+
+ return wpas_pasn_auth_rx(wpa_s, mgmt, len);
+}
+#endif /* CONFIG_PASN */
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -6509,6 +6572,17 @@
break;
#endif /* CONFIG_WNM */
#ifdef CONFIG_PASN
+#ifdef CONFIG_P2P
+ if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
+ data->tx_status.stype == WLAN_FC_STYPE_AUTH &&
+ !wpa_s->pasn_auth_work &&
+ wpa_s->p2p_pasn_auth_work &&
+ wpas_p2p_pasn_auth_tx_status(wpa_s,
+ data->tx_status.data,
+ data->tx_status.data_len,
+ data->tx_status.ack) == 0)
+ break;
+#endif /* CONFIG_P2P */
if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
data->tx_status.stype == WLAN_FC_STYPE_AUTH &&
wpas_pasn_auth_tx_status(wpa_s, data->tx_status.data,
@@ -6792,8 +6866,8 @@
}
#ifdef CONFIG_PASN
if (stype == WLAN_FC_STYPE_AUTH &&
- wpas_pasn_auth_rx(wpa_s, mgmt,
- data->rx_mgmt.frame_len) != -2)
+ wpas_pasn_auth(wpa_s, mgmt, data->rx_mgmt.frame_len,
+ data->rx_mgmt.freq) != -2)
break;
#endif /* CONFIG_PASN */
@@ -6897,12 +6971,12 @@
data->eapol_rx.encrypted);
break;
case EVENT_SIGNAL_CHANGE:
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SIGNAL_CHANGE
- "above=%d signal=%d noise=%d txrate=%lu",
- data->signal_change.above_threshold,
- data->signal_change.data.signal,
- data->signal_change.current_noise,
- data->signal_change.data.current_tx_rate);
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SIGNAL_CHANGE
+ "above=%d signal=%d noise=%d txrate=%lu",
+ data->signal_change.above_threshold,
+ data->signal_change.data.signal,
+ data->signal_change.current_noise,
+ data->signal_change.data.current_tx_rate);
wpa_bss_update_level(wpa_s->current_bss,
data->signal_change.data.signal);
bgscan_notify_signal_change(
diff --git a/wpa_supplicant/mbo.c b/wpa_supplicant/mbo.c
index 80fbe01..273bd25 100644
--- a/wpa_supplicant/mbo.c
+++ b/wpa_supplicant/mbo.c
@@ -460,6 +460,10 @@
{
u8 *len;
+ if (wpa_s->drv_max_probe_req_ie_len <
+ 9 + ((wpa_s->enable_oce & OCE_STA) ? 3 : 0))
+ return;
+
wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
len = wpabuf_put(ie, 1);
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 85c1ea8..869f0b3 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -464,6 +464,9 @@
case 160:
conf->op_class = 134;
break;
+ case 320:
+ conf->op_class = 137;
+ break;
default:
conf->op_class = 131;
break;
@@ -602,7 +605,8 @@
/* EID + 0-length (wildcard) mesh-id */
size_t ielen = 2;
- if (wpabuf_resize(extra_ie, ielen) == 0) {
+ if (ielen <= wpa_s->drv_max_probe_req_ie_len &&
+ wpabuf_resize(extra_ie, ielen) == 0) {
wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
wpabuf_put_u8(*extra_ie, 0);
}
diff --git a/wpa_supplicant/nan_usd.c b/wpa_supplicant/nan_usd.c
index 1125f95..577c8ac 100644
--- a/wpa_supplicant/nan_usd.c
+++ b/wpa_supplicant/nan_usd.c
@@ -321,7 +321,8 @@
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, offload, false, &cb);
+ wpa_s->nan_de = nan_de_init(wpa_s->own_addr, offload, false,
+ wpa_s->max_remain_on_chan, &cb);
if (!wpa_s->nan_de)
return -1;
return 0;
@@ -336,11 +337,12 @@
void wpas_nan_usd_rx_sdf(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *a3,
unsigned int freq, const u8 *buf, size_t len)
{
if (!wpa_s->nan_de)
return;
- nan_de_rx_sdf(wpa_s->nan_de, src, freq, buf, len);
+ nan_de_rx_sdf(wpa_s->nan_de, src, a3, freq, buf, len);
}
@@ -409,7 +411,7 @@
return -1;
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)
+ wpas_drv_nan_update_publish(wpa_s, publish_id, ssi) < 0)
return -1;
return ret;
}
diff --git a/wpa_supplicant/nan_usd.h b/wpa_supplicant/nan_usd.h
index ecb4973..59c0989 100644
--- a/wpa_supplicant/nan_usd.h
+++ b/wpa_supplicant/nan_usd.h
@@ -16,6 +16,7 @@
int wpas_nan_usd_init(struct wpa_supplicant *wpa_s);
void wpas_nan_usd_deinit(struct wpa_supplicant *wpa_s);
void wpas_nan_usd_rx_sdf(struct wpa_supplicant *wpa_s, const u8 *src,
+ const u8 *a3,
unsigned int freq, const u8 *buf, size_t len);
void wpas_nan_usd_flush(struct wpa_supplicant *wpa_s);
int wpas_nan_usd_publish(struct wpa_supplicant *wpa_s, const char *service_name,
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 2dc68b0..d5a34c5 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -122,6 +122,8 @@
enum wpa_states new_state,
enum wpa_states old_state)
{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
if (wpa_s->p2p_mgmt)
return;
@@ -138,10 +140,14 @@
}
#endif /* CONFIG_FST */
- if (new_state == WPA_COMPLETED)
+ if (new_state == WPA_COMPLETED) {
wpas_p2p_notif_connected(wpa_s);
- else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED)
+ if (ssid)
+ wpa_drv_roaming(wpa_s, !ssid->bssid_set,
+ ssid->bssid_set ? ssid->bssid : NULL);
+ } else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED) {
wpas_p2p_notif_disconnected(wpa_s);
+ }
sme_state_changed(wpa_s);
@@ -918,6 +924,18 @@
id, op_freq);
}
+void wpas_notify_p2p_bootstrap_req(struct wpa_supplicant *wpa_s,
+ const u8 *src, u16 bootstrap_method)
+{
+ wpas_dbus_signal_p2p_bootstrap_req(wpa_s, src, bootstrap_method);
+}
+
+void wpas_notify_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s,
+ const u8 *src, int status)
+{
+ wpas_dbus_signal_p2p_bootstrap_completed(wpa_s, src, status);
+}
+
#endif /* CONFIG_P2P */
@@ -1506,12 +1524,20 @@
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);
+ wpa_msg_global(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_aidl_notify_usd_service_discovered(wpa_s, srv_proto_type,
+ subscribe_id, peer_publish_id, peer_addr, fsd, ssi, ssi_len);
+
+ wpas_dbus_signal_nan_discovery_result(wpa_s, srv_proto_type,
+ subscribe_id, peer_publish_id,
+ peer_addr, fsd, fsd_gas,
+ ssi, ssi_len);
}
@@ -1528,12 +1554,19 @@
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);
+ wpa_msg_global(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);
+
+ wpas_aidl_notify_usd_publish_replied(wpa_s, srv_proto_type,
+ publish_id, peer_subscribe_id, peer_addr, ssi, ssi_len);
+
+ wpas_dbus_signal_nan_replied(wpa_s, srv_proto_type, publish_id,
+ peer_subscribe_id, peer_addr,
+ ssi, ssi_len);
}
@@ -1548,10 +1581,16 @@
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);
+ wpa_msg_global(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_aidl_notify_usd_message_received(wpa_s, id, peer_instance_id,
+ peer_addr, ssi, ssi_len);
+
+ wpas_dbus_signal_nan_receive(wpa_s, id, peer_instance_id, peer_addr,
+ ssi, ssi_len);
}
@@ -1574,9 +1613,14 @@
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));
+ wpa_msg_global(wpa_s, MSG_INFO, NAN_PUBLISH_TERMINATED
+ "publish_id=%d reason=%s",
+ publish_id, nan_reason_txt(reason));
+
+ wpas_aidl_notify_usd_publish_terminated(wpa_s, publish_id, reason);
+
+ wpas_dbus_signal_nan_publish_terminated(wpa_s, publish_id,
+ nan_reason_txt(reason));
}
@@ -1584,9 +1628,14 @@
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));
+ wpa_msg_global(wpa_s, MSG_INFO, NAN_SUBSCRIBE_TERMINATED
+ "subscribe_id=%d reason=%s",
+ subscribe_id, nan_reason_txt(reason));
+
+ wpas_aidl_notify_usd_subscribe_terminated(wpa_s, subscribe_id, reason);
+
+ wpas_dbus_signal_nan_subscribe_terminated(wpa_s, subscribe_id,
+ nan_reason_txt(reason));
}
#endif /* CONFIG_NAN_USD */
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 4e172de..5775e37 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -166,6 +166,10 @@
void wpas_notify_p2p_invitation_received(struct wpa_supplicant *wpa_s,
const u8 *sa, const u8 *go_dev_addr,
const u8 *bssid, int id, int op_freq);
+void wpas_notify_p2p_bootstrap_req(struct wpa_supplicant *wpa_s,
+ const u8 *src, u16 bootstrap_method);
+void wpas_notify_p2p_bootstrap_completed(struct wpa_supplicant *wpa_s,
+ const u8 *src, int status);
void wpas_notify_mesh_group_started(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_notify_mesh_group_removed(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 768b917..0c88e17 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -23,8 +23,10 @@
#include "ap/wps_hostapd.h"
#include "ap/p2p_hostapd.h"
#include "ap/dfs.h"
+#include "ap/wpa_auth.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "rsn_supp/wpa.h"
+#include "rsn_supp/pmksa_cache.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "ap.h"
@@ -1229,12 +1231,18 @@
s->bssid_set = 1;
os_memcpy(s->bssid, go_dev_addr, ETH_ALEN);
s->mode = ssid->mode;
- s->auth_alg = WPA_AUTH_ALG_OPEN;
- s->key_mgmt = WPA_KEY_MGMT_PSK;
- s->proto = WPA_PROTO_RSN;
+ s->auth_alg = ssid->auth_alg;
+ s->key_mgmt = ssid->key_mgmt;
+ s->proto = ssid->proto;
s->pbss = ssid->pbss;
+ s->pmk_valid = ssid->pmk_valid;
s->pairwise_cipher = ssid->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
s->export_keys = 1;
+
+ if (ssid->sae_password) {
+ os_free(s->sae_password);
+ s->sae_password = os_strdup(ssid->sae_password);
+ }
if (ssid->passphrase) {
os_free(s->passphrase);
s->passphrase = os_strdup(ssid->passphrase);
@@ -1392,6 +1400,106 @@
}
+int wpas_p2p_remove_all_identity(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_dev_ik *ik;
+
+ for (ik = wpa_s->conf->identity; ik; ik = ik->next)
+ wpa_config_remove_identity(wpa_s->conf, ik->id);
+
+ if (wpa_s->conf->update_config &&
+ wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+ wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+ return -1;
+ }
+ return 0;
+}
+
+
+static void wpas_p2p_store_identity(struct wpa_supplicant *wpa_s, u8 cipher,
+ const u8 *dik_data, size_t dik_len,
+ const u8 *pmk, size_t pmk_len,
+ const u8 *pmkid)
+{
+ struct wpa_dev_ik *ik;
+
+ for (ik = wpa_s->conf->identity; ik; ik = ik->next) {
+ if (dik_len == wpabuf_len(ik->dik) &&
+ os_memcmp(dik_data, wpabuf_head(ik->dik), dik_len) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Remove previous device identity entry for matching DIK");
+ wpa_config_remove_identity(wpa_s->conf, ik->id);
+ break;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Create a new device identity entry");
+ ik = wpa_config_add_identity(wpa_s->conf);
+ if (!ik)
+ return;
+
+ ik->dik = wpabuf_alloc_copy(dik_data, dik_len);
+ if (!ik->dik)
+ goto fail;
+ ik->pmk = wpabuf_alloc_copy(pmk, pmk_len);
+ if (!ik->pmk)
+ goto fail;
+ ik->pmkid = wpabuf_alloc_copy(pmkid, PMKID_LEN);
+ if (!ik->pmkid)
+ goto fail;
+
+ ik->dik_cipher = 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");
+ return;
+
+fail:
+ wpa_config_remove_identity(wpa_s->conf, ik->id);
+}
+
+
+static void wpas_p2p_store_go_identity(struct wpa_supplicant *wpa_s,
+ const u8 *go_dev_addr, const u8 *bssid)
+{
+ int ret;
+ u8 cipher;
+ const u8 *dik_data, *pmk, *pmkid;
+ size_t dik_len, pmk_len;
+ u8 iface_addr[ETH_ALEN];
+ struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s;
+
+ if (!wpa_s->p2p2)
+ return;
+
+ ret = p2p_get_dev_identity_key(p2p_wpa_s->global->p2p, go_dev_addr,
+ &dik_data, &dik_len, &cipher);
+ if (ret)
+ return;
+
+ ret = p2p_get_interface_addr(p2p_wpa_s->global->p2p, go_dev_addr,
+ iface_addr);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Fetch PMK for GO BSSID " MACSTR,
+ MAC2STR(bssid));
+ os_memcpy(iface_addr, bssid, ETH_ALEN);
+ }
+ ret = wpa_sm_pmksa_get_pmk(wpa_s->wpa, iface_addr, &pmk, &pmk_len,
+ &pmkid);
+ if (ret)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "P2P: Storing Device identity of GO (Interface Addr " MACSTR
+ ")",
+ MAC2STR(iface_addr));
+ wpas_p2p_store_identity(p2p_wpa_s, cipher, dik_data, dik_len, pmk,
+ pmk_len, pmkid);
+}
+
+
static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
int success, int already_deleted)
{
@@ -1690,8 +1798,11 @@
if (listen_freq != (int) freq && send_freq != (int) freq) {
int res;
- wpa_printf(MSG_DEBUG, "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d freq=%u)",
- listen_freq, send_freq, freq);
+ wpa_printf(MSG_DEBUG,
+ "P2P: Schedule new radio work for Action frame TX (listen_freq=%d send_freq=%d freq=%u dst="
+ MACSTR " src=" MACSTR " bssid=" MACSTR,
+ listen_freq, send_freq, freq, MAC2STR(dst),
+ MAC2STR(src), MAC2STR(bssid));
res = wpas_send_action_work(wpa_s, freq, dst, src, bssid, buf,
len, wait_time);
if (res == 0 && scheduled)
@@ -1722,6 +1833,125 @@
}
+#ifdef CONFIG_PASN
+
+struct wpa_p2p_pasn_auth_work {
+ u8 peer_addr[ETH_ALEN];
+ int freq;
+ bool verify;
+ int force_freq;
+ int pref_freq;
+ enum p2p_invite_role role;
+ u8 *ssid;
+ size_t ssid_len;
+ u8 bssid[ETH_ALEN];
+ u8 go_dev_addr[ETH_ALEN];
+};
+
+
+static void wpas_p2p_pasn_free_auth_work(struct wpa_p2p_pasn_auth_work *awork)
+{
+ if (!awork)
+ return;
+ os_free(awork->ssid);
+ os_free(awork);
+}
+
+
+static void wpas_p2p_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "P2P PASN: Cancel p2p-pasn-start-auth work");
+
+ /* Remove pending/started work */
+ radio_remove_works(wpa_s, "p2p-pasn-start-auth", 0);
+}
+
+
+static void wpas_p2p_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
+{
+ int ret;
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_p2p_pasn_auth_work *awork = work->ctx;
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ const u8 *peer_addr = NULL;
+ const u8 *bssid = NULL;
+ const u8 *go_dev_addr = NULL;
+
+ if (deinit) {
+ if (!work->started) {
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->p2pdev, NULL);
+ }
+ wpas_p2p_pasn_free_auth_work(awork);
+ return;
+ }
+
+ if (!is_zero_ether_addr(awork->peer_addr))
+ peer_addr = awork->peer_addr;
+ if (!is_zero_ether_addr(awork->bssid))
+ bssid = awork->bssid;
+ if (!is_zero_ether_addr(awork->go_dev_addr))
+ go_dev_addr = awork->go_dev_addr;
+
+
+ if (awork->verify)
+ ret = p2p_initiate_pasn_verify(p2p, peer_addr, awork->freq,
+ awork->role, bssid, awork->ssid,
+ awork->ssid_len,
+ awork->force_freq, go_dev_addr,
+ awork->pref_freq);
+ else
+ ret = p2p_initiate_pasn_auth(p2p, peer_addr, awork->freq);
+
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "P2P PASN: Failed to start PASN authentication");
+ goto fail;
+ }
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->p2pdev, NULL);
+ eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->p2pdev, NULL);
+ wpa_s->p2p_pasn_auth_work = work;
+ return;
+
+fail:
+ wpas_p2p_pasn_free_auth_work(awork);
+ work->ctx = NULL;
+ radio_work_done(work);
+}
+
+
+static int wpas_p2p_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int freq)
+{
+ struct wpa_p2p_pasn_auth_work *awork;
+
+ wpas_p2p_pasn_cancel_auth_work(wpa_s);
+ wpa_s->p2p_pasn_auth_work = NULL;
+
+ awork = os_zalloc(sizeof(*awork));
+ if (!awork)
+ return -1;
+
+ awork->freq = freq;
+ os_memcpy(awork->peer_addr, peer_addr, ETH_ALEN);
+
+ if (radio_add_work(wpa_s, freq, "p2p-pasn-start-auth", 1,
+ wpas_p2p_pasn_auth_start_cb, awork) < 0) {
+ wpas_p2p_pasn_free_auth_work(awork);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "P2P PASN: Authentication work successfully added");
+ return 0;
+}
+
+#endif /* CONFIG_PASN */
+
+
static int wpas_copy_go_neg_results(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params)
{
@@ -1735,6 +1965,101 @@
}
+static void wpas_start_gc(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *res)
+{
+ struct os_reltime now;
+ struct wpa_ssid *ssid;
+ struct rsn_pmksa_cache_entry *entry;
+
+ if (!res->ssid_len) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: SSID info not present");
+ return;
+ }
+
+ wpa_s->group_formation_reported = 0;
+ wpa_printf(MSG_DEBUG, "P2P: Start connect for peer " MACSTR
+ " dev_addr " MACSTR,
+ MAC2STR(res->peer_interface_addr),
+ MAC2STR(res->peer_device_addr));
+ wpa_hexdump_ascii(MSG_DEBUG, "P2P: Start connect for SSID",
+ res->ssid, res->ssid_len);
+ wpa_supplicant_ap_deinit(wpa_s);
+ wpas_copy_go_neg_results(wpa_s, res);
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (!ssid) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Could not add network for client");
+ return;
+ }
+ os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
+ wpa_config_set_network_defaults(ssid);
+ ssid->temporary = 1;
+ ssid->p2p_group = 1;
+
+ ssid->ssid = os_memdup(res->ssid, res->ssid_len);
+ if (!ssid->ssid)
+ return;
+ ssid->ssid_len = res->ssid_len;
+
+ os_memcpy(ssid->bssid, res->peer_interface_addr, ETH_ALEN);
+
+ if (res->akmp == WPA_KEY_MGMT_PASN && res->sae_password[0]) {
+ ssid->auth_alg = WPA_AUTH_ALG_SAE;
+ ssid->sae_password = os_strdup(res->sae_password);
+ if (!ssid->sae_password)
+ return;
+ } else if (res->akmp == WPA_KEY_MGMT_SAE && res->pmk_len) {
+ ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+ entry = os_zalloc(sizeof(*entry));
+ if (!entry)
+ return;
+ os_memcpy(entry->aa, res->peer_interface_addr, ETH_ALEN);
+ os_memcpy(entry->pmkid, res->pmkid, PMKID_LEN);
+ entry->pmk_len = res->pmk_len;
+ os_memcpy(entry->pmk, res->pmk, res->pmk_len);
+ entry->akmp = res->akmp;
+ os_get_reltime(&now);
+ entry->expiration = now.sec + 43200;
+ entry->reauth_time = now.sec + 43200 * 70 / 100;
+ entry->network_ctx = ssid;
+ os_memcpy(entry->spa, wpa_s->own_addr, ETH_ALEN);
+
+ wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
+ ssid->pmk_valid = true;
+ } else if (res->akmp == WPA_KEY_MGMT_SAE && res->sae_password[0]) {
+ ssid->auth_alg = WPA_AUTH_ALG_SAE;
+ ssid->sae_password = os_strdup(res->sae_password);
+ if (!ssid->sae_password)
+ return;
+ }
+
+ if (res->psk_set) {
+ os_memcpy(ssid->psk, res->psk, 32);
+ ssid->psk_set = 1;
+ }
+ ssid->proto = WPA_PROTO_RSN;
+ ssid->key_mgmt = WPA_KEY_MGMT_SAE;
+ ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+ ssid->group_cipher = WPA_CIPHER_CCMP;
+ if (res->cipher)
+ ssid->pairwise_cipher |= res->cipher;
+ ssid->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+ ssid->disabled = 0;
+ wpa_s->show_group_started = 1;
+ wpa_s->p2p_in_invitation = 1;
+ wpa_s->p2p_go_group_formation_completed = 0;
+ wpa_s->global->p2p_group_formation = wpa_s;
+ ssid->rsn_overriding = RSN_OVERRIDING_ENABLED;
+
+ wpa_s->current_ssid = ssid;
+ wpa_supplicant_update_scan_results(wpa_s, res->peer_interface_addr);
+ wpa_supplicant_select_network(wpa_s, ssid);
+}
+
+
static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *res)
{
@@ -1879,6 +2204,19 @@
return;
}
+ if (wpa_s->ap_iface && params->p2p2 &&
+ params->akmp == WPA_KEY_MGMT_SAE) {
+ struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth,
+ params->peer_device_addr,
+ params->pmk, params->pmk_len,
+ params->pmkid, WPA_KEY_MGMT_SAE);
+ hostapd_add_pmkid(hapd, params->peer_device_addr,
+ params->pmk, params->pmk_len,
+ params->pmkid, WPA_KEY_MGMT_SAE);
+ }
+
p2p_go_save_group_common_freqs(wpa_s, params);
p2p_go_dump_common_freqs(wpa_s);
@@ -1944,13 +2282,21 @@
return;
}
- wpa_printf(MSG_DEBUG, "P2P: Setting up WPS for GO provisioning");
if (wpa_supplicant_ap_mac_addr_filter(wpa_s,
params->peer_interface_addr)) {
wpa_printf(MSG_DEBUG, "P2P: Failed to setup MAC address "
"filtering");
return;
}
+
+ if (params->p2p2) {
+ wpas_group_formation_completed(wpa_s, 1, 0);
+ wpa_printf(MSG_DEBUG,
+ "P2P2: Group formation completed - first connection in progress");
+ goto out;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: Setting up WPS for GO provisioning");
if (params->wps_method == WPS_PBC) {
wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
params->peer_device_addr);
@@ -1971,6 +2317,7 @@
} else if (wpa_s->p2p_pin[0])
wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
wpa_s->p2p_pin, NULL, 0, 0);
+out:
os_free(wpa_s->go_params);
wpa_s->go_params = NULL;
}
@@ -2053,9 +2400,9 @@
}
-static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
- struct p2p_go_neg_results *params,
- int group_formation)
+static void wpas_start_go(struct wpa_supplicant *wpa_s,
+ struct p2p_go_neg_results *params,
+ int group_formation, enum wpa_p2p_mode p2p_mode)
{
struct wpa_ssid *ssid;
@@ -2150,6 +2497,24 @@
wpa_config_update_psk(ssid);
ssid->ap_max_inactivity = wpa_s->p2pdev->conf->p2p_go_max_inactivity;
+ ssid->p2p_mode = p2p_mode;
+ if (params->p2p2) {
+ if (params->akmp == WPA_KEY_MGMT_SAE)
+ ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+ else
+ ssid->auth_alg |= WPA_AUTH_ALG_SAE;
+
+ ssid->key_mgmt = WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_PASN;
+ ssid->sae_password = os_strdup(params->sae_password);
+ /* In PCC, RSNE indicates PMF to be disabled while RSNOE/RSNO2E
+ * requires PMF for SAE. */
+ if (ssid->p2p_mode != WPA_P2P_MODE_WFD_PCC)
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+ ssid->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
+ if (params->cipher)
+ ssid->pairwise_cipher |= params->cipher;
+ }
+
wpa_s->ap_configured_cb = p2p_go_configured;
wpa_s->ap_configured_cb_ctx = wpa_s;
wpa_s->ap_configured_cb_data = wpa_s->go_params;
@@ -2364,6 +2729,7 @@
wpa_s->global->pending_group_iface_for_p2ps = 0;
wpas_p2p_clone_config(group_wpa_s, wpa_s);
+ group_wpa_s->p2p2 = wpa_s->p2p2;
if (wpa_s->conf->p2p_interface_random_mac_addr) {
if (wpa_drv_set_mac_addr(group_wpa_s,
@@ -2396,6 +2762,14 @@
void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
+
+#ifdef CONFIG_PASN
+ if (wpa_s->p2p_pasn_auth_work) {
+ wpas_p2p_pasn_cancel_auth_work(wpa_s);
+ wpa_s->p2p_pasn_auth_work = NULL;
+ }
+#endif /* CONFIG_PASN */
+
wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out");
wpas_p2p_group_formation_failed(wpa_s, 0);
}
@@ -2450,6 +2824,49 @@
}
+static void wpas_set_go_security_config(void *ctx,
+ struct p2p_go_neg_results *params)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_supplicant *tmp, *ifs = NULL;
+ struct hostapd_data *hapd;
+
+ if (!params->p2p2)
+ return;
+
+ dl_list_for_each(tmp, &wpa_s->radio->ifaces, struct wpa_supplicant,
+ radio_list) {
+ struct wpa_ssid *ssid = tmp->current_ssid;
+
+ if (ssid && ssid->mode == WPAS_MODE_P2P_GO &&
+ ssid->ssid && ssid->ssid_len == params->ssid_len &&
+ os_memcmp(ssid->ssid, params->ssid, params->ssid_len) == 0)
+ {
+ ifs = tmp;
+ break;
+ }
+ }
+
+ if (!ifs || !ifs->ap_iface)
+ return;
+
+ hapd = ifs->ap_iface->bss[0];
+ hapd->conf->wps_state = 0;
+
+ if (params->akmp == WPA_KEY_MGMT_SAE) {
+ wpa_printf(MSG_DEBUG, "P2P: Adding PMK for peer: " MACSTR,
+ MAC2STR(params->peer_device_addr));
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth,
+ params->peer_device_addr,
+ params->pmk, params->pmk_len,
+ params->pmkid, WPA_KEY_MGMT_SAE);
+ hostapd_add_pmkid(hapd, params->peer_device_addr,
+ params->pmk, params->pmk_len,
+ params->pmkid, WPA_KEY_MGMT_SAE);
+ }
+}
+
+
static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -2461,6 +2878,13 @@
wpa_s->roc_waiting_drv_freq = 0;
}
+#ifdef CONFIG_PASN
+ if (wpa_s->p2p_pasn_auth_work) {
+ wpas_p2p_pasn_cancel_auth_work(wpa_s);
+ wpa_s->p2p_pasn_auth_work = NULL;
+ }
+#endif /* CONFIG_PASN */
+
if (res->status) {
wpa_msg_global(wpa_s, MSG_INFO,
P2P_EVENT_GO_NEG_FAILURE "status=%d",
@@ -2534,12 +2958,18 @@
os_memcpy(group_wpa_s->p2p_pin, wpa_s->p2p_pin,
sizeof(group_wpa_s->p2p_pin));
group_wpa_s->p2p_wps_method = wpa_s->p2p_wps_method;
+ group_wpa_s->p2p2 = res->p2p2;
+ group_wpa_s->p2p_bootstrap = wpa_s->p2p_bootstrap;
}
+
if (res->role_go) {
- wpas_start_wps_go(group_wpa_s, res, 1);
+ wpas_start_go(group_wpa_s, res, 1, group_wpa_s->p2p_mode);
} else {
os_get_reltime(&group_wpa_s->scan_min_time);
- wpas_start_wps_enrollee(group_wpa_s, res);
+ if (res->p2p2)
+ wpas_start_gc(group_wpa_s, res);
+ else
+ wpas_start_wps_enrollee(group_wpa_s, res);
}
wpa_s->global->p2p_long_listen = 0;
@@ -2646,8 +3076,7 @@
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
" p2p_dev_addr=" MACSTR
- " pri_dev_type=%s name='%s' config_methods=0x%x "
- "dev_capab=0x%x group_capab=0x%x%s%s%s%s%s new=%d",
+ " pri_dev_type=%s name='%s' config_methods=0x%x dev_capab=0x%x group_capab=0x%x%s%s%s%s%s new=%d pcea_cap_info=0x%x bootstrap_methods=0x%x pasn_type=0x%x",
MAC2STR(addr), MAC2STR(info->p2p_device_addr),
wps_dev_type_bin2str(info->pri_dev_type, devtype,
sizeof(devtype)),
@@ -2658,7 +3087,9 @@
wfd_r2_dev_info_hex ? " wfd_r2_dev_info=0x" : "",
wfd_r2_dev_info_hex ? wfd_r2_dev_info_hex : "",
info->vendor_elems ? " vendor_elems=1" : "",
- new_device);
+ new_device, info->pcea_cap_info,
+ info->pairing_config.bootstrap_methods,
+ info->pairing_config.pasn_type);
done:
os_free(wfd_dev_info_hex);
@@ -2831,10 +3262,13 @@
wpas_p2p_listen_work_done(wpa_s);
- if (radio_work_pending(wpa_s, "p2p-listen")) {
+ if (!wpa_s->p2p_removing_listen_work &&
+ radio_work_pending(wpa_s, "p2p-listen")) {
+ wpa_s->p2p_removing_listen_work = true;
wpa_printf(MSG_DEBUG,
"P2P: p2p-listen is still pending - remove it");
radio_remove_works(wpa_s, "p2p-listen", 0);
+ wpa_s->p2p_removing_listen_work = false;
}
}
@@ -3217,7 +3651,7 @@
size_t ssid_len, int *go, u8 *group_bssid,
int *force_freq, int persistent_group,
const struct p2p_channels *channels,
- int dev_pw_id)
+ int dev_pw_id, bool p2p2)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
@@ -3281,7 +3715,7 @@
for (s = wpa_s->conf->ssid; s; s = s->next) {
if (s->disabled == 2 &&
- ether_addr_equal(s->bssid, go_dev_addr) &&
+ (p2p2 || ether_addr_equal(s->bssid, go_dev_addr)) &&
s->ssid_len == ssid_len &&
os_memcmp(ssid, s->ssid, ssid_len) == 0)
break;
@@ -3376,7 +3810,8 @@
static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
const u8 *ssid, size_t ssid_len,
const u8 *go_dev_addr, u8 status,
- int op_freq)
+ int op_freq, const u8 *pmkid,
+ const u8 *pmk, size_t pmk_len)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *s;
@@ -3416,7 +3851,7 @@
wpa_s->conf->p2p_go_edmg, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0,
1, is_p2p_allow_6ghz(wpa_s->global->p2p), 0,
- NULL);
+ bssid, sa, pmkid, pmk, pmk_len);
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
wpa_msg_global(wpa_s, MSG_INFO,
@@ -3534,12 +3969,20 @@
static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
const struct p2p_channels *channels,
const u8 *peer, int neg_freq,
- int peer_oper_freq)
+ int peer_oper_freq, const u8 *pmkid,
+ const u8 *pmk, size_t pmk_len)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid;
int freq;
+#ifdef CONFIG_PASN
+ if (wpa_s->p2p_pasn_auth_work) {
+ wpas_p2p_pasn_cancel_auth_work(wpa_s);
+ wpa_s->p2p_pasn_auth_work = NULL;
+ }
+#endif /* CONFIG_PASN */
+
if (bssid) {
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_INVITATION_RESULT
"status=%d " MACSTR,
@@ -3647,7 +4090,7 @@
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
0, 1,
is_p2p_allow_6ghz(wpa_s->global->p2p), 0,
- NULL);
+ bssid, peer, pmkid, pmk, pmk_len);
}
@@ -4716,10 +5159,13 @@
persistent_go->mode ==
WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
- 0, 0, false, 0, NULL);
+ 0, 0, false, 0, NULL, NULL, NULL, NULL,
+ 0);
} else if (response_done) {
wpas_p2p_group_add(wpa_s, 1, freq,
- 0, 0, 0, 0, 0, 0, false);
+ 0, 0, 0, 0, 0, 0, false,
+ wpa_s->p2p2,
+ WPA_P2P_MODE_WFD_R1);
}
if (passwd_id == DEV_PW_P2PS_DEFAULT) {
@@ -4839,10 +5285,12 @@
NULL,
persistent_go->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0,
- is_p2p_allow_6ghz(wpa_s->global->p2p), 0, NULL);
+ is_p2p_allow_6ghz(wpa_s->global->p2p), 0, NULL, NULL,
+ NULL, NULL, 0);
} else {
wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0,
- is_p2p_allow_6ghz(wpa_s->global->p2p));
+ is_p2p_allow_6ghz(wpa_s->global->p2p),
+ wpa_s->p2p2, WPA_P2P_MODE_WFD_R1);
}
return 1;
@@ -4877,7 +5325,7 @@
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);
+ wpa_s->p2p2, wpa_s->p2p_bootstrap, NULL, false);
}
@@ -4903,6 +5351,8 @@
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_BOOTSTRAP_REQUEST MACSTR
" bootstrap_method=%u", MAC2STR(addr), bootstrap_method);
+
+ wpas_notify_p2p_bootstrap_req(wpa_s, addr, bootstrap_method);
}
@@ -4911,18 +5361,175 @@
{
struct wpa_supplicant *wpa_s = ctx;
+ wpas_notify_p2p_bootstrap_completed(wpa_s, addr, status);
+
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);
+ return;
}
+
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_BOOTSTRAP_SUCCESS MACSTR " status=%d",
+ MAC2STR(addr), status);
+
+#ifdef CONFIG_PASN
+ wpas_p2p_initiate_pasn_auth(wpa_s, addr, freq);
+#endif /* CONFIG_PASN */
}
+static void wpas_validate_dira(void *ctx, const u8 *peer_addr,
+ const u8 *dira, size_t dira_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ int ret;
+ u8 tag[DEVICE_MAX_HASH_LEN];
+ struct wpa_dev_ik *ik;
+ const u8 *addr[3];
+ size_t len[3];
+ const char *label = "DIR";
+
+ if (dira_len < 1 || dira[0] != DIRA_CIPHER_VERSION_128) {
+ wpa_printf(MSG_ERROR,
+ "P2P2: Unsupported DIRA cipher version %d", dira[0]);
+ return;
+ }
+
+ if (dira_len < 1 + DEVICE_IDENTITY_NONCE_LEN + DEVICE_IDENTITY_TAG_LEN)
+ {
+ wpa_printf(MSG_INFO, "P2P2: Truncated DIRA (length %zu)",
+ dira_len);
+ return;
+ }
+
+ addr[0] = (const u8 *) label;
+ len[0] = DIR_STR_LEN;
+ addr[1] = peer_addr;
+ len[1] = ETH_ALEN;
+ addr[2] = &dira[1];
+ len[2] = DEVICE_IDENTITY_NONCE_LEN;
+
+ for (ik = wpa_s->conf->identity; ik; ik = ik->next) {
+ if (wpabuf_len(ik->dik) != DEVICE_IDENTITY_KEY_LEN ||
+ ik->dik_cipher != DIRA_CIPHER_VERSION_128)
+ continue;
+
+ ret = hmac_sha256_vector(wpabuf_head(ik->dik),
+ DEVICE_IDENTITY_KEY_LEN,
+ 3, addr, len, tag);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "P2P2: Failed to derive DIRA Tag");
+ return;
+ }
+
+ if (os_memcmp(tag, &dira[1 + DEVICE_IDENTITY_NONCE_LEN],
+ DEVICE_IDENTITY_TAG_LEN) == 0) {
+ wpa_printf(MSG_DEBUG, "P2P2: DIRA Tag matched");
+ break;
+ }
+ }
+
+ if (!ik)
+ return;
+
+#ifdef CONFIG_PASN
+ p2p_pasn_pmksa_set_pmk(wpa_s->global->p2p, wpa_s->global->p2p_dev_addr,
+ peer_addr,
+ wpabuf_head(ik->pmk), wpabuf_len(ik->pmk),
+ wpabuf_head(ik->pmkid));
+#endif /* CONFIG_PASN */
+}
+
+
+#ifdef CONFIG_PASN
+
+static int wpas_p2p_initiate_pasn_verify(struct wpa_supplicant *wpa_s,
+ const u8 *peer,
+ enum p2p_invite_role role,
+ const u8 *bssid, const u8 *ssid,
+ size_t ssid_len,
+ unsigned int force_freq,
+ const u8 *go_dev_addr,
+ unsigned int pref_freq)
+{
+ int freq;
+ struct wpa_p2p_pasn_auth_work *awork;
+
+ wpas_p2p_pasn_cancel_auth_work(wpa_s);
+ wpa_s->p2p_pasn_auth_work = NULL;
+
+ freq = p2p_get_listen_freq(wpa_s->global->p2p, peer);
+ if (freq == -1)
+ return -1;
+
+ awork = os_zalloc(sizeof(*awork));
+ if (!awork)
+ return -1;
+
+ awork->verify = 1;
+ awork->role = role;
+ awork->freq = freq;
+ awork->force_freq = force_freq;
+ awork->pref_freq = pref_freq;
+ os_memcpy(awork->peer_addr, peer, ETH_ALEN);
+ if (go_dev_addr)
+ os_memcpy(awork->go_dev_addr, go_dev_addr, ETH_ALEN);
+ if (bssid)
+ os_memcpy(awork->bssid, bssid, ETH_ALEN);
+ if (ssid_len) {
+ awork->ssid = os_zalloc(ssid_len);
+ if (!awork->ssid) {
+ os_free(awork);
+ return -1;
+ }
+ os_memcpy(awork->ssid, ssid, ssid_len);
+ awork->ssid_len = ssid_len;
+ }
+
+ if (radio_add_work(wpa_s, freq, "p2p-pasn-start-auth", 1,
+ wpas_p2p_pasn_auth_start_cb, awork) < 0) {
+ wpas_p2p_pasn_free_auth_work(awork);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P PASN: Auth work successfully added");
+ return 0;
+}
+
+
+static int wpas_p2p_pasn_send_mgmt(void *ctx, const u8 *data, size_t data_len,
+ int noack, unsigned int freq,
+ unsigned int wait)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait);
+}
+
+
+static int wpas_p2p_prepare_data_element(void *ctx, const u8 *peer_addr)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ return p2p_prepare_data_element(p2p, peer_addr);
+}
+
+
+static int wpas_p2p_parse_data_element(void *ctx, const u8 *data, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ return p2p_parse_data_element(p2p, data, len);
+}
+
+#endif /* CONFIG_PASN */
+
+
int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s)
{
int ret = 0;
@@ -5018,6 +5625,7 @@
p2p.send_action = wpas_send_action;
p2p.send_action_done = wpas_send_action_done;
p2p.go_neg_completed = wpas_go_neg_completed;
+ p2p.set_go_security_config = wpas_set_go_security_config;
p2p.go_neg_req_rx = wpas_go_neg_req_rx;
p2p.dev_found = wpas_dev_found;
p2p.dev_lost = wpas_dev_lost;
@@ -5050,6 +5658,12 @@
p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback;
p2p.bootstrap_req_rx = wpas_bootstrap_req_rx;
p2p.bootstrap_completed = wpas_bootstrap_completed;
+ p2p.validate_dira = wpas_validate_dira;
+#ifdef CONFIG_PASN
+ p2p.pasn_send_mgmt = wpas_p2p_pasn_send_mgmt;
+ p2p.prepare_data_element = wpas_p2p_prepare_data_element;
+ p2p.parse_data_element = wpas_p2p_parse_data_element;
+#endif /* CONFIG_PASN */
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);
@@ -5193,6 +5807,18 @@
"P2P: Failed to update configuration");
}
+ p2p.pairing_config.enable_pairing_setup =
+ wpa_s->conf->p2p_pairing_setup;
+ p2p.pairing_config.enable_pairing_cache =
+ wpa_s->conf->p2p_pairing_cache;
+ p2p.pairing_config.bootstrap_methods =
+ wpa_s->conf->p2p_bootstrap_methods;
+ p2p.pairing_config.pasn_type = wpa_s->conf->p2p_pasn_type;
+ p2p.comeback_after = wpa_s->conf->p2p_comeback_after;
+ p2p.reg_info = wpa_s->conf->p2p_reg_info;
+ p2p.twt_power_mgmt = wpa_s->conf->p2p_twt_power_mgmt;
+ p2p.chan_switch_req_enable = wpa_s->conf->p2p_chan_switch_req_enable;
+
global->p2p = p2p_init(&p2p);
if (global->p2p == NULL)
return -1;
@@ -5325,6 +5951,20 @@
}
+#ifdef CONFIG_PASN
+static int wpas_p2p_config_sae_password(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ if (wpa_s->global->p2p_disabled || !p2p || !ssid->sae_password)
+ return -2;
+
+ return p2p_config_sae_password(p2p, ssid->sae_password);
+}
+#endif /* CONFIG_PASN */
+
+
static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s,
const u8 *peer_addr,
enum p2p_wps_method wps_method,
@@ -5489,7 +6129,7 @@
if (scan_res)
wpas_p2p_scan_res_handler(wpa_s, scan_res);
- if (wpa_s->p2p_auto_pd) {
+ if (!wpa_s->p2p2 && wpa_s->p2p_auto_pd) {
int join = wpas_p2p_peer_go(wpa_s,
wpa_s->pending_join_dev_addr);
if (join == 0 &&
@@ -5530,15 +6170,22 @@
return;
}
- if (wpa_s->p2p_auto_join) {
+ if (wpa_s->p2p2 || wpa_s->p2p_auto_join) {
int join = wpas_p2p_peer_go(wpa_s,
wpa_s->pending_join_dev_addr);
- if (join < 0) {
- wpa_printf(MSG_DEBUG, "P2P: Peer was not found to be "
- "running a GO -> use GO Negotiation");
- wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
- P2P_EVENT_FALLBACK_TO_GO_NEG
- "reason=peer-not-running-GO");
+
+ if (wpa_s->p2p2 || join < 0) {
+ if (join < 0) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Peer was not found to be running a GO -> use GO Negotiation");
+ wpa_msg_global(wpa_s->p2pdev, MSG_INFO,
+ P2P_EVENT_FALLBACK_TO_GO_NEG
+ "reason=peer-not-running-GO");
+ }
+
+ if (wpa_s->p2p2)
+ wpa_printf(MSG_DEBUG,
+ "P2P2: Initiate GO negotiation and provisioning using PASN Authentication");
wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr,
wpa_s->p2p_pin, wpa_s->p2p_wps_method,
wpa_s->p2p_persistent_group, 0, 0, 0,
@@ -5555,7 +6202,9 @@
NULL, 0,
is_p2p_allow_6ghz(wpa_s->global->p2p),
wpa_s->p2p2, wpa_s->p2p_bootstrap,
- NULL);
+ wpa_s->pending_join_password[0] ?
+ wpa_s->pending_join_password : NULL,
+ false);
return;
}
@@ -5709,7 +6358,7 @@
{
int ret;
struct wpa_driver_scan_params params;
- struct wpabuf *wps_ie, *ies;
+ struct wpabuf *wps_ie = NULL, *ies;
size_t ielen;
int freqs[2] = { 0, 0 };
unsigned int bands;
@@ -5729,13 +6378,16 @@
wpa_s->p2p_join_ssid_len = 0;
}
- wpa_s->wps->dev.p2p = 1;
- wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT, &wpa_s->wps->dev,
- wpa_s->wps->uuid, WPS_REQ_ENROLLEE, 0,
- NULL);
- if (wps_ie == NULL) {
- wpas_p2p_scan_res_join(wpa_s, NULL);
- return;
+ if (!wpa_s->p2p2) {
+ wpa_s->wps->dev.p2p = 1;
+ wps_ie = wps_build_probe_req_ie(DEV_PW_DEFAULT,
+ &wpa_s->wps->dev,
+ wpa_s->wps->uuid,
+ WPS_REQ_ENROLLEE, 0, NULL);
+ if (!wps_ie) {
+ wpas_p2p_scan_res_join(wpa_s, NULL);
+ return;
+ }
}
if (!freq) {
@@ -5757,14 +6409,21 @@
}
ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
- ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
- if (ies == NULL) {
+
+ if (wps_ie)
+ ielen += wpabuf_len(wps_ie);
+
+ ies = wpabuf_alloc(ielen);
+ if (!ies) {
wpabuf_free(wps_ie);
wpas_p2p_scan_res_join(wpa_s, NULL);
return;
}
- wpabuf_put_buf(ies, wps_ie);
- wpabuf_free(wps_ie);
+
+ if (wps_ie) {
+ wpabuf_put_buf(ies, wps_ie);
+ wpabuf_free(wps_ie);
+ }
bands = wpas_get_bands(wpa_s, freqs);
p2p_scan_ie(wpa_s->global->p2p, ies, NULL, bands);
@@ -5847,6 +6506,7 @@
struct wpa_supplicant *group;
struct p2p_go_neg_results res;
struct wpa_bss *bss;
+ const u8 *iface_addr = NULL;
group = wpas_p2p_get_group_iface(wpa_s, 0, 0);
if (group == NULL)
@@ -5874,15 +6534,27 @@
os_memcpy(res.peer_device_addr, wpa_s->pending_join_dev_addr, ETH_ALEN);
os_memcpy(res.peer_interface_addr, wpa_s->pending_join_iface_addr,
ETH_ALEN);
+ if (!is_zero_ether_addr(wpa_s->pending_join_iface_addr))
+ iface_addr = wpa_s->pending_join_iface_addr;
+
+ if (wpa_s->pending_join_password[0]) {
+ res.akmp = WPA_KEY_MGMT_SAE;
+ os_strlcpy(res.sae_password, wpa_s->pending_join_password,
+ sizeof(res.sae_password));
+ os_memset(wpa_s->pending_join_password, 0,
+ sizeof(wpa_s->pending_join_password));
+ }
res.wps_method = wpa_s->pending_join_wps_method;
+ res.p2p2 = wpa_s->p2p2;
+ res.cipher = WPA_CIPHER_CCMP;
+
if (freq && ssid && ssid_len) {
res.freq = freq;
res.ssid_len = ssid_len;
os_memcpy(res.ssid, ssid, ssid_len);
} else {
if (ssid && ssid_len) {
- bss = wpa_bss_get(wpa_s, wpa_s->pending_join_iface_addr,
- ssid, ssid_len);
+ bss = wpa_bss_get(wpa_s, iface_addr, ssid, ssid_len);
} else {
bss = wpa_bss_get_bssid_latest(
wpa_s, wpa_s->pending_join_iface_addr);
@@ -5891,6 +6563,8 @@
res.freq = bss->freq;
res.ssid_len = bss->ssid_len;
os_memcpy(res.ssid, bss->ssid, bss->ssid_len);
+ os_memcpy(res.peer_interface_addr, bss->bssid,
+ ETH_ALEN);
wpa_printf(MSG_DEBUG, "P2P: Join target GO operating frequency from BSS table: %d MHz (SSID %s)",
bss->freq,
wpa_ssid_txt(bss->ssid, bss->ssid_len));
@@ -5909,7 +6583,10 @@
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = 0;
}
- wpas_start_wps_enrollee(group, &res);
+ if (res.p2p2)
+ wpas_start_gc(group, &res);
+ else
+ wpas_start_wps_enrollee(group, &res);
/*
* Allow a longer timeout for join-a-running-group than normal 15
@@ -6127,8 +6804,9 @@
* @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
+ * @password: Password for pairing setup or NULL for opportunistic method
* in P2P2
+ * @skip_prov: Connect without provisioning
* 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
@@ -6141,7 +6819,7 @@
unsigned int vht_chwidth, int he, int edmg,
const u8 *group_ssid, size_t group_ssid_len,
bool allow_6ghz, bool p2p2, u16 bootstrap,
- const char *password)
+ const char *password, bool skip_prov)
{
int force_freq = 0, pref_freq = 0;
int ret = 0, res;
@@ -6162,6 +6840,7 @@
}
wpa_s->p2p2 = p2p2;
+ wpa_s->p2p_mode = p2p2 ? WPA_P2P_MODE_WFD_R2 : WPA_P2P_MODE_WFD_R1;
if (wpas_p2p_check_6ghz(wpa_s, peer_addr, allow_6ghz, freq))
return -2;
@@ -6169,6 +6848,7 @@
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
+ p2p_set_go_role(wpa_s->global->p2p, false);
wpa_s->global->p2p_fail_on_wps_complete = 0;
wpa_s->global->pending_p2ps_group = 0;
wpa_s->global->pending_p2ps_group_freq = 0;
@@ -6212,14 +6892,64 @@
} else
wpa_s->p2p_pin[0] = '\0';
+ if (!password)
+ os_memset(wpa_s->pending_join_password, 0,
+ sizeof(wpa_s->pending_join_password));
+
if (join || auto_join) {
u8 iface_addr[ETH_ALEN], dev_addr[ETH_ALEN];
if (auth) {
+#ifdef CONFIG_PASN
+ struct wpa_supplicant *ifs;
+#endif /* CONFIG_PASN */
+
wpa_printf(MSG_DEBUG, "P2P: Authorize invitation to "
"connect a running group from " MACSTR,
MAC2STR(peer_addr));
os_memcpy(wpa_s->p2p_auth_invite, peer_addr, ETH_ALEN);
+
+#ifdef CONFIG_PASN
+ if (!wpa_s->p2p2)
+ return ret;
+
+ wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
+ if (wpa_s->create_p2p_iface) {
+ if_addr = wpa_s->pending_interface_addr;
+ } else {
+ if (wpa_s->p2p_mgmt)
+ if_addr = wpa_s->parent->own_addr;
+ else
+ if_addr = wpa_s->own_addr;
+ os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
+ }
+
+ dl_list_for_each(ifs, &wpa_s->radio->ifaces,
+ struct wpa_supplicant, radio_list) {
+ if (!ifs->current_ssid ||
+ ifs->current_ssid->mode != WPAS_MODE_P2P_GO)
+ continue;
+
+ ssid = ifs->current_ssid;
+
+ if (bootstrap == P2P_PBMA_OPPORTUNISTIC &&
+ wpas_p2p_config_sae_password(wpa_s, ssid)) {
+ ssid = NULL;
+ continue;
+ }
+
+ force_freq = ifs->ap_iface->freq;
+ break;
+ }
+ p2p_set_go_role(wpa_s->global->p2p, true);
+ return wpas_p2p_auth_go_neg(wpa_s, peer_addr,
+ wps_method, 15, if_addr,
+ force_freq,
+ persistent_group, ssid,
+ pref_freq, bootstrap,
+ password);
+#else /* CONFIG_PASN */
return ret;
+#endif /* CONFIG_PASN */
}
os_memcpy(dev_addr, peer_addr, ETH_ALEN);
if (p2p_get_interface_addr(wpa_s->global->p2p, peer_addr,
@@ -6236,6 +6966,20 @@
wpa_s->p2p_auto_started.usec);
}
wpa_s->user_initiated_pd = 1;
+ if (password)
+ os_strlcpy(wpa_s->pending_join_password, password,
+ sizeof(wpa_s->pending_join_password));
+
+ if (skip_prov) {
+ if (!wpa_s->p2p2) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Join without provisioning not supported");
+ return -1;
+ }
+ /* Start join operation immediately */
+ return wpas_p2p_join_start(wpa_s, 0, group_ssid,
+ group_ssid_len);
+ }
if (wpas_p2p_join(wpa_s, iface_addr, dev_addr, wps_method,
auto_join, freq,
group_ssid, group_ssid_len) < 0)
@@ -6592,6 +7336,10 @@
const struct p2p_channels *channels,
int freq)
{
+ if (is_6ghz_freq(freq) &&
+ !is_p2p_6ghz_capable(wpa_s->global->p2p))
+ return 0;
+
if (!wpas_p2p_disallowed_freq(wpa_s->global, freq) &&
p2p_supported_freq_go(wpa_s->global->p2p, freq) &&
freq_included(wpa_s, channels, freq))
@@ -6699,6 +7447,7 @@
params->max_oper_chwidth = max_oper_chwidth;
params->vht_center_freq2 = vht_center_freq2;
params->edmg = edmg;
+ params->p2p2 = wpa_s->p2p2;
freqs = os_calloc(wpa_s->num_multichan_concurrent,
sizeof(struct wpa_used_freq_data));
@@ -7087,6 +7836,7 @@
* @vht_chwidth: channel bandwidth for GO operating with VHT support
* @edmg: Start GO with EDMG support
* @allow_6ghz: Allow P2P group creation on a 6 GHz channel
+ * @p2p_mode: Operation mode for GO (R1/R2/PCC)
* Returns: 0 on success, -1 on failure
*
* This function creates a new P2P group with the local end as the Group Owner,
@@ -7095,7 +7845,7 @@
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
int max_oper_chwidth, int he, int edmg,
- bool allow_6ghz)
+ bool allow_6ghz, bool p2p2, enum wpa_p2p_mode p2p_mode)
{
struct p2p_go_neg_results params;
int selected_freq = 0;
@@ -7107,6 +7857,8 @@
os_free(wpa_s->global->add_psk);
wpa_s->global->add_psk = NULL;
+ wpa_s->p2p2 = p2p2;
+ wpa_s->p2p_mode = p2p_mode;
/* Make sure we are not running find during connection establishment */
wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
@@ -7132,7 +7884,8 @@
return -1;
if (freq > 0)
wpa_s->p2p_go_no_pri_sec_switch = 1;
- wpas_start_wps_go(wpa_s, ¶ms, 0);
+ params.p2p2 = wpa_s->p2p2;
+ wpas_start_go(wpa_s, ¶ms, 0, p2p_mode);
return 0;
}
@@ -7141,11 +7894,14 @@
static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
struct wpa_ssid *params, int addr_allocated,
int freq, int force_scan, int retry_limit,
- const u8 *go_bssid)
+ const u8 *go_bssid, bool p2p2, const u8 *pmkid,
+ const u8 *pmk, size_t pmk_len)
{
+ struct os_reltime now;
struct wpa_ssid *ssid;
int other_iface_found = 0;
struct wpa_supplicant *ifs;
+ struct rsn_pmksa_cache_entry *entry;
wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 0);
if (wpa_s == NULL)
@@ -7199,6 +7955,34 @@
os_memcpy(ssid->bssid, go_bssid, ETH_ALEN);
}
+ if (p2p2) {
+ ssid->key_mgmt = WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_PASN;
+ ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+ ssid->sae_pwe = SAE_PWE_HASH_TO_ELEMENT;
+ ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
+ ssid->disabled = 0;
+
+ if (pmk && pmk_len && pmkid) {
+ entry = os_zalloc(sizeof(*entry));
+ if (!entry)
+ return -1;
+ os_memcpy(entry->aa, ssid->bssid, ETH_ALEN);
+ os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+ entry->pmk_len = pmk_len;
+ os_memcpy(entry->pmk, pmk, pmk_len);
+ entry->akmp = WPA_KEY_MGMT_SAE;
+ os_get_reltime(&now);
+ entry->expiration = now.sec + 43200;
+ entry->reauth_time = now.sec + 43200 * 70 / 100;
+ entry->network_ctx = ssid;
+ os_memcpy(entry->spa, wpa_s->own_addr, ETH_ALEN);
+
+ wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
+ ssid->pmk_valid = true;
+ }
+ wpa_s->current_ssid = ssid;
+ }
+
wpa_s->show_group_started = 1;
wpa_s->p2p_in_invitation = 1;
wpa_s->p2p_retry_limit = retry_limit;
@@ -7246,7 +8030,9 @@
const struct p2p_channels *channels,
int connection_timeout, int force_scan,
bool allow_6ghz, int retry_limit,
- const u8 *go_bssid)
+ const u8 *go_bssid, const u8 *dev_addr,
+ const u8 *pmkid, const u8 *pmk,
+ size_t pmk_len)
{
struct p2p_go_neg_results params;
int go = 0, freq;
@@ -7315,7 +8101,8 @@
}
return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq,
- force_scan, retry_limit, go_bssid);
+ force_scan, retry_limit, go_bssid,
+ wpa_s->p2p2, pmkid, pmk, pmk_len);
} else {
return -1;
}
@@ -7342,6 +8129,15 @@
params.ssid_len = ssid->ssid_len;
params.persistent_group = 1;
+ if (wpa_s->p2p2 && pmk_len && pmk && pmkid) {
+ os_memcpy(params.peer_device_addr, dev_addr, ETH_ALEN);
+ os_memcpy(params.pmkid, pmkid, PMKID_LEN);
+ os_memcpy(params.pmk, pmk, pmk_len);
+ params.pmk_len = pmk_len;
+ params.akmp = WPA_KEY_MGMT_SAE;
+ params.p2p2 = true;
+ }
+
wpa_s = wpas_p2p_get_group_iface(wpa_s, addr_allocated, 1);
if (wpa_s == NULL)
return -1;
@@ -7349,7 +8145,8 @@
p2p_channels_to_freqs(channels, params.freq_list, P2P_MAX_CHANNELS);
wpa_s->p2p_first_connection_timeout = connection_timeout;
- wpas_start_wps_go(wpa_s, ¶ms, 0);
+ params.p2p2 = wpa_s->p2p2;
+ wpas_start_go(wpa_s, ¶ms, 0, wpa_s->p2p_mode);
return 0;
}
@@ -7372,6 +8169,12 @@
}
wpabuf_free(hapd->p2p_probe_resp_ie);
hapd->p2p_probe_resp_ie = proberesp_ies;
+
+ if (wpa_s->p2p2) {
+ hapd->iconf->peer_to_peer_twt = true;
+ hapd->iconf->channel_usage = true;
+ }
+
} else {
wpabuf_free(beacon_ies);
wpabuf_free(proberesp_ies);
@@ -7430,6 +8233,7 @@
cfg->idle_update = wpas_p2p_idle_update;
cfg->ip_addr_alloc = WPA_GET_BE32(wpa_s->p2pdev->conf->ip_addr_start)
!= 0;
+ cfg->p2p2 = wpa_s->p2p2;
group = p2p_group_init(wpa_s->global->p2p, cfg);
if (group == NULL)
@@ -7879,7 +8683,7 @@
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
int vht_center_freq2, int ht40, int vht, int max_chwidth,
- int pref_freq, int he, int edmg, bool allow_6ghz)
+ int pref_freq, int he, int edmg, bool allow_6ghz, bool p2p2)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
@@ -7905,6 +8709,7 @@
wpa_s->p2p_go_max_oper_chwidth = max_chwidth;
wpa_s->p2p_go_vht_center_freq2 = vht_center_freq2;
wpa_s->p2p_go_edmg = !!edmg;
+ wpa_s->p2p2 = p2p2;
if (ssid->mode == WPAS_MODE_P2P_GO) {
role = P2P_INVITE_ROLE_GO;
if (peer_addr == NULL) {
@@ -7927,7 +8732,8 @@
bssid = wpa_s->own_addr;
} else {
role = P2P_INVITE_ROLE_CLIENT;
- peer_addr = ssid->bssid;
+ if (!wpa_s->p2p2)
+ peer_addr = ssid->bssid;
}
wpa_s->pending_invite_ssid_id = ssid->id;
@@ -7958,9 +8764,23 @@
*/
wpas_p2p_stop_find_oper(wpa_s);
+#ifdef CONFIG_PASN
+ if (p2p2) {
+ if (wpas_p2p_initiate_pasn_verify(wpa_s, peer_addr, role, bssid,
+ ssid->ssid, ssid->ssid_len,
+ force_freq, go_dev_addr,
+ pref_freq) < 0) {
+ if (wpa_s->create_p2p_iface)
+ wpas_p2p_remove_pending_group_interface(wpa_s);
+ return -1;
+ }
+ return 0;
+ }
+#endif /* CONFIG_PASN */
+
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len, force_freq, go_dev_addr,
- 1, pref_freq, -1);
+ 1, pref_freq, -1, false);
}
@@ -8044,13 +8864,14 @@
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
ssid->ssid, ssid->ssid_len, force_freq,
- go_dev_addr, persistent, pref_freq, -1);
+ go_dev_addr, persistent, pref_freq, -1, false);
}
void wpas_p2p_completed(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ const u8 *bssid;
u8 go_dev_addr[ETH_ALEN];
int persistent;
int freq;
@@ -8065,6 +8886,11 @@
if (!wpa_s->show_group_started || !ssid)
return;
+ if (wpa_s->go_params)
+ bssid = wpa_s->go_params->peer_interface_addr;
+ else
+ bssid = wpa_s->bssid;
+
wpa_s->show_group_started = 0;
if (!wpa_s->p2p_go_group_formation_completed &&
wpa_s->global->p2p_group_formation == wpa_s) {
@@ -8111,9 +8937,11 @@
ssid->passphrase, go_dev_addr, persistent,
ip_addr);
- if (persistent)
+ if (persistent) {
wpas_p2p_store_persistent_group(wpa_s->p2pdev,
ssid, go_dev_addr);
+ wpas_p2p_store_go_identity(wpa_s, go_dev_addr, bssid);
+ }
wpas_notify_p2p_group_started(wpa_s, ssid, persistent, 1, ip_ptr);
}
@@ -8872,6 +9700,52 @@
}
+static void wpas_p2p_store_client_identity(struct wpa_supplicant *wpa_s,
+ const u8 *addr)
+{
+ u8 cipher;
+ size_t dik_len;
+ const u8 *dik_data;
+ const u8 *pmk, *pmkid;
+ size_t pmk_len;
+ u8 iface_addr[ETH_ALEN];
+ struct hostapd_data *hapd;
+ struct wpa_supplicant *p2p_wpa_s = wpa_s->global->p2p_init_wpa_s;
+
+ if (!wpa_s->p2p2 || !wpa_s->ap_iface)
+ return;
+
+ hapd = wpa_s->ap_iface->bss[0];
+ if (!hapd)
+ return;
+
+ if (p2p_get_dev_identity_key(p2p_wpa_s->global->p2p, addr,
+ &dik_data, &dik_len, &cipher))
+ return;
+
+ wpa_printf(MSG_DEBUG, "P2P: Fetch PMK from client (Device Addr " MACSTR
+ ")", MAC2STR(addr));
+ if (wpa_auth_pmksa_get_pmk(hapd->wpa_auth, addr, &pmk, &pmk_len,
+ &pmkid)) {
+ if (p2p_get_interface_addr(p2p_wpa_s->global->p2p, addr,
+ iface_addr))
+ return;
+ wpa_printf(MSG_DEBUG,
+ "P2P: Fetch PMK from client (Interface Addr " MACSTR
+ ")", MAC2STR(iface_addr));
+ if (wpa_auth_pmksa_get_pmk(hapd->wpa_auth, iface_addr, &pmk,
+ &pmk_len, &pmkid))
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "P2P: Storing device identity of client (Device Addr "
+ MACSTR ")", MAC2STR(addr));
+ wpas_p2p_store_identity(p2p_wpa_s, cipher, dik_data, dik_len, pmk,
+ pmk_len, pmkid);
+}
+
+
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
@@ -8913,6 +9787,8 @@
wpa_s->global->p2p_go_wait_client.sec = 0;
if (addr == NULL)
return;
+
+ wpas_p2p_store_client_identity(wpa_s, addr);
wpas_p2p_add_persistent_group_client(wpa_s, addr);
}
@@ -8942,7 +9818,7 @@
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);
+ wpa_s->p2p2, wpa_s->p2p_bootstrap, NULL, false);
return ret;
}
@@ -9410,6 +10286,8 @@
return NULL;
}
+ wpa_s->p2p2 = false;
+
if (cli_freq == 0) {
wsc = wps_build_nfc_handover_req_p2p(
wpa_s->parent->wps, wpa_s->conf->wps_nfc_dh_pubkey);
@@ -9439,6 +10317,8 @@
&wpa_s->conf->wps_nfc_dh_privkey) < 0)
return NULL;
+ wpa_s->p2p2 = false;
+
if (cli_freq == 0) {
wsc = wps_build_nfc_handover_sel_p2p(
wpa_s->parent->wps,
@@ -9481,7 +10361,7 @@
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
params->go_ssid_len ? params->go_ssid : NULL,
params->go_ssid_len, false, wpa_s->p2p2,
- wpa_s->p2p_bootstrap, NULL);
+ wpa_s->p2p_bootstrap, NULL, false);
}
@@ -9545,7 +10425,7 @@
P2P_INVITE_ROLE_ACTIVE_GO, wpa_s->own_addr,
ssid->ssid, ssid->ssid_len, ssid->frequency,
wpa_s->global->p2p_dev_addr, persistent, 0,
- wpa_s->p2pdev->p2p_oob_dev_pw_id);
+ wpa_s->p2pdev->p2p_oob_dev_pw_id, false);
}
@@ -9561,7 +10441,7 @@
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
NULL, 0, false, wpa_s->p2p2,
- wpa_s->p2p_bootstrap, NULL);
+ wpa_s->p2p_bootstrap, NULL, false);
}
@@ -9579,7 +10459,7 @@
-1, 0, 1, 1, wpa_s->p2p_go_max_oper_chwidth,
wpa_s->p2p_go_he, wpa_s->p2p_go_edmg,
NULL, 0, false, wpa_s->p2p2,
- wpa_s->p2p_bootstrap, NULL);
+ wpa_s->p2p_bootstrap, NULL, false);
if (res)
return res;
@@ -9707,6 +10587,8 @@
params.oob_dev_pw, WPS_OOB_PUBKEY_HASH_LEN);
wpa_s->p2p_peer_oob_pk_hash_known = 1;
+ wpa_s->p2p2 = false;
+
if (tag) {
if (id < 0x10) {
wpa_printf(MSG_DEBUG, "P2P: Static handover - invalid "
@@ -10469,3 +11351,54 @@
return;
p2p_process_usd_elems(p2p, buf, buf_len, peer_addr, freq);
}
+
+
+#ifdef CONFIG_PASN
+
+int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int freq)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ if (wpa_s->global->p2p_disabled || !p2p)
+ return -2;
+ return p2p_pasn_auth_rx(p2p, mgmt, len, freq);
+}
+
+
+int wpas_p2p_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data,
+ size_t data_len, bool acked)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+ struct wpa_p2p_pasn_auth_work *awork;
+
+ if (!wpa_s->p2p_pasn_auth_work)
+ return -1;
+ awork = wpa_s->p2p_pasn_auth_work->ctx;
+
+ return p2p_pasn_auth_tx_status(p2p, data, data_len, acked,
+ awork->verify);
+}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, const u8 **ptk,
+ size_t *ptk_len)
+{
+ struct p2p_data *p2p = wpa_s->global->p2p;
+
+ if (wpa_s->global->p2p_disabled || !p2p)
+ return -2;
+ return p2p_pasn_get_ptk(p2p, ptk, ptk_len);
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+#endif /* CONFIG_PASN */
+
+
+void wpas_p2p_update_dev_addr(struct wpa_supplicant *wpa_s)
+{
+ os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
+ p2p_set_dev_addr(wpa_s->global->p2p, wpa_s->own_addr);
+}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index a0fbddc..888bce5 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -40,12 +40,13 @@
unsigned int vht_chwidth, int he, int edmg,
const u8 *group_ssid, size_t group_ssid_len,
bool allow_6ghz, bool p2p2, u16 bootstrap,
- const char *password);
+ const char *password, bool skip_prov);
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
int freq, struct wpa_ssid *ssid);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
int freq, int vht_center_freq2, int ht40, int vht,
- int max_oper_chwidth, int he, int edmg, bool allow_6ghz);
+ int max_oper_chwidth, int he, int edmg, bool allow_6ghz,
+ bool p2p2, enum wpa_p2p_mode p2p_mode);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int force_freq, int neg_freq,
@@ -54,7 +55,9 @@
const struct p2p_channels *channels,
int connection_timeout, int force_scan,
bool allow_6ghz, int retry_limit,
- const u8 *go_bssid);
+ const u8 *go_bssid, const u8 *dev_addr,
+ const u8 *pmkid, const u8 *pmk,
+ size_t pmk_len);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
enum wpas_p2p_prov_disc_use {
@@ -122,7 +125,8 @@
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
int vht_center_freq2, int ht40, int vht, int max_chwidth,
- int pref_freq, int he, int edmg, bool allow_6ghz);
+ int pref_freq, int he, int edmg, bool allow_6ghz,
+ bool p2p2);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
const u8 *peer_addr, const u8 *go_dev_addr,
bool allow_6ghz);
@@ -182,6 +186,9 @@
void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
u16 buf_len, const u8 *peer_addr,
unsigned int freq);
+int wpas_p2p_pasn_auth_tx_status(struct wpa_supplicant *wpa_s, const u8 *data,
+ size_t data_len, bool acked);
+int wpas_p2p_remove_all_identity(struct wpa_supplicant *wpa_s);
#ifdef CONFIG_P2P
@@ -230,6 +237,12 @@
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);
+void wpas_p2p_update_dev_addr(struct wpa_supplicant *wpa_s);
+int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s,
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ int freq);
+int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, const u8 **ptk,
+ size_t *ptk_len);
#else /* CONFIG_P2P */
@@ -361,6 +374,18 @@
return NULL;
}
+static inline void wpas_p2p_update_dev_addr(struct wpa_supplicant *wpa_s)
+{
+}
+
+#ifdef CONFIG_TESTING_OPTIONS
+static inline int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s,
+ const u8 **ptk, size_t *ptk_len)
+{
+ return 0;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
+
#endif /* CONFIG_P2P */
#endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/pasn_supplicant.c b/wpa_supplicant/pasn_supplicant.c
index 89edad4..a46fe46 100644
--- a/wpa_supplicant/pasn_supplicant.c
+++ b/wpa_supplicant/pasn_supplicant.c
@@ -806,6 +806,9 @@
if (!wpa_s->pasn_auth_work)
return -2;
+ wpabuf_free(pasn->frame);
+ pasn->frame = NULL;
+
pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL);
ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len, &pasn_data);
if (ret == 0) {
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index f0ab122..ccedcc9 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -750,17 +750,20 @@
ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
sizeof(ext_capab), NULL);
if (ext_capab_len > 0 &&
+ (size_t) ext_capab_len < wpa_s->drv_max_probe_req_ie_len &&
wpabuf_resize(&extra_ie, ext_capab_len) == 0)
wpabuf_put_data(extra_ie, ext_capab, ext_capab_len);
#ifdef CONFIG_INTERWORKING
if (wpa_s->conf->interworking &&
+ wpa_s->drv_max_probe_req_ie_len >= 2 &&
wpabuf_resize(&extra_ie, 100) == 0)
wpas_add_interworking_elements(wpa_s, extra_ie);
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_MBO
- if (wpa_s->enable_oce & OCE_STA)
+ if ((wpa_s->enable_oce & OCE_STA) &&
+ wpa_s->drv_max_probe_req_ie_len >= 5)
wpas_fils_req_param_add_max_channel(wpa_s, &extra_ie);
#endif /* CONFIG_MBO */
@@ -774,17 +777,19 @@
&wpa_s->wps->dev,
wpa_s->wps->uuid, req_type,
0, NULL);
- if (wps_ie) {
- if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0)
- wpabuf_put_buf(extra_ie, wps_ie);
- wpabuf_free(wps_ie);
- }
+ if (wps_ie &&
+ wpabuf_len(wps_ie) <= wpa_s->drv_max_probe_req_ie_len &&
+ wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0)
+ wpabuf_put_buf(extra_ie, wps_ie);
+ wpabuf_free(wps_ie);
}
#ifdef CONFIG_P2P
if (wps) {
size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
- if (wpabuf_resize(&extra_ie, ielen) == 0)
+
+ if (ielen <= wpa_s->drv_max_probe_req_ie_len &&
+ wpabuf_resize(&extra_ie, ielen) == 0)
wpas_p2p_scan_ie(wpa_s, extra_ie);
}
#endif /* CONFIG_P2P */
@@ -794,12 +799,14 @@
#endif /* CONFIG_WPS */
#ifdef CONFIG_HS20
- if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 9) == 0)
+ if (wpa_s->conf->hs20 && wpa_s->drv_max_probe_req_ie_len >= 9 &&
+ wpabuf_resize(&extra_ie, 9) == 0)
wpas_hs20_add_indication(extra_ie, -1, 0);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_FST
if (wpa_s->fst_ies &&
+ wpa_s->drv_max_probe_req_ie_len >= wpabuf_len(wpa_s->fst_ies) &&
wpabuf_resize(&extra_ie, wpabuf_len(wpa_s->fst_ies)) == 0)
wpabuf_put_buf(extra_ie, wpa_s->fst_ies);
#endif /* CONFIG_FST */
@@ -813,7 +820,8 @@
if (wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ]) {
struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_PROBE_REQ];
- if (wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0)
+ if (wpa_s->drv_max_probe_req_ie_len >= wpabuf_len(buf) &&
+ wpabuf_resize(&extra_ie, wpabuf_len(buf)) == 0)
wpabuf_put_buf(extra_ie, buf);
}
@@ -2368,7 +2376,9 @@
int wpa_a, wpa_b;
int snr_a, snr_b, snr_a_full, snr_b_full;
size_t ies_len;
+#ifndef CONFIG_NO_WPA
const u8 *rsne_a, *rsne_b;
+#endif /* CONFIG_NO_WPA */
/* WPA/WPA2 support preferred */
wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
@@ -2412,6 +2422,7 @@
snr_b = snr_b_full = wb->level;
}
+#ifndef CONFIG_NO_WPA
/* If SNR of a SAE BSS is good or at least as high as the PSK BSS,
* prefer SAE over PSK for mixed WPA3-Personal transition mode and
* WPA2-Personal deployments */
@@ -2437,6 +2448,7 @@
(snr_b >= GREAT_SNR || snr_b >= snr_a))
return 1;
}
+#endif /* CONFIG_NO_WPA */
/* If SNR is close, decide by max rate or frequency band. For cases
* involving the 6 GHz band, use the throughput estimate irrespective
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index e4be388..0a0a50f 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -105,6 +105,7 @@
int key_mgmt = external ? wpa_s->sme.ext_auth_key_mgmt :
wpa_s->key_mgmt;
const u8 *addr = mld_addr ? mld_addr : bssid;
+ enum sae_pwe sae_pwe;
if (ret_use_pt)
*ret_use_pt = 0;
@@ -198,14 +199,16 @@
rsnxe_capa = rsnxe[2];
}
+ sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
+
if (ssid->sae_password_id &&
- wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
+ sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
use_pt = 1;
if (wpa_key_mgmt_sae_ext_key(key_mgmt) &&
- wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
+ sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
use_pt = 1;
if (bss && is_6ghz_freq(bss->freq) &&
- wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
+ sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
use_pt = 1;
#ifdef CONFIG_SAE_PK
if ((rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_PK)) &&
@@ -225,14 +228,14 @@
}
#endif /* CONFIG_SAE_PK */
- if (use_pt || wpa_s->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
- wpa_s->conf->sae_pwe == SAE_PWE_BOTH) {
+ if (use_pt || sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
+ sae_pwe == SAE_PWE_BOTH) {
use_pt = !!(rsnxe_capa & BIT(WLAN_RSNX_CAPAB_SAE_H2E));
- if ((wpa_s->conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
+ if ((sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
ssid->sae_password_id ||
wpa_key_mgmt_sae_ext_key(key_mgmt)) &&
- wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
+ sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK &&
!use_pt) {
wpa_printf(MSG_DEBUG,
"SAE: Cannot use H2E with the selected AP");
@@ -241,7 +244,7 @@
}
if (use_pt && !ssid->pt)
- wpa_s_setup_sae_pt(wpa_s->conf, ssid, true);
+ wpa_s_setup_sae_pt(wpa_s, ssid, true);
if (use_pt &&
sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
wpa_s->own_addr, addr,
@@ -810,7 +813,6 @@
wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x",
md[0], md[1]);
- omit_rsnxe = !wpa_bss_get_rsnxe(wpa_s, bss, ssid, false);
if (wpa_s->sme.assoc_req_ie_len + 5 <
sizeof(wpa_s->sme.assoc_req_ie)) {
struct rsn_mdie *mdie;
@@ -830,6 +832,8 @@
wpa_sm_has_ft_keys(wpa_s->wpa, md)) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: Trying to use FT "
"over-the-air");
+ omit_rsnxe = !wpa_bss_get_rsnxe(wpa_s, bss, ssid,
+ false);
params.auth_alg = WPA_AUTH_ALG_FT;
params.ie = wpa_s->sme.ft_ies;
params.ie_len = wpa_s->sme.ft_ies_len;
@@ -1453,7 +1457,7 @@
os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0 &&
wpa_key_mgmt_sae(ssid->key_mgmt)) {
/* Make sure PT is derived */
- wpa_s_setup_sae_pt(wpa_s->conf, ssid, false);
+ wpa_s_setup_sae_pt(wpa_s, ssid, false);
wpa_s->sme.ext_auth_wpa_ssid = ssid;
break;
}
@@ -1729,6 +1733,30 @@
return -1;
}
token_len = elen - 1;
+#ifdef CONFIG_IEEE80211BE
+ } else if ((wpa_s->valid_links ||
+ (external && wpa_s->sme.ext_ml_auth)) &&
+ token_len > 12 &&
+ token_pos[token_len - 12] == WLAN_EID_EXTENSION &&
+ token_pos[token_len - 11] == 10 &&
+ token_pos[token_len - 10] ==
+ WLAN_EID_EXT_MULTI_LINK) {
+ /* IEEE P802.11be requires H2E to be used whenever SAE
+ * is used for ML association. However, some early
+ * Wi-Fi 7 APs enable MLO without H2E. Recognize this
+ * special case based on the fixed length Basic
+ * Multi-Link element being at the end of the data that
+ * would contain the unknown variable length
+ * Anti-Clogging Token field. The Basic Multi-Link
+ * element in Authentication frames include the MLD MAC
+ * addreess in the Common Info field and all subfields
+ * of the Presence Bitmap subfield of the Multi-Link
+ * Control field of the element zero and consequently,
+ * has a fixed length of 12 octets. */
+ wpa_printf(MSG_DEBUG,
+ "SME: Detected Basic Multi-Link element at the end of Anti-Clogging Token field");
+ token_len -= 12;
+#endif /* CONFIG_IEEE80211BE */
}
*ie_offset = token_pos + token_len - data;
@@ -2451,6 +2479,12 @@
mscs_fail:
#endif /* CONFIG_NO_ROBUST_AV */
+ wpa_s->sme.assoc_req_ie_len =
+ wpas_populate_wfa_capa(wpa_s, wpa_s->current_bss,
+ wpa_s->sme.assoc_req_ie,
+ wpa_s->sme.assoc_req_ie_len,
+ sizeof(wpa_s->sme.assoc_req_ie));
+
if (ssid && ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
struct multi_ap_params multi_ap = { 0 };
@@ -2472,10 +2506,10 @@
}
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE_SUPPORT,
- wpas_rsn_overriding(wpa_s));
+ wpas_rsn_overriding(wpa_s, ssid));
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
RSN_OVERRIDE_NOT_USED);
- if (wpas_rsn_overriding(wpa_s) &&
+ if (wpas_rsn_overriding(wpa_s, ssid) &&
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)) {
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 3bb621d..31d1007 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -614,38 +614,37 @@
}
-static void wnm_clear_acceptable(struct wpa_supplicant *wpa_s)
-{
- unsigned int i;
-
- for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++)
- wpa_s->wnm_neighbor_report_elements[i].acceptable = 0;
-}
-
-#ifdef CONFIG_MBO
-static struct wpa_bss *
-get_mbo_transition_candidate(struct wpa_supplicant *wpa_s,
+static void
+fetch_drv_mbo_candidate_info(struct wpa_supplicant *wpa_s,
enum mbo_transition_reject_reason *reason)
{
- struct wpa_bss *target = NULL;
+#ifdef CONFIG_MBO
struct wpa_bss_trans_info params;
struct wpa_bss_candidate_info *info = NULL;
- struct neighbor_report *nei = wpa_s->wnm_neighbor_report_elements;
- u8 *first_candidate_bssid = NULL, *pos;
+ struct neighbor_report *nei;
+ u8 *pos;
unsigned int i;
+ if (!wpa_s->wnm_mbo_trans_reason_present)
+ return;
+
params.mbo_transition_reason = wpa_s->wnm_mbo_transition_reason;
params.n_candidates = 0;
params.bssid = os_calloc(wpa_s->wnm_num_neighbor_report, ETH_ALEN);
if (!params.bssid)
- return NULL;
+ return;
pos = params.bssid;
- for (i = 0; i < wpa_s->wnm_num_neighbor_report; nei++, i++) {
- if (nei->is_first)
- first_candidate_bssid = nei->bssid;
- if (!nei->acceptable)
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+
+ nei->drv_mbo_reject = 0;
+
+ if (nei->preference_present && nei->preference == 0)
continue;
+
+ /* Should we query BSSIDs that we reject for other reasons? */
+
os_memcpy(pos, nei->bssid, ETH_ALEN);
pos += ETH_ALEN;
params.n_candidates++;
@@ -655,185 +654,36 @@
goto end;
info = wpa_drv_get_bss_trans_status(wpa_s, ¶ms);
- if (!info) {
- /* If failed to get candidate BSS transition status from driver,
- * get the first acceptable candidate from wpa_supplicant.
- */
- target = wpa_bss_get_bssid(wpa_s, params.bssid);
+ if (!info)
goto end;
- }
- /* Get the first acceptable candidate from driver */
for (i = 0; i < info->num; i++) {
- if (info->candidates[i].is_accept) {
- target = wpa_bss_get_bssid(wpa_s,
- info->candidates[i].bssid);
- goto end;
- }
- }
+ int j;
- /* If Disassociation Imminent is set and driver rejects all the
- * candidate select first acceptable candidate which has
- * rssi > disassoc_imminent_rssi_threshold
- */
- if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
- for (i = 0; i < info->num; i++) {
- target = wpa_bss_get_bssid(wpa_s,
- info->candidates[i].bssid);
- if (target &&
- (target->level <
- wpa_s->conf->disassoc_imminent_rssi_threshold))
+ for (j = 0; j < wpa_s->wnm_num_neighbor_report; j++) {
+ nei = &wpa_s->wnm_neighbor_report_elements[j];
+
+ if (!ether_addr_equal(info->candidates[i].bssid,
+ nei->bssid))
continue;
- goto end;
- }
- }
- /* While sending BTM reject use reason code of the first candidate
- * received in BTM request frame
- */
- if (reason) {
- for (i = 0; i < info->num; i++) {
- if (first_candidate_bssid &&
- ether_addr_equal(first_candidate_bssid,
- info->candidates[i].bssid)) {
+ nei->drv_mbo_reject = !info->candidates[i].is_accept;
+
+ /* Use the reject reason from the first candidate */
+ if (i == 0 && nei->drv_mbo_reject)
*reason = info->candidates[i].reject_reason;
- break;
- }
+
+ break;
}
}
- target = NULL;
-
end:
os_free(params.bssid);
if (info) {
os_free(info->candidates);
os_free(info);
}
- return target;
-}
#endif /* CONFIG_MBO */
-
-
-static struct wpa_bss * find_better_target(struct wpa_bss *a,
- struct wpa_bss *b)
-{
- if (!a)
- return b;
- if (!b)
- return a;
-
- if (a->est_throughput > b->est_throughput) {
- wpa_printf(MSG_DEBUG, "WNM: A is better: " MACSTR
- " est-tput: %d B: " MACSTR " est-tput: %d",
- MAC2STR(a->bssid), a->est_throughput,
- MAC2STR(b->bssid), b->est_throughput);
- return a;
- }
-
- wpa_printf(MSG_DEBUG, "WNM: B is better, A: " MACSTR
- " est-tput: %d B: " MACSTR " est-tput: %d",
- MAC2STR(a->bssid), a->est_throughput,
- MAC2STR(b->bssid), b->est_throughput);
- return b;
-}
-
-static struct wpa_bss *
-compare_scan_neighbor_results(struct wpa_supplicant *wpa_s,
- enum mbo_transition_reject_reason *reason)
-{
- u8 i;
- struct wpa_bss *bss = wpa_s->current_bss;
- struct wpa_bss *target;
- struct wpa_bss *best_target = NULL;
- struct wpa_bss *bss_in_list = NULL;
-
- if (!bss)
- return NULL;
-
- wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
- MAC2STR(wpa_s->bssid), bss->level);
-
- wnm_clear_acceptable(wpa_s);
-
- for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
- struct neighbor_report *nei;
-
- nei = &wpa_s->wnm_neighbor_report_elements[i];
-
- target = wpa_bss_get_bssid(wpa_s, nei->bssid);
- if (!target) {
- wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
- " (pref %d) not found in scan results",
- MAC2STR(nei->bssid),
- nei->preference_present ? nei->preference :
- -1);
- continue;
- }
-
- /*
- * TODO: Could consider allowing transition to another ESS if
- * PMF was enabled for the association.
- */
- if (!wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
- 1, 0)) {
- wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
- " (pref %d) does not match the current network profile",
- MAC2STR(nei->bssid),
- nei->preference_present ? nei->preference :
- -1);
- continue;
- }
-
- if (target->level < bss->level && target->level < -80) {
- wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
- " (pref %d) does not have sufficient signal level (%d)",
- MAC2STR(nei->bssid),
- nei->preference_present ? nei->preference :
- -1,
- target->level);
- continue;
- }
-
- nei->acceptable = 1;
-
- best_target = find_better_target(target, best_target);
- if (target == bss)
- bss_in_list = bss;
- }
-
-#ifdef CONFIG_MBO
- if (wpa_s->wnm_mbo_trans_reason_present)
- target = get_mbo_transition_candidate(wpa_s, reason);
- else
- target = best_target;
-#else /* CONFIG_MBO */
- target = best_target;
-#endif /* CONFIG_MBO */
-
- if (!target)
- return NULL;
-
- wpa_printf(MSG_DEBUG,
- "WNM: Found an acceptable preferred transition candidate BSS "
- MACSTR " (RSSI %d, tput: %d bss-tput: %d)",
- MAC2STR(target->bssid), target->level,
- target->est_throughput, bss->est_throughput);
-
- if (!bss_in_list)
- return target;
-
- if ((!target->est_throughput && !bss_in_list->est_throughput) ||
- (target->est_throughput > bss_in_list->est_throughput &&
- target->est_throughput - bss_in_list->est_throughput >
- bss_in_list->est_throughput >> 4)) {
- /* It is more than 100/16 percent better, so switch. */
- return target;
- }
-
- wpa_printf(MSG_DEBUG,
- "WNM: Stay with our current BSS, not enough change in estimated throughput to switch");
- return bss_in_list;
}
@@ -1154,13 +1004,14 @@
int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check)
{
- struct wpa_bss *bss;
+ struct wpa_bss *bss, *current_bss = wpa_s->current_bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
enum mbo_transition_reject_reason reason =
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
+ struct wpa_ssid *selected_ssid = NULL;
- if (!wpa_s->wnm_dialog_token)
+ if (!ssid || !wpa_s->wnm_dialog_token)
return 0;
wpa_dbg(wpa_s, MSG_DEBUG,
@@ -1178,8 +1029,45 @@
wpa_s->wnm_transition_scan = false;
+ /* Fetch MBO transition candidate rejection information from driver */
+ fetch_drv_mbo_candidate_info(wpa_s, &reason);
+
/* Compare the Neighbor Report and scan results */
- bss = compare_scan_neighbor_results(wpa_s, &reason);
+ bss = wpa_supplicant_select_bss(wpa_s, ssid, &selected_ssid, 1);
+#ifdef CONFIG_MBO
+ if (!bss && wpa_s->wnm_mbo_trans_reason_present &&
+ (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT)) {
+ int i;
+ bool changed = false;
+
+ /*
+ * We didn't find any candidate, the driver had a say about
+ * which targets to reject and disassociation is immiment.
+ *
+ * We should still try to roam, so retry after ignoring the
+ * driver reject for any BSS that has an RSSI better than
+ * disassoc_imminent_rssi_threshold.
+ */
+ for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+ struct neighbor_report *nei;
+
+ nei = &wpa_s->wnm_neighbor_report_elements[i];
+ bss = wpa_bss_get_bssid(wpa_s, nei->bssid);
+ if (bss && bss->level >
+ wpa_s->conf->disassoc_imminent_rssi_threshold) {
+ nei->drv_mbo_reject = 0;
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Ignore driver rejection due to imminent disassociation and acceptable RSSI");
+ bss = wpa_supplicant_select_bss(wpa_s, ssid,
+ &selected_ssid, 1);
+ }
+ }
+#endif /* CONFIG_MBO */
/*
* If this is a pre-scan check, returning 0 will trigger a scan and
@@ -1202,20 +1090,35 @@
return 0;
#ifndef CONFIG_NO_ROAMING
- if (wpa_s->current_bss && bss != wpa_s->current_bss &&
- wpa_supplicant_need_to_roam_within_ess(wpa_s,
- wpa_s->current_bss,
- bss))
+ if (current_bss && bss != current_bss &&
+ wpa_supplicant_need_to_roam_within_ess(wpa_s, bss,
+ current_bss, false))
return 0;
#endif /* CONFIG_NO_ROAMING */
}
+#ifndef CONFIG_NO_ROAMING
+ /* Apply normal roaming rules if we can stay with the current BSS */
+ if (current_bss && bss != current_bss &&
+ wpa_scan_res_match(wpa_s, 0, current_bss, wpa_s->current_ssid,
+ 1, 0) &&
+ !wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss, bss,
+ true))
+ bss = current_bss;
+#endif /* CONFIG_NO_ROAMING */
+
if (!bss) {
wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
goto send_bss_resp_fail;
}
+ wpa_printf(MSG_DEBUG,
+ "WNM: Found an acceptable preferred transition candidate BSS "
+ MACSTR " (RSSI %d, tput: %d bss-tput: %d)",
+ MAC2STR(bss->bssid), bss->level, bss->est_throughput,
+ current_bss ? (int) current_bss->est_throughput : -1);
+
/* Associate to the network */
wnm_bss_tm_connect(wpa_s, bss, ssid, 1);
return 1;
@@ -1409,15 +1312,6 @@
*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;
@@ -2133,6 +2027,11 @@
if (nei->preference_present && nei->preference == 0)
return true;
+#ifdef CONFIG_MBO
+ if (nei->drv_mbo_reject)
+ return true;
+#endif /* CONFIG_MBO */
+
break;
}
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index 235a838..80928f7 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -44,9 +44,8 @@
unsigned int rm_capab_present:1;
unsigned int bearing_present:1;
unsigned int bss_term_present:1;
- unsigned int acceptable:1;
#ifdef CONFIG_MBO
- unsigned int is_first:1;
+ unsigned int drv_mbo_reject:1;
#endif /* CONFIG_MBO */
struct measurement_pilot *meas_pilot;
struct multiple_bssid *mul_bssid;
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index af00e79..2f57be8 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -3335,6 +3335,59 @@
}
+#ifdef CONFIG_NAN_USD
+
+static int wpa_cli_cmd_nan_publish(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NAN_PUBLISH", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nan_cancel_publish(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NAN_CANCEL_PUBLISH", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nan_update_publish(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NAN_UPDATE_PUBLISH", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nan_subscribe(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NAN_SUBSCRIBE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nan_cancel_subscribe(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NAN_CANCEL_SUBSCRIBE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nan_transmit(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "NAN_TRANSMIT", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_nan_flush(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "NAN_FLUSH");
+}
+
+#endif /* CONFIG_NAN_USD */
+
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -4084,6 +4137,24 @@
{ "mlo_signal_poll", wpa_cli_cmd_mlo_signal_poll, NULL,
cli_cmd_flag_none,
"= get mlo signal parameters" },
+#ifdef CONFIG_NAN_USD
+ { "nan_publish", wpa_cli_cmd_nan_publish, NULL,
+ cli_cmd_flag_none,
+ "service_name=<name> [ttl=<time-to-live-in-sec>] [freq=<in MHz>] [freq_list=<comma separate list of MHz>] [srv_proto_type=<type>] [ssi=<service specific information (hexdump)>] [solicited=0] [unsolicited=0] [fsd=0] [p2p=1] = Publish NAN service" },
+ { "nan_cancel_publish", wpa_cli_cmd_nan_cancel_publish, NULL,
+ cli_cmd_flag_none, "publish_id=<id from NAN_PUBLISH> = Cancel NAN USD publish instance" },
+ { "nan_update_publish", wpa_cli_cmd_nan_update_publish, NULL,
+ cli_cmd_flag_none, "publish_id=<id from NAN_PUBLISH> [ssi=<service specific information (hexdump)> = Update publish" },
+ { "nan_subscribe", wpa_cli_cmd_nan_subscribe, NULL,
+ cli_cmd_flag_none,
+ "service_name=<name> [active=1] [ttl=<time-to-live-in-sec>] [freq=<in MHz>] [srv_proto_type=<type>] [ssi=<service specific information (hexdump)>] [p2p=1] = Subscribe to NAN service" },
+ { "nan_cancel_subscribe", wpa_cli_cmd_nan_cancel_subscribe, NULL,
+ cli_cmd_flag_none, "subscribe_id=<id from NAN_PUBLISH> = Cancel NAN USD subscribe instance" },
+ { "nan_transmit", wpa_cli_cmd_nan_transmit, NULL,
+ cli_cmd_flag_none, "handle=<id from NAN_PUBLISH or NAN_SUBSCRIBE> req_instance_id=<peer's id> address=<peer's MAC address> [ssi=<service specific information (hexdump)>] = Transmit NAN follow up" },
+ { "nan_flush", wpa_cli_cmd_nan_flush, NULL,
+ cli_cmd_flag_none, "= Flush all NAN USD services" },
+#endif /* CONFIG_NAN_USD */
{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index e3ed858..9843679 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -507,6 +507,102 @@
}
+static struct wpabuf * wpas_wfa_gen_capab_attr(struct wpa_supplicant *wpa_s)
+{
+ struct wpabuf *attr;
+ size_t gen_len, supp_len;
+ const u8 *supp;
+ u8 supp_buf[1];
+ bool add_cert;
+
+ if (wpa_s->conf->wfa_gen_capa == WFA_GEN_CAPA_DISABLED)
+ return NULL;
+
+ if (!wpa_s->conf->wfa_gen_capa_supp ||
+ wpabuf_len(wpa_s->conf->wfa_gen_capa_supp) == 0) {
+ supp_len = 1;
+ supp_buf[0] = 0;
+ if (wpa_s->hw_capab & BIT(CAPAB_HT))
+ supp_buf[0] |= BIT(0); /* Wi-Fi 4 */
+ if (wpa_s->hw_capab & BIT(CAPAB_VHT))
+ supp_buf[0] |= BIT(1); /* Wi-Fi 5 */
+ if (wpa_s->hw_capab & BIT(CAPAB_HE))
+ supp_buf[0] |= BIT(2); /* Wi-Fi 6 */
+ if (wpa_s->hw_capab & BIT(CAPAB_EHT))
+ supp_buf[0] |= BIT(3); /* Wi-Fi 7 */
+ supp = supp_buf;
+ } else {
+ supp_len = wpabuf_len(wpa_s->conf->wfa_gen_capa_supp);
+ supp = wpabuf_head(wpa_s->conf->wfa_gen_capa_supp);
+ }
+
+ add_cert = wpa_s->conf->wfa_gen_capa_cert &&
+ wpabuf_len(wpa_s->conf->wfa_gen_capa_cert) == supp_len;
+
+ gen_len = 1 + supp_len;
+ if (add_cert) {
+ gen_len++;
+ gen_len += wpabuf_len(wpa_s->conf->wfa_gen_capa_cert);
+ }
+
+ attr = wpabuf_alloc(2 + gen_len);
+ if (!attr)
+ return NULL;
+
+ wpabuf_put_u8(attr, WFA_CAPA_ATTR_GENERATIONAL_CAPAB);
+ wpabuf_put_u8(attr, gen_len);
+ wpabuf_put_u8(attr, supp_len);
+ wpabuf_put_data(attr, supp, supp_len);
+ if (add_cert) {
+ wpabuf_put_u8(attr,
+ wpabuf_len(wpa_s->conf->wfa_gen_capa_cert));
+ wpabuf_put_buf(attr, wpa_s->conf->wfa_gen_capa_cert);
+ }
+
+ return attr;
+}
+
+
+
+static void wpas_wfa_capab_tx(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wpabuf *attr, *buf;
+ size_t buf_len;
+
+ if (wpa_s->conf->wfa_gen_capa != WFA_GEN_CAPA_PROTECTED ||
+ wpa_s->wpa_state != WPA_COMPLETED ||
+ !pmf_in_use(wpa_s, wpa_s->bssid))
+ return;
+
+ attr = wpas_wfa_gen_capab_attr(wpa_s);
+ if (!attr)
+ return;
+
+ buf_len = 1 + 3 + 1 + 1 + wpabuf_len(attr);
+ buf = wpabuf_alloc(buf_len);
+ if (!buf) {
+ wpabuf_free(attr);
+ return;
+ }
+
+ wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC_PROTECTED);
+ wpabuf_put_be32(buf, WFA_CAPAB_VENDOR_TYPE);
+ wpabuf_put_u8(buf, 0); /* Capabilities Length */
+ wpabuf_put_buf(buf, attr);
+ wpabuf_free(attr);
+
+ wpa_printf(MSG_DEBUG, "WFA: Send WFA Capabilities frame");
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ wpabuf_head(buf), wpabuf_len(buf), 0) < 0)
+ wpa_printf(MSG_DEBUG,
+ "WFA: Failed to send WFA Capabilities frame");
+
+ wpabuf_free(buf);
+}
+
+
void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
@@ -620,6 +716,7 @@
eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL);
eloop_cancel_timeout(wpas_verify_ssid_beacon, wpa_s, NULL);
+ eloop_cancel_timeout(wpas_wfa_capab_tx, wpa_s, NULL);
wpas_wps_deinit(wpa_s);
@@ -1148,6 +1245,12 @@
#ifdef CONFIG_HS20
hs20_configure_frame_filters(wpa_s);
#endif
+ if (wpa_s->conf->wfa_gen_capa == WFA_GEN_CAPA_PROTECTED &&
+ pmf_in_use(wpa_s, wpa_s->bssid)) {
+ eloop_cancel_timeout(wpas_wfa_capab_tx, wpa_s, NULL);
+ eloop_register_timeout(0, 100000, wpas_wfa_capab_tx,
+ wpa_s, NULL);
+ }
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
@@ -1581,6 +1684,9 @@
{
int akm_count = wpa_s->max_num_akms;
u8 capab = 0;
+#ifdef CONFIG_SAE
+ enum sae_pwe sae_pwe;
+#endif /* CONFIG_SAE */
if (akm_count < 2)
return;
@@ -1659,13 +1765,16 @@
return;
}
- if (wpa_s->conf->sae_pwe != SAE_PWE_HUNT_AND_PECK &&
- wpa_s->conf->sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
+#ifdef CONFIG_SAE
+ sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
+ if (sae_pwe != SAE_PWE_HUNT_AND_PECK &&
+ sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
#ifdef CONFIG_SAE_PK
if (ssid->sae_pk)
capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
#endif /* CONFIG_SAE_PK */
+#endif /* CONFIG_SAE */
if (!((wpa_s->allowed_key_mgmts &
(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY)) && capab))
@@ -1704,7 +1813,9 @@
{
struct wpa_ie_data ie;
int sel, proto;
+#ifdef CONFIG_SAE
enum sae_pwe sae_pwe;
+#endif /* CONFIG_SAE */
const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
bool wmm;
@@ -2063,7 +2174,8 @@
(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_OCV))
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
#endif /* CONFIG_OCV */
- sae_pwe = wpa_s->conf->sae_pwe;
+#ifdef CONFIG_SAE
+ sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
if ((ssid->sae_password_id ||
wpa_key_mgmt_sae_ext_key(wpa_s->key_mgmt)) &&
sae_pwe != SAE_PWE_FORCE_HUNT_AND_PECK)
@@ -2084,6 +2196,7 @@
(!ssid->sae_password && ssid->passphrase &&
sae_pk_valid_password(ssid->passphrase))));
#endif /* CONFIG_SAE_PK */
+#endif /* CONFIG_SAE */
if (bss && is_6ghz_freq(bss->freq) &&
wpas_get_ssid_pmf(wpa_s, ssid) != MGMT_FRAME_PROTECTION_REQUIRED) {
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: Force MFPR=1 on 6 GHz");
@@ -2103,6 +2216,9 @@
wpa_s->oci_freq_override_fils_assoc);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DISABLE_EAPOL_G2_TX,
wpa_s->disable_eapol_g2_tx);
+ wpa_sm_set_param(wpa_s->wpa,
+ WPA_PARAM_EAPOL_2_KEY_INFO_SET_MASK,
+ wpa_s->eapol_2_key_info_set_mask);
#endif /* CONFIG_TESTING_OPTIONS */
/* Extended Key ID is only supported in infrastructure BSS so far */
@@ -2208,9 +2324,9 @@
(ssid->sae_password || ssid->passphrase || ssid->ext_psk))
psk_set = 1;
- if (!psk_set) {
+ if (!psk_set && !ssid->pmk_valid) {
wpa_msg(wpa_s, MSG_INFO,
- "No PSK available for association");
+ "No PSK/PMK available for association");
wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE", NULL);
return -1;
}
@@ -2340,6 +2456,8 @@
if (!wpa_s->disable_fils)
*pos |= 0x01;
#endif /* CONFIG_FILS */
+ if (wpa_s->conf->twt_requester)
+ *pos |= 0x20; /* Bit 77 - TWT Requester Support */
break;
case 10: /* Bits 80-87 */
#ifndef CONFIG_NO_ROBUST_AV
@@ -2526,6 +2644,8 @@
return -1;
}
+ wpas_p2p_update_dev_addr(wpa_s);
+
wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
MAC2STR(addr));
@@ -2544,13 +2664,15 @@
}
-void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid,
+void wpa_s_setup_sae_pt(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
bool force)
{
#ifdef CONFIG_SAE
+ struct wpa_config *conf = wpa_s->conf;
int *groups = conf->sae_groups;
int default_groups[] = { 19, 20, 21, 0 };
const char *password;
+ enum sae_pwe sae_pwe;
if (!groups || groups[0] <= 0)
groups = default_groups;
@@ -2559,13 +2681,15 @@
if (!password)
password = ssid->passphrase;
+ sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
+
if (!password ||
!wpa_key_mgmt_sae(ssid->key_mgmt) ||
- (conf->sae_pwe == SAE_PWE_HUNT_AND_PECK && !ssid->sae_password_id &&
+ (sae_pwe == SAE_PWE_HUNT_AND_PECK && !ssid->sae_password_id &&
!wpa_key_mgmt_sae_ext_key(ssid->key_mgmt) &&
!force &&
!sae_pk_valid_password(password)) ||
- conf->sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) {
+ sae_pwe == SAE_PWE_FORCE_HUNT_AND_PECK) {
/* PT derivation not needed */
sae_deinit_pt(ssid->pt);
ssid->pt = NULL;
@@ -2616,6 +2740,9 @@
"Could not update MAC address information");
return -1;
}
+
+ wpas_p2p_update_dev_addr(wpa_s);
+
wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
return 0;
}
@@ -2686,7 +2813,7 @@
wpa_s_clear_sae_rejected(wpa_s);
#ifdef CONFIG_SAE
- wpa_s_setup_sae_pt(wpa_s->conf, ssid, false);
+ wpa_s_setup_sae_pt(wpa_s, ssid, false);
#endif /* CONFIG_SAE */
if (rand_style > WPAS_MAC_ADDR_STYLE_PERMANENT) {
@@ -3096,6 +3223,27 @@
}
+static int ibss_get_center_320mhz(int channel)
+{
+ int seg0;
+
+ if (channel >= 1 && channel <= 45)
+ seg0 = 31;
+ else if (channel >= 49 && channel <= 77)
+ seg0 = 63;
+ else if (channel >= 81 && channel <= 109)
+ seg0 = 95;
+ else if (channel >= 113 && channel <= 141)
+ seg0 = 127;
+ else if (channel >= 145 && channel <= 173)
+ seg0 = 159;
+ else
+ seg0 = 191;
+
+ return seg0;
+}
+
+
static bool ibss_mesh_select_80_160mhz(struct wpa_supplicant *wpa_s,
const struct wpa_ssid *ssid,
struct hostapd_hw_modes *mode,
@@ -3109,6 +3257,11 @@
static const int bw160[] = {
5955, 6115, 6275, 6435, 6595, 6755, 6915
};
+ static const int bw320[]= {
+ 5955, 6255, 6115, 6415, 6275, 6575, 6435,
+ 6735, 6595, 6895, 6755, 7055
+ };
+
struct hostapd_freq_params vht_freq;
int i;
unsigned int j, k;
@@ -3169,6 +3322,26 @@
}
}
+ /* In 320 MHz, the initial four 20 MHz channels were validated
+ * above. If 320 MHz is supported, check the remaining 12 20 MHz
+ * channels for the total of 320 MHz bandwidth for 6 GHz.
+ */
+ if ((mode->eht_capab[ieee80211_mode].phy_cap[
+ EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_IDX] &
+ EHT_PHYCAP_320MHZ_IN_6GHZ_SUPPORT_MASK) && is_6ghz &&
+ ibss_mesh_is_80mhz_avail(channel + 16, mode) &&
+ ibss_mesh_is_80mhz_avail(channel + 32, mode) &&
+ ibss_mesh_is_80mhz_avail(channel + 48, mode)) {
+ for (j = 0; j < ARRAY_SIZE(bw320); j += 2) {
+ if (freq->freq >= bw320[j] &&
+ freq->freq <= bw320[j + 1]) {
+ chwidth = CONF_OPER_CHWIDTH_320MHZ;
+ seg0 = ibss_get_center_320mhz(freq->channel);
+ break;
+ }
+ }
+ }
+
if (ssid->max_oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
/* setup center_freq2, bandwidth */
for (k = 0; k < ARRAY_SIZE(bw80); k++) {
@@ -3413,13 +3586,12 @@
}
-static int wpas_populate_wfa_capa(struct wpa_supplicant *wpa_s,
- struct wpa_bss *bss,
- u8 *wpa_ie, size_t wpa_ie_len,
- size_t max_wpa_ie_len)
+int wpas_populate_wfa_capa(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ u8 *wpa_ie, size_t wpa_ie_len, size_t max_wpa_ie_len)
{
- struct wpabuf *wfa_ie = NULL;
+ struct wpabuf *wfa_ie = NULL, *attr = NULL;
u8 wfa_capa[1];
+ u8 capab_len = 0;
size_t wfa_ie_len, buf_len;
os_memset(wfa_capa, 0, sizeof(wfa_capa));
@@ -3431,7 +3603,13 @@
if (wpa_is_non_eht_scs_traffic_desc_supported(bss))
wfa_capa[0] |= WFA_CAPA_QM_NON_EHT_SCS_TRAFFIC_DESC;
- if (!wfa_capa[0])
+ if (wfa_capa[0])
+ capab_len = 1;
+
+ if (wpa_s->conf->wfa_gen_capa == WFA_GEN_CAPA_UNPROTECTED)
+ attr = wpas_wfa_gen_capab_attr(wpa_s);
+
+ if (capab_len == 0 && !attr)
return wpa_ie_len;
/* Wi-Fi Alliance element */
@@ -3440,17 +3618,23 @@
3 + /* OUI */
1 + /* OUI Type */
1 + /* Capabilities Length */
- sizeof(wfa_capa); /* Capabilities */
+ capab_len + /* Capabilities */
+ (attr ? wpabuf_len(attr) : 0) /* Attributes */;
wfa_ie = wpabuf_alloc(buf_len);
- if (!wfa_ie)
+ if (!wfa_ie) {
+ wpabuf_free(attr);
return wpa_ie_len;
+ }
wpabuf_put_u8(wfa_ie, WLAN_EID_VENDOR_SPECIFIC);
wpabuf_put_u8(wfa_ie, buf_len - 2);
wpabuf_put_be24(wfa_ie, OUI_WFA);
wpabuf_put_u8(wfa_ie, WFA_CAPA_OUI_TYPE);
- wpabuf_put_u8(wfa_ie, sizeof(wfa_capa));
- wpabuf_put_data(wfa_ie, wfa_capa, sizeof(wfa_capa));
+ wpabuf_put_u8(wfa_ie, capab_len);
+ wpabuf_put_data(wfa_ie, wfa_capa, capab_len);
+ if (attr)
+ wpabuf_put_buf(wfa_ie, attr);
+ wpabuf_free(attr);
wfa_ie_len = wpabuf_len(wfa_ie);
if (wpa_ie_len + wfa_ie_len <= max_wpa_ie_len) {
@@ -3995,10 +4179,10 @@
}
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE_SUPPORT,
- wpas_rsn_overriding(wpa_s));
+ wpas_rsn_overriding(wpa_s, ssid));
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_OVERRIDE,
RSN_OVERRIDE_NOT_USED);
- if (wpas_rsn_overriding(wpa_s) &&
+ if (wpas_rsn_overriding(wpa_s, ssid) &&
wpas_ap_supports_rsn_overriding(wpa_s, bss) &&
wpa_ie_len + 2 + 4 + 1 <= max_wpa_ie_len) {
u8 *pos = wpa_ie + wpa_ie_len, *start = pos;
@@ -4035,7 +4219,7 @@
wpa_ie_len += pos - start;
}
- params->rsn_overriding = wpas_rsn_overriding(wpa_s);
+ params->rsn_overriding = wpas_rsn_overriding(wpa_s, ssid);
params->wpa_ie = wpa_ie;
params->wpa_ie_len = wpa_ie_len;
params->auth_alg = algs;
@@ -4686,7 +4870,7 @@
params.prev_bssid = prev_bssid;
#ifdef CONFIG_SAE
- params.sae_pwe = wpa_s->conf->sae_pwe;
+ params.sae_pwe = wpas_get_ssid_sae_pwe(wpa_s, ssid);
#endif /* CONFIG_SAE */
ret = wpa_drv_associate(wpa_s, ¶ms);
@@ -5144,6 +5328,51 @@
}
+static bool ssid_in_last_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ size_t i;
+
+ /* Check if the previous scan included the selected network */
+ if (wpa_s->last_scan_num_ssids <= 1 ||
+ !ssid->ssid || ssid->ssid_len == 0)
+ return false;
+
+ /* Iterate through the previous scan SSIDs */
+ for (i = 0; i < wpa_s->last_scan_num_ssids; i++) {
+ if (os_memcmp(wpa_s->last_scan_ssids[i].ssid, ssid->ssid,
+ ssid->ssid_len) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+
+/**
+ * Checks whether an SSID was discovered in the last scan.
+ * @wpa_s: wpa_supplicant structure for a network interface.
+ * @ssid: wpa_ssid structure for a configured network.
+ * Returns: true if ssid found, false otherwise.
+ */
+static bool ssid_in_last_scan_res(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ size_t i;
+
+ if (!wpa_s->last_scan_res || !ssid->ssid || ssid->ssid_len == 0)
+ return false;
+
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ if (os_memcmp(wpa_s->last_scan_res[i]->ssid,
+ ssid->ssid, ssid->ssid_len) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+
/**
* wpa_supplicant_select_network - Attempt association with a network
* @wpa_s: wpa_supplicant structure for a network interface
@@ -5201,13 +5430,22 @@
(ssid->mode == WPAS_MODE_MESH ||
ssid->mode == WPAS_MODE_AP) ? ssid : NULL;
- if (ssid->scan_ssid &&
- (wpa_s->no_suitable_network || wpa_s->last_scan_external)) {
- wpa_printf(MSG_DEBUG,
- "Request a new scan for hidden network");
- request_new_scan = true;
- } else if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
- !ssid->owe_only) {
+ if (ssid->scan_ssid) {
+ if (ssid_in_last_scan(wpa_s, ssid)) {
+ wpa_printf(MSG_DEBUG,
+ "Hidden network was scanned for in last scan");
+ } else if (ssid_in_last_scan_res(wpa_s, ssid)) {
+ wpa_printf(MSG_DEBUG,
+ "Hidden network was found in last scan results");
+ } else {
+ request_new_scan = true;
+ wpa_printf(MSG_DEBUG,
+ "Request a new scan for hidden network");
+ }
+ }
+
+ if (!request_new_scan && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
+ !ssid->owe_only) {
wpa_printf(MSG_DEBUG,
"Request a new scan for OWE transition SSID");
request_new_scan = true;
@@ -5229,7 +5467,7 @@
wpa_s->last_owe_group = 0;
if (ssid) {
ssid->owe_transition_bss_select_count = 0;
- wpa_s_setup_sae_pt(wpa_s->conf, ssid, false);
+ wpa_s_setup_sae_pt(wpa_s, ssid, false);
}
if (wpa_s->connect_without_scan || request_new_scan ||
@@ -5765,6 +6003,7 @@
MACSTR ")",
wpa_supplicant_state_txt(wpa_s->wpa_state),
MAC2STR(connected_addr));
+ delay_processing:
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
if (wpa_s->pending_eapol_rx) {
@@ -5862,9 +6101,23 @@
encrypted) > 0)
return;
wpa_drv_poll(wpa_s);
- if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK))
- wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len, encrypted);
- else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK)) {
+ if (wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len,
+ encrypted) == -2 &&
+#ifdef CONFIG_AP
+ !wpa_s->ap_iface &&
+#endif /* CONFIG_AP */
+ wpa_s->last_eapol_matches_bssid) {
+ /* Handle the case where reassociation occurs to the
+ * current connected AP */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Delay processing of received EAPOL frame for reassociation to the current connected AP (state=%s connected_addr="
+ MACSTR ")",
+ wpa_supplicant_state_txt(wpa_s->wpa_state),
+ MAC2STR(connected_addr));
+ goto delay_processing;
+ }
+ } else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
* Set portValid = true here since we are going to skip 4-way
* handshake processing which would normally set portValid. We
@@ -6119,6 +6372,10 @@
wpa_s->new_connection = 1;
wpa_s->parent = parent ? parent : wpa_s;
wpa_s->p2pdev = wpa_s->parent;
+#ifdef CONFIG_P2P
+ if (parent)
+ wpa_s->p2p_mode = parent->p2p_mode;
+#endif /* CONFIG_P2P */
wpa_s->sched_scanning = 0;
wpa_s->setband_mask = WPA_SETBAND_AUTO;
@@ -7470,17 +7727,16 @@
u16 i;
for (i = 0; i < wpa_s->hw.num_modes; i++) {
- if (wpa_s->hw.modes[i].vht_capab) {
- wpa_s->hw_capab = CAPAB_VHT;
- break;
- }
-
- if (wpa_s->hw.modes[i].ht_capab &
- HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
- wpa_s->hw_capab = CAPAB_HT40;
- else if (wpa_s->hw.modes[i].ht_capab &&
- wpa_s->hw_capab == CAPAB_NO_HT_VHT)
- wpa_s->hw_capab = CAPAB_HT;
+ if (wpa_s->hw.modes[i].eht_capab[IEEE80211_MODE_INFRA].
+ eht_supported)
+ wpa_s->hw_capab |= BIT(CAPAB_EHT);
+ if (wpa_s->hw.modes[i].he_capab[IEEE80211_MODE_INFRA].
+ he_supported)
+ wpa_s->hw_capab |= BIT(CAPAB_HE);
+ if (wpa_s->hw.modes[i].vht_capab)
+ wpa_s->hw_capab |= BIT(CAPAB_VHT);
+ if (wpa_s->hw.modes[i].ht_capab)
+ wpa_s->hw_capab |= BIT(CAPAB_HT);
}
wpa_s->support_6ghz = wpas_is_6ghz_supported(wpa_s, false);
}
@@ -7522,12 +7778,15 @@
capa.mac_addr_rand_sched_scan_supported)
wpa_s->mac_addr_rand_supported |=
(MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
+ wpa_s->drv_max_probe_req_ie_len = capa.max_probe_req_ie_len;
wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
if (wpa_s->extended_capa &&
wpa_s->extended_capa_len >= 3 &&
wpa_s->extended_capa[2] & 0x40)
wpa_s->multi_bss_support = 1;
+ } else {
+ wpa_s->drv_max_probe_req_ie_len = 1500;
}
#ifdef CONFIG_PASN
wpa_pasn_sm_set_caps(wpa_s->wpa, wpa_s->drv_flags2);
@@ -8713,12 +8972,19 @@
}
-bool wpas_rsn_overriding(struct wpa_supplicant *wpa_s)
+bool wpas_rsn_overriding(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
- if (wpa_s->conf->rsn_overriding == RSN_OVERRIDING_DISABLED)
+ enum wpas_rsn_overriding rsno;
+
+ if (ssid && ssid->rsn_overriding != RSN_OVERRIDING_NOT_SET)
+ rsno = ssid->rsn_overriding;
+ else
+ rsno = wpa_s->conf->rsn_overriding;
+
+ if (rsno == RSN_OVERRIDING_DISABLED)
return false;
- if (wpa_s->conf->rsn_overriding == RSN_OVERRIDING_ENABLED)
+ if (rsno == RSN_OVERRIDING_ENABLED)
return true;
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) ||
@@ -8912,7 +9178,8 @@
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
(!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
- !(wpa_key_mgmt_sae(ssid->key_mgmt) && ssid->sae_password) &&
+ !(wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ (ssid->sae_password || ssid->pmk_valid)) &&
!ssid->mem_only_psk)
return 1;
@@ -8981,6 +9248,16 @@
#ifdef CONFIG_SAE
+
+enum sae_pwe wpas_get_ssid_sae_pwe(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (!ssid || ssid->sae_pwe == DEFAULT_SAE_PWE)
+ return wpa_s->conf->sae_pwe;
+ return ssid->sae_pwe;
+}
+
+
bool wpas_is_sae_avoided(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
const struct wpa_ie_data *ie)
@@ -8990,6 +9267,7 @@
(WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) ||
wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION);
}
+
#endif /* CONFIG_SAE */
@@ -9725,7 +10003,7 @@
}
return wpa_s->driver->send_action(wpa_s->drv_priv, freq, wait, dst, src,
- bssid, data, data_len, no_cck);
+ bssid, data, data_len, no_cck, -1);
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index abbe7d7..ae181ee 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -401,6 +401,50 @@
# it from taking 100% of radio resources. The default value is 500 ms.
#p2p_search_delay=500
+# Enable/disable P2P pairing setup
+#p2p_pairing_setup=0
+
+# Enable/disable P2P pairing cache for verification
+#p2p_pairing_cache=0
+
+# Enable/disable P2P pairing verification with cached NIK/NPK
+#p2p_pairing_verification=0
+
+# Supported P2P bootstrapping method bitmap
+# b0: whether opportunistic bootstrapping is supported
+# b1: whether PIN display is supported
+# b2: whether passphrase display is supported
+# b3: whether QR Code display is supported
+# b4: whether NFC tag is supported
+# b5: whether keypad (PIN only) is supported
+# b6: whether keypad (passphrase) is supported
+# b7: whether QR Code scan is supported
+# b8: whether NFC reader is supported
+# b14: whether service managed bootstrapping is supported
+# b15: whether bootstrapping handshakes skipped is supported
+#p2p_bootstrap_methods=0
+
+# Bitmap of supported PASN types
+# B0: whether DH Group 19 with unauthenticated PASN is supported
+# B1: whether DH Group 19 with authenticated PASN is supported
+# B2: whether DH Group 20 with unauthenticated PASN is supported
+# B3: whether DH Group 20 authenticated PASN is supported
+#p2p_pasn_type=0
+
+# Bootstrap request for unauthorized peer is asked to come back after
+# this many TUs.
+#p2p_comeback_after=977
+
+# Enable/disable TWT based power management for P2P
+#p2p_twt_power_mgmt=0
+
+# Enable/disable P2P client channel switch request
+#p2p_chan_switch_req_enable=0
+
+# Regulatory info encoding for operation in 6 GHz band
+# As defined in Table E-12 and E-13 of IEEE P802.11-REVme/D7.0.
+#p2p_reg_info=0
+
# Opportunistic Key Caching (also known as Proactive Key Caching) default
# This parameter can be used to set the default behavior for the
# proactive_key_caching parameter. By default, OKC is disabled unless enabled
@@ -608,6 +652,34 @@
# 1 = Publish
#ftm_initiator=0
+#twt_requester: Whether TWT requester is enabled
+# 0 = disabled (default)
+# 1 = enabled if supported by the driver
+#twt_requester=0
+
+# Wi-Fi Alliance generational capabilities indication
+#
+# wfa_gen_capa: Whether to indicate Wi-Fi generational capability to the AP
+# 0 = do not indicate (default)
+# 1 = indicate in protected Action frame
+# 2 = indicate in unprotected (Re)Association Request frame
+#wfa_gen_capa=0
+#
+# wfa_gen_capa_supp: Supported Generations (hexdump of a bit field)
+# A bit field of supported Wi-Fi generations. This is encoded as an little
+# endian octet string. If this is not set, the driver capabilities are
+# determined automatically.
+# bit 0: Wi-Fi 4
+# bit 1: Wi-Fi 5
+# bit 2: Wi-Fi 6
+# bit 3: Wi-Fi 7
+#wfa_gen_capa_supp=07
+#
+# wfa_gen_capa_cert: Certified Generations (hexdump of a bit field)
+# This has the same format as wfa_gen_capa_supp. This is an optional field, but
+# if included, shall have the same length as wfa_gen_capa_supp.
+#wfa_gen_capa_cert=07
+
# credential block
#
# Each credential used for automatic network selection is configured as a set
@@ -882,6 +954,8 @@
# NOTE: The protocol used for this mechanism is still subject to change and as
# such, this should not yet be enabled for production uses to avoid issues if
# something were to change.
+# A per-network block parameter with the same name can be used to override this
+# global parameter.
# 0 = Disabled (default)
# 1 = Enabled automatically if the driver indicates support
# 2 = Forced to be enabled even without driver capability indication
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 84b7bd5..d27ff1a 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -686,6 +686,18 @@
};
+enum local_hw_capab {
+ CAPAB_HT,
+ CAPAB_VHT,
+ CAPAB_HE,
+ CAPAB_EHT,
+};
+
+struct last_scan_ssid {
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -823,6 +835,8 @@
size_t last_scan_res_size;
struct os_reltime last_scan;
bool last_scan_external;
+ struct last_scan_ssid last_scan_ssids[WPAS_MAX_SCAN_SSIDS];
+ size_t last_scan_num_ssids;
const struct wpa_driver_ops *driver;
int interface_removed; /* whether the network interface has been
@@ -844,7 +858,7 @@
int eapol_received; /* number of EAPOL packets received after the
* previous association event */
- u8 rsnxe[20];
+ u8 rsnxe[257];
size_t rsnxe_len;
struct scard_data *scard;
@@ -941,6 +955,7 @@
unsigned int drv_key_mgmt;
unsigned int drv_rrm_flags;
unsigned int drv_max_acl_mac_addrs;
+ size_t drv_max_probe_req_ie_len;
/*
* A bitmap of supported protocols for probe response offload. See
@@ -1137,6 +1152,7 @@
u8 pending_join_dev_addr[ETH_ALEN];
u8 p2p_bootstrap_dev_addr[ETH_ALEN];
int pending_join_wps_method;
+ char pending_join_password[100];
u8 p2p_join_ssid[SSID_MAX_LEN];
size_t p2p_join_ssid_len;
int p2p_join_scan_count;
@@ -1193,6 +1209,7 @@
unsigned int p2p2:1;
u16 p2p_bootstrap;
enum hostapd_hw_mode p2p_go_acs_band;
+ enum wpa_p2p_mode p2p_mode;
int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;
@@ -1202,6 +1219,7 @@
struct wpa_radio_work *p2p_scan_work;
struct wpa_radio_work *p2p_listen_work;
struct wpa_radio_work *p2p_send_action_work;
+ bool p2p_removing_listen_work;
u16 p2p_oob_dev_pw_id; /* OOB Device Password Id for group formation */
struct wpabuf *p2p_oob_dev_pw; /* OOB Device Password for group
@@ -1274,12 +1292,7 @@
u16 num_modes;
u16 flags;
} hw;
- enum local_hw_capab {
- CAPAB_NO_HT_VHT,
- CAPAB_HT,
- CAPAB_HT40,
- CAPAB_VHT,
- } hw_capab;
+ unsigned int hw_capab; /* bitmap of enum local_hw_capab bits */
#ifdef CONFIG_MACSEC
struct ieee802_1x_kay *kay;
#endif /* CONFIG_MACSEC */
@@ -1400,6 +1413,7 @@
unsigned int oci_freq_override_fils_assoc;
unsigned int oci_freq_override_wnm_sleep;
unsigned int disable_eapol_g2_tx;
+ unsigned int eapol_2_key_info_set_mask;
int test_assoc_comeback_type;
#endif /* CONFIG_TESTING_OPTIONS */
@@ -1619,6 +1633,9 @@
struct wpa_radio_work *pasn_auth_work;
unsigned int pasn_count;
struct pasn_auth *pasn_params;
+#ifdef CONFIG_P2P
+ struct wpa_radio_work *p2p_pasn_auth_work;
+#endif /* CONFIG_P2P */
#endif /* CONFIG_PASN */
bool is_6ghz_enabled;
@@ -1760,7 +1777,7 @@
void fils_connection_failure(struct wpa_supplicant *wpa_s);
void fils_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
-bool wpas_rsn_overriding(struct wpa_supplicant *wpa_s);
+bool wpas_rsn_overriding(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
void wpas_auth_failed(struct wpa_supplicant *wpa_s, const char *reason,
const u8 *bssid);
@@ -1773,6 +1790,9 @@
void wpas_request_disconnection(struct wpa_supplicant *wpa_s);
int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen,
struct wpa_bss *bss);
+int wpas_populate_wfa_capa(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+ u8 *wpa_ie, size_t wpa_ie_len,
+ size_t max_wpa_ie_len);
int wpas_update_random_addr(struct wpa_supplicant *wpa_s,
enum wpas_mac_addr_style style,
struct wpa_ssid *ssid);
@@ -1908,7 +1928,8 @@
struct channel_list_changed *info);
int wpa_supplicant_need_to_roam_within_ess(struct wpa_supplicant *wpa_s,
struct wpa_bss *current_bss,
- struct wpa_bss *seleceted);
+ struct wpa_bss *selected,
+ bool poll_current);
void wpas_reset_mlo_info(struct wpa_supplicant *wpa_s);
/* eap_register.c */
@@ -1944,8 +1965,10 @@
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+enum sae_pwe wpas_get_ssid_sae_pwe(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
int pmf_in_use(struct wpa_supplicant *wpa_s, const u8 *addr);
-void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid,
+void wpa_s_setup_sae_pt(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
bool force);
void wpa_s_clear_sae_rejected(struct wpa_supplicant *wpa_s);
@@ -2003,6 +2026,11 @@
struct wpa_ssid *group,
int only_first_ssid, int debug_print);
+struct wpa_bss * wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *group,
+ struct wpa_ssid **selected_ssid,
+ int only_first_ssid);
+
int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
enum wpa_driver_if_type if_type,
unsigned int *num,
diff --git a/wpa_supplicant/wpa_supplicant_template.conf b/wpa_supplicant/wpa_supplicant_template.conf
index cec26c4..6a45d4a 100644
--- a/wpa_supplicant/wpa_supplicant_template.conf
+++ b/wpa_supplicant/wpa_supplicant_template.conf
@@ -9,3 +9,4 @@
sae_pwe=2
p2p_optimize_listen_chan=1
wowlan_disconnect_on_deinit=1
+rsn_overriding=1
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 741ac6c..0011274 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -355,7 +355,10 @@
"driver-based 4-way hs and FT");
res = eapol_sm_get_key(eapol, buf, 2 * PMK_LEN);
if (res == 0) {
- os_memcpy(pmk, buf + PMK_LEN, PMK_LEN);
+ if (wpa_key_mgmt_sha384(wpa_s->key_mgmt))
+ os_memcpy(pmk, buf, pmk_len);
+ else
+ os_memcpy(pmk, buf + PMK_LEN, PMK_LEN);
os_memset(buf, 0, sizeof(buf));
}
#else /* CONFIG_IEEE80211R */
@@ -1473,8 +1476,6 @@
ptk, NULL, NULL, 0);
}
-#endif /* CONFIG_NO_WPA */
-
#ifdef CONFIG_PASN
static int wpa_supplicant_set_ltf_keyseed(void *_wpa_s, const u8 *own_addr,
@@ -1509,6 +1510,8 @@
wpa_msg(wpa_s, MSG_INFO, "RSN: SSID matched expected value");
}
+#endif /* CONFIG_NO_WPA */
+
int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
{
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index f3a8c9c..d8f6198 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1375,7 +1375,7 @@
wpa_printf(MSG_DEBUG, "WPS: Cancel operation - cancel scan");
wpa_supplicant_cancel_scan(wpa_s);
wpas_clear_wps(wpa_s);
- } else if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
+ } else if (wpa_s->wpa_state >= WPA_ASSOCIATING) {
wpa_printf(MSG_DEBUG, "WPS: Cancel operation - "
"deauthenticate");
wpa_s->own_disconnect_req = 1;