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/Android.mk b/wpa_supplicant/Android.mk
index 4f0319e..f65076c 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -269,6 +269,7 @@
 ifdef CONFIG_IBSS_RSN
 NEED_RSN_AUTHENTICATOR=y
 L_CFLAGS += -DCONFIG_IBSS_RSN
+L_CFLAGS += -DCONFIG_NO_VLAN
 OBJS += ibss_rsn.c
 endif
 
@@ -1345,6 +1346,16 @@
 OBJS += $(DBUS_OBJS)
 L_CFLAGS += $(DBUS_CFLAGS)
 
+ifdef CONFIG_CTRL_IFACE_BINDER
+BINDER=y
+L_CFLAGS += -DCONFIG_BINDER -DCONFIG_CTRL_IFACE_BINDER
+OBJS += binder/binder.cpp binder/binder_manager.cpp
+OBJS += binder/supplicant.cpp binder/iface.cpp
+OBJS += binder/fi/w1/wpa_supplicant/ISupplicant.aidl
+OBJS += binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
+OBJS += binder/fi/w1/wpa_supplicant/IIface.aidl
+endif
+
 ifdef CONFIG_READLINE
 OBJS_c += src/utils/edit_readline.c
 LIBS_c += -lncurses -lreadline
@@ -1582,6 +1593,10 @@
 ifeq ($(DBUS), y)
 LOCAL_SHARED_LIBRARIES += libdbus
 endif
+ifeq ($(BINDER), y)
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder frameworks/native/aidl/binder
+LOCAL_SHARED_LIBRARIES += libutils libbinder
+endif
 include $(BUILD_EXECUTABLE)
 
 ########################
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 8fa2b5a..550d44b 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -312,9 +312,14 @@
 ifdef CONFIG_IBSS_RSN
 NEED_RSN_AUTHENTICATOR=y
 CFLAGS += -DCONFIG_IBSS_RSN
+CFLAGS += -DCONFIG_NO_VLAN
 OBJS += ibss_rsn.o
 endif
 
+ifdef CONFIG_MATCH_IFACE
+CFLAGS += -DCONFIG_MATCH_IFACE
+endif
+
 ifdef CONFIG_P2P
 OBJS += p2p_supplicant.o
 OBJS += p2p_supplicant_sd.o
@@ -1637,6 +1642,7 @@
 OBJS += $(FST_OBJS)
 OBJS_t += $(FST_OBJS)
 OBJS_t2 += $(FST_OBJS)
+OBJS_nfc += $(FST_OBJS)
 endif
 
 ifndef LDO
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index fefc0d3..11ab01a 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -410,7 +410,7 @@
   wpa_supplicant [-BddfhKLqqtuvW] [-P<pid file>] [-g<global ctrl>] \
         [-G<group>] \
         -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
-        [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
+        [-b<br_ifname> [-MN -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
         [-p<driver_param>] [-b<br_ifname>] [-m<P2P Device config file>] ...
 
 options:
@@ -434,6 +434,7 @@
   -u = enable DBus control interface
   -v = show version
   -W = wait for a control interface monitor before starting
+  -M = start describing matching interface
   -N = start describing new interface
   -m = Configuration file for the P2P Device
 
@@ -476,6 +477,22 @@
 	-c wpa2.conf -i wlan1 -D wext
 
 
+If the interfaces on which wpa_supplicant is to run are not known or do
+not exist, wpa_supplicant can match an interface when it arrives. Each
+matched interface is separated with -M argument and the -i argument now
+allows for pattern matching.
+
+As an example, the following command would start wpa_supplicant for a
+specific wired interface called lan0, any interface starting with wlan
+and lastly any other interface. Each match has its own configuration
+file, and for the wired interface a specific driver has also been given.
+
+wpa_supplicant \
+	-M -c wpa_wired.conf -ilan0 -D wired \
+	-M -c wpa1.conf -iwlan* \
+	-M -c wpa2.conf
+
+
 If the interface is added in a Linux bridge (e.g., br0), the bridge
 interface needs to be configured to wpa_supplicant in addition to the
 main interface:
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 190bc5a..0a8bf98 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -324,6 +324,10 @@
 # Add introspection support for new DBus control interface
 #CONFIG_CTRL_IFACE_DBUS_INTRO=y
 
+# Add support for Binder control interface
+# Only applicable for Android platforms.
+#CONFIG_CTRL_IFACE_BINDER=y
+
 # Add support for loading EAP methods dynamically as shared libraries.
 # When this option is enabled, each EAP method can be either included
 # statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index fd5b03f..b133d03 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -1366,6 +1366,58 @@
 #endif /* CONFIG_CTRL_IFACE */
 
 
+int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
+			     size_t len)
+{
+	size_t reply_len = 0, i;
+	char ap_delimiter[] = "---- AP ----\n";
+	char mesh_delimiter[] = "---- mesh ----\n";
+	size_t dlen;
+
+	if (wpa_s->ap_iface) {
+		dlen = os_strlen(ap_delimiter);
+		if (dlen > len - reply_len)
+			return reply_len;
+		os_memcpy(&buf[reply_len], ap_delimiter, dlen);
+		reply_len += dlen;
+
+		for (i = 0; i < wpa_s->ap_iface->num_bss; i++) {
+			reply_len += hostapd_ctrl_iface_pmksa_list(
+				wpa_s->ap_iface->bss[i],
+				&buf[reply_len], len - reply_len);
+		}
+	}
+
+	if (wpa_s->ifmsh) {
+		dlen = os_strlen(mesh_delimiter);
+		if (dlen > len - reply_len)
+			return reply_len;
+		os_memcpy(&buf[reply_len], mesh_delimiter, dlen);
+		reply_len += dlen;
+
+		reply_len += hostapd_ctrl_iface_pmksa_list(
+			wpa_s->ifmsh->bss[0], &buf[reply_len],
+			len - reply_len);
+	}
+
+	return reply_len;
+}
+
+
+void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s)
+{
+	size_t i;
+
+	if (wpa_s->ap_iface) {
+		for (i = 0; i < wpa_s->ap_iface->num_bss; i++)
+			hostapd_ctrl_iface_pmksa_flush(wpa_s->ap_iface->bss[i]);
+	}
+
+	if (wpa_s->ifmsh)
+		hostapd_ctrl_iface_pmksa_flush(wpa_s->ifmsh->bss[0]);
+}
+
+
 #ifdef NEED_AP_MLME
 void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
 				   struct dfs_event *radar)
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 2b8a1d4..5a59ddc 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -82,6 +82,10 @@
 
 int wpas_ap_stop_ap(struct wpa_supplicant *wpa_s);
 
+int wpas_ap_pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf,
+			     size_t len);
+void wpas_ap_pmksa_cache_flush(struct wpa_supplicant *wpa_s);
+
 void wpas_event_dfs_radar_detected(struct wpa_supplicant *wpa_s,
 				   struct dfs_event *radar);
 void wpas_event_dfs_cac_started(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/binder/binder.cpp b/wpa_supplicant/binder/binder.cpp
new file mode 100644
index 0000000..28f7a2b
--- /dev/null
+++ b/wpa_supplicant/binder/binder.cpp
@@ -0,0 +1,108 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
+#include "binder_manager.h"
+
+extern "C" {
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "binder.h"
+#include "binder_i.h"
+}
+
+void wpas_binder_sock_handler(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_global *global = (wpa_global *) eloop_ctx;
+	struct wpas_binder_priv *priv = (wpas_binder_priv *) sock_ctx;
+
+	wpa_printf(MSG_DEBUG, "Processing binder events on FD %d",
+		   priv->binder_fd);
+	android::IPCThreadState::self()->handlePolledCommands();
+}
+
+
+struct wpas_binder_priv * wpas_binder_init(struct wpa_global *global)
+{
+	struct wpas_binder_priv *priv;
+	wpa_supplicant_binder::BinderManager *binder_manager;
+
+	priv = (wpas_binder_priv *) os_zalloc(sizeof(*priv));
+	if (!priv)
+		return NULL;
+	priv->global = global;
+
+	android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
+	android::IPCThreadState::self()->disableBackgroundScheduling(true);
+	android::IPCThreadState::self()->setupPolling(&priv->binder_fd);
+	wpa_printf(MSG_INFO, "Process binder events on FD %d", priv->binder_fd);
+	if (priv->binder_fd < 0)
+		goto err;
+	/* Look for read events from the binder socket in the eloop. */
+	if (eloop_register_read_sock(priv->binder_fd, wpas_binder_sock_handler,
+				     global, priv) < 0)
+		goto err;
+
+	binder_manager = wpa_supplicant_binder::BinderManager::getInstance();
+	if (!binder_manager)
+		goto err;
+	binder_manager->registerBinderService(global);
+	/* We may not need to store this binder manager reference in the
+	 * global data strucure because we've made it a singleton class. */
+	priv->binder_manager = (void *) binder_manager;
+
+	return priv;
+
+err:
+	wpas_binder_deinit(priv);
+	return NULL;
+}
+
+
+void wpas_binder_deinit(struct wpas_binder_priv *priv)
+{
+	if (!priv)
+		return;
+
+	wpa_supplicant_binder::BinderManager::destroyInstance();
+	eloop_unregister_read_sock(priv->binder_fd);
+	android::IPCThreadState::shutdown();
+}
+
+
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->global->binder)
+		return 1;
+
+	wpa_supplicant_binder::BinderManager *binder_manager =
+		wpa_supplicant_binder::BinderManager::getInstance();
+	if (!binder_manager)
+		return 1;
+
+	return binder_manager->registerInterface(wpa_s);
+}
+
+
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->global->binder)
+		return 1;
+
+	wpa_supplicant_binder::BinderManager *binder_manager =
+		wpa_supplicant_binder::BinderManager::getInstance();
+	if (!binder_manager)
+		return 1;
+
+	return binder_manager->unregisterInterface(wpa_s);
+}
diff --git a/wpa_supplicant/binder/binder.h b/wpa_supplicant/binder/binder.h
new file mode 100644
index 0000000..a165074
--- /dev/null
+++ b/wpa_supplicant/binder/binder.h
@@ -0,0 +1,46 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BINDER_H
+#define BINDER_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif /* _cplusplus */
+
+/**
+ * This is the binder RPC interface entry point to the wpa_supplicant core.
+ * This initializes the binder driver & BinderManager instance and then forwards
+ * all the notifcations from the supplicant core to the BinderManager.
+ */
+struct wpas_binder_priv;
+struct wpa_global;
+
+struct wpas_binder_priv * wpas_binder_init(struct wpa_global *global);
+void wpas_binder_deinit(struct wpas_binder_priv *priv);
+
+#ifdef CONFIG_CTRL_IFACE_BINDER
+int wpas_binder_register_interface(struct wpa_supplicant *wpa_s);
+int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s);
+#else /* CONFIG_CTRL_IFACE_BINDER */
+static inline int wpas_binder_register_interface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+static inline int wpas_binder_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+#endif /* CONFIG_CTRL_IFACE_BINDER */
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* BINDER_H */
diff --git a/wpa_supplicant/binder/binder_i.h b/wpa_supplicant/binder/binder_i.h
new file mode 100644
index 0000000..e8087b6
--- /dev/null
+++ b/wpa_supplicant/binder/binder_i.h
@@ -0,0 +1,27 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BINDER_I_H
+#define BINDER_I_H
+
+#ifdef _cplusplus
+extern "C" {
+#endif // _cplusplus
+
+struct wpas_binder_priv {
+	int binder_fd;
+	struct wpa_global *global;
+	void *binder_manager;
+};
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+#endif /* BINDER_I_H */
diff --git a/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant/binder/binder_manager.cpp
new file mode 100644
index 0000000..728f4b7
--- /dev/null
+++ b/wpa_supplicant/binder/binder_manager.cpp
@@ -0,0 +1,107 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <binder/IServiceManager.h>
+
+#include "binder_manager.h"
+
+extern "C" {
+#include "utils/includes.h"
+#include "utils/common.h"
+}
+
+namespace wpa_supplicant_binder {
+
+const char BinderManager::kBinderServiceName[] = "fi.w1.wpa_supplicant";
+BinderManager *BinderManager::instance_ = NULL;
+
+
+BinderManager * BinderManager::getInstance()
+{
+	if (!instance_)
+		instance_ = new BinderManager();
+	return instance_;
+}
+
+
+void BinderManager::destroyInstance()
+{
+	if (instance_)
+		delete instance_;
+	instance_ = NULL;
+}
+
+
+int BinderManager::registerBinderService(struct wpa_global *global)
+{
+	/* Create the main binder service object and register with
+	 * system service manager. */
+	supplicant_object_ = new Supplicant(global);
+	android::String16 service_name(kBinderServiceName);
+	android::defaultServiceManager()->addService(
+		service_name,
+		android::IInterface::asBinder(supplicant_object_));
+	return 0;
+}
+
+
+int BinderManager::registerInterface(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s)
+		return 1;
+
+	/* Using the corresponding wpa_supplicant pointer as key to our
+	 * object map. */
+	const void *iface_key = wpa_s;
+
+	/* Return failure if we already have an object for that iface_key. */
+	if (iface_object_map_.find(iface_key) != iface_object_map_.end())
+		return 1;
+
+	iface_object_map_[iface_key] = new Iface(wpa_s);
+	if (!iface_object_map_[iface_key].get())
+		return 1;
+
+	wpa_s->binder_object_key = iface_key;
+
+	return 0;
+}
+
+
+int BinderManager::unregisterInterface(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s || !wpa_s->binder_object_key)
+		return 1;
+
+	const void *iface_key = wpa_s;
+	if (iface_object_map_.find(iface_key) == iface_object_map_.end())
+		return 1;
+
+	/* Delete the corresponding iface object from our map. */
+	iface_object_map_.erase(iface_key);
+	wpa_s->binder_object_key = NULL;
+	return 0;
+}
+
+
+int BinderManager::getIfaceBinderObjectByKey(
+	const void *iface_object_key,
+	android::sp<fi::w1::wpa_supplicant::IIface> *iface_object)
+{
+	if (!iface_object_key || !iface_object)
+		return 1;
+
+	if (iface_object_map_.find(iface_object_key) == iface_object_map_.end())
+		return 1;
+
+	*iface_object = iface_object_map_[iface_object_key];
+	return 0;
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h
new file mode 100644
index 0000000..687e740
--- /dev/null
+++ b/wpa_supplicant/binder/binder_manager.h
@@ -0,0 +1,59 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BINDER_MANAGER_H
+#define BINDER_MANAGER_H
+
+#include <map>
+#include <string>
+
+#include "supplicant.h"
+#include "iface.h"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+namespace wpa_supplicant_binder {
+
+/**
+ * BinderManager is responsible for managing the lifetime of all
+ * binder objects created by wpa_supplicant. This is a singleton
+ * class which is created by the supplicant core and can be used
+ * to get references to the binder objects.
+ */
+class BinderManager {
+public:
+	static const char kBinderServiceName[];
+
+	static BinderManager * getInstance();
+	static void destroyInstance();
+	int registerBinderService(struct wpa_global *global);
+	int registerInterface(struct wpa_supplicant *wpa_s);
+	int unregisterInterface(struct wpa_supplicant *wpa_s);
+	int getIfaceBinderObjectByKey(
+		const void *iface_object_key,
+		android::sp<fi::w1::wpa_supplicant::IIface> *iface_object);
+
+private:
+	BinderManager() = default;
+	~BinderManager() = default;
+
+	/* Singleton instance of this class. */
+	static BinderManager *instance_;
+	/* The main binder service object. */
+	android::sp<Supplicant> supplicant_object_;
+	/* Map of all the interface specific binder objects controlled by
+	 * wpa_supplicant. This map is keyed in by the corresponding
+	 * wpa_supplicant structure pointer. */
+	std::map<const void *, android::sp<Iface>> iface_object_map_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* BINDER_MANAGER_H */
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
new file mode 100644
index 0000000..ea11d42
--- /dev/null
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/IIface.aidl
@@ -0,0 +1,16 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+/**
+ * Interface exposed by wpa_supplicant for each network interface it controls.
+ */
+interface IIface {
+}
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
new file mode 100644
index 0000000..1cbee20
--- /dev/null
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicant.aidl
@@ -0,0 +1,59 @@
+/*
+ * WPA Supplicant - binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+import android.os.PersistableBundle;
+import fi.w1.wpa_supplicant.IIface;
+
+/**
+ * Interface exposed by the wpa_supplicant binder service registered
+ * with the service manager with name: fi.w1.wpa_supplicant.
+ */
+interface ISupplicant {
+	/* Error values returned by the service to RPC method calls. */
+	const int ERROR_INVALID_ARGS = 1;
+	const int ERROR_UNKNOWN = 2;
+	const int ERROR_IFACE_EXISTS = 3;
+	const int ERROR_IFACE_UNKNOWN = 4;
+
+	/**
+	 * Registers a wireless interface in wpa_supplicant.
+	 *
+	 * @param args A dictionary with arguments used to add the interface to
+	 *             wpa_supplicant.
+	 * The dictionary may contain the following entries:
+	 *   Ifname(String) Name of the network interface to control, e.g.,
+	 *   wlan0.
+	 *   BridgeIfname(String) Name of the bridge interface to control, e.g.,
+	 *   br0.
+	 *   Driver(String) Driver name which the interface uses, e.g., nl80211.
+	 *   ConfigFile(String) Configuration file path.
+	 *
+	 * @return Binder object representing the interface.
+	 */
+	IIface CreateInterface(in PersistableBundle args);
+
+	/**
+	 * Deregisters a wireless interface from wpa_supplicant.
+	 *
+	 * @param ifname Name of the network interface, e.g., wlan0
+	 */
+	void RemoveInterface(in @utf8InCpp String ifname);
+
+	/**
+	 * Gets a binder object for the interface corresponding to ifname
+	 * which wpa_supplicant already controls.
+	 *
+	 * @param ifname Name of the network interface, e.g., wlan0
+	 *
+	 * @return Binder object representing the interface.
+	 */
+	IIface GetInterface(in @utf8InCpp String ifname);
+}
diff --git a/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
new file mode 100644
index 0000000..d624d91
--- /dev/null
+++ b/wpa_supplicant/binder/fi/w1/wpa_supplicant/ISupplicantCallbacks.aidl
@@ -0,0 +1,20 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+package fi.w1.wpa_supplicant;
+
+import android.os.PersistableBundle;
+
+/**
+ * Callback Interface exposed by the wpa_supplicant service. Clients need
+ * to host an instance of this binder object and pass a reference of the object
+ * to wpa_supplicant via the registerCallbacksObject method.
+ */
+interface ISupplicantCallbacks {
+}
diff --git a/wpa_supplicant/binder/iface.cpp b/wpa_supplicant/binder/iface.cpp
new file mode 100644
index 0000000..af2548d
--- /dev/null
+++ b/wpa_supplicant/binder/iface.cpp
@@ -0,0 +1,19 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "iface.h"
+
+namespace wpa_supplicant_binder {
+
+Iface::Iface(struct wpa_supplicant *wpa_s)
+	: wpa_s_(wpa_s)
+{
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/iface.h b/wpa_supplicant/binder/iface.h
new file mode 100644
index 0000000..acc8e55
--- /dev/null
+++ b/wpa_supplicant/binder/iface.h
@@ -0,0 +1,42 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IFACE_H
+#define IFACE_H
+
+#include "fi/w1/wpa_supplicant/BnIface.h"
+
+extern "C" {
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "../wpa_supplicant_i.h"
+}
+
+namespace wpa_supplicant_binder {
+
+/**
+ * Implementation of Iface binder object. Each unique binder
+ * object is used for control operations on a specific interface
+ * controlled by wpa_supplicant.
+ */
+class Iface : public fi::w1::wpa_supplicant::BnIface
+{
+public:
+	Iface(struct wpa_supplicant *wpa_s);
+	virtual ~Iface() = default;
+
+private:
+	/* Raw pointer to the structure maintained by the core for this
+	 * interface. */
+	struct wpa_supplicant *wpa_s_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* IFACE_H */
diff --git a/wpa_supplicant/binder/supplicant.cpp b/wpa_supplicant/binder/supplicant.cpp
new file mode 100644
index 0000000..6844e5a
--- /dev/null
+++ b/wpa_supplicant/binder/supplicant.cpp
@@ -0,0 +1,125 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "binder_manager.h"
+#include "supplicant.h"
+
+namespace wpa_supplicant_binder {
+
+Supplicant::Supplicant(struct wpa_global *global)
+	: wpa_global_(global)
+{
+}
+
+
+android::binder::Status Supplicant::CreateInterface(
+	const android::os::PersistableBundle &params,
+	android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+	android::String16 driver, ifname, confname, bridge_ifname;
+
+	/* Check if required Ifname argument is missing */
+	if (!params.getString(android::String16("Ifname"), &ifname))
+		return android::binder::Status::fromServiceSpecificError(
+			ERROR_INVALID_ARGS,
+			android::String8("Ifname missing in params."));
+	/* Retrieve the remaining params from the dictionary */
+	params.getString(android::String16("Driver"), &driver);
+	params.getString(android::String16("ConfigFile"), &confname);
+	params.getString(android::String16("BridgeIfname"), &bridge_ifname);
+
+	/*
+	 * Try to get the wpa_supplicant record for this iface, return
+	 * an error if we already control it.
+	 */
+	if (wpa_supplicant_get_iface(wpa_global_,
+				     android::String8(ifname).string()) != NULL)
+		return android::binder::Status::fromServiceSpecificError(
+			ERROR_IFACE_EXISTS,
+			android::String8("wpa_supplicant already controls this interface."));
+
+	android::binder::Status status;
+	struct wpa_supplicant *wpa_s = NULL;
+	struct wpa_interface iface;
+
+	os_memset(&iface, 0, sizeof(iface));
+	iface.driver = os_strdup(android::String8(driver).string());
+	iface.ifname = os_strdup(android::String8(ifname).string());
+	iface.confname = os_strdup(android::String8(confname).string());
+	iface.bridge_ifname = os_strdup(
+		android::String8(bridge_ifname).string());
+	/* Otherwise, have wpa_supplicant attach to it. */
+	wpa_s = wpa_supplicant_add_iface(wpa_global_, &iface, NULL);
+	/* The supplicant core creates a corresponding binder object via
+	 * BinderManager when |wpa_supplicant_add_iface| is called. */
+	if (!wpa_s || !wpa_s->binder_object_key) {
+		status = android::binder::Status::fromServiceSpecificError(
+			ERROR_UNKNOWN,
+			android::String8("wpa_supplicant couldn't grab this interface."));
+	} else {
+		BinderManager *binder_manager = BinderManager::getInstance();
+
+		if (!binder_manager ||
+		    binder_manager->getIfaceBinderObjectByKey(
+			    wpa_s->binder_object_key, aidl_return))
+			status = android::binder::Status::fromServiceSpecificError(
+				ERROR_UNKNOWN,
+				android::String8("wpa_supplicant encountered a binder error."));
+		else
+			status = android::binder::Status::ok();
+	}
+	os_free((void *) iface.driver);
+	os_free((void *) iface.ifname);
+	os_free((void *) iface.confname);
+	os_free((void *) iface.bridge_ifname);
+	return status;
+}
+
+
+android::binder::Status Supplicant::RemoveInterface(const std::string &ifname)
+{
+	struct wpa_supplicant *wpa_s;
+
+	wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+	if (!wpa_s || !wpa_s->binder_object_key)
+		return android::binder::Status::fromServiceSpecificError(
+			ERROR_IFACE_UNKNOWN,
+			android::String8("wpa_supplicant does not control this interface."));
+	if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0))
+		return android::binder::Status::fromServiceSpecificError(
+			ERROR_UNKNOWN,
+			android::String8("wpa_supplicant couldn't remove this interface."));
+	return android::binder::Status::ok();
+}
+
+
+android::binder::Status Supplicant::GetInterface(
+	const std::string &ifname,
+	android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+{
+	struct wpa_supplicant *wpa_s;
+
+	wpa_s = wpa_supplicant_get_iface(wpa_global_, ifname.c_str());
+	if (!wpa_s || !wpa_s->binder_object_key)
+		return android::binder::Status::fromServiceSpecificError(
+			ERROR_IFACE_UNKNOWN,
+			android::String8("wpa_supplicant does not control this interface."));
+
+	BinderManager *binder_manager = BinderManager::getInstance();
+	if (!binder_manager ||
+	    binder_manager->getIfaceBinderObjectByKey(wpa_s->binder_object_key,
+						      aidl_return))
+		return android::binder::Status::fromServiceSpecificError(
+			ERROR_UNKNOWN,
+			android::String8("wpa_supplicant encountered a binder error."));
+
+	return android::binder::Status::ok();
+}
+
+} /* namespace wpa_supplicant_binder */
diff --git a/wpa_supplicant/binder/supplicant.h b/wpa_supplicant/binder/supplicant.h
new file mode 100644
index 0000000..b96f4e6
--- /dev/null
+++ b/wpa_supplicant/binder/supplicant.h
@@ -0,0 +1,57 @@
+/*
+ * binder interface for wpa_supplicant daemon
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Roshan Pius <rpius@google.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SUPPLICANT_H
+#define SUPPLICANT_H
+
+#include "fi/w1/wpa_supplicant/BnSupplicant.h"
+#include "fi/w1/wpa_supplicant/IIface.h"
+#include "fi/w1/wpa_supplicant/ISupplicantCallbacks.h"
+
+extern "C" {
+#include "utils/includes.h"
+#include "utils/common.h"
+#include "../wpa_supplicant_i.h"
+}
+
+namespace wpa_supplicant_binder {
+
+/**
+ * Implementation of the supplicant binder object. This binder
+ * object is used core for global control operations on
+ * wpa_supplicant.
+ */
+class Supplicant : public fi::w1::wpa_supplicant::BnSupplicant
+{
+public:
+	Supplicant(struct wpa_global *global);
+	virtual ~Supplicant() = default;
+
+	android::binder::Status CreateInterface(
+		const android::os::PersistableBundle &params,
+		android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+		override;
+	android::binder::Status RemoveInterface(
+		const std::string &ifname) override;
+	android::binder::Status GetInterface(
+		const std::string &ifname,
+		android::sp<fi::w1::wpa_supplicant::IIface> *aidl_return)
+		override;
+
+private:
+	/* Raw pointer to the global structure maintained by the core. */
+	struct wpa_global *wpa_global_;
+	/* All the callback objects registered by the clients. */
+	std::vector<android::sp<fi::w1::wpa_supplicant::ISupplicantCallbacks>>
+		callbacks_;
+};
+
+} /* namespace wpa_supplicant_binder */
+
+#endif /* SUPPLICANT_H */
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);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 4e16987..8574437 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2727,6 +2727,40 @@
 	return 0;
 }
 
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_remove(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 addr[ETH_ALEN];
+
+	if (hwaddr_aton(cmd, addr) < 0)
+		return -1;
+
+	return wpas_mesh_peer_remove(wpa_s, addr);
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_peer_add(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	int duration;
+	char *pos;
+
+	pos = os_strstr(cmd, " duration=");
+	if (pos) {
+		*pos = '\0';
+		duration = atoi(pos + 10);
+	} else {
+		duration = -1;
+	}
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	return wpas_mesh_peer_add(wpa_s, addr, duration);
+}
+
 #endif /* CONFIG_MESH */
 
 
@@ -2969,22 +3003,29 @@
 	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
 	char *name, char *value)
 {
-	if (wpa_config_set(ssid, name, value, 0) < 0) {
+	int ret;
+
+	ret = wpa_config_set(ssid, name, value, 0);
+	if (ret < 0) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
 			   "variable '%s'", name);
 		return -1;
 	}
+	if (ret == 1)
+		return 0; /* No change to the previously configured value */
 
 	if (os_strcmp(name, "bssid") != 0 &&
-	    os_strcmp(name, "priority") != 0)
+	    os_strcmp(name, "priority") != 0) {
 		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
 
-	if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
-		/*
-		 * Invalidate the EAP session cache if anything in the current
-		 * or previously used configuration changes.
-		 */
-		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+		if (wpa_s->current_ssid == ssid ||
+		    wpa_s->current_ssid == NULL) {
+			/*
+			 * Invalidate the EAP session cache if anything in the
+			 * current or previously used configuration changes.
+			 */
+			eapol_sm_invalidate_cached_session(wpa_s->eapol);
+		}
 	}
 
 	if ((os_strcmp(name, "psk") == 0 &&
@@ -8328,6 +8369,29 @@
 }
 
 
+static int wpas_ctrl_iface_pmksa(struct wpa_supplicant *wpa_s,
+				 char *buf, size_t buflen)
+{
+	size_t reply_len;
+
+	reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, buf, buflen);
+#ifdef CONFIG_AP
+	reply_len += wpas_ap_pmksa_cache_list(wpa_s, &buf[reply_len],
+					      buflen - reply_len);
+#endif /* CONFIG_AP */
+	return reply_len;
+}
+
+
+static void wpas_ctrl_iface_pmksa_flush(struct wpa_supplicant *wpa_s)
+{
+	wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+#ifdef CONFIG_AP
+	wpas_ap_pmksa_cache_flush(wpa_s);
+#endif /* CONFIG_AP */
+}
+
+
 static int wpas_ctrl_cmd_debug_level(const char *cmd)
 {
 	if (os_strcmp(cmd, "PING") == 0 ||
@@ -8399,10 +8463,9 @@
 		reply_len = wpa_supplicant_ctrl_iface_status(
 			wpa_s, buf + 6, reply, reply_size);
 	} else if (os_strcmp(buf, "PMKSA") == 0) {
-		reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
-						    reply_size);
+		reply_len = wpas_ctrl_iface_pmksa(wpa_s, reply, reply_size);
 	} else if (os_strcmp(buf, "PMKSA_FLUSH") == 0) {
-		wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+		wpas_ctrl_iface_pmksa_flush(wpa_s);
 	} else if (os_strncmp(buf, "SET ", 4) == 0) {
 		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
 			reply_len = -1;
@@ -8570,6 +8633,12 @@
 		if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
 								buf + 18))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "MESH_PEER_REMOVE ", 17) == 0) {
+		if (wpa_supplicant_ctrl_iface_mesh_peer_remove(wpa_s, buf + 17))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "MESH_PEER_ADD ", 14) == 0) {
+		if (wpa_supplicant_ctrl_iface_mesh_peer_add(wpa_s, buf + 14))
+			reply_len = -1;
 #endif /* CONFIG_MESH */
 #ifdef CONFIG_P2P
 	} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 503052a..0dc0937 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / UDP socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -378,6 +378,7 @@
 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
 {
 	struct ctrl_iface_priv *priv;
+	char port_str[40];
 	int port = WPA_CTRL_IFACE_PORT;
 	char *pos;
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
@@ -439,13 +440,21 @@
 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 		port--;
-		if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT &&
-		    !pos)
+		if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
 			goto try_again;
 		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
 		goto fail;
 	}
 
+	/* Update the ctrl_interface value to match the selected port */
+	os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
+	os_free(wpa_s->conf->ctrl_interface);
+	wpa_s->conf->ctrl_interface = os_strdup(port_str);
+	if (!wpa_s->conf->ctrl_interface) {
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface");
+		goto fail;
+	}
+
 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
 	wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
@@ -593,7 +602,11 @@
 	struct ctrl_iface_global_priv *priv = sock_ctx;
 	char buf[256], *pos;
 	int res;
+#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
+	struct sockaddr_in6 from;
+#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 	struct sockaddr_in from;
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 	socklen_t fromlen = sizeof(from);
 	char *reply = NULL;
 	size_t reply_len;
@@ -608,6 +621,7 @@
 	}
 
 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
+#ifndef CONFIG_CTRL_IFACE_UDP_IPV6
 	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
 		/*
 		 * The OS networking stack is expected to drop this kind of
@@ -619,6 +633,7 @@
 			   "source %s", inet_ntoa(from.sin_addr));
 		return;
 	}
+#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 
 	buf[res] = '\0';
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 2fc89a9..4db712f 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -15,7 +15,6 @@
 #include <fcntl.h>
 #ifdef __linux__
 #include <sys/ioctl.h>
-#include <linux/sockios.h>
 #endif /* __linux__ */
 #ifdef ANDROID
 #include <cutils/sockets.h>
@@ -90,7 +89,7 @@
 	if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0)
 		sndbuf = -1;
 
-	if (ioctl(sock, SIOCOUTQ, &outq) < 0)
+	if (ioctl(sock, TIOCOUTQ, &outq) < 0)
 		outq = -1;
 
 	wpa_printf(level,
@@ -289,7 +288,7 @@
 	optlen = sizeof(sndbuf);
 	sndbuf = 0;
 	if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0 ||
-	    ioctl(sock, SIOCOUTQ, &outq) < 0 ||
+	    ioctl(sock, TIOCOUTQ, &outq) < 0 ||
 	    sndbuf <= 0 || outq < 0)
 		return 0;
 	return outq > sndbuf / 2;
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 79632e6..1d05198 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -467,6 +467,9 @@
 # Hotspot 2.0
 #CONFIG_HS20=y
 
+# Enable interface matching in wpa_supplicant
+#CONFIG_MATCH_IFACE=y
+
 # Disable roaming in wpa_supplicant
 #CONFIG_NO_ROAMING=y
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index a84ba2d..6b3a2c0 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1346,6 +1346,7 @@
 	struct wpa_bss *current_bss = NULL;
 #ifndef CONFIG_NO_ROAMING
 	int min_diff;
+	int to_5ghz;
 #endif /* CONFIG_NO_ROAMING */
 
 	if (wpa_s->reassociate)
@@ -1401,7 +1402,10 @@
 		return 1;
 	}
 
-	if (current_bss->level < 0 && current_bss->level > selected->level) {
+	to_5ghz = selected->freq > 4000 && current_bss->freq < 4000;
+
+	if (current_bss->level < 0 &&
+	    current_bss->level > selected->level + to_5ghz * 2) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
 			"signal level");
 		return 0;
@@ -1420,6 +1424,13 @@
 		else
 			min_diff = 5;
 	}
+	if (to_5ghz) {
+		/* Make it easier to move to 5 GHz band */
+		if (min_diff > 2)
+			min_diff -= 2;
+		else
+			min_diff = 0;
+	}
 	if (abs(current_bss->level - selected->level) < min_diff) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
 			"in signal level");
@@ -1984,6 +1995,8 @@
 		}
 		if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
 		     (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+		    (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+		     (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
 		    (p[0] == WLAN_EID_RSN && p[1] >= 2)) {
 			if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
 				break;
@@ -2760,6 +2773,13 @@
 		}
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_MATCH_IFACE
+		if (wpa_s->matched) {
+			wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+			break;
+		}
+#endif /* CONFIG_MATCH_IFACE */
+
 #ifdef CONFIG_TERMINATE_ONLASTIF
 		/* check if last interface */
 		if (!any_interfaces(wpa_s->global->ifaces))
@@ -3690,12 +3710,14 @@
 #endif /* CONFIG_AP */
 #ifdef CONFIG_P2P
 			if (stype == WLAN_FC_STYPE_PROBE_REQ &&
-			    data->rx_mgmt.frame_len > 24) {
+			    data->rx_mgmt.frame_len > IEEE80211_HDRLEN) {
 				const u8 *src = mgmt->sa;
-				const u8 *ie = mgmt->u.probe_req.variable;
-				size_t ie_len = data->rx_mgmt.frame_len -
-					(mgmt->u.probe_req.variable -
-					 data->rx_mgmt.frame);
+				const u8 *ie;
+				size_t ie_len;
+
+				ie = data->rx_mgmt.frame + IEEE80211_HDRLEN;
+				ie_len = data->rx_mgmt.frame_len -
+					IEEE80211_HDRLEN;
 				wpas_p2p_probe_req_rx(
 					wpa_s, src, mgmt->da,
 					mgmt->bssid, ie, ie_len,
@@ -3735,11 +3757,12 @@
 		}
 
 		if (stype == WLAN_FC_STYPE_PROBE_REQ &&
-		    data->rx_mgmt.frame_len > 24) {
-			const u8 *ie = mgmt->u.probe_req.variable;
-			size_t ie_len = data->rx_mgmt.frame_len -
-				(mgmt->u.probe_req.variable -
-				 data->rx_mgmt.frame);
+		    data->rx_mgmt.frame_len > IEEE80211_HDRLEN) {
+			const u8 *ie;
+			size_t ie_len;
+
+			ie = data->rx_mgmt.frame + IEEE80211_HDRLEN;
+			ie_len = data->rx_mgmt.frame_len - IEEE80211_HDRLEN;
 
 			wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
 					 mgmt->bssid, ie, ie_len,
@@ -4010,3 +4033,43 @@
 		break;
 	}
 }
+
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+				 union wpa_event_data *data)
+{
+	struct wpa_supplicant *wpa_s;
+
+	if (event != EVENT_INTERFACE_STATUS)
+		return;
+
+	wpa_s = wpa_supplicant_get_iface(ctx, data->interface_status.ifname);
+	if (wpa_s && wpa_s->driver->get_ifindex) {
+		unsigned int ifindex;
+
+		ifindex = wpa_s->driver->get_ifindex(wpa_s->drv_priv);
+		if (ifindex != data->interface_status.ifindex) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"interface status ifindex %d mismatch (%d)",
+				ifindex, data->interface_status.ifindex);
+			return;
+		}
+	}
+#ifdef CONFIG_MATCH_IFACE
+	else if (data->interface_status.ievent == EVENT_INTERFACE_ADDED) {
+		struct wpa_interface *wpa_i;
+
+		wpa_i = wpa_supplicant_match_iface(
+			ctx, data->interface_status.ifname);
+		if (!wpa_i)
+			return;
+		wpa_s = wpa_supplicant_add_iface(ctx, wpa_i, NULL);
+		os_free(wpa_i);
+		if (wpa_s)
+			wpa_s->matched = 1;
+	}
+#endif /* CONFIG_MATCH_IFACE */
+
+	if (wpa_s)
+		wpa_supplicant_event(wpa_s, event, data);
+}
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 9df1607..589ee57 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1451,7 +1451,24 @@
 		os_free(anon);
 	}
 
-	if (cred->username && cred->username[0] &&
+	if (!ttls && cred->username && cred->username[0] && cred->realm &&
+	    !os_strchr(cred->username, '@')) {
+		char *id;
+		size_t buflen;
+		int res;
+
+		buflen = os_strlen(cred->username) + 1 +
+			os_strlen(cred->realm) + 1;
+
+		id = os_malloc(buflen);
+		if (!id)
+			return -1;
+		os_snprintf(id, buflen, "%s@%s", cred->username, cred->realm);
+		res = wpa_config_set_quoted(ssid, "identity", id);
+		os_free(id);
+		if (res < 0)
+			return -1;
+	} else if (cred->username && cred->username[0] &&
 	    wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
 		return -1;
 
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 3ab80a5..e08c2fd 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -81,6 +81,9 @@
 #ifdef CONFIG_P2P
 	       "  -m = Configuration file for the P2P Device interface\n"
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_MATCH_IFACE
+	       "  -M = start describing new matching interface\n"
+#endif /* CONFIG_MATCH_IFACE */
 	       "  -N = start describing new interface\n"
 	       "  -o = override driver parameter for new interfaces\n"
 	       "  -O = override ctrl_interface parameter for new interfaces\n"
@@ -153,6 +156,28 @@
 }
 
 
+#ifdef CONFIG_MATCH_IFACE
+static int wpa_supplicant_init_match(struct wpa_global *global)
+{
+	/*
+	 * The assumption is that the first driver is the primary driver and
+	 * will handle the arrival / departure of interfaces.
+	 */
+	if (wpa_drivers[0]->global_init && !global->drv_priv[0]) {
+		global->drv_priv[0] = wpa_drivers[0]->global_init(global);
+		if (!global->drv_priv[0]) {
+			wpa_printf(MSG_ERROR,
+				   "Failed to initialize driver '%s'",
+				   wpa_drivers[0]->name);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+#endif /* CONFIG_MATCH_IFACE */
+
+
 int main(int argc, char *argv[])
 {
 	int c, i;
@@ -176,7 +201,7 @@
 
 	for (;;) {
 		c = getopt(argc, argv,
-			   "b:Bc:C:D:de:f:g:G:hi:I:KLm:No:O:p:P:qsTtuvW");
+			   "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -282,6 +307,20 @@
 		case 'W':
 			params.wait_for_monitor++;
 			break;
+#ifdef CONFIG_MATCH_IFACE
+		case 'M':
+			params.match_iface_count++;
+			iface = os_realloc_array(params.match_ifaces,
+						 params.match_iface_count,
+						 sizeof(struct wpa_interface));
+			if (!iface)
+				goto out;
+			params.match_ifaces = iface;
+			iface = &params.match_ifaces[params.match_iface_count -
+						     1];
+			os_memset(iface, 0, sizeof(*iface));
+			break;
+#endif /* CONFIG_MATCH_IFACE */
 		case 'N':
 			iface_count++;
 			iface = os_realloc_array(ifaces, iface_count,
@@ -328,6 +367,9 @@
 		     ifaces[i].ctrl_interface == NULL) ||
 		    ifaces[i].ifname == NULL) {
 			if (iface_count == 1 && (params.ctrl_interface ||
+#ifdef CONFIG_MATCH_IFACE
+						 params.match_iface_count ||
+#endif /* CONFIG_MATCH_IFACE */
 						 params.dbus_ctrl_interface))
 				break;
 			usage();
@@ -341,6 +383,11 @@
 		}
 	}
 
+#ifdef CONFIG_MATCH_IFACE
+	if (exitcode == 0)
+		exitcode = wpa_supplicant_init_match(global);
+#endif /* CONFIG_MATCH_IFACE */
+
 	if (exitcode == 0)
 		exitcode = wpa_supplicant_run(global);
 
@@ -351,6 +398,9 @@
 out:
 	wpa_supplicant_fd_workaround(0);
 	os_free(ifaces);
+#ifdef CONFIG_MATCH_IFACE
+	os_free(params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
 	os_free(params.pid_file);
 
 	os_program_deinit();
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
index 7925aa9..89b033b 100644
--- a/wpa_supplicant/mesh.c
+++ b/wpa_supplicant/mesh.c
@@ -597,3 +597,16 @@
 	mesh_wpa_s->mesh_if_created = 1;
 	return 0;
 }
+
+
+int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+	return mesh_mpm_close_peer(wpa_s, addr);
+}
+
+
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+		       int duration)
+{
+	return mesh_mpm_connect_peer(wpa_s, addr, duration);
+}
diff --git a/wpa_supplicant/mesh.h b/wpa_supplicant/mesh.h
index 3cb7f1b..7317083 100644
--- a/wpa_supplicant/mesh.h
+++ b/wpa_supplicant/mesh.h
@@ -18,6 +18,9 @@
 			       char *end);
 int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
 			    size_t len);
+int wpas_mesh_peer_remove(struct wpa_supplicant *wpa_s, const u8 *addr);
+int wpas_mesh_peer_add(struct wpa_supplicant *wpa_s, const u8 *addr,
+		       int duration);
 
 #ifdef CONFIG_MESH
 
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 27be46c..c014eaf 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -14,6 +14,7 @@
 #include "ap/hostapd.h"
 #include "ap/sta_info.h"
 #include "ap/ieee802_11.h"
+#include "ap/wpa_auth.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "mesh_mpm.h"
@@ -419,6 +420,7 @@
 	struct sta_info *sta = user_data;
 	u16 reason = 0;
 	struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+	struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
 
 	switch (sta->plink_state) {
 	case PLINK_OPEN_RCVD:
@@ -448,6 +450,13 @@
 		break;
 	case PLINK_HOLDING:
 		/* holding timer */
+
+		if (sta->mesh_sae_pmksa_caching) {
+			wpa_printf(MSG_DEBUG, "MPM: Peer " MACSTR
+				   " looks like it does not support mesh SAE PMKSA caching, so remove the cached entry for it",
+				   MAC2STR(sta->addr));
+			wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+		}
 		mesh_mpm_fsm_restart(wpa_s, sta);
 		break;
 	default:
@@ -472,8 +481,8 @@
 }
 
 
-int mesh_mpm_plink_close(struct hostapd_data *hapd,
-			 struct sta_info *sta, void *ctx)
+static int mesh_mpm_plink_close(struct hostapd_data *hapd, struct sta_info *sta,
+				void *ctx)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
@@ -491,6 +500,85 @@
 }
 
 
+int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+	struct hostapd_data *hapd;
+	struct sta_info *sta;
+
+	if (!wpa_s->ifmsh) {
+		wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet");
+		return -1;
+	}
+
+	hapd = wpa_s->ifmsh->bss[0];
+	sta = ap_get_sta(hapd, addr);
+	if (!sta) {
+		wpa_msg(wpa_s, MSG_INFO, "No such mesh peer");
+		return -1;
+	}
+
+	return mesh_mpm_plink_close(hapd, sta, wpa_s) == 0 ? 0 : -1;
+}
+
+
+static void peer_add_timer(void *eloop_ctx, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+	os_memset(hapd->mesh_required_peer, 0, ETH_ALEN);
+}
+
+
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+			  int duration)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	struct hostapd_data *hapd;
+	struct sta_info *sta;
+	struct mesh_conf *conf;
+
+	if (!wpa_s->ifmsh) {
+		wpa_msg(wpa_s, MSG_INFO, "Mesh is not prepared yet");
+		return -1;
+	}
+
+	if (!ssid || !ssid->no_auto_peer) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"This command is available only with no_auto_peer mesh network");
+		return -1;
+	}
+
+	hapd = wpa_s->ifmsh->bss[0];
+	conf = wpa_s->ifmsh->mconf;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta) {
+		wpa_msg(wpa_s, MSG_INFO, "No such mesh peer");
+		return -1;
+	}
+
+	if ((PLINK_OPEN_SENT <= sta->plink_state &&
+	    sta->plink_state <= PLINK_ESTAB) ||
+	    (sta->sae && sta->sae->state > SAE_NOTHING)) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"Specified peer is connecting/connected");
+		return -1;
+	}
+
+	if (conf->security == MESH_CONF_SEC_NONE) {
+		mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+	} else {
+		mesh_rsn_auth_sae_sta(wpa_s, sta);
+		os_memcpy(hapd->mesh_required_peer, addr, ETH_ALEN);
+		eloop_register_timeout(duration == -1 ? 10 : duration, 0,
+				       peer_add_timer, wpa_s, NULL);
+	}
+
+	return 0;
+}
+
+
 void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
 {
 	struct hostapd_data *hapd = ifmsh->bss[0];
@@ -500,6 +588,7 @@
 
 	hapd->num_plinks = 0;
 	hostapd_free_stas(hapd);
+	eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
 }
 
 
@@ -640,7 +729,9 @@
 	if (!sta)
 		return;
 
-	if (ssid && ssid->no_auto_peer) {
+	if (ssid && ssid->no_auto_peer &&
+	    (is_zero_ether_addr(data->mesh_required_peer) ||
+	     os_memcmp(data->mesh_required_peer, addr, ETH_ALEN) != 0)) {
 		wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
 			MACSTR " because of no_auto_peer", MAC2STR(addr));
 		if (data->mesh_pending_auth) {
@@ -720,7 +811,10 @@
 	hapd->num_plinks++;
 
 	sta->flags |= WLAN_STA_ASSOC;
+	sta->mesh_sae_pmksa_caching = 0;
 
+	eloop_cancel_timeout(peer_add_timer, wpa_s, NULL);
+	peer_add_timer(wpa_s, NULL);
 	eloop_cancel_timeout(plink_timer, wpa_s, sta);
 
 	/* Send ctrl event */
@@ -1000,7 +1094,8 @@
 	 * open mesh, then go ahead and add the peer before proceeding.
 	 */
 	if (!sta && action_field == PLINK_OPEN &&
-	    !(mconf->security & MESH_CONF_SEC_AMPE))
+	    (!(mconf->security & MESH_CONF_SEC_AMPE) ||
+	     wpa_auth_pmksa_get(hapd->wpa_auth, mgmt->sa)))
 		sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
 
 	if (!sta) {
diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h
index 9af7563..5fc1e61 100644
--- a/wpa_supplicant/mesh_mpm.h
+++ b/wpa_supplicant/mesh_mpm.h
@@ -18,6 +18,9 @@
 void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
 			      struct sta_info *sta,
 			      enum mesh_plink_state state);
+int mesh_mpm_close_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
+int mesh_mpm_connect_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+			  int duration);
 
 #ifdef CONFIG_MESH
 
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 5d88274..1994f3f 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -27,12 +27,12 @@
 
 #define MESH_AUTH_TIMEOUT 10
 #define MESH_AUTH_RETRY 3
-#define MESH_AUTH_BLOCK_DURATION 3600
 
 void mesh_auth_timer(void *eloop_ctx, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	struct sta_info *sta = user_data;
+	struct hostapd_data *hapd;
 
 	if (sta->sae->state != SAE_ACCEPTED) {
 		wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR
@@ -43,23 +43,20 @@
 		if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
 			mesh_rsn_auth_sae_sta(wpa_s, sta);
 		} else {
+			hapd = wpa_s->ifmsh->bss[0];
+
 			if (sta->sae_auth_retry > MESH_AUTH_RETRY) {
-				ap_free_sta(wpa_s->ifmsh->bss[0], sta);
+				ap_free_sta(hapd, sta);
 				return;
 			}
 
 			/* block the STA if exceeded the number of attempts */
 			wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED);
 			sta->sae->state = SAE_NOTHING;
-			if (wpa_s->mesh_auth_block_duration <
-			    MESH_AUTH_BLOCK_DURATION)
-				wpa_s->mesh_auth_block_duration += 60;
-			eloop_register_timeout(wpa_s->mesh_auth_block_duration,
-					       0, mesh_auth_timer, wpa_s, sta);
 			wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr="
 				MACSTR " duration=%d",
 				MAC2STR(sta->addr),
-				wpa_s->mesh_auth_block_duration);
+				hapd->conf->ap_max_inactivity);
 		}
 		sta->sae_auth_retry++;
 	}
@@ -291,6 +288,7 @@
 {
 	struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	struct rsn_pmksa_cache_entry *pmksa;
 	unsigned int rnd;
 	int ret;
 
@@ -306,6 +304,29 @@
 			return -1;
 	}
 
+	pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr);
+	if (pmksa) {
+		if (!sta->wpa_sm)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr, NULL);
+		if (!sta->wpa_sm) {
+			wpa_printf(MSG_ERROR,
+				   "mesh: Failed to initialize RSN state machine");
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG,
+			   "AUTH: Mesh PMKSA cache entry found for " MACSTR
+			   " - try to use PMKSA caching instead of new SAE authentication",
+			   MAC2STR(sta->addr));
+		wpa_auth_pmksa_set_to_sm(pmksa, sta->wpa_sm, hapd->wpa_auth,
+					 sta->sae->pmkid, sta->sae->pmk);
+		sae_accept_sta(hapd, sta);
+		sta->mesh_sae_pmksa_caching = 1;
+		return 0;
+	}
+	sta->mesh_sae_pmksa_caching = 0;
+
 	if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta))
 		return -1;
 
@@ -514,6 +535,17 @@
 	const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
 				   (elems->mic - 2) - cat };
 
+	if (!sta->sae) {
+		struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+		if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr)) {
+			wpa_printf(MSG_INFO,
+				   "Mesh RSN: SAE is not prepared yet");
+			return -1;
+		}
+		mesh_rsn_auth_sae_sta(wpa_s, sta);
+	}
+
 	if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) {
 		wpa_msg(wpa_s, MSG_DEBUG,
 			"Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)");
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 325883d..e739363 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -13,6 +13,7 @@
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "wps_supplicant.h"
+#include "binder/binder.h"
 #include "dbus/dbus_common.h"
 #include "dbus/dbus_old.h"
 #include "dbus/dbus_new.h"
@@ -34,6 +35,12 @@
 	}
 #endif /* CONFIG_DBUS */
 
+#ifdef CONFIG_BINDER
+	global->binder = wpas_binder_init(global);
+	if (!global->binder)
+		return -1;
+#endif /* CONFIG_BINDER */
+
 	return 0;
 }
 
@@ -44,6 +51,11 @@
 	if (global->dbus)
 		wpas_dbus_deinit(global->dbus);
 #endif /* CONFIG_DBUS */
+
+#ifdef CONFIG_BINDER
+	if (global->binder)
+		wpas_binder_deinit(global->binder);
+#endif /* CONFIG_BINDER */
 }
 
 
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 5ff758f..b310885 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1134,7 +1134,8 @@
 	s->auth_alg = WPA_AUTH_ALG_OPEN;
 	s->key_mgmt = WPA_KEY_MGMT_PSK;
 	s->proto = WPA_PROTO_RSN;
-	s->pairwise_cipher = WPA_CIPHER_CCMP;
+	s->pbss = ssid->pbss;
+	s->pairwise_cipher = ssid->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
 	s->export_keys = 1;
 	if (ssid->passphrase) {
 		os_free(s->passphrase);
@@ -6107,8 +6108,10 @@
 	wpa_config_set_network_defaults(ssid);
 	ssid->temporary = 1;
 	ssid->proto = WPA_PROTO_RSN;
-	ssid->pairwise_cipher = WPA_CIPHER_CCMP;
-	ssid->group_cipher = WPA_CIPHER_CCMP;
+	ssid->pbss = params->pbss;
+	ssid->pairwise_cipher = params->pbss ? WPA_CIPHER_GCMP :
+		WPA_CIPHER_CCMP;
+	ssid->group_cipher = params->pbss ? WPA_CIPHER_GCMP : WPA_CIPHER_CCMP;
 	ssid->key_mgmt = WPA_KEY_MGMT_PSK;
 	ssid->ssid = os_malloc(params->ssid_len);
 	if (ssid->ssid == NULL) {
@@ -6328,6 +6331,8 @@
 	cfg->cb_ctx = wpa_s;
 	cfg->ie_update = wpas_p2p_ie_update;
 	cfg->idle_update = wpas_p2p_idle_update;
+	cfg->ip_addr_alloc = WPA_GET_BE32(wpa_s->p2pdev->conf->ip_addr_start)
+		!= 0;
 
 	group = p2p_group_init(wpa_s->global->p2p, cfg);
 	if (group == NULL)
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 3463dd9..7a52826 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1895,7 +1895,7 @@
 
 /*
  * Noise floor values to use when we have signal strength
- * measurements, but no noise floor measurments. These values were
+ * measurements, but no noise floor measurements. These values were
  * measured in an office environment with many APs.
  */
 #define DEFAULT_NOISE_FLOOR_2GHZ (-89)
@@ -2334,10 +2334,18 @@
 	struct wpa_ssid *ssid;
 	struct wpa_driver_scan_params params;
 	struct sched_scan_plan scan_plan;
+	unsigned int max_sched_scan_ssids;
 
 	if (!wpa_s->sched_scan_supported)
 		return -1;
 
+	if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
+		max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
+	else
+		max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
+	if (max_sched_scan_ssids < 1)
+		return -1;
+
 	if (wpa_s->pno || wpa_s->pno_sched_pending)
 		return 0;
 
@@ -2381,10 +2389,10 @@
 		num_ssid++;
 	}
 
-	if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
+	if (num_ssid > max_sched_scan_ssids) {
 		wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
-			   "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
-		num_ssid = WPAS_MAX_SCAN_SSIDS;
+			   "%u", max_sched_scan_ssids, (unsigned int) num_ssid);
+		num_ssid = max_sched_scan_ssids;
 	}
 
 	if (num_match_ssid > wpa_s->max_match_sets) {
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 7d2a92f..f77d51a 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -546,6 +546,17 @@
 			continue;
 		}
 
+		if (wpa_s->current_ssid &&
+		    !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
+					1)) {
+			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 (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
 			wpa_printf(MSG_DEBUG,
 				   "MBO: Candidate BSS " MACSTR
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index eecb1dc..36a7a4e 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -2042,6 +2042,20 @@
 	return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv);
 }
 
+
+static int wpa_cli_cmd_mesh_peer_remove(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "MESH_PEER_REMOVE", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_peer_add(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "MESH_PEER_ADD", 1, argc, argv);
+}
+
 #endif /* CONFIG_MESH */
 
 
@@ -3210,6 +3224,12 @@
 	{ "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL,
 	  cli_cmd_flag_none,
 	  "<ifname> = Remove mesh group interface" },
+	{ "mesh_peer_remove", wpa_cli_cmd_mesh_peer_remove, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = Remove a mesh peer" },
+	{ "mesh_peer_add", wpa_cli_cmd_mesh_peer_add, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> [duration=<seconds>] = Add a mesh peer" },
 #endif /* CONFIG_MESH */
 #ifdef CONFIG_P2P
 	{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 3f91cc1..511df4f 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -29,6 +29,8 @@
 	char *sock_name;
 	int fd;
 
+	void *ctx;
+
 	const struct wpa_driver_ops *driver;
 	void *drv_priv;
 	void *drv_global_priv;
@@ -40,6 +42,10 @@
 	struct sockaddr_un l2_addr;
 };
 
+struct wpa_priv_global {
+	struct wpa_priv_interface *interfaces;
+};
+
 
 static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
 				  struct sockaddr_un *from)
@@ -65,7 +71,8 @@
 
 	if (iface->driver->init2) {
 		if (iface->driver->global_init) {
-			iface->drv_global_priv = iface->driver->global_init();
+			iface->drv_global_priv =
+				iface->driver->global_init(iface->ctx);
 			if (!iface->drv_global_priv) {
 				wpa_printf(MSG_INFO,
 					   "Failed to initialize driver global context");
@@ -638,7 +645,7 @@
 
 
 static struct wpa_priv_interface *
-wpa_priv_interface_init(const char *dir, const char *params)
+wpa_priv_interface_init(void *ctx, const char *dir, const char *params)
 {
 	struct wpa_priv_interface *iface;
 	char *pos;
@@ -654,6 +661,7 @@
 	if (iface == NULL)
 		return NULL;
 	iface->fd = -1;
+	iface->ctx = ctx;
 
 	len = pos - params;
 	iface->driver_name = dup_binstr(params, len);
@@ -1002,6 +1010,37 @@
 }
 
 
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+				 union wpa_event_data *data)
+{
+	struct wpa_priv_global *global = ctx;
+	struct wpa_priv_interface *iface;
+
+	if (event != EVENT_INTERFACE_STATUS)
+		return;
+
+	for (iface = global->interfaces; iface; iface = iface->next) {
+		if (os_strcmp(iface->ifname, data->interface_status.ifname) ==
+		    0)
+			break;
+	}
+	if (iface && iface->driver->get_ifindex) {
+		unsigned int ifindex;
+
+		ifindex = iface->driver->get_ifindex(iface->drv_priv);
+		if (ifindex != data->interface_status.ifindex) {
+			wpa_printf(MSG_DEBUG,
+				   "%s: interface status ifindex %d mismatch (%d)",
+				   iface->ifname, ifindex,
+				   data->interface_status.ifindex);
+			return;
+		}
+	}
+	if (iface)
+		wpa_supplicant_event(iface, event, data);
+}
+
+
 void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 			     const u8 *buf, size_t len)
 {
@@ -1077,13 +1116,17 @@
 	char *pid_file = NULL;
 	int daemonize = 0;
 	char *ctrl_dir = "/var/run/wpa_priv";
-	struct wpa_priv_interface *interfaces = NULL, *iface;
+	struct wpa_priv_global global;
+	struct wpa_priv_interface *iface;
 
 	if (os_program_init())
 		return -1;
 
 	wpa_priv_fd_workaround();
 
+	os_memset(&global, 0, sizeof(global));
+	global.interfaces = NULL;
+
 	for (;;) {
 		c = getopt(argc, argv, "Bc:dP:");
 		if (c < 0)
@@ -1121,11 +1164,11 @@
 
 	for (i = optind; i < argc; i++) {
 		wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]);
-		iface = wpa_priv_interface_init(ctrl_dir, argv[i]);
+		iface = wpa_priv_interface_init(&global, ctrl_dir, argv[i]);
 		if (iface == NULL)
 			goto out;
-		iface->next = interfaces;
-		interfaces = iface;
+		iface->next = global.interfaces;
+		global.interfaces = iface;
 	}
 
 	if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
@@ -1137,7 +1180,7 @@
 	ret = 0;
 
 out:
-	iface = interfaces;
+	iface = global.interfaces;
 	while (iface) {
 		struct wpa_priv_interface *prev = iface;
 		iface = iface->next;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 136cb58..51bb245 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -11,6 +11,10 @@
  */
 
 #include "includes.h"
+#ifdef CONFIG_MATCH_IFACE
+#include <net/if.h>
+#include <fnmatch.h>
+#endif /* CONFIG_MATCH_IFACE */
 
 #include "common.h"
 #include "crypto/random.h"
@@ -1642,9 +1646,11 @@
 
 	wmm_ac_clear_saved_tspecs(wpa_s);
 	wpa_s->reassoc_same_bss = 0;
+	wpa_s->reassoc_same_ess = 0;
 
 	if (wpa_s->last_ssid == ssid) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+		wpa_s->reassoc_same_ess = 1;
 		if (wpa_s->current_bss && wpa_s->current_bss == bss) {
 			wmm_ac_save_tspecs(wpa_s);
 			wpa_s->reassoc_same_bss = 1;
@@ -2059,6 +2065,7 @@
 	int wep_keys_set = 0;
 	int assoc_failed = 0;
 	struct wpa_ssid *old_ssid;
+	u8 prev_bssid[ETH_ALEN];
 #ifdef CONFIG_HT_OVERRIDES
 	struct ieee80211_ht_capabilities htcaps;
 	struct ieee80211_ht_capabilities htcaps_mask;
@@ -2092,6 +2099,7 @@
 		return;
 	}
 
+	os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
 	os_memset(&params, 0, sizeof(params));
 	wpa_s->reassociate = 0;
 	wpa_s->eap_expected_failure = 0;
@@ -2532,6 +2540,10 @@
 	}
 #endif /* CONFIG_P2P */
 
+	if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
+	    wpa_s->current_ssid)
+		params.prev_bssid = prev_bssid;
+
 	ret = wpa_drv_associate(wpa_s, &params);
 	if (ret < 0) {
 		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
@@ -3143,7 +3155,7 @@
 	struct wpa_global *global = wpa_s->global;
 
 	if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
-		global->drv_priv[i] = wpa_drivers[i]->global_init();
+		global->drv_priv[i] = wpa_drivers[i]->global_init(global);
 		if (global->drv_priv[i] == NULL) {
 			wpa_printf(MSG_ERROR, "Failed to initialize driver "
 				   "'%s'", wpa_drivers[i]->name);
@@ -4911,6 +4923,74 @@
 }
 
 
+#ifdef CONFIG_MATCH_IFACE
+
+/**
+ * wpa_supplicant_match_iface - Match an interface description to a name
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @ifname: Name of the interface to match
+ * Returns: Pointer to the created interface description or %NULL on failure
+ */
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+						  const char *ifname)
+{
+	int i;
+	struct wpa_interface *iface, *miface;
+
+	for (i = 0; i < global->params.match_iface_count; i++) {
+		miface = &global->params.match_ifaces[i];
+		if (!miface->ifname ||
+		    fnmatch(miface->ifname, ifname, 0) == 0) {
+			iface = os_zalloc(sizeof(*iface));
+			if (!iface)
+				return NULL;
+			*iface = *miface;
+			iface->ifname = ifname;
+			return iface;
+		}
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_supplicant_match_existing - Match existing interfaces
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_supplicant_match_existing(struct wpa_global *global)
+{
+	struct if_nameindex *ifi, *ifp;
+	struct wpa_supplicant *wpa_s;
+	struct wpa_interface *iface;
+
+	ifp = if_nameindex();
+	if (!ifp) {
+		wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno));
+		return -1;
+	}
+
+	for (ifi = ifp; ifi->if_name; ifi++) {
+		wpa_s = wpa_supplicant_get_iface(global, ifi->if_name);
+		if (wpa_s)
+			continue;
+		iface = wpa_supplicant_match_iface(global, ifi->if_name);
+		if (iface) {
+			wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
+			os_free(iface);
+			if (wpa_s)
+				wpa_s->matched = 1;
+		}
+	}
+
+	if_freenameindex(ifp);
+	return 0;
+}
+
+#endif /* CONFIG_MATCH_IFACE */
+
+
 /**
  * wpa_supplicant_add_iface - Add a new network interface
  * @global: Pointer to global data from wpa_supplicant_init()
@@ -5212,6 +5292,18 @@
 	if (params->override_ctrl_interface)
 		global->params.override_ctrl_interface =
 			os_strdup(params->override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+	global->params.match_iface_count = params->match_iface_count;
+	if (params->match_iface_count) {
+		global->params.match_ifaces =
+			os_calloc(params->match_iface_count,
+				  sizeof(struct wpa_interface));
+		os_memcpy(global->params.match_ifaces,
+			  params->match_ifaces,
+			  params->match_iface_count *
+			  sizeof(struct wpa_interface));
+	}
+#endif /* CONFIG_MATCH_IFACE */
 #ifdef CONFIG_P2P
 	if (params->conf_p2p_dev)
 		global->params.conf_p2p_dev =
@@ -5291,6 +5383,11 @@
 	     eloop_sock_requeue()))
 		return -1;
 
+#ifdef CONFIG_MATCH_IFACE
+	if (wpa_supplicant_match_existing(global))
+		return -1;
+#endif
+
 	if (global->params.wait_for_monitor) {
 		for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
 			if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
@@ -5359,6 +5456,9 @@
 	os_free(global->params.ctrl_interface_group);
 	os_free(global->params.override_driver);
 	os_free(global->params.override_ctrl_interface);
+#ifdef CONFIG_MATCH_IFACE
+	os_free(global->params.match_ifaces);
+#endif /* CONFIG_MATCH_IFACE */
 #ifdef CONFIG_P2P
 	os_free(global->params.conf_p2p_dev);
 #endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 269bac0..c485891 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -44,6 +44,7 @@
 struct ctrl_iface_priv;
 struct ctrl_iface_global_priv;
 struct wpas_dbus_priv;
+struct wpas_binder_priv;
 
 /**
  * struct wpa_interface - Parameters for wpa_supplicant_add_iface()
@@ -228,6 +229,17 @@
 	char *conf_p2p_dev;
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_MATCH_IFACE
+	/**
+	 * match_ifaces - Interface descriptions to match
+	 */
+	struct wpa_interface *match_ifaces;
+
+	/**
+	 * match_iface_count - Number of defined matching interfaces
+	 */
+	int match_iface_count;
+#endif /* CONFIG_MATCH_IFACE */
 };
 
 struct p2p_srv_bonjour {
@@ -253,6 +265,7 @@
 	struct wpa_params params;
 	struct ctrl_iface_global_priv *ctrl_iface;
 	struct wpas_dbus_priv *dbus;
+	struct wpas_binder_priv *binder;
 	void **drv_priv;
 	size_t drv_count;
 	struct os_time suspend_time;
@@ -458,6 +471,9 @@
 	unsigned char own_addr[ETH_ALEN];
 	unsigned char perm_addr[ETH_ALEN];
 	char ifname[100];
+#ifdef CONFIG_MATCH_IFACE
+	int matched;
+#endif /* CONFIG_MATCH_IFACE */
 #ifdef CONFIG_CTRL_IFACE_DBUS
 	char *dbus_path;
 #endif /* CONFIG_CTRL_IFACE_DBUS */
@@ -468,6 +484,9 @@
 	char *preq_notify_peer;
 #endif /* CONFIG_AP */
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+#ifdef CONFIG_CTRL_IFACE_BINDER
+	const void *binder_object_key;
+#endif /* CONFIG_CTRL_IFACE_BINDER */
 	char bridge_ifname[16];
 
 	char *confname;
@@ -480,7 +499,8 @@
 	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
 				     * field contains the target BSSID. */
 	int reassociate; /* reassociation requested */
-	int reassoc_same_bss; /* reassociating to the same bss */
+	unsigned int reassoc_same_bss:1; /* reassociating to the same BSS */
+	unsigned int reassoc_same_ess:1; /* reassociating to the same ESS */
 	int disconnected; /* all connections disabled; i.e., do no reassociate
 			   * before this has been cleared */
 	struct wpa_ssid *current_ssid;
@@ -754,7 +774,6 @@
 	unsigned int mesh_if_created:1;
 	unsigned int mesh_ht_enabled:1;
 	unsigned int mesh_vht_enabled:1;
-	int mesh_auth_block_duration; /* sec */
 #endif /* CONFIG_MESH */
 
 	unsigned int off_channel_freq;
@@ -1109,6 +1128,8 @@
 
 void wpa_show_license(void);
 
+struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
+						  const char *ifname);
 struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
 						 struct wpa_interface *iface,
 						 struct wpa_supplicant *parent);