Accumulative patch from commit 932659696e2755bb1ecd6a27e1968fd27eef4948

9326596 nl80211: Remove unused WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT
0d08efa P2P: Use the number of concurrent channels in P2P flows
a21816a Use wpa_drv_shared_freq() if get_radio_name() is not supported
53c5dfc Change share_vif_oper_freq() to handle multiple freqs
4752147 nl80211: Report the number of concurrent support channels
d7df0fa Clean up wpa_supplicant_event() with deauth/disassoc helper functions
fd9f170 Remove unnecessary nested ifdef CONFIG_AP
13adc57 IBSS RSN: Add peer restart detection
b21990b nl80211: Register for AUTH frames when joining an IBSS network
c91f796 nl80211: Support not specifying the frame frequency
ec384c5 IBSS RSN: Fix disconnect() with internal SME
ed07764 nl80211: Remove redundant assignment of ifindex
4ed8d95 TDLS: Tear down TDLS using wpas_drv_tlds_oper() if not external
831770b Cancel delayed scheduled scan when wpa_supplicant cleans up
69dd296 WDS: Fix WEP usage with nl80211 wds_sta=1
c8ebeda wpa_supplicant: Add support for VHT BSS membership selector
3f9a813 hostapd: Add a config option to control beaconing
182b2e5 Add missing host_to_le32() for big endian hosts
3f53c00 nl80211: Ignore disconnect event in case of locally generated request

Change-Id: Ia7368e71ae40966a92970ac82b002c09a7971d41
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 8e6f35a..bf17abe 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1781,6 +1781,8 @@
 			}
 		} else if (os_strcmp(buf, "wds_sta") == 0) {
 			bss->wds_sta = atoi(pos);
+		} else if (os_strcmp(buf, "start_disabled") == 0) {
+			bss->start_disabled = atoi(pos);
 		} else if (os_strcmp(buf, "ap_isolate") == 0) {
 			bss->isolate = atoi(pos);
 		} else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 68c4069..c46dff5 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -389,6 +389,9 @@
 # use a separate bridge.
 #wds_bridge=wds-br0
 
+# Start the AP with beaconing disabled by default.
+#start_disabled=0
+
 # Client isolation can be used to prevent low-level bridging of frames between
 # associated stations in the BSS. By default, this bridging is allowed.
 #ap_isolate=1
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index a744ba6..c9b2599 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -243,6 +243,7 @@
 	int num_deny_mac;
 	int wds_sta;
 	int isolate;
+	int start_disabled;
 
 	int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
 			* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 8205d13..3072562 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -296,19 +296,19 @@
 }
 
 
-int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
-			int val)
+int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
+			const u8 *addr, int aid, int val)
 {
 	const char *bridge = NULL;
 
 	if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
-		return 0;
+		return -1;
 	if (hapd->conf->wds_bridge[0])
 		bridge = hapd->conf->wds_bridge;
 	else if (hapd->conf->bridge[0])
 		bridge = hapd->conf->bridge;
 	return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
-					 bridge);
+					 bridge, ifname_wds);
 }
 
 
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 70fab55..cfc30ce 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -31,8 +31,8 @@
 			      int enabled);
 int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
 int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
-int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
-			int val);
+int hostapd_set_wds_sta(struct hostapd_data *hapd, char *ifname_wds,
+			const u8 *addr, int aid, int val);
 int hostapd_sta_add(struct hostapd_data *hapd,
 		    const u8 *addr, u16 aid, u16 capability,
 		    const u8 *supp_rates, size_t supp_rates_len,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 780b2e2..ac67001 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -806,7 +806,8 @@
 		return -1;
 	}
 
-	ieee802_11_set_beacon(hapd);
+	if (!hapd->conf->start_disabled)
+		ieee802_11_set_beacon(hapd);
 
 	if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
 		return -1;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 5503af1..35282af 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1818,6 +1818,30 @@
 }
 
 
+static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
+				       struct sta_info *sta,
+				       char *ifname_wds)
+{
+	int i;
+	struct hostapd_ssid *ssid = sta->ssid;
+
+	if (hapd->conf->ieee802_1x || hapd->conf->wpa)
+		return;
+
+	for (i = 0; i < 4; i++) {
+		if (ssid->wep.key[i] &&
+		    hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
+					i == ssid->wep.idx, NULL, 0,
+					ssid->wep.key[i], ssid->wep.len[i])) {
+			wpa_printf(MSG_WARNING,
+				   "Could not set WEP keys for WDS interface; %s",
+				   ifname_wds);
+			break;
+		}
+	}
+}
+
+
 static void handle_assoc_cb(struct hostapd_data *hapd,
 			    const struct ieee80211_mgmt *mgmt,
 			    size_t len, int reassoc, int ok)
@@ -1920,8 +1944,15 @@
 		goto fail;
 	}
 
-	if (sta->flags & WLAN_STA_WDS)
-		hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1);
+	if (sta->flags & WLAN_STA_WDS) {
+		int ret;
+		char ifname_wds[IFNAMSIZ + 1];
+
+		ret = hostapd_set_wds_sta(hapd, ifname_wds, sta->addr,
+					  sta->aid, 1);
+		if (!ret)
+			hostapd_set_wds_encryption(hapd, sta, ifname_wds);
+	}
 
 	if (sta->eapol_sm == NULL) {
 		/*
@@ -2162,11 +2193,18 @@
 			return;
 
 		if (wds && !(sta->flags & WLAN_STA_WDS)) {
+			int ret;
+			char ifname_wds[IFNAMSIZ + 1];
+
 			wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
 				   "STA " MACSTR " (aid %u)",
 				   MAC2STR(sta->addr), sta->aid);
 			sta->flags |= WLAN_STA_WDS;
-			hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1);
+			ret = hostapd_set_wds_sta(hapd, ifname_wds,
+						  sta->addr, sta->aid, 1);
+			if (!ret)
+				hostapd_set_wds_encryption(hapd, sta,
+							   ifname_wds);
 		}
 		return;
 	}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 833f1b2..21235f2 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -129,7 +129,7 @@
 	ap_sta_set_authorized(hapd, sta, 0);
 
 	if (sta->flags & WLAN_STA_WDS)
-		hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
+		hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
 
 	if (!(sta->flags & WLAN_STA_PREAUTH))
 		hostapd_drv_sta_remove(hapd, sta->addr);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 0604fef..160ac0c 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -61,6 +61,7 @@
 };
 
 #define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
+#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
 
 /**
  * struct hostapd_hw_modes - Supported hardware mode information
@@ -832,8 +833,7 @@
 #define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
 /* This interface is P2P capable (P2P GO or P2P Client) */
 #define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
-/* Driver supports concurrent operations on multiple channels */
-#define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT	0x00001000
+/* unused: 0x00001000 */
 /*
  * Driver uses the initial interface for P2P management interface and non-P2P
  * purposes (e.g., connect to infra AP), but this interface cannot be used for
@@ -911,6 +911,11 @@
 	unsigned int max_acl_mac_addrs;
 
 	/**
+	 * Number of supported concurrent channels
+	 */
+	unsigned int num_multichan_concurrent;
+
+	/**
 	 * extended_capa - extended capabilities in driver/device
 	 *
 	 * Must be allocated and freed by driver and the pointers must be
@@ -2049,10 +2054,12 @@
 	 * @val: 1 = bind to 4-address WDS; 0 = unbind
 	 * @bridge_ifname: Bridge interface to use for the WDS station or %NULL
 	 *	to indicate that bridge is not to be used
+	 * @ifname_wds: Buffer to return the interface name for the new WDS
+	 *	station or %NULL to indicate name is not returned.
 	 * Returns: 0 on success, -1 on failure
 	 */
 	int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val,
-	                   const char *bridge_ifname);
+	                   const char *bridge_ifname, char *ifname_wds);
 
 	/**
 	 * send_action - Transmit an Action frame
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index bcd0a94..eaecc36 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -310,6 +310,9 @@
 				  unsigned int freq, unsigned int wait,
 				  const u8 *buf, size_t buf_len, u64 *cookie,
 				  int no_cck, int no_ack, int offchanok);
+static int nl80211_register_frame(struct i802_bss *bss,
+				  struct nl_handle *hl_handle,
+				  u16 type, const u8 *match, size_t match_len);
 static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
 					       int report);
 #ifdef ANDROID
@@ -1067,7 +1070,6 @@
 		return 1;
 
 	if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
-		drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
 		wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
 			   "interface");
 		wpa_driver_nl80211_finish_drv_init(drv);
@@ -1829,12 +1831,19 @@
 static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
 				 struct nlattr *tb[])
 {
+	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+
 	if (tb[NL80211_ATTR_MAC] == NULL) {
 		wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
 			   "event");
 		return;
 	}
 	os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+	/* register for any AUTH message */
+	nl80211_register_frame(&drv->first_bss, drv->first_bss.nl_mgmt,
+			       type, NULL, 0);
+
 	drv->associated = 1;
 	wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
 		   MAC2STR(drv->bssid));
@@ -2881,6 +2890,8 @@
 	struct wpa_driver_nl80211_data *drv;
 	struct wpa_driver_capa *capa;
 
+	unsigned int num_multichan_concurrent;
+
 	unsigned int error:1;
 	unsigned int device_ap_sme:1;
 	unsigned int poll_command_supported:1;
@@ -2891,7 +2902,6 @@
 	unsigned int p2p_go_supported:1;
 	unsigned int p2p_client_supported:1;
 	unsigned int p2p_concurrent:1;
-	unsigned int p2p_multichan_concurrent:1;
 };
 
 
@@ -3001,8 +3011,8 @@
 
 	if (combination_has_p2p && combination_has_mgd) {
 		info->p2p_concurrent = 1;
-		if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
-			info->p2p_multichan_concurrent = 1;
+		info->num_multichan_concurrent =
+			nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
 		return 1;
 	}
 
@@ -3252,10 +3262,11 @@
 		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
 		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
 	}
-	if (info->p2p_multichan_concurrent) {
+	if (info->num_multichan_concurrent > 1) {
 		wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
 			   "concurrent (driver advertised support)");
-		drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+		drv->capa.num_multichan_concurrent =
+			info->num_multichan_concurrent;
 	}
 
 	/* default to 5000 since early versions of mac80211 don't set it */
@@ -5189,12 +5200,20 @@
 static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
 					 int reason_code)
 {
+	int ret;
+
 	wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
 	nl80211_mark_disconnected(drv);
-	drv->ignore_next_local_disconnect = 0;
 	/* Disconnect command doesn't need BSSID - it uses cached value */
-	return wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
-				       reason_code, 0);
+	ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
+				      reason_code, 0);
+	/*
+	 * For locally generated disconnect, supplicant already generates a
+	 * DEAUTH event, so ignore the event from NL80211.
+	 */
+	drv->ignore_next_local_disconnect = ret == 0;
+
+	return ret;
 }
 
 
@@ -5674,7 +5693,20 @@
 		mode = &phy_info->modes[*(phy_info->num_modes)];
 		os_memset(mode, 0, sizeof(*mode));
 		mode->mode = NUM_HOSTAPD_MODES;
-		mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
+		mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
+			HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
+
+		/*
+		 * Unsupported VHT MCS stream is defined as value 3, so the VHT
+		 * MCS RX/TX map must be initialized with 0xffff to mark all 8
+		 * possible streams as unsupported. This will be overridden if
+		 * driver advertises VHT support.
+		 */
+		mode->vht_mcs_set[0] = 0xff;
+		mode->vht_mcs_set[1] = 0xff;
+		mode->vht_mcs_set[4] = 0xff;
+		mode->vht_mcs_set[5] = 0xff;
+
 		*(phy_info->num_modes) += 1;
 		phy_info->last_mode = nl_band->nla_type;
 		phy_info->last_chan_idx = 0;
@@ -7835,8 +7867,6 @@
 		if (wpa_driver_nl80211_disconnect(
 			    drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
 			return -1;
-		/* Ignore the next local disconnect message. */
-		drv->ignore_next_local_disconnect = 1;
 		ret = wpa_driver_nl80211_try_connect(drv, params);
 	}
 	return ret;
@@ -8690,13 +8720,16 @@
 
 
 static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
-                            const char *bridge_ifname)
+                            const char *bridge_ifname, char *ifname_wds)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	char name[IFNAMSIZ + 1];
 
 	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+	if (ifname_wds)
+		os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
+
 	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
 		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
 	if (val) {
@@ -9216,12 +9249,13 @@
 	wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
 		   "no_ack=%d offchanok=%d",
 		   freq, wait, no_cck, no_ack, offchanok);
+	wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
 	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
 	if (nl80211_set_iface_id(msg, bss) < 0)
 		goto nla_put_failure;
-
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+	if (freq)
+		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
 	if (wait)
 		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
 	if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
@@ -9809,7 +9843,7 @@
 		struct wpa_driver_nl80211_data *drv = bss->drv;
 		wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel "
 			   "concurrency");
-		drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+		drv->capa.num_multichan_concurrent = 2;
 	}
 #endif
 #endif /* CONFIG_P2P */
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index c392d57..6b5679c 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -375,14 +375,6 @@
 	 */
 	unsigned int max_listen;
 
-#ifdef ANDROID_P2P
-	enum p2p_concurrency_type {
-		P2P_NON_CONCURRENT,
-		P2P_SINGLE_CHANNEL_CONCURRENT,
-		P2P_MULTI_CHANNEL_CONCURRENT,
-	} p2p_concurrency;
-#endif
-
 	/**
 	 * cb_ctx - Context to use with callback functions
 	 */
diff --git a/src/utils/common.h b/src/utils/common.h
index e4f7031..29f0b95 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -205,6 +205,7 @@
 #define be_to_host16(n) (n)
 #define host_to_be16(n) (n)
 #define le_to_host32(n) bswap_32(n)
+#define host_to_le32(n) bswap_32(n)
 #define be_to_host32(n) (n)
 #define host_to_be32(n) (n)
 #define le_to_host64(n) bswap_64(n)
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index a24abaf..8edf086 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -577,6 +577,7 @@
 	struct wpa_supplicant *wpa_s, char *addr)
 {
 	u8 peer[ETH_ALEN];
+	int ret;
 
 	if (hwaddr_aton(addr, peer)) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
@@ -587,8 +588,14 @@
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
 		   MAC2STR(peer));
 
-	return wpa_tdls_teardown_link(wpa_s->wpa, peer,
-				      WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_teardown_link(
+			wpa_s->wpa, peer,
+			WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+
+	return ret;
 }
 
 #endif /* CONFIG_TDLS */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 9922e07..5e7dbf7 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -133,7 +133,8 @@
 				     const u8 *addr, int reason_code)
 {
 	if (wpa_s->driver->sta_deauth) {
-		return wpa_s->driver->sta_deauth(wpa_s->drv_priv, NULL, addr,
+		return wpa_s->driver->sta_deauth(wpa_s->drv_priv,
+						 wpa_s->own_addr, addr,
 						 reason_code);
 	}
 	return -1;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index d39216f..7c0d2e8 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -551,6 +551,24 @@
 }
 
 
+static int vht_supported(const struct hostapd_hw_modes *mode)
+{
+	if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) {
+		/*
+		 * The driver did not indicate whether it supports VHT. Assume
+		 * it does to avoid connection issues.
+		 */
+		return 1;
+	}
+
+	/*
+	 * A VHT non-AP STA shall support MCS 0-7 for one spatial stream.
+	 * TODO: Verify if this complies with the standard
+	 */
+	return (mode->vht_mcs_set[0] & 0x3) != 3;
+}
+
+
 static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
 	const struct hostapd_hw_modes *mode = NULL, *modes;
@@ -616,6 +634,18 @@
 				continue;
 			}
 
+			/* There's also a VHT selector for 802.11ac */
+			if (flagged && ((rate_ie[j] & 0x7f) ==
+					BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) {
+				if (!vht_supported(mode)) {
+					wpa_dbg(wpa_s, MSG_DEBUG,
+						"   hardware does not support "
+						"VHT PHY");
+					return 0;
+				}
+				continue;
+			}
+
 			if (!flagged)
 				continue;
 
@@ -2311,6 +2341,23 @@
 
 	ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer);
 }
+
+
+static void wpa_supplicant_event_ibss_auth(struct wpa_supplicant *wpa_s,
+					   union wpa_event_data *data)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (ssid == NULL)
+		return;
+
+	/* check if the ssid is correctly configured as IBSS/RSN */
+	if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt))
+		return;
+
+	ibss_rsn_handle_auth(wpa_s->ibss_rsn, data->rx_mgmt.frame,
+			     data->rx_mgmt.frame_len);
+}
 #endif /* CONFIG_IBSS_RSN */
 
 
@@ -2394,12 +2441,141 @@
 }
 
 
+static void wpas_event_disconnect(struct wpa_supplicant *wpa_s, const u8 *addr,
+				  u16 reason_code, int locally_generated,
+				  const u8 *ie, size_t ie_len, int deauth)
+{
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface && addr) {
+		hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], addr);
+		return;
+	}
+
+	if (wpa_s->ap_iface) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in AP mode");
+		return;
+	}
+#endif /* CONFIG_AP */
+
+	wpa_supplicant_event_disassoc(wpa_s, reason_code, locally_generated);
+
+	if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
+	    ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+	      (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
+	     eapol_sm_failed(wpa_s->eapol)))
+		wpas_auth_failed(wpa_s);
+
+#ifdef CONFIG_P2P
+	if (deauth && ie && ie_len > 0) {
+		if (wpas_p2p_deauth_notif(wpa_s, addr, reason_code, ie, ie_len,
+					  locally_generated) > 0) {
+			/*
+			 * The interface was removed, so cannot continue
+			 * processing any additional operations after this.
+			 */
+			return;
+		}
+	}
+#endif /* CONFIG_P2P */
+
+	wpa_supplicant_event_disassoc_finish(wpa_s, reason_code,
+					     locally_generated);
+}
+
+
+static void wpas_event_disassoc(struct wpa_supplicant *wpa_s,
+				struct disassoc_info *info)
+{
+	u16 reason_code = 0;
+	int locally_generated = 0;
+	const u8 *addr = NULL;
+	const u8 *ie = NULL;
+	size_t ie_len = 0;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
+
+	if (info) {
+		addr = info->addr;
+		ie = info->ie;
+		ie_len = info->ie_len;
+		reason_code = info->reason_code;
+		locally_generated = info->locally_generated;
+		wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s", reason_code,
+			locally_generated ? " (locally generated)" : "");
+		if (addr)
+			wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
+				MAC2STR(addr));
+		wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
+			    ie, ie_len);
+	}
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface && info && info->addr) {
+		hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], info->addr);
+		return;
+	}
+
+	if (wpa_s->ap_iface) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in AP mode");
+		return;
+	}
+#endif /* CONFIG_AP */
+
+#ifdef CONFIG_P2P
+	if (info) {
+		wpas_p2p_disassoc_notif(
+			wpa_s, info->addr, reason_code, info->ie, info->ie_len,
+			locally_generated);
+	}
+#endif /* CONFIG_P2P */
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+		sme_event_disassoc(wpa_s, info);
+
+	wpas_event_disconnect(wpa_s, addr, reason_code, locally_generated,
+			      ie, ie_len, 0);
+}
+
+
+static void wpas_event_deauth(struct wpa_supplicant *wpa_s,
+			      struct deauth_info *info)
+{
+	u16 reason_code = 0;
+	int locally_generated = 0;
+	const u8 *addr = NULL;
+	const u8 *ie = NULL;
+	size_t ie_len = 0;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Deauthentication notification");
+
+	if (info) {
+		addr = info->addr;
+		ie = info->ie;
+		ie_len = info->ie_len;
+		reason_code = info->reason_code;
+		locally_generated = info->locally_generated;
+		wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
+			reason_code,
+			locally_generated ? " (locally generated)" : "");
+		if (addr) {
+			wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
+				MAC2STR(addr));
+		}
+		wpa_hexdump(MSG_DEBUG, "Deauthentication frame IE(s)",
+			    ie, ie_len);
+	}
+
+	wpa_reset_ft_completed(wpa_s->wpa);
+
+	wpas_event_disconnect(wpa_s, addr, reason_code,
+			      locally_generated, ie, ie_len, 1);
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	u16 reason_code = 0;
-	int locally_generated = 0;
 
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
 	    event != EVENT_INTERFACE_ENABLED &&
@@ -2438,109 +2614,12 @@
 		wpa_supplicant_event_assoc(wpa_s, data);
 		break;
 	case EVENT_DISASSOC:
-		wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
-		if (data) {
-			wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
-				data->disassoc_info.reason_code,
-				data->disassoc_info.locally_generated ?
-				" (locally generated)" : "");
-			if (data->disassoc_info.addr)
-				wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
-					MAC2STR(data->disassoc_info.addr));
-		}
-#ifdef CONFIG_AP
-		if (wpa_s->ap_iface && data && data->disassoc_info.addr) {
-			hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
-					       data->disassoc_info.addr);
-			break;
-		}
-		if (wpa_s->ap_iface) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in "
-				"AP mode");
-			break;
-		}
-#endif /* CONFIG_AP */
-		if (data) {
-			reason_code = data->disassoc_info.reason_code;
-			locally_generated =
-				data->disassoc_info.locally_generated;
-			wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
-				    data->disassoc_info.ie,
-				    data->disassoc_info.ie_len);
-#ifdef CONFIG_P2P
-			wpas_p2p_disassoc_notif(
-				wpa_s, data->disassoc_info.addr, reason_code,
-				data->disassoc_info.ie,
-				data->disassoc_info.ie_len,
-				locally_generated);
-#endif /* CONFIG_P2P */
-		}
-		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
-			sme_event_disassoc(wpa_s, data);
-		/* fall through */
+		wpas_event_disassoc(wpa_s,
+				    data ? &data->disassoc_info : NULL);
+		break;
 	case EVENT_DEAUTH:
-		if (event == EVENT_DEAUTH) {
-			wpa_dbg(wpa_s, MSG_DEBUG,
-				"Deauthentication notification");
-			if (data) {
-				reason_code = data->deauth_info.reason_code;
-				locally_generated =
-					data->deauth_info.locally_generated;
-				wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
-					data->deauth_info.reason_code,
-					data->deauth_info.locally_generated ?
-					" (locally generated)" : "");
-				if (data->deauth_info.addr) {
-					wpa_dbg(wpa_s, MSG_DEBUG, " * address "
-						MACSTR,
-						MAC2STR(data->deauth_info.
-							addr));
-				}
-				wpa_hexdump(MSG_DEBUG,
-					    "Deauthentication frame IE(s)",
-					    data->deauth_info.ie,
-					    data->deauth_info.ie_len);
-			}
-			wpa_reset_ft_completed(wpa_s->wpa);
-		}
-#ifdef CONFIG_AP
-		if (wpa_s->ap_iface && data && data->deauth_info.addr) {
-			hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
-					       data->deauth_info.addr);
-			break;
-		}
-		if (wpa_s->ap_iface) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in "
-				"AP mode");
-			break;
-		}
-#endif /* CONFIG_AP */
-		wpa_supplicant_event_disassoc(wpa_s, reason_code,
-					      locally_generated);
-		if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
-		    ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
-		      (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
-		     eapol_sm_failed(wpa_s->eapol)))
-			wpas_auth_failed(wpa_s);
-#ifdef CONFIG_P2P
-		if (event == EVENT_DEAUTH && data) {
-			if (wpas_p2p_deauth_notif(wpa_s,
-						  data->deauth_info.addr,
-						  reason_code,
-						  data->deauth_info.ie,
-						  data->deauth_info.ie_len,
-						  locally_generated) > 0) {
-				/*
-				 * The interface was removed, so cannot
-				 * continue processing any additional
-				 * operations after this.
-				 */
-				break;
-			}
-		}
-#endif /* CONFIG_P2P */
-		wpa_supplicant_event_disassoc_finish(wpa_s, reason_code,
-						     locally_generated);
+		wpas_event_deauth(wpa_s,
+				  data ? &data->deauth_info : NULL);
 		break;
 	case EVENT_MICHAEL_MIC_FAILURE:
 		wpa_supplicant_event_michael_mic_failure(wpa_s, data);
@@ -2740,12 +2819,12 @@
 			break;
 		}
 
-#ifdef CONFIG_AP
 		wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
 				  data->ch_switch.ht_enabled,
 				  data->ch_switch.ch_offset);
-#endif /* CONFIG_AP */
 		break;
+#endif /* CONFIG_AP */
+#if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN)
 	case EVENT_RX_MGMT: {
 		u16 fc, stype;
 		const struct ieee80211_mgmt *mgmt;
@@ -2755,7 +2834,9 @@
 		fc = le_to_host16(mgmt->frame_control);
 		stype = WLAN_FC_GET_STYPE(fc);
 
+#ifdef CONFIG_AP
 		if (wpa_s->ap_iface == NULL) {
+#endif /* CONFIG_AP */
 #ifdef CONFIG_P2P
 			if (stype == WLAN_FC_STYPE_PROBE_REQ &&
 			    data->rx_mgmt.frame_len > 24) {
@@ -2771,9 +2852,17 @@
 				break;
 			}
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_IBSS_RSN
+			if (stype == WLAN_FC_STYPE_AUTH &&
+			    data->rx_mgmt.frame_len >= 30) {
+				wpa_supplicant_event_ibss_auth(wpa_s, data);
+				break;
+			}
+#endif /* CONFIG_IBSS_RSN */
 			wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
 				"management frame in non-AP mode");
 			break;
+#ifdef CONFIG_AP
 		}
 
 		if (stype == WLAN_FC_STYPE_PROBE_REQ &&
@@ -2789,9 +2878,10 @@
 		}
 
 		ap_mgmt_rx(wpa_s, &data->rx_mgmt);
+#endif /* CONFIG_AP */
 		break;
 		}
-#endif /* CONFIG_AP */
+#endif /* CONFIG_AP || CONFIG_IBSS_RSN */
 	case EVENT_RX_ACTION:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
 			" Category=%u DataLen=%d freq=%d MHz",
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 687c042..62d68b8 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -15,6 +15,7 @@
 #include "ap/wpa_auth.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
+#include "common/ieee802_11_defs.h"
 #include "ibss_rsn.h"
 
 
@@ -438,48 +439,135 @@
 }
 
 
-int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
+static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq)
+{
+	struct ieee80211_mgmt auth;
+	const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth);
+	struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s;
+
+	if (wpa_s->driver->send_frame == NULL)
+		return -1;
+
+	os_memset(&auth, 0, sizeof(auth));
+
+	auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_AUTH);
+	os_memcpy(auth.da, da, ETH_ALEN);
+	os_memcpy(auth.sa, wpa_s->own_addr, ETH_ALEN);
+	os_memcpy(auth.bssid, wpa_s->bssid, ETH_ALEN);
+
+	auth.u.auth.auth_alg = host_to_le16(WLAN_AUTH_OPEN);
+	auth.u.auth.auth_transaction = host_to_le16(seq);
+	auth.u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+
+	wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR,
+		   seq, MAC2STR(da));
+
+	return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth,
+					 auth_length, 0);
+}
+
+
+static int ibss_rsn_is_auth_started(struct ibss_rsn_peer * peer)
+{
+	return peer->authentication_status &
+	       (IBSS_RSN_AUTH_BY_US | IBSS_RSN_AUTH_EAPOL_BY_US);
+}
+
+
+static struct ibss_rsn_peer *
+ibss_rsn_peer_init(struct ibss_rsn *ibss_rsn, const u8 *addr)
 {
 	struct ibss_rsn_peer *peer;
-
 	if (ibss_rsn == NULL)
-		return -1;
+		return NULL;
 
-	if (ibss_rsn_get_peer(ibss_rsn, addr)) {
-		wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and Supplicant "
-			   "for peer " MACSTR " already running",
-			   MAC2STR(addr));
-		return 0;
+	peer = ibss_rsn_get_peer(ibss_rsn, addr);
+	if (peer) {
+		wpa_printf(MSG_DEBUG, "RSN: IBSS Supplicant for peer "MACSTR
+			   " already running", MAC2STR(addr));
+		return peer;
 	}
 
-	wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and "
-		   "Supplicant for peer " MACSTR, MAC2STR(addr));
+	wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Supplicant for peer "MACSTR,
+		   MAC2STR(addr));
 
 	peer = os_zalloc(sizeof(*peer));
-	if (peer == NULL)
-		return -1;
+	if (peer == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: Could not allocate memory.");
+		return NULL;
+	}
 
 	peer->ibss_rsn = ibss_rsn;
 	os_memcpy(peer->addr, addr, ETH_ALEN);
+	peer->authentication_status = IBSS_RSN_AUTH_NOT_AUTHENTICATED;
 
-	if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk)
-	    < 0) {
+	if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr,
+			       ibss_rsn->psk) < 0) {
 		ibss_rsn_free(peer);
-		return -1;
-	}
-
-	if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) {
-		ibss_rsn_free(peer);
-		return -1;
+		return NULL;
 	}
 
 	peer->next = ibss_rsn->peers;
 	ibss_rsn->peers = peer;
 
+	return peer;
+}
+
+
+int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
+{
+	struct ibss_rsn_peer *peer;
+	int res;
+
+	/* if the peer already exists, exit immediately */
+	peer = ibss_rsn_get_peer(ibss_rsn, addr);
+	if (peer)
+		return 0;
+
+	peer = ibss_rsn_peer_init(ibss_rsn, addr);
+	if (peer == NULL)
+		return -1;
+
+	/* Open Authentication: send first Authentication frame */
+	res = ibss_rsn_send_auth(ibss_rsn, addr, 1);
+	if (res) {
+		/*
+		 * The driver may not support Authentication frame exchange in
+		 * IBSS. Ignore authentication and go through EAPOL exchange.
+		 */
+		peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
+		return ibss_rsn_auth_init(ibss_rsn, peer);
+	}
+
 	return 0;
 }
 
 
+static int ibss_rsn_peer_authenticated(struct ibss_rsn *ibss_rsn,
+				       struct ibss_rsn_peer *peer, int reason)
+{
+	int already_started;
+
+	if (ibss_rsn == NULL || peer == NULL)
+		return -1;
+
+	already_started = ibss_rsn_is_auth_started(peer);
+	peer->authentication_status |= reason;
+
+	if (already_started) {
+		wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator already "
+			   "started for peer " MACSTR, MAC2STR(peer->addr));
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator "
+		   "for now-authenticated peer " MACSTR, MAC2STR(peer->addr));
+
+	return ibss_rsn_auth_init(ibss_rsn, peer);
+}
+
+
 void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac)
 {
 	struct ibss_rsn_peer *peer, *prev;
@@ -617,10 +705,21 @@
 		return -1;
 	os_memcpy(tmp, buf, len);
 	if (supp) {
-		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant");
+		peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER;
+		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from "
+			   MACSTR, MAC2STR(peer->addr));
 		wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len);
 	} else {
-		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator");
+		if (ibss_rsn_is_auth_started(peer) == 0) {
+			wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for "
+				   "Authenticator dropped as " MACSTR " is not "
+				   "authenticated", MAC2STR(peer->addr));
+			os_free(tmp);
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator "
+			   "from "MACSTR, MAC2STR(peer->addr));
 		wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len);
 	}
 	os_free(tmp);
@@ -646,8 +745,16 @@
 		 * Create new IBSS peer based on an EAPOL message from the peer
 		 * Authenticator.
 		 */
-		if (ibss_rsn_start(ibss_rsn, src_addr) < 0)
+		peer = ibss_rsn_peer_init(ibss_rsn, src_addr);
+		if (peer == NULL)
 			return -1;
+
+		/* assume the peer is authenticated already */
+		wpa_printf(MSG_DEBUG, "RSN: IBSS Not using IBSS Auth for peer "
+			   MACSTR, MAC2STR(src_addr));
+		ibss_rsn_peer_authenticated(ibss_rsn, peer,
+					    IBSS_RSN_AUTH_EAPOL_BY_US);
+
 		return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers,
 						 buf, len);
 	}
@@ -655,10 +762,89 @@
 	return 0;
 }
 
-
 void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk)
 {
 	if (ibss_rsn == NULL)
 		return;
 	os_memcpy(ibss_rsn->psk, psk, PMK_LEN);
 }
+
+
+static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
+					struct ibss_rsn_peer *peer,
+					const u8* addr)
+{
+	wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 1) from " MACSTR,
+		   MAC2STR(addr));
+
+	if (peer &&
+	    peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
+		/*
+		 * A peer sent us an Authentication frame even though it already
+		 * started an EAPOL session. We should reinit state machines
+		 * here, but it's much more complicated than just deleting and
+		 * recreating the state machine
+		 */
+		wpa_printf(MSG_DEBUG, "RSN: IBSS Reinitializing station "
+			   MACSTR, MAC2STR(addr));
+
+		ibss_rsn_stop(ibss_rsn, addr);
+		peer = NULL;
+	}
+
+	if (!peer) {
+		peer = ibss_rsn_peer_init(ibss_rsn, addr);
+		if (!peer)
+			return;
+
+		wpa_printf(MSG_DEBUG, "RSN: IBSS Auth started by peer " MACSTR,
+			   MAC2STR(addr));
+	}
+
+	/* reply with an Authentication frame now, before sending an EAPOL */
+	ibss_rsn_send_auth(ibss_rsn, addr, 2);
+	/* no need to start another AUTH challenge in the other way.. */
+	ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_EAPOL_BY_US);
+}
+
+
+void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
+			  size_t len)
+{
+	const struct ieee80211_mgmt *header;
+	struct ibss_rsn_peer *peer;
+	size_t auth_length;
+
+	header = (const struct ieee80211_mgmt *) auth_frame;
+	auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth);
+
+	if (ibss_rsn == NULL || len < auth_length)
+		return;
+
+	if (le_to_host16(header->u.auth.auth_alg) != WLAN_AUTH_OPEN ||
+	    le_to_host16(header->u.auth.status_code) != WLAN_STATUS_SUCCESS)
+		return;
+
+	peer = ibss_rsn_get_peer(ibss_rsn, header->sa);
+
+	switch (le_to_host16(header->u.auth.auth_transaction)) {
+	case 1:
+		ibss_rsn_handle_auth_1_of_2(ibss_rsn, peer, header->sa);
+		break;
+	case 2:
+		wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 2) from "
+			   MACSTR, MAC2STR(header->sa));
+		if (!peer) {
+			wpa_printf(MSG_DEBUG, "RSN: Received Auth seq 2 from "
+				   "unknown STA " MACSTR, MAC2STR(header->sa));
+			break;
+		}
+
+		/* authentication has been completed */
+		wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with "MACSTR,
+			   MAC2STR(header->sa));
+		ibss_rsn_peer_authenticated(ibss_rsn, peer,
+					    IBSS_RSN_AUTH_BY_US);
+		break;
+	}
+}
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 1da94ab..5a8eda4 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -11,6 +11,15 @@
 
 struct ibss_rsn;
 
+/* not authenticated */
+#define IBSS_RSN_AUTH_NOT_AUTHENTICATED	0x00
+/* remote peer sent an EAPOL message */
+#define IBSS_RSN_AUTH_EAPOL_BY_PEER	0x01
+/* we sent an AUTH message with seq 1 */
+#define IBSS_RSN_AUTH_BY_US		0x02
+/* we sent an EAPOL message */
+#define IBSS_RSN_AUTH_EAPOL_BY_US	0x04
+
 struct ibss_rsn_peer {
 	struct ibss_rsn_peer *next;
 	struct ibss_rsn *ibss_rsn;
@@ -23,6 +32,7 @@
 	size_t supp_ie_len;
 
 	struct wpa_state_machine *auth;
+	int authentication_status;
 };
 
 struct ibss_rsn {
@@ -40,5 +50,7 @@
 int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
 		      const u8 *buf, size_t len);
 void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk);
+void ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame,
+			  size_t len);
 
 #endif /* IBSS_RSN_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 37f5ad3..08ae9e5 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -105,13 +105,64 @@
 static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
 
 
+/*
+ * Get the number of concurrent channels that the HW can operate, but that are
+ * currently not in use by any of the wpa_supplicant interfaces.
+ */
+static int wpas_p2p_num_unused_channels(struct wpa_supplicant *wpa_s)
+{
+	int *freqs;
+	int num;
+
+	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+	if (!freqs)
+		return -1;
+
+	num = get_shared_radio_freqs(wpa_s, freqs,
+				     wpa_s->num_multichan_concurrent);
+	os_free(freqs);
+
+	return wpa_s->num_multichan_concurrent - num;
+}
+
+
+/*
+ * Get the frequencies that are currently in use by one or more of the virtual
+ * interfaces, and that are also valid for P2P operation.
+ */
+static int wpas_p2p_valid_oper_freqs(struct wpa_supplicant *wpa_s,
+				     int *p2p_freqs, unsigned int len)
+{
+	int *freqs;
+	unsigned int num, i, j;
+
+	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+	if (!freqs)
+		return -1;
+
+	num = get_shared_radio_freqs(wpa_s, freqs,
+				     wpa_s->num_multichan_concurrent);
+
+	os_memset(p2p_freqs, 0, sizeof(int) * len);
+
+	for (i = 0, j = 0; i < num && j < len; i++) {
+		if (p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
+			p2p_freqs[j++] = freqs[i];
+	}
+
+	os_free(freqs);
+
+	return j;
+}
+
+
 static void wpas_p2p_set_own_freq_preference(struct wpa_supplicant *wpa_s,
 					     int freq)
 {
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
-	if (freq > 0 &&
-	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+	if (freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+	    wpas_p2p_num_unused_channels(wpa_s) > 0 &&
 	    wpa_s->parent->conf->p2p_ignore_shared_freq)
 		freq = 0;
 	p2p_set_own_freq_preference(wpa_s->global->p2p, freq);
@@ -2473,7 +2524,6 @@
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *s;
-	u8 cur_bssid[ETH_ALEN];
 	int res;
 	struct wpa_supplicant *grp;
 
@@ -2550,25 +2600,15 @@
 accept_inv:
 	wpas_p2p_set_own_freq_preference(wpa_s, 0);
 
-	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, cur_bssid) == 0 &&
-	    wpa_s->assoc_freq) {
-		wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
-			   "the channel we are already using");
-		*force_freq = wpa_s->assoc_freq;
-		wpas_p2p_set_own_freq_preference(wpa_s, wpa_s->assoc_freq);
-	}
-
-	res = wpa_drv_shared_freq(wpa_s);
-	if (res > 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match "
-			   "with the channel we are already using on a "
-			   "shared interface");
+	/* Get one of the frequencies currently in use */
+	if (wpas_p2p_valid_oper_freqs(wpa_s, &res, 1) > 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Trying to force channel to match a channel already used by one of the interfaces");
 		*force_freq = res;
 		wpas_p2p_set_own_freq_preference(wpa_s, res);
 	}
 
-	if (*force_freq > 0 &&
-	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+	if (*force_freq > 0 && wpa_s->num_multichan_concurrent > 1 &&
+	    wpas_p2p_num_unused_channels(wpa_s) > 0) {
 		if (*go == 0) {
 			/* We are the client */
 			wpa_printf(MSG_DEBUG, "P2P: Peer was found to be "
@@ -3268,17 +3308,6 @@
 
 	p2p.max_listen = wpa_s->max_remain_on_chan;
 
-#ifdef ANDROID_P2P
-	if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
-		p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT;
-		wpa_printf(MSG_DEBUG, "P2P: Multi channel concurrency support");
-	} else {
-	// Add support for WPA_DRIVER_FLAGS_P2P_CONCURRENT
-		p2p.p2p_concurrency = P2P_SINGLE_CHANNEL_CONCURRENT;
-		wpa_printf(MSG_DEBUG, "P2P: Single channel concurrency support");
-	}
-#endif
-
 	global->p2p = p2p_init(&p2p);
 	if (global->p2p == NULL)
 		return -1;
@@ -3475,43 +3504,38 @@
 
 static int wpas_check_freq_conflict(struct wpa_supplicant *wpa_s, int freq)
 {
-	struct wpa_supplicant *iface;
-	int shared_freq;
-	u8 bssid[ETH_ALEN];
+	int *freqs, res, num, i;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
+	if (wpas_p2p_num_unused_channels(wpa_s) > 0) {
+		/* Multiple channels are supported and not all are in use */
 		return 0;
+	}
 
-	for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
-		if (!wpas_p2p_create_iface(wpa_s) && iface == wpa_s)
-			continue;
-		if (iface->current_ssid == NULL || iface->assoc_freq == 0)
-			continue;
-		if (iface->current_ssid->mode == WPAS_MODE_AP ||
-		    iface->current_ssid->mode == WPAS_MODE_P2P_GO)
-			shared_freq = iface->current_ssid->frequency;
-		else if (wpa_drv_get_bssid(iface, bssid) == 0)
-			shared_freq = iface->assoc_freq;
-		else
-			shared_freq = 0;
+	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+	if (!freqs)
+		return 1;
 
-		if (shared_freq && freq != shared_freq) {
-			wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - %s "
-				   "connected on %d MHz - new connection on "
-				   "%d MHz", iface->ifname, shared_freq, freq);
-			return 1;
+	num = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+					wpa_s->num_multichan_concurrent);
+	if (num < 0) {
+		res = 1;
+		goto exit_free;
+	}
+
+	for (i = 0; i < num; i++) {
+		if (freqs[i] == freq) {
+			wpa_printf(MSG_DEBUG, "P2P: Frequency %d MHz in use by another virtual interface and can be used",
+				   freq);
+			res = 0;
+			goto exit_free;
 		}
 	}
 
-	shared_freq = wpa_drv_shared_freq(wpa_s);
-	if (shared_freq > 0 && shared_freq != freq) {
-		wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - shared "
-			   "virtual interface connected on %d MHz - new "
-			   "connection on %d MHz", shared_freq, freq);
-		return 1;
-	}
+	res = 1;
 
-	return 0;
+exit_free:
+	os_free(freqs);
+	return res;
 }
 
 
@@ -3891,56 +3915,75 @@
 
 
 static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
-				int *force_freq, int *pref_freq,
-				int *oper_freq)
+				int *force_freq, int *pref_freq)
 {
+	int *freqs, res;
+	unsigned int freq_in_use = 0, num, i;
+
+	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+	if (!freqs)
+		return -1;
+
+	num = get_shared_radio_freqs(wpa_s, freqs,
+				     wpa_s->num_multichan_concurrent);
+
 	if (freq > 0) {
 		if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
 			wpa_printf(MSG_DEBUG, "P2P: The forced channel "
 				   "(%u MHz) is not supported for P2P uses",
 				   freq);
-			return -3;
+			res = -3;
+			goto exit_free;
 		}
 
-		if (*oper_freq > 0 && freq != *oper_freq &&
-		    !(wpa_s->drv_flags &
-		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
-				   "on %u MHz while connected on another "
-				   "channel (%u MHz)", freq, *oper_freq);
-			return -2;
+		for (i = 0; i < num; i++) {
+			if (freqs[i] == freq)
+				freq_in_use = 1;
+		}
+
+		if (num == wpa_s->num_multichan_concurrent && !freq_in_use) {
+			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz as there are no available channels",
+				   freq);
+			res = -2;
+			goto exit_free;
 		}
 		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
 			   "requested channel (%u MHz)", freq);
 		*force_freq = freq;
-	} else if (*oper_freq > 0 &&
-		   !p2p_supported_freq(wpa_s->global->p2p, *oper_freq)) {
-		if (!(wpa_s->drv_flags &
-		      WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-			wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group "
-				   "while connected on non-P2P supported "
-				   "channel (%u MHz)", *oper_freq);
-			return -2;
-		}
-		wpa_printf(MSG_DEBUG, "P2P: Current operating channel "
-			   "(%u MHz) not available for P2P - try to use "
-			   "another channel", *oper_freq);
-		*force_freq = 0;
-	} else if (*oper_freq > 0 && *pref_freq == 0 &&
-		   (wpa_s->drv_flags &
-		    WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-		wpa_printf(MSG_DEBUG, "P2P: Trying to prefer the channel we "
-			   "are already using (%u MHz) on another interface",
-			   *oper_freq);
-		*pref_freq = *oper_freq;
-	} else if (*oper_freq > 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Trying to force us to use the "
-			   "channel we are already using (%u MHz) on another "
-			   "interface", *oper_freq);
-		*force_freq = *oper_freq;
+		goto exit_ok;
 	}
 
-	return 0;
+	for (i = 0; i < num; i++) {
+		if (!p2p_supported_freq(wpa_s->global->p2p, freqs[i]))
+			continue;
+
+		wpa_printf(MSG_DEBUG, "P2P: Try to force us to use frequency (%u MHz) which is already in use",
+			   *force_freq);
+		*force_freq = freqs[i];
+
+		if (*pref_freq == 0 && num < wpa_s->num_multichan_concurrent) {
+			wpa_printf(MSG_DEBUG, "P2P: Try to prefer a frequency we are already using");
+			*pref_freq = *force_freq;
+		}
+		break;
+	}
+
+	if (i == num) {
+		if (num < wpa_s->num_multichan_concurrent) {
+			wpa_printf(MSG_DEBUG, "P2P: Current operating channels are not available for P2P. Try to use another channel");
+			*force_freq = 0;
+		} else {
+			wpa_printf(MSG_DEBUG, "P2P: All channels are in use and none of them are P2P enabled. Cannot start P2P group");
+			res = -2;
+			goto exit_free;
+		}
+	}
+
+exit_ok:
+	res = 0;
+exit_free:
+	os_free(freqs);
+	return res;
 }
 
 
@@ -3972,8 +4015,7 @@
 		     int go_intent, int freq, int persistent_id, int pd,
 		     int ht40)
 {
-	int force_freq = 0, pref_freq = 0, oper_freq = 0;
-	u8 bssid[ETH_ALEN];
+	int force_freq = 0, pref_freq = 0;
 	int ret = 0, res;
 	enum wpa_driver_if_type iftype;
 	const u8 *if_addr;
@@ -4045,20 +4087,10 @@
 		return ret;
 	}
 
-	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
-	    wpa_s->assoc_freq) {
-		oper_freq = wpa_s->assoc_freq;
-	} else {
-		oper_freq = wpa_drv_shared_freq(wpa_s);
-		if (oper_freq < 0)
-			oper_freq = 0;
-	}
-
-	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
-				   &oper_freq);
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
 	if (res)
 		return res;
-	wpas_p2p_set_own_freq_preference(wpa_s, oper_freq);
+	wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
 
 	wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
 
@@ -4259,9 +4291,9 @@
 				   int freq, int ht40,
 				   const struct p2p_channels *channels)
 {
-	u8 bssid[ETH_ALEN];
-	int res;
+	int res, *freqs;
 	unsigned int pref_freq;
+	unsigned int num, i;
 
 	os_memset(params, 0, sizeof(*params));
 	params->role_go = 1;
@@ -4341,64 +4373,54 @@
 			   "known)", params->freq);
 	}
 
-	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
-	    wpa_s->assoc_freq && !freq) {
-		if (!p2p_supported_freq(wpa_s->global->p2p, wpa_s->assoc_freq)
-		    || !freq_included(channels, wpa_s->assoc_freq)) {
-			if (wpa_s->drv_flags &
-			    WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on "
-					   "the channel we are already using "
-					   "(%u MHz) - allow multi-channel "
-					   "concurrency", wpa_s->assoc_freq);
-			} else {
-				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on "
-					   "the channel we are already using "
-					   "(%u MHz)", wpa_s->assoc_freq);
-				return -1;
-			}
-		} else {
-			wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we "
-				   "are already using (%u MHz)",
-				   wpa_s->assoc_freq);
-			params->freq = wpa_s->assoc_freq;
-		}
-	}
+	freqs = os_calloc(wpa_s->num_multichan_concurrent, sizeof(int));
+	if (!freqs)
+		return -1;
 
-	res = wpa_drv_shared_freq(wpa_s);
-	if (res > 0 && !freq &&
-	    (!p2p_supported_freq(wpa_s->global->p2p, res) ||
-	     !freq_included(channels, res))) {
-		if (wpa_s->drv_flags &
-		    WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) {
-			wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on the "
-				   "channel we are already using on a shared "
-				   "interface (%u MHz) - allow multi-channel "
-				   "concurrency", res);
-		} else {
-			wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on the "
-				   "channel we are already using on a shared "
-				   "interface (%u MHz)", res);
-			return -1;
-		}
-	} else if (res > 0 && !freq) {
-		wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
-			   "already using on a shared interface");
-		params->freq = res;
-		if (!freq_included(channels, params->freq)) {
-			wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
-				   "accepted", params->freq);
-			return -1;
-		}
-	} else if (res > 0 && freq != res &&
-		   !(wpa_s->drv_flags &
-		     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
-		wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz "
-			   "while connected on another channel (%u MHz)",
-			   freq, res);
+	res = wpas_p2p_valid_oper_freqs(wpa_s, freqs,
+					wpa_s->num_multichan_concurrent);
+	if (res < 0) {
+		os_free(freqs);
 		return -1;
 	}
+	num = res;
 
+	if (!freq) {
+		for (i = 0; i < num; i++) {
+			if (freq_included(channels, freqs[i])) {
+				wpa_printf(MSG_DEBUG, "P2P: Force GO on a channel we are already using (%u MHz)",
+					   freqs[i]);
+				params->freq = freqs[i];
+				break;
+			}
+		}
+
+		if (i == num) {
+			if (num == wpa_s->num_multichan_concurrent) {
+				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using");
+				os_free(freqs);
+				return -1;
+			} else {
+				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+			}
+		}
+	} else {
+		for (i = 0; i < num; i++) {
+			if (freqs[i] == freq)
+				break;
+		}
+
+		if (i == num) {
+			if (num == wpa_s->num_multichan_concurrent) {
+				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on freq (%u MHz) as all the channels are in use", freq);
+				os_free(freqs);
+				return -1;
+			} else {
+				wpa_printf(MSG_DEBUG, "P2P: Cannot force GO on any of the channels we are already using. Use one of the free channels");
+			}
+		}
+	}
+	os_free(freqs);
 	return 0;
 }
 
@@ -5002,8 +5024,8 @@
 		    int ht40, int pref_freq)
 {
 	enum p2p_invite_role role;
-	u8 *bssid = NULL, bssid_buf[ETH_ALEN];
-	int force_freq = 0, oper_freq = 0;
+	u8 *bssid = NULL;
+	int force_freq = 0;
 	int res;
 
 	wpa_s->global->p2p_invite_group = NULL;
@@ -5038,19 +5060,7 @@
 	}
 	wpa_s->pending_invite_ssid_id = ssid->id;
 
-	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 &&
-	    wpa_s->assoc_freq) {
-		oper_freq = wpa_s->assoc_freq;
-		if (bssid == NULL)
-			bssid = bssid_buf;
-	} else {
-		oper_freq = wpa_drv_shared_freq(wpa_s);
-		if (oper_freq < 0)
-			oper_freq = 0;
-	}
-
-	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
-				   &oper_freq);
+	res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
 	if (res)
 		return res;
 
@@ -5074,10 +5084,10 @@
 {
 	struct wpa_global *global = wpa_s->global;
 	enum p2p_invite_role role;
-	u8 *bssid = NULL, bssid_buf[ETH_ALEN];
+	u8 *bssid = NULL;
 	struct wpa_ssid *ssid;
 	int persistent;
-	int force_freq = 0, oper_freq = 0, pref_freq = 0;
+	int force_freq = 0, pref_freq = 0;
 	int res;
 
 	wpa_s->p2p_persistent_go_freq = 0;
@@ -5131,22 +5141,10 @@
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
-	if (wpa_s->current_ssid && wpa_drv_get_bssid(wpa_s, bssid_buf) == 0 &&
-	    wpa_s->assoc_freq) {
-		oper_freq = wpa_s->assoc_freq;
-		if (bssid == NULL)
-			bssid = bssid_buf;
-	} else {
-		oper_freq = wpa_drv_shared_freq(wpa_s);
-		if (oper_freq < 0)
-			oper_freq = 0;
-	}
-
-	res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq,
-				   &oper_freq);
+	res = wpas_p2p_setup_freqs(wpa_s, 0, &force_freq, &pref_freq);
 	if (res)
 		return res;
-	wpas_p2p_set_own_freq_preference(wpa_s, oper_freq);
+	wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
 
 	return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
 			  ssid->ssid, ssid->ssid_len, force_freq,
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 8cd0f1d..9b6cd46 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -488,44 +488,6 @@
 
 #endif /* CONFIG_P2P */
 
-/*
- * Find the operating frequency of any other virtual interface that is using
- * the same radio concurrently.
- */
-static int shared_vif_oper_freq(struct wpa_supplicant *wpa_s)
-{
-	const char *rn, *rn2;
-	struct wpa_supplicant *ifs;
-	u8 bssid[ETH_ALEN];
-
-	if (!wpa_s->driver->get_radio_name)
-		return -1;
-
-	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
-	if (rn == NULL || rn[0] == '\0')
-		return -1;
-
-	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-		if (ifs == wpa_s || !ifs->driver->get_radio_name)
-			continue;
-
-		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
-		if (!rn2 || os_strcmp(rn, rn2) != 0)
-			continue;
-
-		if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
-			continue;
-
-		if (ifs->current_ssid->mode == WPAS_MODE_AP ||
-		    ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
-			return ifs->current_ssid->frequency;
-		if (wpa_drv_get_bssid(ifs, bssid) == 0)
-			return ifs->assoc_freq;
-	}
-
-	return 0;
-}
-
 
 static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
 					  u16 num_modes,
@@ -828,14 +790,19 @@
 
 	/* Use current associated channel? */
 	if (wpa_s->conf->scan_cur_freq && !params.freqs) {
-		int freq = shared_vif_oper_freq(wpa_s);
-		if (freq > 0) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current "
-				"operating channel (%d MHz) since "
-				"scan_cur_freq is enabled", freq);
-			params.freqs = os_zalloc(sizeof(int) * 2);
-			if (params.freqs)
-				params.freqs[0] = freq;
+		unsigned int num = wpa_s->num_multichan_concurrent;
+
+		params.freqs = os_calloc(num + 1, sizeof(int));
+		if (params.freqs) {
+			num = get_shared_radio_freqs(wpa_s, params.freqs, num);
+			if (num > 0) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the "
+					"current operating channels since "
+					"scan_cur_freq is enabled");
+			} else {
+				os_free(params.freqs);
+				params.freqs = NULL;
+			}
 		}
 	}
 
@@ -873,18 +840,19 @@
 	if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ &&
 	    !scan_params->freqs && !params.freqs &&
 	    wpas_is_p2p_prioritized(wpa_s) &&
-	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
 	    wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
 	    non_p2p_network_enabled(wpa_s)) {
-		int freq = shared_vif_oper_freq(wpa_s);
-		if (freq > 0) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current "
-				"operating channel (%d MHz) since driver does "
-				"not support multi-channel concurrency", freq);
-			params.freqs = os_zalloc(sizeof(int) * 2);
-			if (params.freqs)
-				params.freqs[0] = freq;
-			scan_params->freqs = params.freqs;
+		unsigned int num = wpa_s->num_multichan_concurrent;
+
+		params.freqs = os_calloc(num + 1, sizeof(int));
+		if (params.freqs) {
+			num = get_shared_radio_freqs(wpa_s, params.freqs, num);
+			if (num > 0 && num == wpa_s->num_multichan_concurrent) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the current operating channels since all channels are already used");
+			} else {
+				os_free(params.freqs);
+				params.freqs = NULL;
+			}
 		}
 	}
 #endif /* CONFIG_P2P */
@@ -1249,6 +1217,23 @@
 
 
 /**
+ * wpa_supplicant_cancel_delayed_sched_scan - Stop a delayed scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to stop a delayed scheduled scan.
+ */
+void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->sched_scan_supported)
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling delayed sched scan");
+	eloop_cancel_timeout(wpa_supplicant_delayed_sched_scan_timeout,
+			     wpa_s, NULL);
+}
+
+
+/**
  * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans
  * @wpa_s: Pointer to wpa_supplicant data
  *
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index e892479..2144787 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -15,6 +15,7 @@
 				      int sec, int usec);
 int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_delayed_sched_scan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
 				    int scanning);
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 0371628..925d132 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -805,7 +805,7 @@
 
 
 void sme_event_disassoc(struct wpa_supplicant *wpa_s,
-			union wpa_event_data *data)
+			struct disassoc_info *info)
 {
 	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Disassociation event received");
 	if (wpa_s->sme.prev_bssid_set) {
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index a7cc507..04404c1 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -25,7 +25,7 @@
 void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
 			       union wpa_event_data *data);
 void sme_event_disassoc(struct wpa_supplicant *wpa_s,
-			union wpa_event_data *data);
+			struct disassoc_info *info);
 void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
 				 const u8 *da, u16 reason_code);
 void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
@@ -74,7 +74,7 @@
 }
 
 static inline void sme_event_disassoc(struct wpa_supplicant *wpa_s,
-				      union wpa_event_data *data)
+				      struct disassoc_info *info)
 {
 }
 
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f6b881b..a6bd935 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -421,6 +421,7 @@
 
 	wpa_bss_deinit(wpa_s);
 
+	wpa_supplicant_cancel_delayed_sched_scan(wpa_s);
 	wpa_supplicant_cancel_scan(wpa_s);
 	wpa_supplicant_cancel_auth_timeout(wpa_s);
 	eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
@@ -1630,7 +1631,7 @@
 	/* If multichannel concurrency is not supported, check for any frequency
 	 * conflict and take appropriate action.
 	 */
-	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+	if ((wpa_s->num_multichan_concurrent < 2) &&
 		((freq = wpa_drv_shared_freq(wpa_s)) > 0) && (freq != params.freq)) {
 		wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)"
 																, freq, params.freq);
@@ -2985,6 +2986,8 @@
 		wpa_s->extended_capa = capa.extended_capa;
 		wpa_s->extended_capa_mask = capa.extended_capa_mask;
 		wpa_s->extended_capa_len = capa.extended_capa_len;
+		wpa_s->num_multichan_concurrent =
+			capa.num_multichan_concurrent;
 	}
 	if (wpa_s->max_remain_on_chan == 0)
 		wpa_s->max_remain_on_chan = 1000;
@@ -2999,6 +3002,9 @@
 	else
 		iface->p2p_mgmt = 1;
 
+	if (wpa_s->num_multichan_concurrent == 0)
+		wpa_s->num_multichan_concurrent = 1;
+
 	if (wpa_supplicant_driver_init(wpa_s) < 0)
 		return -1;
 
@@ -3957,3 +3963,72 @@
 
 	return 0;
 }
+
+
+/*
+ * Find the operating frequencies of any of the virtual interfaces that
+ * are using the same radio as the current interface.
+ */
+int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
+			   int *freq_array, unsigned int len)
+{
+	const char *rn, *rn2;
+	struct wpa_supplicant *ifs;
+	u8 bssid[ETH_ALEN];
+	int freq;
+	unsigned int idx = 0, i;
+
+	os_memset(freq_array, 0, sizeof(int) * len);
+
+	/* First add the frequency of the local interface */
+	if (wpa_s->current_ssid != NULL && wpa_s->assoc_freq != 0) {
+		if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
+		    wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO)
+			freq_array[idx++] = wpa_s->current_ssid->frequency;
+		else if (wpa_drv_get_bssid(wpa_s, bssid) == 0)
+			freq_array[idx++] = wpa_s->assoc_freq;
+	}
+
+	/* If get_radio_name is not supported, use only the local freq */
+	if (!wpa_s->driver->get_radio_name) {
+		freq = wpa_drv_shared_freq(wpa_s);
+		if (freq > 0 && idx < len &&
+		    (idx == 0 || freq_array[0] != freq))
+			freq_array[idx++] = freq;
+		return idx;
+	}
+
+	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+	if (rn == NULL || rn[0] == '\0')
+		return idx;
+
+	for (ifs = wpa_s->global->ifaces, idx = 0; ifs && idx < len;
+	     ifs = ifs->next) {
+		if (wpa_s == ifs || !ifs->driver->get_radio_name)
+			continue;
+
+		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+		if (!rn2 || os_strcmp(rn, rn2) != 0)
+			continue;
+
+		if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+			continue;
+
+		if (ifs->current_ssid->mode == WPAS_MODE_AP ||
+		    ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
+			freq = ifs->current_ssid->frequency;
+		else if (wpa_drv_get_bssid(ifs, bssid) == 0)
+			freq = ifs->assoc_freq;
+		else
+			continue;
+
+		/* Hold only distinct freqs */
+		for (i = 0; i < idx; i++)
+			if (freq_array[i] == freq)
+				break;
+
+		if (i == idx)
+			freq_array[idx++] = freq;
+	}
+	return idx;
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 9240863..0858bbc 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -722,6 +722,8 @@
 	u8 last_gtk[32];
 	size_t last_gtk_len;
 #endif /* CONFIG_TESTING_GET_GTK */
+
+	unsigned int num_multichan_concurrent;
 };
 
 
@@ -860,4 +862,7 @@
 
 int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
 
+int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
+			   int *freq_array, unsigned int len);
+
 #endif /* WPA_SUPPLICANT_I_H */