Cumulative patch from commit 075131e32e6967977da4bbfa8a7f63dbfbf86008i

075131e Android: Do not compile wpa_supplicant if not chosen
f7154ce DFS: Use channel switch when radar is detected
6c6c58d hostapd: Make hostapd_set_freq_params() public
b72f949 DFS: Allow skipping radar channels
8d1fdde nl80211/hostapd: Extend channel switch notify handling
10e694a AP: Use monotonic clock for SA query timeout
af53896 Use monotonic clock for RADIUS cache timeouts
fe52c21 Use monotonic clock for last_sae_token_key_update
100298e AP: Use monotonic time for AP list
e5c9e40 OS utils: Add os_reltime_expired()
b3493fa AP: Use monotonic time for STA connected time
ed0ebee OS utils: Provide os_reltime_age()
8567866 P2P: Handle frequency conflict in single channel concurrency case
b125c48 P2P: Add wfd_dev_info= field for device found event
e706d2d bsd: Fix compilation error for NetBSD
f757950 eap_proxy: Extend Android.mk to support additional libraries

Change-Id: I6d4f0f559f420680903d12966c7a6a87da97d61a
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 0dc0600..09b5f68 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -464,11 +464,11 @@
 }
 
 
-static int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
-				   int freq, int channel, int ht_enabled,
-				   int vht_enabled, int sec_channel_offset,
-				   int vht_oper_chwidth, int center_segment0,
-				   int center_segment1, u32 vht_caps)
+int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
+			    int freq, int channel, int ht_enabled,
+			    int vht_enabled, int sec_channel_offset,
+			    int vht_oper_chwidth, int center_segment0,
+			    int center_segment1, u32 vht_caps)
 {
 	int tmp;
 
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 1eab939..b5f6a02 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -14,6 +14,7 @@
 struct wpa_driver_scan_params;
 struct ieee80211_ht_capabilities;
 struct ieee80211_vht_capabilities;
+struct hostapd_freq_params;
 
 u32 hostapd_sta_flags_to_drv(u32 flags);
 int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
@@ -105,6 +106,11 @@
 			  int channel, int ht_enabled, int vht_enabled,
 			  int sec_channel_offset, int vht_oper_chwidth,
 			  int center_segment0, int center_segment1);
+int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
+			    int freq, int channel, int ht_enabled,
+			    int vht_enabled, int sec_channel_offset,
+			    int vht_oper_chwidth, int center_segment0,
+			    int center_segment1, u32 vht_caps);
 
 
 #include "drivers/driver.h"
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 9f02151..0dab39f 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -172,7 +172,6 @@
 			    struct hostapd_frame_info *fi)
 {
 	struct ap_info *ap;
-	struct os_time now;
 	int new_ap = 0;
 	int set_beacon = 0;
 
@@ -210,8 +209,7 @@
 	else
 		ap->ht_support = 0;
 
-	os_get_time(&now);
-	ap->last_beacon = now.sec;
+	os_get_reltime(&ap->last_beacon);
 
 	if (!new_ap && ap != iface->ap_list) {
 		/* move AP entry into the beginning of the list so that the
@@ -252,7 +250,7 @@
 static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
 {
 	struct hostapd_iface *iface = eloop_ctx;
-	struct os_time now;
+	struct os_reltime now;
 	struct ap_info *ap;
 	int set_beacon = 0;
 
@@ -261,12 +259,12 @@
 	if (!iface->ap_list)
 		return;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 
 	while (iface->ap_list) {
 		ap = iface->ap_list->prev;
-		if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
-		    now.sec)
+		if (!os_reltime_expired(&now, &ap->last_beacon,
+					iface->conf->ap_table_expiration_time))
 			break;
 
 		ap_free_ap(iface, ap);
diff --git a/src/ap/ap_list.h b/src/ap/ap_list.h
index d0529a1..93dc0ed 100644
--- a/src/ap/ap_list.h
+++ b/src/ap/ap_list.h
@@ -26,7 +26,7 @@
 
 	int ht_support;
 
-	os_time_t last_beacon;
+	struct os_reltime last_beacon;
 };
 
 struct ieee802_11_elems;
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index ac33068..4125fd5 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -24,14 +24,13 @@
 static int hostapd_get_sta_conn_time(struct sta_info *sta,
 				     char *buf, size_t buflen)
 {
-	struct os_time now, age;
+	struct os_reltime age;
 	int len = 0, ret;
 
 	if (!sta->connected_time.sec)
 		return 0;
 
-	os_get_time(&now);
-	os_time_sub(&now, &sta->connected_time, &age);
+	os_reltime_age(&sta->connected_time, &age);
 
 	ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
 			  (unsigned int) age.sec);
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 0a909f4..caf4092 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -44,8 +44,17 @@
 }
 
 
-static int dfs_channel_available(struct hostapd_channel_data *chan)
+static int dfs_channel_available(struct hostapd_channel_data *chan,
+				 int skip_radar)
 {
+	/*
+	 * When radar detection happens, CSA is performed. However, there's no
+	 * time for CAC, so radar channels must be skipped when finding a new
+	 * channel for CSA.
+	 */
+	if (skip_radar && chan->flag & HOSTAPD_CHAN_RADAR)
+		return 0;
+
 	if (chan->flag & HOSTAPD_CHAN_DISABLED)
 		return 0;
 	if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
@@ -96,7 +105,8 @@
 
 
 static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
-				    int first_chan_idx, int num_chans)
+				    int first_chan_idx, int num_chans,
+				    int skip_radar)
 {
 	struct hostapd_channel_data *first_chan, *chan;
 	int i;
@@ -112,7 +122,7 @@
 		if (first_chan->freq + i * 20 != chan->freq)
 			return 0;
 
-		if (!dfs_channel_available(chan))
+		if (!dfs_channel_available(chan, skip_radar))
 			return 0;
 	}
 
@@ -129,7 +139,7 @@
  */
 static int dfs_find_channel(struct hostapd_iface *iface,
 			    struct hostapd_channel_data **ret_chan,
-			    int idx)
+			    int idx, int skip_radar)
 {
 	struct hostapd_hw_modes *mode;
 	struct hostapd_channel_data *chan;
@@ -149,7 +159,7 @@
 			continue;
 
 		/* Skip incompatible chandefs */
-		if (!dfs_chan_range_available(mode, i, n_chans))
+		if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
 			continue;
 
 		if (ret_chan && idx == channel_idx) {
@@ -322,7 +332,8 @@
 dfs_get_valid_channel(struct hostapd_iface *iface,
 		      int *secondary_channel,
 		      u8 *vht_oper_centr_freq_seg0_idx,
-		      u8 *vht_oper_centr_freq_seg1_idx)
+		      u8 *vht_oper_centr_freq_seg1_idx,
+		      int skip_radar)
 {
 	struct hostapd_hw_modes *mode;
 	struct hostapd_channel_data *chan = NULL;
@@ -340,13 +351,13 @@
 		return NULL;
 
 	/* Get the count first */
-	num_available_chandefs = dfs_find_channel(iface, NULL, 0);
+	num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
 	if (num_available_chandefs == 0)
 		return NULL;
 
 	os_get_random((u8 *) &_rand, sizeof(_rand));
 	chan_idx = _rand % num_available_chandefs;
-	dfs_find_channel(iface, &chan, chan_idx);
+	dfs_find_channel(iface, &chan, chan_idx, skip_radar);
 
 	/* dfs_find_channel() calculations assume HT40+ */
 	if (iface->conf->secondary_channel)
@@ -518,6 +529,7 @@
 {
 	struct hostapd_channel_data *channel;
 	int res, n_chans, start_chan_idx;
+	int skip_radar = 0;
 
 	iface->cac_started = 0;
 
@@ -555,7 +567,8 @@
 			int sec;
 			u8 cf1, cf2;
 
-			channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2);
+			channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
+							skip_radar);
 			if (!channel) {
 				wpa_printf(MSG_ERROR, "could not get valid channel");
 				return -1;
@@ -614,25 +627,111 @@
 }
 
 
-static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
 {
 	struct hostapd_channel_data *channel;
-	int err = 1;
 	int secondary_channel;
 	u8 vht_oper_centr_freq_seg0_idx;
 	u8 vht_oper_centr_freq_seg1_idx;
+	int skip_radar = 0;
+	int err = 1;
 
-	wpa_printf(MSG_DEBUG, "%s called", __func__);
+	/* Radar detected during active CAC */
+	iface->cac_started = 0;
 	channel = dfs_get_valid_channel(iface, &secondary_channel,
 					&vht_oper_centr_freq_seg0_idx,
-					&vht_oper_centr_freq_seg1_idx);
-	if (channel) {
-		wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
-			   channel->chan);
-		wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
-			"freq=%d chan=%d sec_chan=%d", channel->freq,
-			channel->chan, secondary_channel);
+					&vht_oper_centr_freq_seg1_idx,
+					skip_radar);
 
+	if (!channel) {
+		wpa_printf(MSG_ERROR, "No valid channel available");
+		hostapd_setup_interface_complete(iface, err);
+		return err;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+		   channel->chan);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+		"freq=%d chan=%d sec_chan=%d", channel->freq,
+		channel->chan, secondary_channel);
+
+	iface->freq = channel->freq;
+	iface->conf->channel = channel->chan;
+	iface->conf->secondary_channel = secondary_channel;
+	iface->conf->vht_oper_centr_freq_seg0_idx =
+		vht_oper_centr_freq_seg0_idx;
+	iface->conf->vht_oper_centr_freq_seg1_idx =
+		vht_oper_centr_freq_seg1_idx;
+	err = 0;
+
+	hostapd_setup_interface_complete(iface, err);
+	return err;
+}
+
+
+static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+{
+	struct hostapd_channel_data *channel;
+	int secondary_channel;
+	u8 vht_oper_centr_freq_seg0_idx;
+	u8 vht_oper_centr_freq_seg1_idx;
+	int skip_radar = 1;
+	struct csa_settings csa_settings;
+	struct hostapd_data *hapd = iface->bss[0];
+	int err = 1;
+
+	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s)", __func__,
+		   iface->cac_started ? "yes" : "no");
+
+	/* Check if active CAC */
+	if (iface->cac_started)
+		return hostapd_dfs_start_channel_switch_cac(iface);
+
+
+	/* Perform channel switch/CSA */
+	channel = dfs_get_valid_channel(iface, &secondary_channel,
+					&vht_oper_centr_freq_seg0_idx,
+					&vht_oper_centr_freq_seg1_idx,
+					skip_radar);
+
+	if (!channel) {
+		/* FIXME: Wait for channel(s) to become available */
+		hostapd_disable_iface(iface);
+		return err;
+	}
+
+	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+		   channel->chan);
+	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+		"freq=%d chan=%d sec_chan=%d", channel->freq,
+		channel->chan, secondary_channel);
+
+	/* Setup CSA request */
+	os_memset(&csa_settings, 0, sizeof(csa_settings));
+	csa_settings.cs_count = 5;
+	csa_settings.block_tx = 1;
+	err = hostapd_set_freq_params(&csa_settings.freq_params,
+				      iface->conf->hw_mode,
+				      channel->freq,
+				      channel->chan,
+				      iface->conf->ieee80211n,
+				      iface->conf->ieee80211ac,
+				      secondary_channel,
+				      iface->conf->vht_oper_chwidth,
+				      vht_oper_centr_freq_seg0_idx,
+				      vht_oper_centr_freq_seg1_idx,
+				      iface->current_mode->vht_capab);
+
+	if (err) {
+		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
+		hostapd_disable_iface(iface);
+		return err;
+	}
+
+	err = hostapd_switch_channel(hapd, &csa_settings);
+	if (err) {
+		wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
+			   err);
 		iface->freq = channel->freq;
 		iface->conf->channel = channel->chan;
 		iface->conf->secondary_channel = secondary_channel;
@@ -640,29 +739,16 @@
 			vht_oper_centr_freq_seg0_idx;
 		iface->conf->vht_oper_centr_freq_seg1_idx =
 			vht_oper_centr_freq_seg1_idx;
-		err = 0;
-	} else {
-		wpa_printf(MSG_ERROR, "No valid channel available");
-	}
 
-	if (iface->cac_started) {
-		wpa_printf(MSG_DEBUG, "DFS radar detected during CAC");
-		iface->cac_started = 0;
-		/* FIXME: Wait for channel(s) to become available if no channel
-		 * has been found */
-		hostapd_setup_interface_complete(iface, err);
-		return err;
-	}
-
-	if (err) {
-		/* FIXME: Wait for channel(s) to become available */
 		hostapd_disable_iface(iface);
-		return err;
+		hostapd_enable_iface(iface);
+		return 0;
 	}
 
-	wpa_printf(MSG_DEBUG, "DFS radar detected");
-	hostapd_disable_iface(iface);
-	hostapd_enable_iface(iface);
+	/* Channel configuration will be updated once CSA completes and
+	 * ch_switch_notify event is received */
+
+	wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
 	return 0;
 }
 
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 1b69ba8..b066bff 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -381,14 +381,15 @@
 
 
 void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
-			     int offset)
+			     int offset, int width, int cf1, int cf2)
 {
 #ifdef NEED_AP_MLME
-	int channel;
+	int channel, chwidth, seg0_idx = 0, seg1_idx = 0;
 
 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "driver had channel switch: "
-		       "freq=%d, ht=%d, offset=%d", freq, ht, offset);
+		       "freq=%d, ht=%d, offset=%d, width=%d, cf1=%d, cf2=%d",
+		       freq, ht, offset, width, cf1, cf2);
 
 	hapd->iface->freq = freq;
 
@@ -400,9 +401,43 @@
 		return;
 	}
 
+	switch (width) {
+	case CHAN_WIDTH_80:
+		chwidth = VHT_CHANWIDTH_80MHZ;
+		break;
+	case CHAN_WIDTH_80P80:
+		chwidth = VHT_CHANWIDTH_80P80MHZ;
+		break;
+	case CHAN_WIDTH_160:
+		chwidth = VHT_CHANWIDTH_160MHZ;
+		break;
+	case CHAN_WIDTH_20_NOHT:
+	case CHAN_WIDTH_20:
+	case CHAN_WIDTH_40:
+	default:
+		chwidth = VHT_CHANWIDTH_USE_HT;
+		break;
+	}
+
+	switch (hapd->iface->current_mode->mode) {
+	case HOSTAPD_MODE_IEEE80211A:
+		if (cf1 > 5000)
+			seg0_idx = (cf1 - 5000) / 5;
+		if (cf2 > 5000)
+			seg1_idx = (cf2 - 5000) / 5;
+		break;
+	default:
+		seg0_idx = hostapd_hw_get_channel(hapd, cf1);
+		seg1_idx = hostapd_hw_get_channel(hapd, cf2);
+		break;
+	}
+
 	hapd->iconf->channel = channel;
 	hapd->iconf->ieee80211n = ht;
 	hapd->iconf->secondary_channel = offset;
+	hapd->iconf->vht_oper_chwidth = chwidth;
+	hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
+	hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
 
 	if (hapd->iface->csa_in_progress && freq == hapd->iface->cs_freq) {
 		hostapd_cleanup_cs_params(hapd);
@@ -976,7 +1011,10 @@
 			break;
 		hostapd_event_ch_switch(hapd, data->ch_switch.freq,
 					data->ch_switch.ht_enabled,
-					data->ch_switch.ch_offset);
+					data->ch_switch.ch_offset,
+					data->ch_switch.ch_width,
+					data->ch_switch.cf1,
+					data->ch_switch.cf2);
 		break;
 	case EVENT_CONNECT_FAILED_REASON:
 		if (!data)
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 492861e..6fe2956 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1967,7 +1967,7 @@
 	 * IEEE 802.1X/WPA code will start accounting after the station has
 	 * been authorized. */
 	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
-		os_get_time(&sta->connected_time);
+		os_get_reltime(&sta->connected_time);
 		accounting_sta_start(hapd, sta);
 	}
 
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index c25917d..84468de 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -241,7 +241,7 @@
 #ifdef CONFIG_SAE
 	/** Key used for generating SAE anti-clogging tokens */
 	u8 sae_token_key[8];
-	os_time_t last_sae_token_key_update;
+	struct os_reltime last_sae_token_key_update;
 #endif /* CONFIG_SAE */
 };
 
@@ -414,7 +414,7 @@
 			 const u8 *bssid, const u8 *ie, size_t ie_len,
 			 int ssi_signal);
 void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
-			     int offset);
+			     int offset, int width, int cf1, int cf2);
 
 const struct hostapd_eap_user *
 hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index d553caa..e55f843 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -411,17 +411,17 @@
 {
 	struct wpabuf *buf;
 	u8 *token;
-	struct os_time t;
+	struct os_reltime now;
 
-	os_get_time(&t);
-	if (hapd->last_sae_token_key_update == 0 ||
-	    t.sec > hapd->last_sae_token_key_update + 60) {
+	os_get_reltime(&now);
+	if (!os_reltime_initialized(&hapd->last_sae_token_key_update) ||
+	    os_reltime_expired(&now, &hapd->last_sae_token_key_update, 60)) {
 		if (random_get_bytes(hapd->sae_token_key,
 				     sizeof(hapd->sae_token_key)) < 0)
 			return NULL;
 		wpa_hexdump(MSG_DEBUG, "SAE: Updated token key",
 			    hapd->sae_token_key, sizeof(hapd->sae_token_key));
-		hapd->last_sae_token_key_update = t.sec;
+		hapd->last_sae_token_key_update = now;
 	}
 
 	buf = wpabuf_alloc(SHA256_MAC_LEN);
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index c311e55..56c3ce0 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -29,7 +29,7 @@
 
 
 struct hostapd_cached_radius_acl {
-	os_time_t timestamp;
+	struct os_reltime timestamp;
 	macaddr addr;
 	int accepted; /* HOSTAPD_ACL_* */
 	struct hostapd_cached_radius_acl *next;
@@ -43,7 +43,7 @@
 
 
 struct hostapd_acl_query_data {
-	os_time_t timestamp;
+	struct os_reltime timestamp;
 	u8 radius_id;
 	macaddr addr;
 	u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
@@ -104,15 +104,16 @@
 				 char **identity, char **radius_cui)
 {
 	struct hostapd_cached_radius_acl *entry;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
+	os_get_reltime(&now);
 
 	for (entry = hapd->acl_cache; entry; entry = entry->next) {
 		if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
 			continue;
 
-		if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
+		if (os_reltime_expired(&now, &entry->timestamp,
+				       RADIUS_ACL_TIMEOUT))
 			return -1; /* entry has expired */
 		if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
 			if (session_timeout)
@@ -265,7 +266,6 @@
 		return HOSTAPD_ACL_REJECT;
 #else /* CONFIG_NO_RADIUS */
 		struct hostapd_acl_query_data *query;
-		struct os_time t;
 
 		/* Check whether ACL cache has an entry for this station */
 		int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
@@ -305,8 +305,7 @@
 			wpa_printf(MSG_ERROR, "malloc for query data failed");
 			return HOSTAPD_ACL_REJECT;
 		}
-		os_get_time(&t);
-		query->timestamp = t.sec;
+		os_get_reltime(&query->timestamp);
 		os_memcpy(query->addr, addr, ETH_ALEN);
 		if (hostapd_radius_acl_query(hapd, addr, query)) {
 			wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
@@ -338,7 +337,8 @@
 
 
 #ifndef CONFIG_NO_RADIUS
-static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
+static void hostapd_acl_expire_cache(struct hostapd_data *hapd,
+				     struct os_reltime *now)
 {
 	struct hostapd_cached_radius_acl *prev, *entry, *tmp;
 
@@ -346,7 +346,8 @@
 	entry = hapd->acl_cache;
 
 	while (entry) {
-		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+		if (os_reltime_expired(now, &entry->timestamp,
+				       RADIUS_ACL_TIMEOUT)) {
 			wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
 				   " has expired.", MAC2STR(entry->addr));
 			if (prev)
@@ -367,7 +368,7 @@
 
 
 static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
-				       os_time_t now)
+				       struct os_reltime *now)
 {
 	struct hostapd_acl_query_data *prev, *entry, *tmp;
 
@@ -375,7 +376,8 @@
 	entry = hapd->acl_queries;
 
 	while (entry) {
-		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+		if (os_reltime_expired(now, &entry->timestamp,
+				       RADIUS_ACL_TIMEOUT)) {
 			wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
 				   " has expired.", MAC2STR(entry->addr));
 			if (prev)
@@ -403,11 +405,11 @@
 static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
 {
 	struct hostapd_data *hapd = eloop_ctx;
-	struct os_time now;
+	struct os_reltime now;
 
-	os_get_time(&now);
-	hostapd_acl_expire_cache(hapd, now.sec);
-	hostapd_acl_expire_queries(hapd, now.sec);
+	os_get_reltime(&now);
+	hostapd_acl_expire_cache(hapd, &now);
+	hostapd_acl_expire_queries(hapd, &now);
 
 	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
 }
@@ -480,7 +482,6 @@
 	struct hostapd_acl_query_data *query, *prev;
 	struct hostapd_cached_radius_acl *cache;
 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
-	struct os_time t;
 
 	query = hapd->acl_queries;
 	prev = NULL;
@@ -515,8 +516,7 @@
 		wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
 		goto done;
 	}
-	os_get_time(&t);
-	cache->timestamp = t.sec;
+	os_get_reltime(&cache->timestamp);
 	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
 	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
 		u8 *buf;
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 76688b5..eadaa4d 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -24,13 +24,13 @@
 {
 	u8 *pos = eid;
 	u32 timeout, tu;
-	struct os_time now, passed;
+	struct os_reltime now, passed;
 
 	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
 	*pos++ = 5;
 	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
-	os_get_time(&now);
-	os_time_sub(&now, &sta->sa_query_start, &passed);
+	os_get_reltime(&now);
+	os_reltime_sub(&now, &sta->sa_query_start, &passed);
 	tu = (passed.sec * 1000000 + passed.usec) / 1024;
 	if (hapd->conf->assoc_sa_query_max_timeout > tu)
 		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 7874332..4465d12 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -102,7 +102,7 @@
 	}
 
 	if (authorized) {
-		os_get_time(&sta->connected_time);
+		os_get_reltime(&sta->connected_time);
 		accounting_sta_start(hapd, sta);
 	}
 }
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 474597e..d1d8657 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -825,9 +825,9 @@
 int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	u32 tu;
-	struct os_time now, passed;
-	os_get_time(&now);
-	os_time_sub(&now, &sta->sa_query_start, &passed);
+	struct os_reltime now, passed;
+	os_get_reltime(&now);
+	os_reltime_sub(&now, &sta->sa_query_start, &passed);
 	tu = (passed.sec * 1000000 + passed.usec) / 1024;
 	if (hapd->conf->assoc_sa_query_max_timeout < tu) {
 		hostapd_logger(hapd, sta->addr,
@@ -864,7 +864,7 @@
 		return;
 	if (sta->sa_query_count == 0) {
 		/* Starting a new SA Query procedure */
-		os_get_time(&sta->sa_query_start);
+		os_get_reltime(&sta->sa_query_start);
 	}
 	trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
 	sta->sa_query_trans_id = nbuf;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index dc74219..ea3fe40 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -113,7 +113,7 @@
 	u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
 				* sa_query_count octets of pending SA Query
 				* transaction identifiers */
-	struct os_time sa_query_start;
+	struct os_reltime sa_query_start;
 #endif /* CONFIG_IEEE80211W */
 
 #ifdef CONFIG_INTERWORKING
@@ -126,7 +126,7 @@
 	struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
 	struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
 
-	struct os_time connected_time;
+	struct os_reltime connected_time;
 
 #ifdef CONFIG_SAE
 	struct sae_data *sae;
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index b435310..88bfb4d 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -66,6 +66,12 @@
 /** RSN IBSS 4-way handshakes completed with specified peer */
 #define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
 
+/** Notification of frequency conflict due to a concurrent operation.
+ *
+ * The indicated network is disabled and needs to be re-enabled before it can
+ * be used again.
+ */
+#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
 /** WPS overlap detected in PBC mode */
 #define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
 /** Available WPS AP with active PBC found in scan results */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 3502eb8..a3602ed 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -4028,11 +4028,17 @@
 	 * @freq: Frequency of new channel in MHz
 	 * @ht_enabled: Whether this is an HT channel
 	 * @ch_offset: Secondary channel offset
+	 * @ch_width: Channel width
+	 * @cf1: Center frequency 1
+	 * @cf2: Center frequency 2
 	 */
 	struct ch_switch {
 		int freq;
 		int ht_enabled;
 		int ch_offset;
+		enum chan_width ch_width;
+		int cf1;
+		int cf2;
 	} ch_switch;
 
 	/**
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 45d6b19..fb6402d 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -85,8 +85,10 @@
 			return IEEE80211_M_HOSTAP;
 		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
 			return IEEE80211_M_MONITOR;
+#ifdef IEEE80211_M_MBSS
 		if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
 			return IEEE80211_M_MBSS;
+#endif /* IEEE80211_M_MBSS */
 	}
 	return IEEE80211_M_STA;
 }
@@ -324,7 +326,9 @@
 	    size_t seq_len, const u8 *key, size_t key_len)
 {
 	struct ieee80211req_key wk;
+#ifdef IEEE80211_KEY_NOREPLAY
 	struct bsd_driver_data *drv = priv;
+#endif /* IEEE80211_KEY_NOREPLAY */
 
 	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
 		   "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
@@ -380,12 +384,14 @@
 	if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
 		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
 #ifndef HOSTAPD
+#ifdef IEEE80211_KEY_NOREPLAY
 	/*
 	 * Ignore replay failures in IBSS and AHDEMO mode.
 	 */
 	if (drv->opmode == IEEE80211_M_IBSS ||
 	    drv->opmode == IEEE80211_M_AHDEMO)
 		wk.ik_flags |= IEEE80211_KEY_NOREPLAY;
+#endif /* IEEE80211_KEY_NOREPLAY */
 #endif /* HOSTAPD */
 	wk.ik_keylen = key_len;
 	if (seq) {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 64ab29a..42dddf0 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -504,6 +504,27 @@
 }
 
 
+/* Converts nl80211_chan_width to a common format */
+static enum chan_width convert2width(int width)
+{
+	switch (width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+		return CHAN_WIDTH_20_NOHT;
+	case NL80211_CHAN_WIDTH_20:
+		return CHAN_WIDTH_20;
+	case NL80211_CHAN_WIDTH_40:
+		return CHAN_WIDTH_40;
+	case NL80211_CHAN_WIDTH_80:
+		return CHAN_WIDTH_80;
+	case NL80211_CHAN_WIDTH_80P80:
+		return CHAN_WIDTH_80P80;
+	case NL80211_CHAN_WIDTH_160:
+		return CHAN_WIDTH_160;
+	}
+	return CHAN_WIDTH_UNKNOWN;
+}
+
+
 static int is_ap_interface(enum nl80211_iftype nlmode)
 {
 	return (nlmode == NL80211_IFTYPE_AP ||
@@ -1484,36 +1505,60 @@
 
 
 static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
-				 struct nlattr *freq, struct nlattr *type)
+				 struct nlattr *ifindex, struct nlattr *freq,
+				 struct nlattr *type, struct nlattr *bw,
+				 struct nlattr *cf1, struct nlattr *cf2)
 {
+	struct i802_bss *bss;
 	union wpa_event_data data;
 	int ht_enabled = 1;
 	int chan_offset = 0;
+	int ifidx;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
 
-	if (!freq || !type)
+	if (!freq)
 		return;
 
-	switch (nla_get_u32(type)) {
-	case NL80211_CHAN_NO_HT:
-		ht_enabled = 0;
-		break;
-	case NL80211_CHAN_HT20:
-		break;
-	case NL80211_CHAN_HT40PLUS:
-		chan_offset = 1;
-		break;
-	case NL80211_CHAN_HT40MINUS:
-		chan_offset = -1;
-		break;
+	ifidx = nla_get_u32(ifindex);
+	for (bss = drv->first_bss; bss; bss = bss->next)
+		if (bss->ifindex == ifidx)
+			break;
+
+	if (bss == NULL) {
+		wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+			   ifidx);
+		return;
 	}
 
+	if (type) {
+		switch (nla_get_u32(type)) {
+		case NL80211_CHAN_NO_HT:
+			ht_enabled = 0;
+			break;
+		case NL80211_CHAN_HT20:
+			break;
+		case NL80211_CHAN_HT40PLUS:
+			chan_offset = 1;
+			break;
+		case NL80211_CHAN_HT40MINUS:
+			chan_offset = -1;
+			break;
+		}
+	}
+
+	os_memset(&data, 0, sizeof(data));
 	data.ch_switch.freq = nla_get_u32(freq);
 	data.ch_switch.ht_enabled = ht_enabled;
 	data.ch_switch.ch_offset = chan_offset;
+	if (bw)
+		data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+	if (cf1)
+		data.ch_switch.cf1 = nla_get_u32(cf1);
+	if (cf2)
+		data.ch_switch.cf2 = nla_get_u32(cf2);
 
-	drv->first_bss->freq = data.ch_switch.freq;
+	bss->freq = data.ch_switch.freq;
 
 	wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
 }
@@ -2534,8 +2579,6 @@
 }
 
 
-static enum chan_width convert2width(int width);
-
 static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
 				struct nlattr **tb)
 {
@@ -2702,8 +2745,13 @@
 				   tb[NL80211_ATTR_RESP_IE]);
 		break;
 	case NL80211_CMD_CH_SWITCH_NOTIFY:
-		mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
-				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+		mlme_event_ch_switch(drv,
+				     tb[NL80211_ATTR_IFINDEX],
+				     tb[NL80211_ATTR_WIPHY_FREQ],
+				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+				     tb[NL80211_ATTR_CHANNEL_WIDTH],
+				     tb[NL80211_ATTR_CENTER_FREQ1],
+				     tb[NL80211_ATTR_CENTER_FREQ2]);
 		break;
 	case NL80211_CMD_DISCONNECT:
 		mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
@@ -10020,27 +10068,6 @@
 }
 
 
-/* Converts nl80211_chan_width to a common format */
-static enum chan_width convert2width(int width)
-{
-	switch (width) {
-	case NL80211_CHAN_WIDTH_20_NOHT:
-		return CHAN_WIDTH_20_NOHT;
-	case NL80211_CHAN_WIDTH_20:
-		return CHAN_WIDTH_20;
-	case NL80211_CHAN_WIDTH_40:
-		return CHAN_WIDTH_40;
-	case NL80211_CHAN_WIDTH_80:
-		return CHAN_WIDTH_80;
-	case NL80211_CHAN_WIDTH_80P80:
-		return CHAN_WIDTH_80P80;
-	case NL80211_CHAN_WIDTH_160:
-		return CHAN_WIDTH_160;
-	}
-	return CHAN_WIDTH_UNKNOWN;
-}
-
-
 static int get_channel_width(struct nl_msg *msg, void *arg)
 {
 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -11288,9 +11315,11 @@
 	struct nlattr *beacon_csa;
 	int ret = -ENOBUFS;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d)",
+	wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)",
 		   settings->cs_count, settings->block_tx,
-		   settings->freq_params.freq);
+		   settings->freq_params.freq, settings->freq_params.bandwidth,
+		   settings->freq_params.center_freq1,
+		   settings->freq_params.center_freq2);
 
 	if (!drv->channel_switch_supported) {
 		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
diff --git a/src/utils/os.h b/src/utils/os.h
index 77dc6e3..2e2350a 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -86,6 +86,34 @@
 }
 
 
+static inline void os_reltime_age(struct os_reltime *start,
+				  struct os_reltime *age)
+{
+	struct os_reltime now;
+
+	os_get_reltime(&now);
+	os_reltime_sub(&now, start, age);
+}
+
+
+static inline int os_reltime_expired(struct os_reltime *now,
+				     struct os_reltime *ts,
+				     os_time_t timeout_secs)
+{
+	struct os_reltime age;
+
+	os_reltime_sub(now, ts, &age);
+	return (age.sec > timeout_secs) ||
+	       (age.sec == timeout_secs && age.usec > 0);
+}
+
+
+static inline int os_reltime_initialized(struct os_reltime *t)
+{
+	return t->sec != 0 || t->usec != 0;
+}
+
+
 /**
  * os_mktime - Convert broken-down time into seconds since 1970-01-01
  * @year: Four digit year
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 373a344..a030a0b 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -504,7 +504,7 @@
 ifdef CONFIG_EAP_PROXY
 L_CFLAGS += -DCONFIG_EAP_PROXY
 OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c
-include eap_proxy_$(CONFIG_EAP_PROXY).mk
+include $(LOCAL_PATH)/eap_proxy_$(CONFIG_EAP_PROXY).mk
 CONFIG_IEEE8021X_EAPOL=y
 endif
 
@@ -1559,6 +1559,10 @@
 LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)
 endif
 LOCAL_SHARED_LIBRARIES := libc libcutils liblog
+ifdef CONFIG_EAP_PROXY
+LOCAL_STATIC_LIBRARIES += $(LIB_STATIC_EAP_PROXY)
+LOCAL_SHARED_LIBRARIES += $(LIB_SHARED_EAP_PROXY)
+endif
 ifeq ($(CONFIG_TLS), openssl)
 LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder
 endif
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index cbe67a4..394ab30 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -1085,13 +1085,13 @@
 
 
 void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
-		       int offset)
+		       int offset, int width, int cf1, int cf2)
 {
 	if (!wpa_s->ap_iface)
 		return;
 
 	wpa_s->assoc_freq = freq;
-	hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset);
+	hostapd_event_ch_switch(wpa_s->ap_iface->bss[0], freq, ht, offset, width, cf1, cf1);
 }
 
 
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 33a3d0f..c382898 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -54,7 +54,7 @@
 		      struct csa_settings *settings);
 int ap_ctrl_iface_chanswitch(struct wpa_supplicant *wpa_s, const char *txtaddr);
 void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
-		       int offset);
+		       int offset, int width, int cf1, int cf2);
 struct wpabuf * wpas_ap_wps_nfc_config_token(struct wpa_supplicant *wpa_s,
 					     int ndef);
 #ifdef CONFIG_AP
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 4d9eea8..c03dcc2 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2895,7 +2895,10 @@
 
 		wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
 				  data->ch_switch.ht_enabled,
-				  data->ch_switch.ch_offset);
+				  data->ch_switch.ch_offset,
+				  data->ch_switch.ch_width,
+				  data->ch_switch.cf1,
+				  data->ch_switch.cf2);
 		break;
 #endif /* CONFIG_AP */
 #if defined(CONFIG_AP) || defined(CONFIG_IBSS_RSN)
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 21d99f1..e6a88e6 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -33,6 +33,7 @@
 #include "offchannel.h"
 #include "wps_supplicant.h"
 #include "p2p_supplicant.h"
+#include "wifi_display.h"
 
 
 /*
@@ -92,7 +93,8 @@
 	P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
 	P2P_GROUP_REMOVAL_UNAVAILABLE,
 	P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
-	P2P_GROUP_REMOVAL_PSK_FAILURE
+	P2P_GROUP_REMOVAL_PSK_FAILURE,
+	P2P_GROUP_REMOVAL_FREQ_CONFLICT
 };
 
 
@@ -112,6 +114,7 @@
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
 static void wpas_p2p_group_formation_timeout(void *eloop_ctx,
 					     void *timeout_ctx);
+static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
 					int group_added);
 static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
@@ -426,6 +429,9 @@
 	case P2P_GROUP_REMOVAL_PSK_FAILURE:
 		reason = " reason=PSK_FAILURE";
 		break;
+	case P2P_GROUP_REMOVAL_FREQ_CONFLICT:
+		reason = " reason=FREQ_CONFLICT";
+		break;
 	default:
 		reason = "";
 		break;
@@ -436,6 +442,8 @@
 			       wpa_s->ifname, gtype, reason);
 	}
 
+	if (eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL) > 0)
+		wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group freq_conflict timeout");
 	if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
 		wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
 	if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
@@ -1442,16 +1450,13 @@
 #ifndef CONFIG_NO_STDOUT_DEBUG
 	struct wpa_supplicant *wpa_s = ctx;
 	char devtype[WPS_DEV_TYPE_BUFSIZE];
-#define WFD_DEV_INFO_SIZE 9
-	char wfd_dev_info_hex[2 * WFD_DEV_INFO_SIZE + 1];
-	os_memset(wfd_dev_info_hex, 0, sizeof(wfd_dev_info_hex));
+	char *wfd_dev_info_hex = NULL;
+
 #ifdef CONFIG_WIFI_DISPLAY
-	if (info->wfd_subelems) {
-		wpa_snprintf_hex(wfd_dev_info_hex, sizeof(wfd_dev_info_hex),
-					wpabuf_head(info->wfd_subelems),
-					WFD_DEV_INFO_SIZE);
-	}
+	wfd_dev_info_hex = wifi_display_subelem_hex(info->wfd_subelems,
+						    WFD_SUBELEM_DEVICE_INFO);
 #endif /* CONFIG_WIFI_DISPLAY */
+
 	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
 		       " p2p_dev_addr=" MACSTR
 		       " pri_dev_type=%s name='%s' config_methods=0x%x "
@@ -1461,9 +1466,12 @@
 					    sizeof(devtype)),
 		       info->device_name, info->config_methods,
 		       info->dev_capab, info->group_capab,
-		       wfd_dev_info_hex[0] ? " wfd_dev_info=0x" : "", wfd_dev_info_hex);
+		       wfd_dev_info_hex ? " wfd_dev_info=0x" : "",
+		       wfd_dev_info_hex ? wfd_dev_info_hex : "");
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
+	os_free(wfd_dev_info_hex);
+
 	wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
 }
 
@@ -3579,6 +3587,7 @@
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
 	wpas_p2p_remove_pending_group_interface(wpa_s);
+	eloop_cancel_timeout(wpas_p2p_group_freq_conflict, wpa_s, NULL);
 
 	/* TODO: remove group interface from the driver if this wpa_s instance
 	 * is on top of a P2P group interface */
@@ -6562,6 +6571,63 @@
 }
 
 
+static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_printf(MSG_DEBUG, "P2P: Frequency conflict - terminate group");
+	wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
+}
+
+
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq,
+					struct wpa_ssid *ssid)
+{
+	struct wpa_supplicant *iface;
+
+	for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+		if (!iface->current_ssid ||
+		    iface->current_ssid->frequency == freq ||
+		    (iface->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+		     !iface->current_ssid->p2p_group))
+			continue;
+
+		/* Remove the connection with least priority */
+		if (!wpas_is_p2p_prioritized(iface)) {
+			/* STA connection has priority over existing
+			 * P2P connection, so remove the interface. */
+			wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to single channel concurrent mode frequency conflict");
+			eloop_register_timeout(0, 0,
+					       wpas_p2p_group_freq_conflict,
+					       iface, NULL);
+			/* If connection in progress is P2P connection, do not
+			 * proceed for the connection. */
+			if (wpa_s == iface)
+				return -1;
+			else
+				return 0;
+		} else {
+			/* P2P connection has priority, disable the STA network
+			 */
+			wpa_supplicant_disable_network(wpa_s->global->ifaces,
+						       ssid);
+			wpa_msg(wpa_s->global->ifaces, MSG_INFO,
+				WPA_EVENT_FREQ_CONFLICT " id=%d", ssid->id);
+			os_memset(wpa_s->global->ifaces->pending_bssid, 0,
+				  ETH_ALEN);
+			/* If P2P connection is in progress, continue
+			 * connecting...*/
+			if (wpa_s == iface)
+				return 0;
+			else
+				return -1;
+		}
+	}
+
+	return 0;
+}
+
+
 int wpas_p2p_4way_hs_failed(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 785062d..9630eb5 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -29,6 +29,8 @@
 				   unsigned int freq, unsigned int duration);
 void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 					  unsigned int freq);
+int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
+                                          int freq, struct wpa_ssid *ssid);
 int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 		       int freq, int ht40, int vht);
diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c
index 92ca536..578199e 100644
--- a/wpa_supplicant/wifi_display.c
+++ b/wpa_supplicant/wifi_display.c
@@ -16,6 +16,9 @@
 #include "wifi_display.h"
 
 
+#define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
+
+
 int wifi_display_init(struct wpa_global *global)
 {
 	global->wifi_display = 1;
@@ -249,3 +252,41 @@
 				1,
 				wpabuf_len(global->wfd_subelem[subelem]) - 1);
 }
+
+
+char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
+{
+	char *subelem = NULL;
+	const u8 *buf;
+	size_t buflen;
+	size_t i = 0;
+	u16 elen;
+
+	if (!wfd_subelems)
+		return NULL;
+
+	buf = wpabuf_head_u8(wfd_subelems);
+	if (!buf)
+		return NULL;
+
+	buflen = wpabuf_len(wfd_subelems);
+
+	while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
+		elen = WPA_GET_BE16(buf + i + 1);
+
+		if (buf[i] == id) {
+			subelem = os_zalloc(2 * elen + 1);
+			if (!subelem)
+				return NULL;
+			wpa_snprintf_hex(subelem, 2 * elen + 1,
+					 buf + i +
+					 WIFI_DISPLAY_SUBELEM_HEADER_LEN,
+					 elen);
+			break;
+		}
+
+		i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
+	}
+
+	return subelem;
+}
diff --git a/wpa_supplicant/wifi_display.h b/wpa_supplicant/wifi_display.h
index b75d4f2..7554817 100644
--- a/wpa_supplicant/wifi_display.h
+++ b/wpa_supplicant/wifi_display.h
@@ -16,5 +16,6 @@
 int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
 int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
 			     char *buf, size_t buflen);
+char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id);
 
 #endif /* WIFI_DISPLAY_H */
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index f43ef14..e8bca8a 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1647,6 +1647,25 @@
 	wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
 #endif /* CONFIG_HT_OVERRIDES */
 
+#ifdef CONFIG_P2P
+	/*
+	 * If multi-channel concurrency is not supported, check for any
+	 * frequency conflict. In case of any frequency conflict, remove the
+	 * least prioritized connection.
+	 */
+	if (wpa_s->num_multichan_concurrent < 2) {
+		int freq = wpa_drv_shared_freq(wpa_s);
+		if (freq > 0 && freq != params.freq) {
+			wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)",
+				   freq, params.freq);
+			if (wpas_p2p_handle_frequency_conflicts(wpa_s,
+								params.freq,
+								ssid) < 0)
+				return;
+		}
+	}
+#endif /* CONFIG_P2P */
+
 	ret = wpa_drv_associate(wpa_s, &params);
 	if (ret < 0) {
 		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "