Merge "Process DPP connection status result"
diff --git a/hostapd/Android.bp b/hostapd/Android.bp
index 3194d36..020396d 100644
--- a/hostapd/Android.bp
+++ b/hostapd/Android.bp
@@ -169,6 +169,35 @@
         "-Wno-unused-variable",
         "-Wno-macro-redefined",
     ],
+    // Similar to suppressing clang compiler warnings, here we
+    // suppress clang-tidy warnings to reduce noises in Android build.log.
+    tidy_checks: [
+        "-android-cloexec-*",
+        "-bugprone-branch-clone",
+        "-bugprone-macro-parentheses",
+        "-bugprone-misplaced-widening-cast",
+        "-bugprone-signal-handler",
+        "-bugprone-signed-char-misuse",
+        "-bugprone-sizeof-expression",
+        "-bugprone-suspicious-string-compare",
+        "-bugprone-too-small-loop-variable",
+        "-cert-err34-c",
+        "-cert-msc30-c",
+        "-cert-msc50-cpp",
+        "-cert-msc54-cpp",
+        "-cert-sig30-c",
+        "-cert-str34-c",
+        "-clang-analyzer-core.NullDereference",
+        "-clang-analyzer-core.UndefinedBinaryOperatorResult",
+        "-clang-analyzer-deadcode.DeadStores",
+        "-clang-analyzer-optin.performance.Padding",
+        "-clang-analyzer-optin.portability.UnixAPI",
+        "-clang-analyzer-security.insecureAPI.UncheckedReturn",
+        "-clang-analyzer-unix.cstring.NullArg",
+        "-clang-analyzer-unix.Malloc",
+        "-clang-diagnostic-unused-but-set-variable",
+        "-misc-redundant-expression",
+    ],
 }
 
 
diff --git a/hostapd/aidl/hostapd.cpp b/hostapd/aidl/hostapd.cpp
index f2200d6..35bfbe7 100644
--- a/hostapd/aidl/hostapd.cpp
+++ b/hostapd/aidl/hostapd.cpp
@@ -702,6 +702,9 @@
 			   const std::vector<uint8_t>& client_address,
 			   const uint16_t reason_code) {
 	struct sta_info *sta;
+	if (client_address.size() != ETH_ALEN) {
+		return false;
+	}
 	for (sta = hapd->sta_list; sta; sta = sta->next) {
 		int res;
 		res = memcmp(sta->addr, client_address.data(), ETH_ALEN);
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index db46d95..d23556d 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -1731,6 +1731,9 @@
 		wpa_hexdump_ascii(MSG_DEBUG,
 				  "EAP: using IMSI privacy anonymous identity",
 				  identity, identity_len);
+	} else if (config->strict_conservative_peer_mode) {
+		wpa_printf(MSG_DEBUG, "EAP: never use real identity in conservative peer mode.");
+		return NULL;
 	} else {
 		identity = config->identity;
 		identity_len = config->identity_len;
@@ -2816,6 +2819,24 @@
 	return config->identity;
 }
 
+
+/**
+ * eap_get_config_strict_conservative_peer_mode - get the value of
+ * strict conservative peer mode in eap_peer_config.
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+*/
+int eap_get_config_strict_conservative_peer_mode(struct eap_sm *sm)
+{
+	struct eap_peer_config *config;
+	config = eap_get_config(sm);
+	if (config) {
+		return config->strict_conservative_peer_mode;
+	}
+
+	return 0;
+}
+
+
 static const u8 * strnchr(const u8 *str, size_t len, u8 needle) {
 	const u8 *cur = str;
 
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index aae1a41..06654ce 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -371,6 +371,7 @@
 const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len);
 const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
 struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
+int eap_get_config_strict_conservative_peer_mode(struct eap_sm *sm);
 void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
 void eap_invalidate_cached_session(struct eap_sm *sm);
 
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 7f660e6..fc2b16f 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -708,6 +708,11 @@
 		identity_len = data->pseudonym_len;
 		eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
 	} else if (id_req != NO_ID_REQ) {
+		if (id_req == PERMANENT_ID && eap_get_config_strict_conservative_peer_mode(sm)) {
+			wpa_printf(MSG_INFO,
+				   "EAP-AKA: reject permanent identity in conservative peer mode");
+			return eap_aka_client_error(data, id, EAP_AKA_UNABLE_TO_PROCESS_PACKET);
+		}
 		identity = eap_get_config_identity(sm, &identity_len);
 		if (identity) {
 			int ids = CLEAR_PSEUDONYM | CLEAR_REAUTH_ID;
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 26744ab..e28ebad 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -338,6 +338,18 @@
 	char *imsi_privacy_attr;
 
 	/**
+	 * strict_conservative_peer_mode - Whether the strict conservative peer
+	 * mode is enabled or not
+	 *
+	 * This field is used to handle the reponse of AT_PERMANENT_ID_REQ
+	 * for EAP-SIM/AKA/AKA', in convervative peer mode, a client error would
+	 * be sent to the server, but it allows to send the permanent identity
+	 * in some special cases according to 4.6.2 of RFC 4187; With the strict
+	 * mode, it never send the permanent identity to server for privacy concern.
+	 */
+	int strict_conservative_peer_mode;
+
+	/**
 	 * machine_identity - EAP Identity for machine credential
 	 *
 	 * This field is used to set the machine identity or NAI for cases where
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 71e9108..0ccb9a8 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -576,6 +576,11 @@
 		identity_len = data->pseudonym_len;
 		eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
 	} else if (id_req != NO_ID_REQ) {
+		if (id_req == PERMANENT_ID && eap_get_config_strict_conservative_peer_mode(sm)) {
+			wpa_printf(MSG_INFO,
+				   "EAP-SIM: reject permanent identity in conservative peer mode");
+			return  eap_sim_client_error(data, id, EAP_SIM_UNABLE_TO_PROCESS_PACKET);
+		}
 		identity = eap_get_config_identity(sm, &identity_len);
 		if (identity) {
 			int ids = CLEAR_PSEUDONYM | CLEAR_REAUTH_ID;
diff --git a/wpa_supplicant/Android.bp b/wpa_supplicant/Android.bp
index 01f6662..05c79c0 100644
--- a/wpa_supplicant/Android.bp
+++ b/wpa_supplicant/Android.bp
@@ -216,6 +216,35 @@
         "-Wno-unused-parameter",
         "-Wno-unused-variable",
     ],
+    // Similar to suppressing clang compiler warnings, here we
+    // suppress clang-tidy warnings to reduce noises in Android build.log.
+    tidy_checks: [
+        "-android-cloexec-*",
+        "-bugprone-branch-clone",
+        "-bugprone-macro-parentheses",
+        "-bugprone-misplaced-widening-cast",
+        "-bugprone-signal-handler",
+        "-bugprone-signed-char-misuse",
+        "-bugprone-sizeof-expression",
+        "-bugprone-suspicious-string-compare",
+        "-bugprone-too-small-loop-variable",
+        "-cert-err34-c",
+        "-cert-msc30-c",
+        "-cert-msc50-cpp",
+        "-cert-msc54-cpp",
+        "-cert-sig30-c",
+        "-cert-str34-c",
+        "-clang-analyzer-core.NullDereference",
+        "-clang-analyzer-core.UndefinedBinaryOperatorResult",
+        "-clang-analyzer-deadcode.DeadStores",
+        "-clang-analyzer-optin.performance.Padding",
+        "-clang-analyzer-optin.portability.UnixAPI",
+        "-clang-analyzer-security.insecureAPI.UncheckedReturn",
+        "-clang-analyzer-unix.cstring.NullArg",
+        "-clang-analyzer-unix.Malloc",
+        "-clang-diagnostic-unused-but-set-variable",
+        "-misc-redundant-expression",
+    ],
 }
 
 // Generated by building wpa_supplicant and printing LOCAL_SRC_FILES.
diff --git a/wpa_supplicant/aidl/p2p_iface.cpp b/wpa_supplicant/aidl/p2p_iface.cpp
index 1fd015b..b19895b 100644
--- a/wpa_supplicant/aidl/p2p_iface.cpp
+++ b/wpa_supplicant/aidl/p2p_iface.cpp
@@ -1287,6 +1287,9 @@
 	if (go_intent > 15) {
 		return {"", createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID)};
 	}
+	if (peer_address.size() != ETH_ALEN) {
+		return {"", createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID)};
+	}
 	int go_intent_signed = join_existing_group ? -1 : go_intent;
 	p2p_wps_method wps_method = {};
 	switch (provision_method) {
@@ -1382,6 +1385,9 @@
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
 		return createStatus(SupplicantStatusCode::FAILURE_IFACE_DISABLED);
 	}
+	if (peer_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	if (wpas_p2p_reject(wpa_s, peer_address.data())) {
 		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
 	}
@@ -1394,6 +1400,9 @@
 	const std::vector<uint8_t>& peer_address)
 {
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	if (peer_address.size() != ETH_ALEN) {
+		return {createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	if (wpas_p2p_invite_group(
 		wpa_s, group_ifname.c_str(), peer_address.data(),
 		go_device_address.data(), is6GhzAllowed(wpa_s))) {
@@ -1416,6 +1425,9 @@
 	if (ssid == NULL || ssid->disabled != 2) {
 		return createStatus(SupplicantStatusCode::FAILURE_NETWORK_UNKNOWN);
 	}
+	if (peer_address.size() != ETH_ALEN) {
+		return {createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	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))) {
@@ -1579,6 +1591,9 @@
 	if (!query_buf) {
 		return {0, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
 	}
+	if (peer_address.size() != ETH_ALEN) {
+		return {0, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	const uint8_t* dst_addr = is_zero_ether_addr(peer_address.data())
 					  ? nullptr
 					  : peer_address.data();
@@ -1625,6 +1640,9 @@
 	if (!wpa_group_s) {
 		return createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN);
 	}
+	if (bssid.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	const uint8_t* bssid_addr =
 		is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
 #ifdef CONFIG_AP
@@ -1673,6 +1691,9 @@
 	if (!wpa_group_s) {
 		return {"", createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN)};
 	}
+	if (bssid.size() != ETH_ALEN) {
+		return {"", createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
+	}
 	const uint8_t* bssid_addr =
 		is_zero_ether_addr(bssid.data()) ? nullptr : bssid.data();
 	int pin = wpas_wps_start_pin(
@@ -1705,6 +1726,9 @@
 	const std::vector<uint8_t>& type)
 {
 	std::array<uint8_t, 8> type_arr;
+	if (type.size() != 8) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	std::copy_n(type.begin(), 8, type_arr.begin());
 	return iface_config_utils::setWpsDeviceType(retrieveIfacePtr(), type_arr);
 }
@@ -2097,6 +2121,9 @@
     const std::vector<uint8_t>& peer_address, bool isLegacyClient)
 {
 	struct wpa_supplicant* wpa_s = retrieveIfacePtr();
+	if (peer_address.size() != ETH_ALEN) {
+		return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
+	}
 	wpas_p2p_remove_client(wpa_s, peer_address.data(), isLegacyClient? 1 : 0);
 	return ndk::ScopedAStatus::ok();
 }
diff --git a/wpa_supplicant/aidl/sta_iface.cpp b/wpa_supplicant/aidl/sta_iface.cpp
index d88f6f0..eb3e559 100644
--- a/wpa_supplicant/aidl/sta_iface.cpp
+++ b/wpa_supplicant/aidl/sta_iface.cpp
@@ -1956,6 +1956,21 @@
 		wpa_printf(MSG_DEBUG, "Add MLO Link ID %d info", i);
 		link.linkId = i;
 		link.staLinkMacAddress.assign(wpa_s->links[i].addr, wpa_s->links[i].addr + ETH_ALEN);
+		// TODO (b/259710591): Once suppllicant implements TID-to-link
+		// mapping, copy it here. Mapping can be changed in two
+		// scenarios
+		//    1. Mandatory mapping from AP
+		//    2. Negotiated mapping
+		// After association, framework call this API to get
+		// MloLinksInfo. If there is an update in mapping later, notify
+		// framework on the change using the callback,
+		// ISupplicantStaIfaceCallback.onMloLinksInfoChanged() with
+		// reason code as TID_TO_LINK_MAP. In absence of an advertised
+		// mapping by the AP, a default TID-to-link mapping is assumed
+		// unless an individual TID-to-link mapping is successfully
+		// negotiated.
+		link.tidsUplinkMap = 0xFF;
+		link.tidsDownlinkMap = 0xFF;
 		linksInfo.links.push_back(link);
 	}
 
diff --git a/wpa_supplicant/aidl/sta_network.cpp b/wpa_supplicant/aidl/sta_network.cpp
index f9f980c..0d5d4e6 100644
--- a/wpa_supplicant/aidl/sta_network.cpp
+++ b/wpa_supplicant/aidl/sta_network.cpp
@@ -304,6 +304,15 @@
 		in_identity);
 }
 
+::ndk::ScopedAStatus StaNetwork::setStrictConservativePeerMode(
+	bool in_enable)
+{
+	return validateAndCall(
+		this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+		&StaNetwork::setStrictConservativePeerModeInternal,
+		in_enable);
+}
+
 ::ndk::ScopedAStatus StaNetwork::setEapAnonymousIdentity(
 	const std::vector<uint8_t>& in_identity)
 {
@@ -1246,6 +1255,13 @@
 	return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus StaNetwork::setStrictConservativePeerModeInternal(bool enable)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	wpa_ssid->eap.strict_conservative_peer_mode = enable ? 1 : 0;
+	return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus StaNetwork::setEapAnonymousIdentityInternal(
 	const std::vector<uint8_t> &identity)
 {
diff --git a/wpa_supplicant/aidl/sta_network.h b/wpa_supplicant/aidl/sta_network.h
index 6661130..f794844 100644
--- a/wpa_supplicant/aidl/sta_network.h
+++ b/wpa_supplicant/aidl/sta_network.h
@@ -85,6 +85,8 @@
 		const std::vector<uint8_t>& in_identity) override;
 	::ndk::ScopedAStatus setEapEncryptedImsiIdentity(
 		const std::vector<uint8_t>& in_identity) override;
+	::ndk::ScopedAStatus setStrictConservativePeerMode(
+		bool in_enable) override;
 	::ndk::ScopedAStatus setEapAnonymousIdentity(
 		const std::vector<uint8_t>& in_identity) override;
 	::ndk::ScopedAStatus setEapPassword(
@@ -212,6 +214,8 @@
 		const std::vector<uint8_t>& identity);
 	ndk::ScopedAStatus setEapEncryptedImsiIdentityInternal(
 		const std::vector<uint8_t>& identity);
+	ndk::ScopedAStatus setStrictConservativePeerModeInternal(
+		bool enable);
 	ndk::ScopedAStatus setEapAnonymousIdentityInternal(
 		const std::vector<uint8_t>& identity);
 	ndk::ScopedAStatus setEapPasswordInternal(
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 065b6fb..2b1bdeb 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2529,6 +2529,7 @@
 	{ INTe(sim_num, sim_num) },
 	{ STRe(imsi_privacy_cert, imsi_privacy_cert) },
 	{ STRe(imsi_privacy_attr, imsi_privacy_attr) },
+	{ INTe(strict_conservative_peer_mode, strict_conservative_peer_mode) },
 	{ STRe(openssl_ciphers, openssl_ciphers) },
 	{ INTe(erp, erp) },
 #endif /* IEEE8021X_EAPOL */
@@ -3953,6 +3954,11 @@
 		return 0;
 	}
 
+	if (os_strcmp(var, "strict_conservative_peer_mode") == 0) {
+		cred->strict_conservative_peer_mode = atoi(val);
+		return 0;
+	}
+
 	if (line) {
 		wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
 			   line, var);
@@ -4109,6 +4115,9 @@
 	if (os_strcmp(var, "imsi_privacy_attr") == 0)
 		return alloc_strdup(cred->imsi_privacy_attr);
 
+	if (os_strcmp(var, "strict_conservative_peer_mode") == 0)
+		return alloc_int_str(cred->strict_conservative_peer_mode);
+
 	if (os_strcmp(var, "milenage") == 0) {
 		if (!(cred->milenage))
 			return NULL;
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index a81e9eb..0316e9b 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -202,6 +202,18 @@
 	char *imsi_privacy_attr;
 
 	/**
+	 * strict_conservative_peer_mode - Whether the strict conservative peer
+	 * mode is enabled or not
+	 *
+	 * This field is used to handle the reponse of AT_PERMANENT_ID_REQ
+	 * for EAP-SIM/AKA/AKA', in convervative peer mode, a client error would
+	 * be sent to the server, but it allows to send the permanent identity
+	 * in some special cases according to 4.6.2 of RFC 4187; With the strict
+	 * mode, it never send the permanent identity to server for privacy concern.
+	 */
+	int strict_conservative_peer_mode;
+
+	/**
 	 * engine - Use an engine for private key operations
 	 */
 	int engine;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 260df8f..372a57b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1044,6 +1044,9 @@
 	if (cred->imsi_privacy_attr)
 		fprintf(f, "\timsi_privacy_attr=\"%s\"\n",
 			cred->imsi_privacy_attr);
+	if (cred->strict_conservative_peer_mode)
+		fprintf(f,"\tstrict_conservative_peer_mode=\"%d\"\n",
+			cred->strict_conservative_peer_mode);
 }
 
 
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 6198bd7..acd9044 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1077,6 +1077,12 @@
 			goto fail;
 	}
 
+	if (cred->strict_conservative_peer_mode) {
+		if (wpa_config_set_quoted(ssid, "strict_conservative_peer_mode",
+					  "1") < 0)
+			goto fail;
+	}
+
 	wpa_s->next_ssid = ssid;
 	wpa_config_update_prio_list(wpa_s->conf);
 	if (!only_add)
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 8262eef..b6a1a74 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1175,6 +1175,14 @@
 #	unencrypted identity with EAP types that support different tunnelled
 #	identity, e.g., EAP-TTLS). This field can also be used with
 #	EAP-SIM/AKA/AKA' to store the pseudonym identity.
+# strict_conservative_peer_mode: Whether the strict conservative peer mode
+#	is enabled. This field is used to handle the reponse of AT_PERMANENT_ID_REQ
+#	for EAP-SIM/AKA/AKA'. In non-strict convervative peer mode, a client
+#	error would be sent to the server, but the mode will send the permanent
+#	identity in some special cases according to 4.6.2 of RFC 4187; With the
+#	strict mode, the permanent identity is never sent to the server.
+#	0 = disabled (default)
+#	1 = enabled
 # password: Password string for EAP. This field can include either the
 #	plaintext password (using ASCII or hex string) or a NtPasswordHash
 #	(16-byte MD4 hash of password) in hash:<32 hex digits> format.