Accumulative patch from commit 20a0b03debef66cc57b0c34a05f8be5229be907c

atheros: Fix auth_alg configuration for static WEP
nl80211: Implement set_rate_sets for non-hostapd AP case
nl80211: Enable more AP callbacks for non-hostapd AP mode
nl80211: Re-order functions to group AP/hostapd specific code
Remove compiler warning for non-P2P builds
random: Add support for maintaining internal entropy store over restarts
Fix a compiler warning on WPS-AP-without-UPnP builds
P2P: Retry provision discovery requests in IDLE state
P2P: Add callback for provision discovery failure
P2P: Add wpas_notify_p2p_provision_discovery()
P2P: Add group started notification
DBus: Move wpas_dbus_new_decompose_object_path()
DBus: Refactor array adding, add binary arrays
DBus: Add support for P2P primitives
DBus: Fix some typos on comments
Fix CONFIG_AP=y build without CONFIG_P2P=y
Fix non-P2P D-Bus build
nl80211: Add support for driver-based PMKSA cache
P2P: Start GO without extra scan step
Remove a compiler warning on uninitialized variable
Add EVENT_RX_ACTION handler for hostapd
Fix hostapd build without NEED_AP_MLME=y
Fix AP selection to check privacy mismatch and IBSS with WPA/RSN IE
bsd: Fix set_key() sequence number endian issue
Add a copyright and license statement for a radiotap header file
Use nl80211 as an example instead of WEXT
Add notes for CONFIG_WPS_ER build configuration option
Fix CONFIG_NO_WPA_PASSPHRASE=y build
hostapd: Don't mask out non-symmetric STA HT caps
P2P: Enable P2P capability advertisement on D-Bus
P2P: Update D-Bus network object semantics during group formation
P2P: Show P2P peer signal level in D-Bus P2P device properties
P2P: Fix P2P device signal level type in D-Bus
P2P: Add dissasoc_low_ack in P2P device properties
P2P: More complete persistent group management over D-Bus
P2P: Add WpsFailed signal in P2P D-Bus
P2P: Update listen and operating channel from P2P D-Bus
P2P: Fix WpsFailed signal in P2P D-Bus
atheros: Fix glibc 'invalid pointer' error when WPA_TRACE is enabled
Clear WPA and EAPOL state machine config pointer on network removal
	20a0b03debef66cc57b0c34a05f8be5229be907c

Change-Id: I2b83bf86ba9c7a9a218638be7b4de31d209cdde1
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 653609e..191099a 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -576,7 +576,7 @@
 	dev->listen_freq = freq;
 	if (msg.group_info)
 		dev->oper_freq = freq;
-	dev->level = level;
+	dev->info.level = level;
 
 	p2p_copy_wps_info(dev, 0, &msg);
 
@@ -2250,19 +2250,81 @@
 	p2p_set_timeout(p2p, 0, 200000);
 }
 
+
+/**
+ * p2p_retry_pd - Retry any pending provision disc requests in IDLE state
+ * @p2p: P2P module context from p2p_init()
+ */
+void p2p_retry_pd(struct p2p_data *p2p)
+{
+	struct p2p_device *dev;
+
+	if (p2p->state != P2P_IDLE)
+		return;
+
+	/*
+	 * Retry the prov disc req attempt only for the peer that the user had
+	 * requested for and provided a join has not been initiated on it
+	 * in the meantime.
+	 */
+
+	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+		if (os_memcmp(p2p->pending_pd_devaddr,
+			      dev->info.p2p_device_addr, ETH_ALEN) != 0)
+			continue;
+		if (!dev->req_config_methods)
+			continue;
+		if (dev->flags & P2P_DEV_PD_FOR_JOIN)
+			continue;
+
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
+			"pending Provisioning Discovery Request to "
+			MACSTR " (config methods 0x%x)",
+			MAC2STR(dev->info.p2p_device_addr),
+			dev->req_config_methods);
+		p2p_send_prov_disc_req(p2p, dev, 0);
+		return;
+	}
+}
+
+
 static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
 {
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 		"P2P: Provision Discovery Request TX callback: success=%d",
 		success);
-	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+	/*
+	 * Postpone resetting the pending action state till after we actually
+	 * time out. This allows us to take some action like notifying any
+	 * interested parties about no response to the request.
+	 *
+	 * When the timer (below) goes off we check in IDLE, SEARCH, or
+	 * LISTEN_ONLY state, which are the only allowed states to issue a PD
+	 * requests in, if this was still pending and then raise notification.
+	 */
 
 	if (!success) {
+		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
 		if (p2p->state != P2P_IDLE)
 			p2p_continue_find(p2p);
+		else if (p2p->user_initiated_pd) {
+			p2p->pending_action_state = P2P_PENDING_PD;
+			p2p_set_timeout(p2p, 0, 300000);
+		}
 		return;
 	}
 
+	/*
+	 * This postponing, of resetting pending_action_state, needs to be
+	 * done only for user initiated PD requests and not internal ones.
+	 */
+	if (p2p->user_initiated_pd)
+		p2p->pending_action_state = P2P_PENDING_PD;
+	else
+		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
 	/* Wait for response from the peer */
 	if (p2p->state == P2P_SEARCH)
 		p2p_set_state(p2p, P2P_PD_DURING_FIND);
@@ -2653,6 +2715,34 @@
 }
 
 
+static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
+{
+	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+	/*
+	 * For user initiated PD requests that we have not gotten any responses
+	 * for while in IDLE state, we retry them a couple of times before
+	 * giving up.
+	 */
+	if (!p2p->user_initiated_pd)
+		return;
+
+	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+		"P2P: User initiated Provision Discovery Request timeout");
+
+	if (p2p->pd_retries) {
+		p2p->pd_retries--;
+		p2p_retry_pd(p2p);
+	} else {
+		if (p2p->cfg->prov_disc_fail)
+			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
+						 p2p->pending_pd_devaddr,
+						 P2P_PROV_DISC_TIMEOUT);
+		p2p_reset_pending_pd(p2p);
+	}
+}
+
+
 static void p2p_timeout_invite(struct p2p_data *p2p)
 {
 	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
@@ -2701,8 +2791,14 @@
 
 	switch (p2p->state) {
 	case P2P_IDLE:
+		/* Check if we timed out waiting for PD req */
+		if (p2p->pending_action_state == P2P_PENDING_PD)
+			p2p_timeout_prov_disc_req(p2p);
 		break;
 	case P2P_SEARCH:
+		/* Check if we timed out waiting for PD req */
+		if (p2p->pending_action_state == P2P_PENDING_PD)
+			p2p_timeout_prov_disc_req(p2p);
 		p2p_search(p2p);
 		break;
 	case P2P_CONNECT:
@@ -2714,6 +2810,10 @@
 	case P2P_GO_NEG:
 		break;
 	case P2P_LISTEN_ONLY:
+		/* Check if we timed out waiting for PD req */
+		if (p2p->pending_action_state == P2P_PENDING_PD)
+			p2p_timeout_prov_disc_req(p2p);
+
 		if (p2p->ext_listen_only) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: Extended Listen Timing - Listen State "
@@ -2861,7 +2961,7 @@
 			  "invitation_reqs=%u\n",
 			  (int) (now.sec - dev->last_seen.sec),
 			  dev->listen_freq,
-			  dev->level,
+			  dev->info.level,
 			  p2p_wps_method_text(dev->wps_method),
 			  MAC2STR(dev->interface_addr),
 			  MAC2STR(dev->member_in_go_dev),
@@ -3328,6 +3428,22 @@
 }
 
 
+int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
+			 int cfg_op_channel)
+{
+	if (p2p_channel_to_freq(p2p->cfg->country, op_reg_class, op_channel)
+	    < 0)
+		return -1;
+
+	wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, "P2P: Set Operating channel: "
+		"reg_class %u channel %u", op_reg_class, op_channel);
+	p2p->cfg->op_reg_class = op_reg_class;
+	p2p->cfg->op_channel = op_channel;
+	p2p->cfg->cfg_op_channel = cfg_op_channel;
+	return 0;
+}
+
+
 int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
 			   u8 *iface_addr)
 {