Cumulative patch from commit f89c32e63f71e66d7b55e284016762b603ae02db

f89c32e Android: Fix max number of sched scan SSIDs based on driver capability
f1a5a34 binder: Implement interface add/remove methods
7b4bbb9 binder: Add binder skeletal code for Android
5914ebf Remove struct ieee80211_mgmt::u.probe_req
094e949 atheros: Do not use struct ieee80211_mgmt::u.probe_req
c01120a wpa_supplicant: Do not use struct ieee80211_mgmt::u.probe_req
e1b9962 AP: Do not use struct ieee80211_mgmt::u.probe_req
5cd317d Do not clear PMKSA entry or EAP session cache if config does not change
f933216 Revert "Assign QCA vendor command and attribute for Tx/Rx aggregation"
bde9a4e Comment out UDP/UNIX socket code from common ctrl_iface based on build
a6fbff2 Fix CONFIG_CTRL_IFACE=udp6/udp6-remote builds
0741c48 SAE: Check SHA256-PRF operation result
ea86a34 SAE: Remove dead code in FFC pwd-value derivation
87faf1f nl80211: Fix libnl-tiny build with CONFIG_LIBNL20=y
31afdd2 Use TIOCOUTQ instead of SIOCOUTQ to avoid need for linux/sockios.h
6d07e76 wlantest: Use local ETH_P_IP define instead of linux/if_ether.h
795abc8 Drop USE_KERNEL_HEADERS define
9b7cd57 Use a separate header file for Linux bridge interface definitions
c815fab Use own header file for defining Linux VLAN kernel interface
81606ab vlan: Fix musl libc conflict with Linux kernel headers
f347429 P2P: Fix persistent group for 60 GHz networks
e868599 vlan: Move if_nametoindex() use out of vlan_init.c
7c03c08 vlan: Move ifconfig helpers to a separate file
59d6390 vlan: Move CONFIG_FULL_DYNAMIC_VLAN functionality into a separate file
0fe28dd vlan: Remove unnecessary header includes from netlink implementation
84d6755 vlan: Clean up netlink vs. ioctl API implementation
cb38bc8 vlan: Fix musl build error
954e10e Make it a bit easier to roam from 2.4 GHz to 5 GHz within ESS
585141b Fix a typo in a comment
1126c07 nl80211: Ignore deauth/disassoc event during Connect reassociation
6a5ee81 Include previous BSSID in connection request to indicate reassociation
00c3c4a nl80211: Add NL80211_ATTR_PREV_BSSID with Connect command
cbc3d6f WNM: Verify BSS TM target match against the current network profile
8854f90 mesh: Simplify wpa_auth_pmksa_set_to_sm()
32d4fe9 privsep: Fix a compiler warning on unsigned/signed comparison
2e997ee Add interface matching support with -M, guarded by CONFIG_MATCH_IFACE
45e3fc7 Find correct driver for interface additions/removals
9037702 wpa_supplicant: Fix CONFIG_IBSS_RSN=y build without CONFIG_AP=y
5ae65de wpa_supplicant: Fix p2p_group_add when UDP-based ctrl_iface is used
24bce46 FST: Fix a compiler warning
e567c58 Fix nfc_pw_token build with CONFIG_FST=y
d774c46 mesh: Use appropriate BLOCKED state duration
9f2cf23 mesh: Add support for PMKSA caching
4c522c7 PMKSA: Flush AP/mesh PMKSA cache by PMKSA_FLUSH command
b8daac1 PMKSA: Show AP/mesh PMKSA list in PMKSA command
2604edb mesh: Add MESH_PEER_ADD command
e174ef3 mesh: Add MESH_PEER_REMOVE command
f7648c8 P2P: Advertise IP Address Allocation only if it is enabled on GO
7f46ad9 BSD: Only down the interface once we are sure we can work with it
192964d Handle OSEN IE in Assoc Request info if req_ies exists
29eddc3 nl80211: Fix error path in if_indices_reason reallocation
ee298f1 nl80211: Do not add NL80211_ATTR_SMPS_MODE attribute if HT is disabled
4ca16b5 Assign QCA vendor command and attribute for Tx/Rx aggregation
64ce590 libxml2: Check for xmlDocDumpFormatMemory() error case
8b827c3 BoringSSL: Keep static analyzers happier with X509_get0_pubkey_bitstr()
42a9553 hs20-osu-client: Fix pol_upd command line parsing
ec1eae8 hs20-osu-client: Remove dead code from sub_rem command line parsing
c3dc68e Do not invalidate EAP session cache on all network block parameter changes
9231c24 wlantest: Fix bip_protect() memory allocation
c6c29be Interworking: Add credential realm to EAP-TLS identity

Change-Id: I870f325171d00fed9c4fcd82a695fe5e2efee792
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 796977b..4376676 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -32,7 +32,11 @@
 	/* Configuration variable name */
 	char *name;
 
-	/* Parser function for this variable */
+	/* Parser function for this variable. The parser functions return 0 or 1
+	 * to indicate success. Value 0 indicates that the parameter value may
+	 * have changed while value 1 means that the value did not change.
+	 * Error cases (failure to parse the string) are indicated by returning
+	 * -1. */
 	int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
 		      int line, const char *value);
 
@@ -59,7 +63,7 @@
 				struct wpa_ssid *ssid,
 				int line, const char *value)
 {
-	size_t res_len, *dst_len;
+	size_t res_len, *dst_len, prev_len;
 	char **dst, *tmp;
 
 	if (os_strcmp(value, "NULL") == 0) {
@@ -105,6 +109,21 @@
 set:
 	dst = (char **) (((u8 *) ssid) + (long) data->param1);
 	dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
+
+	if (data->param2)
+		prev_len = *dst_len;
+	else if (*dst)
+		prev_len = os_strlen(*dst);
+	else
+		prev_len = 0;
+	if ((*dst == NULL && tmp == NULL) ||
+	    (*dst && tmp && prev_len == res_len &&
+	     os_memcmp(*dst, tmp, res_len) == 0)) {
+		/* No change to the previously configured value */
+		os_free(tmp);
+		return 1;
+	}
+
 	os_free(*dst);
 	*dst = tmp;
 	if (data->param2)
@@ -190,6 +209,9 @@
 			   line, value);
 		return -1;
 	}
+
+	if (*dst == val)
+		return 1;
 	*dst = val;
 	wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
 
@@ -457,8 +479,10 @@
 		wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
 				      (u8 *) value, len);
 		if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
-		    os_memcmp(ssid->passphrase, value, len) == 0)
-			return 0;
+		    os_memcmp(ssid->passphrase, value, len) == 0) {
+			/* No change to the previously configured value */
+			return 1;
+		}
 		ssid->psk_set = 0;
 		str_clear_free(ssid->passphrase);
 		ssid->passphrase = dup_binstr(value, len);
@@ -569,6 +593,8 @@
 		errors++;
 	}
 
+	if (!errors && ssid->proto == val)
+		return 1;
 	wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
 	ssid->proto = val;
 	return errors ? -1 : 0;
@@ -705,6 +731,8 @@
 		errors++;
 	}
 
+	if (!errors && ssid->key_mgmt == val)
+		return 1;
 	wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
 	ssid->key_mgmt = val;
 	return errors ? -1 : 0;
@@ -953,6 +981,8 @@
 		return -1;
 	}
 
+	if (ssid->pairwise_cipher == val)
+		return 1;
 	wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
 	ssid->pairwise_cipher = val;
 	return 0;
@@ -989,6 +1019,8 @@
 		return -1;
 	}
 
+	if (ssid->group_cipher == val)
+		return 1;
 	wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
 	ssid->group_cipher = val;
 	return 0;
@@ -1050,6 +1082,8 @@
 		errors++;
 	}
 
+	if (!errors && ssid->auth_alg == val)
+		return 1;
 	wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
 	ssid->auth_alg = val;
 	return errors ? -1 : 0;
@@ -1304,6 +1338,32 @@
 	methods[num_methods].method = EAP_TYPE_NONE;
 	num_methods++;
 
+	if (!errors && ssid->eap.eap_methods) {
+		struct eap_method_type *prev_m;
+		size_t i, j, prev_methods, match = 0;
+
+		prev_m = ssid->eap.eap_methods;
+		for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF ||
+			     prev_m[i].method != EAP_TYPE_NONE; i++) {
+			/* Count the methods */
+		}
+		prev_methods = i + 1;
+
+		for (i = 0; prev_methods == num_methods && i < prev_methods;
+		     i++) {
+			for (j = 0; j < num_methods; j++) {
+				if (prev_m[i].vendor == methods[j].vendor &&
+				    prev_m[i].method == methods[j].method) {
+					match++;
+					break;
+				}
+			}
+		}
+		if (match == num_methods) {
+			os_free(methods);
+			return 1;
+		}
+	}
 	wpa_hexdump(MSG_MSGDUMP, "eap methods",
 		    (u8 *) methods, num_methods * sizeof(*methods));
 	os_free(ssid->eap.eap_methods);
@@ -1356,6 +1416,8 @@
 	u8 *hash;
 
 	if (os_strcmp(value, "NULL") == 0) {
+		if (!ssid->eap.password)
+			return 1; /* Already unset */
 		wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
 		bin_clear_free(ssid->eap.password, ssid->eap.password_len);
 		ssid->eap.password = NULL;
@@ -1419,6 +1481,12 @@
 
 	wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
 
+	if (ssid->eap.password && ssid->eap.password_len == 16 &&
+	    os_memcmp(ssid->eap.password, hash, 16) == 0 &&
+	    (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+		bin_clear_free(hash, 16);
+		return 1;
+	}
 	bin_clear_free(ssid->eap.password, ssid->eap.password_len);
 	ssid->eap.password = hash;
 	ssid->eap.password_len = 16;
@@ -2472,7 +2540,8 @@
  * @var: Variable name, e.g., "ssid"
  * @value: Variable value
  * @line: Line number in configuration file or 0 if not used
- * Returns: 0 on success, -1 on failure
+ * Returns: 0 on success with possible change in the value, 1 on success with
+ * no change to previously configured value, or -1 on failure
  *
  * This function can be used to set network configuration variables based on
  * both the configuration file and management interface input. The value
@@ -2493,7 +2562,8 @@
 		if (os_strcmp(var, field->name) != 0)
 			continue;
 
-		if (field->parser(field, ssid, line, value)) {
+		ret = field->parser(field, ssid, line, value);
+		if (ret < 0) {
 			if (line) {
 				wpa_printf(MSG_ERROR, "Line %d: failed to "
 					   "parse %s '%s'.", line, var, value);