From ae3e342108d87672ceec1a799cac5bfe82067fae Mon Sep 17 00:00:00 2001
From: Jouni Malinen <jouni.malinen@atheros.com>
Date: Mon, 6 Sep 2010 21:04:01 +0300
Subject: [PATCH] P2P: Add peer timeout into group formation 15 second timeout

This adds some more time for WPS provisioning step in case the peer
takes long time to start group interface operations.
---
 src/p2p/p2p.c                   | 2 ++
 src/p2p/p2p.h                   | 5 +++++
 src/p2p/p2p_go_neg.c            | 8 ++++++++
 src/p2p/p2p_i.h                 | 3 +++
 wpa_supplicant/p2p_supplicant.c | 6 +++---
 5 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 5d4581109..e4d967ff0 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1121,6 +1121,8 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
 		}
 	}
 
+	res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
+
 	p2p_clear_timeout(p2p);
 	peer->go_neg_req_sent = 0;
 	peer->wps_method = WPS_NOT_READY;
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 46a4e29ee..8d7985b2e 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -122,6 +122,11 @@ struct p2p_go_neg_results {
 	 * persistent_group - Whether the group should be made persistent
 	 */
 	int persistent_group;
+
+	/**
+	 * peer_config_timeout - Peer configuration timeout (in 10 msec units)
+	 */
+	unsigned int peer_config_timeout;
 };
 
 struct p2p_data;
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 1e6404731..0a3d0c451 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -567,6 +567,11 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa,
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer operating "
 			"channel preference: %d MHz", dev->oper_freq);
 
+		if (msg.config_timeout) {
+			dev->go_timeout = msg.config_timeout[0];
+			dev->client_timeout = msg.config_timeout[1];
+		}
+
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: GO Negotiation with " MACSTR, MAC2STR(sa));
 		if (p2p->state != P2P_IDLE)
@@ -810,6 +815,9 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa,
 		status = P2P_SC_FAIL_INVALID_PARAMS;
 		goto fail;
 #endif /* CONFIG_P2P_STRICT */
+	} else {
+		dev->go_timeout = msg.config_timeout[0];
+		dev->client_timeout = msg.config_timeout[1];
 	}
 
 	if (!msg.operating_channel && !go) {
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 8225d64e8..6119b60f8 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -101,6 +101,9 @@ struct p2p_device {
 
 	u16 ext_listen_period;
 	u16 ext_listen_interval;
+
+	u8 go_timeout;
+	u8 client_timeout;
 };
 
 struct p2p_sd_query {
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index b2faf35d1..c9a38a16e 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -985,9 +985,9 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 
 	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
-	/* TODO: add peer Config Timeout */
-	eloop_register_timeout(15, 0, wpas_p2p_group_formation_timeout, wpa_s,
-			       NULL);
+	eloop_register_timeout(15 + res->peer_config_timeout / 100,
+			       (res->peer_config_timeout % 100) * 10000,
+			       wpas_p2p_group_formation_timeout, wpa_s, NULL);
 }