Accumulative patch from commit 8cee87ab139e52516ee4185789b40a0459fa7406

P2P: Only schedule a single p2p_go_neg_start timeout at a time
P2P: Do not start new GO Neg on Probe Req when waiting for Confirm
P2P: Fail GO Negotiation on missing Group ID
P2P: Assign GO tie breaker bit at the same time with dialog token

Change-Id: Ie7d1a795988cd5e8420234392e9a83a3ad4165f0
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 985227c..6de50f2 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1435,12 +1435,14 @@
 	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.
+		 * Assign dialog token and tie breaker here to use the same
+		 * values in each retry within the same GO Negotiation exchange.
 		 */
 		dev->dialog_token++;
 		if (dev->dialog_token == 0)
 			dev->dialog_token = 1;
+		dev->tie_breaker = p2p->next_tie_breaker;
+		p2p->next_tie_breaker = !p2p->next_tie_breaker;
 	}
 	dev->connect_reqs = 0;
 	dev->go_neg_req_sent = 0;
@@ -2231,11 +2233,13 @@
 	if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
 	    p2p->go_neg_peer &&
 	    os_memcmp(addr, p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN)
-	    == 0) {
+	    == 0 &&
+	    !(p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
 		/* Received a Probe Request from GO Negotiation peer */
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Found GO Negotiation peer - try to start GO "
 			"negotiation from timeout");
+		eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
 		eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
 		return P2P_PREQ_PROCESSED;
 	}
@@ -2549,6 +2553,7 @@
 	eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL);
 	eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
 	eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
+	eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
 	p2p_flush(p2p);
 	p2p_free_req_dev_types(p2p);
 	os_free(p2p->cfg->dev_name);
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 37d43bb..bc27e6e 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -161,9 +161,7 @@
 	p2p_buf_add_capability(buf, p2p->dev_capab &
 			       ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
 			       group_capab);
-	p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) |
-			      p2p->next_tie_breaker);
-	p2p->next_tie_breaker = !p2p->next_tie_breaker;
+	p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | peer->tie_breaker);
 	p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
 	p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
 				   p2p->cfg->channel);
@@ -985,10 +983,8 @@
 			"P2P: Mandatory P2P Group ID attribute missing from "
 			"GO Negotiation Response");
 		p2p->ssid_len = 0;
-#ifdef CONFIG_P2P_STRICT
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
-#endif /* CONFIG_P2P_STRICT */
 	}
 
 	if (!msg.config_timeout) {
@@ -1118,6 +1114,11 @@
 		p2p_go_neg_failed(p2p, dev, -1);
 	}
 	wpabuf_free(conf);
+	if (status != P2P_SC_SUCCESS) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+			"P2P: GO Negotiation failed");
+		p2p_go_neg_failed(p2p, dev, status);
+	}
 }
 
 
@@ -1175,6 +1176,7 @@
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: GO Negotiation rejected: status %d",
 			*msg.status);
+		p2p_go_neg_failed(p2p, dev, *msg.status);
 		p2p_parse_free(&msg);
 		return;
 	}
@@ -1188,10 +1190,9 @@
 			"P2P: Mandatory P2P Group ID attribute missing from "
 			"GO Negotiation Confirmation");
 		p2p->ssid_len = 0;
-#ifdef CONFIG_P2P_STRICT
+		p2p_go_neg_failed(p2p, dev, P2P_SC_FAIL_INVALID_PARAMS);
 		p2p_parse_free(&msg);
 		return;
-#endif /* CONFIG_P2P_STRICT */
 	}
 
 	if (!msg.operating_channel) {
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index b2a3d3f..d59a8ac 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -52,6 +52,7 @@
 	int go_neg_req_sent;
 	enum p2p_go_state go_state;
 	u8 dialog_token;
+	u8 tie_breaker;
 	u8 intended_addr[ETH_ALEN];
 
 	char country[3];