Accumulative patch from commit dc013f1e37df3462085cf01a13f0c432f146ad7a

Author: Jouni Malinen <jouni@qca.qualcomm.com>
Date:   Tue Jan 15 12:03:29 2013 +0200
    eapol_test: Remove unnecessary header file inclusion

 - P2P: Send P2P-FIND-STOPPED event in the new continue-search states
 - P2P: Add some more details on Service Query TLV format
 - P2P: Use the same Dialog Token value for every GO Negotiation retry
 - P2P: Publish more connected clients info in Probe Response frames
 - P2P: Fix some memory leaks in p2p_add_device()
 - P2P: Use the same Dialog Token value for every PD retry
 - P2P: Document operating channel selection functions
 - P2P: Always re-select operating channel if not hard coded
 - P2P: Do not allow re-selection of GO channel if forced_freq in use
 - P2P: Set FORCE_FREQ flag as part of p2p_prepare_channel()
 - P2P: Share a single function for GO channel selection
 - P2P: Prefer operating channels where HT40 is possible
 - P2P: Be more careful with wpa_config_update_psk() call
 - P2P: Allow PSK to be used instead of passphrase for persistent GO
 - P2P: Consider age for the P2P scan results
 - Move some P2P offchannel operations to offchannel.c
 - P2P: Add more complete description of p2p_cancel
 - P2P: Allow p2p_cancel to be used to stop p2p_connect-join operation
 - Interworking changes
 - WNM changes
 - WPS changes
 - SAE changes

Change-Id: I38b847d3460066cc58aecbcf67266bfcff1d344e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index b122f7c..aaacc9a 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -630,6 +630,7 @@
  *	P2P Device Address or P2P Interface Address)
  * @level: Signal level (signal strength of the received frame from the peer)
  * @freq: Frequency on which the Beacon or Probe Response frame was received
+ * @age_ms: Age of the information in milliseconds
  * @ies: IEs from the Beacon or Probe Response frame
  * @ies_len: Length of ies buffer in octets
  * @scan_res: Whether this was based on scan results
@@ -640,13 +641,15 @@
  * like Provision Discovery Request that contains P2P Capability and P2P Device
  * Info attributes.
  */
-int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
-		   const u8 *ies, size_t ies_len, int scan_res)
+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
+		   unsigned int age_ms, int level, const u8 *ies,
+		   size_t ies_len, int scan_res)
 {
 	struct p2p_device *dev;
 	struct p2p_message msg;
 	const u8 *p2p_dev_addr;
 	int i;
+	struct os_time time_now, time_tmp_age, entry_ts;
 
 	os_memset(&msg, 0, sizeof(msg));
 	if (p2p_parse_ies(ies, ies_len, &msg)) {
@@ -673,6 +676,7 @@
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Do not add peer "
 			"filter for " MACSTR " due to peer filter",
 			MAC2STR(p2p_dev_addr));
+		p2p_parse_free(&msg);
 		return 0;
 	}
 
@@ -681,7 +685,24 @@
 		p2p_parse_free(&msg);
 		return -1;
 	}
-	os_get_time(&dev->last_seen);
+
+	os_get_time(&time_now);
+	time_tmp_age.sec = age_ms / 1000;
+	time_tmp_age.usec = (age_ms % 1000) * 1000;
+	os_time_sub(&time_now, &time_tmp_age, &entry_ts);
+
+	/*
+	 * Update the device entry only if the new peer
+	 * entry is newer than the one previously stored.
+	 */
+	if (dev->last_seen.usec > 0 &&
+	    os_time_before(&entry_ts, &dev->last_seen)) {
+		p2p_parse_free(&msg);
+		return -1;
+	}
+
+	os_memcpy(&dev->last_seen, &entry_ts, sizeof(struct os_time));
+
 	dev->flags &= ~(P2P_DEV_PROBE_REQ_ONLY | P2P_DEV_GROUP_CLIENT_ONLY);
 
 	if (os_memcmp(addr, p2p_dev_addr, ETH_ALEN) != 0)
@@ -1123,7 +1144,9 @@
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
 	eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	p2p_clear_timeout(p2p);
-	if (p2p->state == P2P_SEARCH)
+	if (p2p->state == P2P_SEARCH ||
+	    p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY ||
+	    p2p->state == P2P_SEARCH_WHEN_READY)
 		wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
 	p2p_set_state(p2p, P2P_IDLE);
 	p2p_free_req_dev_types(p2p);
@@ -1166,89 +1189,115 @@
 }
 
 
-static int p2p_prepare_channel(struct p2p_data *p2p, unsigned int force_freq,
-			       unsigned int pref_freq)
+static int p2p_prepare_channel_pref(struct p2p_data *p2p,
+				    unsigned int force_freq,
+				    unsigned int pref_freq)
 {
-	if (force_freq || pref_freq) {
-		u8 op_reg_class, op_channel;
-		unsigned int freq = force_freq ? force_freq : pref_freq;
-		if (p2p_freq_to_channel(p2p->cfg->country, freq,
-					&op_reg_class, &op_channel) < 0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Unsupported frequency %u MHz",
-				freq);
-			return -1;
-		}
-		if (!p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
-					   op_channel)) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Frequency %u MHz (oper_class %u "
-				"channel %u) not allowed for P2P",
-				freq, op_reg_class, op_channel);
-			return -1;
-		}
-		p2p->op_reg_class = op_reg_class;
-		p2p->op_channel = op_channel;
-		if (force_freq) {
-			p2p->channels.reg_classes = 1;
-			p2p->channels.reg_class[0].channels = 1;
-			p2p->channels.reg_class[0].reg_class =
-				p2p->op_reg_class;
-			p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
-		} else {
-			os_memcpy(&p2p->channels, &p2p->cfg->channels,
-				  sizeof(struct p2p_channels));
-		}
+	u8 op_class, op_channel;
+	unsigned int freq = force_freq ? force_freq : pref_freq;
+
+	if (p2p_freq_to_channel(p2p->cfg->country, freq,
+				&op_class, &op_channel) < 0) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+			"P2P: Unsupported frequency %u MHz", freq);
+		return -1;
+	}
+
+	if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+			"P2P: Frequency %u MHz (oper_class %u channel %u) not "
+			"allowed for P2P", freq, op_class, op_channel);
+		return -1;
+	}
+
+	p2p->op_reg_class = op_class;
+	p2p->op_channel = op_channel;
+
+	if (force_freq) {
+		p2p->channels.reg_classes = 1;
+		p2p->channels.reg_class[0].channels = 1;
+		p2p->channels.reg_class[0].reg_class = p2p->op_reg_class;
+		p2p->channels.reg_class[0].channel[0] = p2p->op_channel;
 	} else {
-		u8 op_reg_class, op_channel;
-
-		if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
-		    p2p_supported_freq(p2p, p2p->best_freq_overall) &&
-		    p2p_freq_to_channel(p2p->cfg->country,
-					p2p->best_freq_overall,
-					&op_reg_class, &op_channel) == 0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Select best overall channel as "
-				"operating channel preference");
-			p2p->op_reg_class = op_reg_class;
-			p2p->op_channel = op_channel;
-		} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
-			   p2p_supported_freq(p2p, p2p->best_freq_5) &&
-			   p2p_freq_to_channel(p2p->cfg->country,
-					       p2p->best_freq_5,
-					       &op_reg_class, &op_channel) ==
-			   0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Select best 5 GHz channel as "
-				"operating channel preference");
-			p2p->op_reg_class = op_reg_class;
-			p2p->op_channel = op_channel;
-		} else if (!p2p->cfg->cfg_op_channel &&
-			   p2p->best_freq_24 > 0 &&
-			   p2p_supported_freq(p2p, p2p->best_freq_24) &&
-			   p2p_freq_to_channel(p2p->cfg->country,
-					       p2p->best_freq_24,
-					       &op_reg_class, &op_channel) ==
-			   0) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: Select best 2.4 GHz channel as "
-				"operating channel preference");
-			p2p->op_reg_class = op_reg_class;
-			p2p->op_channel = op_channel;
-		} else {
-			p2p->op_reg_class = p2p->cfg->op_reg_class;
-			p2p->op_channel = p2p->cfg->op_channel;
-		}
-
 		os_memcpy(&p2p->channels, &p2p->cfg->channels,
 			  sizeof(struct p2p_channels));
 	}
+
+	return 0;
+}
+
+
+static void p2p_prepare_channel_best(struct p2p_data *p2p)
+{
+	u8 op_class, op_channel;
+
+	if (!p2p->cfg->cfg_op_channel && p2p->best_freq_overall > 0 &&
+	    p2p_supported_freq(p2p, p2p->best_freq_overall) &&
+	    p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_overall,
+				&op_class, &op_channel) == 0) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best "
+			"overall channel as operating channel preference");
+		p2p->op_reg_class = op_class;
+		p2p->op_channel = op_channel;
+	} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_5 > 0 &&
+		   p2p_supported_freq(p2p, p2p->best_freq_5) &&
+		   p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_5,
+				       &op_class, &op_channel) == 0) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 5 GHz "
+			"channel as operating channel preference");
+		p2p->op_reg_class = op_class;
+		p2p->op_channel = op_channel;
+	} else if (!p2p->cfg->cfg_op_channel && p2p->best_freq_24 > 0 &&
+		   p2p_supported_freq(p2p, p2p->best_freq_24) &&
+		   p2p_freq_to_channel(p2p->cfg->country, p2p->best_freq_24,
+				       &op_class, &op_channel) == 0) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Select best 2.4 "
+			"GHz channel as operating channel preference");
+		p2p->op_reg_class = op_class;
+		p2p->op_channel = op_channel;
+	} else {
+		p2p->op_reg_class = p2p->cfg->op_reg_class;
+		p2p->op_channel = p2p->cfg->op_channel;
+	}
+
+	os_memcpy(&p2p->channels, &p2p->cfg->channels,
+		  sizeof(struct p2p_channels));
+}
+
+
+/**
+ * p2p_prepare_channel - Select operating channel for GO Negotiation
+ * @p2p: P2P module context from p2p_init()
+ * @dev: Selected peer device
+ * @force_freq: Forced frequency in MHz or 0 if not forced
+ * @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * Returns: 0 on success, -1 on failure (channel not supported for P2P)
+ *
+ * This function is used to do initial operating channel selection for GO
+ * Negotiation prior to having received peer information. The selected channel
+ * may be further optimized in p2p_reselect_channel() once the peer information
+ * is available.
+ */
+static int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
+			       unsigned int force_freq, unsigned int pref_freq)
+{
+	if (force_freq || pref_freq) {
+		if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+			return -1;
+	} else {
+		p2p_prepare_channel_best(p2p);
+	}
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 		"P2P: Own preference for operation channel: "
 		"Operating Class %u Channel %u%s",
 		p2p->op_reg_class, p2p->op_channel,
 		force_freq ? " (forced)" : "");
 
+	if (force_freq)
+		dev->flags |= P2P_DEV_FORCE_FREQ;
+	else
+		dev->flags &= ~P2P_DEV_FORCE_FREQ;
+
 	return 0;
 }
 
@@ -1289,9 +1338,6 @@
 		MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
 		wps_method, persistent_group, pd_before_go_neg);
 
-	if (p2p_prepare_channel(p2p, force_freq, pref_freq) < 0)
-		return -1;
-
 	dev = p2p_get_device(p2p, peer_addr);
 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1300,6 +1346,9 @@
 		return -1;
 	}
 
+	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+		return -1;
+
 	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
 		if (!(dev->info.dev_capab &
 		      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
@@ -1339,8 +1388,16 @@
 	dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM;
 	if (pd_before_go_neg)
 		dev->flags |= P2P_DEV_PD_BEFORE_GO_NEG;
-	else
+	else {
 		dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
+		/*
+		 * Assign dialog token here to use the same value in each
+		 * retry within the same GO Negotiation exchange.
+		 */
+		dev->dialog_token++;
+		if (dev->dialog_token == 0)
+			dev->dialog_token = 1;
+	}
 	dev->connect_reqs = 0;
 	dev->go_neg_req_sent = 0;
 	dev->go_state = UNKNOWN_GO;
@@ -1367,11 +1424,6 @@
 	dev->wps_method = wps_method;
 	dev->status = P2P_SC_SUCCESS;
 
-	if (force_freq)
-		dev->flags |= P2P_DEV_FORCE_FREQ;
-	else
-		dev->flags &= ~P2P_DEV_FORCE_FREQ;
-
 	if (p2p->p2p_scan_running) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: p2p_scan running - delay connect send");
@@ -1401,9 +1453,6 @@
 		MAC2STR(peer_addr), go_intent, MAC2STR(own_interface_addr),
 		wps_method, persistent_group);
 
-	if (p2p_prepare_channel(p2p, force_freq, pref_freq) < 0)
-		return -1;
-
 	dev = p2p_get_device(p2p, peer_addr);
 	if (dev == NULL) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1412,6 +1461,9 @@
 		return -1;
 	}
 
+	if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+		return -1;
+
 	p2p->ssid_set = 0;
 	if (force_ssid) {
 		wpa_hexdump_ascii(MSG_DEBUG, "P2P: Forced SSID",
@@ -1432,11 +1484,6 @@
 	dev->wps_method = wps_method;
 	dev->status = P2P_SC_SUCCESS;
 
-	if (force_freq)
-		dev->flags |= P2P_DEV_FORCE_FREQ;
-	else
-		dev->flags &= ~P2P_DEV_FORCE_FREQ;
-
 	return 0;
 }
 
@@ -2840,9 +2887,10 @@
 
 
 int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
-			 int level, const u8 *ies, size_t ies_len)
+			 unsigned int age, int level, const u8 *ies,
+			 size_t ies_len)
 {
-	p2p_add_device(p2p, bssid, freq, level, ies, ies_len, 1);
+	p2p_add_device(p2p, bssid, freq, age, level, ies, ies_len, 1);
 
 	return 0;
 }
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 045e6f7..18e733b 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -1200,6 +1200,7 @@
  * @p2p: P2P module context from p2p_init()
  * @bssid: BSSID of the scan result
  * @freq: Frequency of the channel on which the device was found in MHz
+ * @age: Age of the scan result in milliseconds
  * @level: Signal level (signal strength of the received Beacon/Probe Response
  *	frame)
  * @ies: Pointer to IEs from the scan result
@@ -1221,7 +1222,8 @@
  * start of a pending operation, e.g., to start a pending GO negotiation.
  */
 int p2p_scan_res_handler(struct p2p_data *p2p, const u8 *bssid, int freq,
-			 int level, const u8 *ies, size_t ies_len);
+			 unsigned int age, int level, const u8 *ies,
+			 size_t ies_len);
 
 /**
  * p2p_scan_res_handled - Indicate end of scan results
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index fe4b560..37d43bb 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -145,9 +145,6 @@
 	if (buf == NULL)
 		return NULL;
 
-	peer->dialog_token++;
-	if (peer->dialog_token == 0)
-		peer->dialog_token = 1;
 	p2p_buf_add_public_action_hdr(buf, P2P_GO_NEG_REQ, peer->dialog_token);
 
 	len = p2p_buf_add_ie_hdr(buf);
@@ -336,6 +333,17 @@
 }
 
 
+/**
+ * p2p_reselect_channel - Re-select operating channel based on peer information
+ * @p2p: P2P module context from p2p_init()
+ * @intersection: Support channel list intersection from local and peer
+ *
+ * This function is used to re-select the best channel after having received
+ * information from the peer to allow supported channel lists to be intersected.
+ * This can be used to improve initial channel selection done in
+ * p2p_prepare_channel() prior to the start of GO Negotiation. In addition, this
+ * can be used for Invitation case.
+ */
 void p2p_reselect_channel(struct p2p_data *p2p,
 			  struct p2p_channels *intersection)
 {
@@ -390,6 +398,35 @@
 		}
 	}
 
+	/* Try a channel where we might be able to use HT40 */
+	for (i = 0; i < intersection->reg_classes; i++) {
+		struct p2p_reg_class *c = &intersection->reg_class[i];
+		if (c->reg_class == 116 || c->reg_class == 117 ||
+		    c->reg_class == 126 || c->reg_class == 127) {
+			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+				"P2P: Pick possible HT40 channel (reg_class "
+				"%u channel %u) from intersection",
+				c->reg_class, c->channel[0]);
+			p2p->op_reg_class = c->reg_class;
+			p2p->op_channel = c->channel[0];
+			return;
+		}
+	}
+
+	/*
+	 * Try to see if the original channel is in the intersection. If
+	 * so, no need to change anything, as it already contains some
+	 * randomness.
+	 */
+	if (p2p_channels_includes(intersection, p2p->op_reg_class,
+				  p2p->op_channel)) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+			"P2P: Using original operating class and channel "
+			"(op_class %u channel %u) from intersection",
+			p2p->op_reg_class, p2p->op_channel);
+		return;
+	}
+
 	/*
 	 * Fall back to whatever is included in the channel intersection since
 	 * no better options seems to be available.
@@ -403,6 +440,60 @@
 }
 
 
+static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
+				 u8 *status)
+{
+	struct p2p_channels intersection;
+	size_t i;
+
+	p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
+	if (intersection.reg_classes == 0 ||
+	    intersection.reg_class[0].channels == 0) {
+		*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+			"P2P: No common channels found");
+		return -1;
+	}
+
+	for (i = 0; i < intersection.reg_classes; i++) {
+		struct p2p_reg_class *c;
+		c = &intersection.reg_class[i];
+		wpa_printf(MSG_DEBUG, "P2P: reg_class %u", c->reg_class);
+		wpa_hexdump(MSG_DEBUG, "P2P: channels",
+			    c->channel, c->channels);
+	}
+
+	if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
+				   p2p->op_channel)) {
+		if (dev->flags & P2P_DEV_FORCE_FREQ) {
+			*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer does "
+				"not support the forced channel");
+			return -1;
+		}
+
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Selected operating "
+			"channel (op_class %u channel %u) not acceptable to "
+			"the peer", p2p->op_reg_class, p2p->op_channel);
+		p2p_reselect_channel(p2p, &intersection);
+	} else if (!(dev->flags & P2P_DEV_FORCE_FREQ) &&
+		   !p2p->cfg->cfg_op_channel) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Try to optimize "
+			"channel selection with peer information received; "
+			"previously selected op_class %u channel %u",
+			p2p->op_reg_class, p2p->op_channel);
+		p2p_reselect_channel(p2p, &intersection);
+	}
+
+	if (!p2p->ssid_set) {
+		p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+		p2p->ssid_set = 1;
+	}
+
+	return 0;
+}
+
+
 void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
 			    const u8 *data, size_t len, int rx_freq)
 {
@@ -619,36 +710,8 @@
 			goto fail;
 		}
 
-		if (go) {
-			struct p2p_channels intersection;
-			size_t i;
-			p2p_channels_intersect(&p2p->channels, &dev->channels,
-					       &intersection);
-			if (intersection.reg_classes == 0 ||
-			    intersection.reg_class[0].channels == 0) {
-				status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: No common channels found");
-				goto fail;
-			}
-			for (i = 0; i < intersection.reg_classes; i++) {
-				struct p2p_reg_class *c;
-				c = &intersection.reg_class[i];
-				wpa_printf(MSG_DEBUG, "P2P: reg_class %u",
-					   c->reg_class);
-				wpa_hexdump(MSG_DEBUG, "P2P: channels",
-					    c->channel, c->channels);
-			}
-			if (!p2p_channels_includes(&intersection,
-						   p2p->op_reg_class,
-						   p2p->op_channel))
-				p2p_reselect_channel(p2p, &intersection);
-
-			if (!p2p->ssid_set) {
-				p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
-				p2p->ssid_set = 1;
-			}
-		}
+		if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
+			goto fail;
 
 		dev->go_state = go ? LOCAL_GO : REMOTE_GO;
 		dev->oper_freq = p2p_channel_to_freq((const char *)
@@ -1021,35 +1084,8 @@
 		goto fail;
 	}
 
-	if (go) {
-		struct p2p_channels intersection;
-		size_t i;
-		p2p_channels_intersect(&p2p->channels, &dev->channels,
-				       &intersection);
-		if (intersection.reg_classes == 0 ||
-		    intersection.reg_class[0].channels == 0) {
-			status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: No common channels found");
-			goto fail;
-		}
-		for (i = 0; i < intersection.reg_classes; i++) {
-			struct p2p_reg_class *c;
-			c = &intersection.reg_class[i];
-			wpa_printf(MSG_DEBUG, "P2P: reg_class %u",
-				   c->reg_class);
-			wpa_hexdump(MSG_DEBUG, "P2P: channels",
-				    c->channel, c->channels);
-		}
-		if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
-					   p2p->op_channel))
-			p2p_reselect_channel(p2p, &intersection);
-
-		if (!p2p->ssid_set) {
-			p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
-			p2p->ssid_set = 1;
-		}
-	}
+	if (go && p2p_go_select_channel(p2p, dev, &status) < 0)
+		goto fail;
 
 	p2p_set_state(p2p, P2P_GO_NEG);
 	p2p_clear_timeout(p2p);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 8687320..633dd5c 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -169,6 +169,39 @@
 }
 
 
+static struct wpabuf * p2p_group_encaps_probe_resp(struct wpabuf *subelems)
+{
+	struct wpabuf *ie;
+	const u8 *pos, *end;
+	size_t len;
+
+	if (subelems == NULL)
+		return NULL;
+
+	len = wpabuf_len(subelems) + 100;
+
+	ie = wpabuf_alloc(len);
+	if (ie == NULL)
+		return NULL;
+
+	pos = wpabuf_head(subelems);
+	end = pos + wpabuf_len(subelems);
+
+	while (end > pos) {
+		size_t frag_len = end - pos;
+		if (frag_len > 251)
+			frag_len = 251;
+		wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+		wpabuf_put_u8(ie, 4 + frag_len);
+		wpabuf_put_be32(ie, P2P_IE_VENDOR_TYPE);
+		wpabuf_put_data(ie, pos, frag_len);
+		pos += frag_len;
+	}
+
+	return ie;
+}
+
+
 static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
 {
 	struct wpabuf *ie;
@@ -367,9 +400,8 @@
 static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
 {
 	u8 *group_info;
-	struct wpabuf *ie;
+	struct wpabuf *p2p_subelems, *ie;
 	struct p2p_group_member *m;
-	u8 *len;
 	size_t extra = 0;
 
 #ifdef CONFIG_WIFI_DISPLAY
@@ -377,33 +409,32 @@
 		extra += wpabuf_len(group->wfd_ie);
 #endif /* CONFIG_WIFI_DISPLAY */
 
-	ie = wpabuf_alloc(257 + extra);
-	if (ie == NULL)
+	p2p_subelems = wpabuf_alloc(500 + extra);
+	if (p2p_subelems == NULL)
 		return NULL;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	if (group->wfd_ie)
-		wpabuf_put_buf(ie, group->wfd_ie);
+		wpabuf_put_buf(p2p_subelems, group->wfd_ie);
 #endif /* CONFIG_WIFI_DISPLAY */
 
-	len = p2p_buf_add_ie_hdr(ie);
-
-	p2p_group_add_common_ies(group, ie);
-	p2p_group_add_noa(ie, group->noa);
+	p2p_group_add_common_ies(group, p2p_subelems);
+	p2p_group_add_noa(p2p_subelems, group->noa);
 
 	/* P2P Device Info */
-	p2p_buf_add_device_info(ie, group->p2p, NULL);
+	p2p_buf_add_device_info(p2p_subelems, group->p2p, NULL);
 
 	/* P2P Group Info */
-	group_info = wpabuf_put(ie, 0);
-	wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO);
-	wpabuf_put_le16(ie, 0); /* Length to be filled */
+	group_info = wpabuf_put(p2p_subelems, 0);
+	wpabuf_put_u8(p2p_subelems, P2P_ATTR_GROUP_INFO);
+	wpabuf_put_le16(p2p_subelems, 0); /* Length to be filled */
 	for (m = group->members; m; m = m->next)
-		p2p_client_info(ie, m);
+		p2p_client_info(p2p_subelems, m);
 	WPA_PUT_LE16(group_info + 1,
-		     (u8 *) wpabuf_put(ie, 0) - group_info - 3);
+		     (u8 *) wpabuf_put(p2p_subelems, 0) - group_info - 3);
 
-	p2p_buf_update_ie_hdr(ie, len);
+	ie = p2p_group_encaps_probe_resp(p2p_subelems);
+	wpabuf_free(p2p_subelems);
 
 	return ie;
 }
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index d2868fb..712544b 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -705,8 +705,9 @@
 						struct p2p_message *msg);
 void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
 		      struct p2p_device *dev, struct p2p_message *msg);
-int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
-		   const u8 *ies, size_t ies_len, int scan_res);
+int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq,
+		   unsigned int age_ms, int level, const u8 *ies,
+		   size_t ies_len, int scan_res);
 struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
 struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
 					     const u8 *addr);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 7bf6600..ac67932 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -176,8 +176,8 @@
 			"P2P: Invitation Request from unknown peer "
 			MACSTR, MAC2STR(sa));
 
-		if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
-		{
+		if (p2p_add_device(p2p, sa, rx_freq, 0, 0, data + 1, len - 1,
+				   0)) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: Invitation Request add device failed "
 				MACSTR, MAC2STR(sa));
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index e40f2b7..ca33f17 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -151,8 +151,9 @@
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Provision Discovery Request from "
 			"unknown peer " MACSTR, MAC2STR(sa));
-		if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
-		{
+
+		if (p2p_add_device(p2p, sa, rx_freq, 0, 0, data + 1, len - 1,
+				   0)) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			        "P2P: Provision Discovery Request add device "
 				"failed " MACSTR, MAC2STR(sa));
@@ -379,9 +380,6 @@
 		/* TODO: use device discoverability request through GO */
 	}
 
-	dev->dialog_token++;
-	if (dev->dialog_token == 0)
-		dev->dialog_token = 1;
 	req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
 				      dev->req_config_methods,
 				      join ? dev : NULL);
@@ -452,6 +450,14 @@
 	if (p2p->user_initiated_pd)
 		p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
 
+	/*
+	 * Assign dialog token here to use the same value in each retry within
+	 * the same PD exchange.
+	 */
+	dev->dialog_token++;
+	if (dev->dialog_token == 0)
+		dev->dialog_token = 1;
+
 	return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
 }