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)
 {
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 954f562..db816a6 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -180,6 +180,11 @@
 	char serial_number[33];
 
 	/**
+	 * level - Signal level
+	 */
+	int level;
+
+	/**
 	 * config_methods - WPS Configuration Methods
 	 */
 	u16 config_methods;
@@ -210,6 +215,12 @@
 	struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
 };
 
+enum p2p_prov_disc_status {
+	P2P_PROV_DISC_SUCCESS,
+	P2P_PROV_DISC_TIMEOUT,
+	P2P_PROV_DISC_REJECTED,
+};
+
 /**
  * struct p2p_config - P2P configuration
  *
@@ -603,6 +614,21 @@
 	void (*prov_disc_resp)(void *ctx, const u8 *peer, u16 config_methods);
 
 	/**
+	 * prov_disc_fail - Callback on Provision Discovery failure
+	 * @ctx: Callback context from cb_ctx
+	 * @peer: Source address of the response
+	 * @status: Cause of failure, will not be %P2P_PROV_DISC_SUCCESS
+	 *
+	 * This callback is used to indicate either a failure or no response
+	 * to an earlier provision discovery request.
+	 *
+	 * This callback handler can be set to %NULL if provision discovery
+	 * is not used or failures do not need to be indicated.
+	 */
+	void (*prov_disc_fail)(void *ctx, const u8 *peer,
+			       enum p2p_prov_disc_status status);
+
+	/**
 	 * invitation_process - Optional callback for processing Invitations
 	 * @ctx: Callback context from cb_ctx
 	 * @sa: Source address of the Invitation Request
@@ -1470,4 +1496,15 @@
 int p2p_add_wps_vendor_extension(struct p2p_data *p2p,
 				 const struct wpabuf *vendor_ext);
 
+/**
+ * p2p_set_oper_channel - Set the P2P operating channel
+ * @p2p: P2P module context from p2p_init()
+ * @op_reg_class: Operating regulatory class to set
+ * @op_channel: operating channel to set
+ * @cfg_op_channel : Whether op_channel is hardcoded in configuration
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
+			 int cfg_op_channel);
+
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 68b1194..52d9311 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -33,7 +33,6 @@
 	struct dl_list list;
 	struct os_time last_seen;
 	int listen_freq;
-	int level;
 	enum p2p_wps_method wps_method;
 
 	struct p2p_peer_info info;
@@ -393,6 +392,23 @@
 	 * wps_vendor_ext - WPS Vendor Extensions to add
 	 */
 	struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+	/*
+	 * user_initiated_pd - Whether a PD request is user initiated or not.
+	 */
+	u8 user_initiated_pd;
+
+	/*
+	 * Keep track of which peer a given PD request was sent to.
+	 * Used to raise a timeout alert in case there is no response.
+	 */
+	u8 pending_pd_devaddr[ETH_ALEN];
+
+	/*
+	 * Retry counter for provision discovery requests when issued
+	 * in IDLE state.
+	 */
+	int pd_retries;
 };
 
 /**
@@ -586,6 +602,7 @@
 				const u8 *data, size_t len);
 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
 			   int join);
+void p2p_reset_pending_pd(struct p2p_data *p2p);
 
 /* p2p_invitation.c */
 void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index e064216..f7ff06c 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -21,6 +21,13 @@
 #include "p2p.h"
 
 
+/*
+ * Number of retries to attempt for provision discovery requests during IDLE
+ * state in case the peer is not listening.
+ */
+#define MAX_PROV_DISC_REQ_RETRIES 10
+
+
 static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
 					    u16 config_methods)
 {
@@ -215,6 +222,11 @@
 		return;
 	}
 
+	if (p2p->pending_action_state == P2P_PENDING_PD) {
+		os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+		p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+	}
+
 	if (dev->dialog_token != msg.dialog_token) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Ignore Provisioning Discovery Response with "
@@ -224,9 +236,20 @@
 		return;
 	}
 
+	/*
+	 * If the response is from the peer to whom a user initiated request
+	 * was sent earlier, we reset that state info here.
+	 */
+	if (p2p->user_initiated_pd &&
+	    os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
+		p2p_reset_pending_pd(p2p);
+
 	if (msg.wps_config_methods != dev->req_config_methods) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
 			"our Provisioning Discovery Request");
+		if (p2p->cfg->prov_disc_fail)
+			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
+						 P2P_PROV_DISC_REJECTED);
 		p2p_parse_free(&msg);
 		goto out;
 	}
@@ -301,6 +324,8 @@
 		return -1;
 	}
 
+	os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
+
 	wpabuf_free(req);
 	return 0;
 }
@@ -343,5 +368,23 @@
 		return 0;
 	}
 
+	/*
+	 * We use the join param as a cue to differentiate between user
+	 * initiated PD request and one issued during finds (internal).
+	 */
+	p2p->user_initiated_pd = !join;
+
+	/* Also set some retries to attempt in case of IDLE state */
+	if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
+		p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
+
 	return p2p_send_prov_disc_req(p2p, dev, join);
 }
+
+
+void p2p_reset_pending_pd(struct p2p_data *p2p)
+{
+	p2p->user_initiated_pd = 0;
+	os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+	p2p->pd_retries = 0;
+}