Cumulative patch from commit commit add7add09d72c3294c63a113635d69b766acf504

add7add IBSS RSN: Add a timeout for Authentication frame exchange
c1c0b35 P2P: Postpone concurrent scans when waiting for first client as GO
6fb7b58 IBSS RSN: Work around Data RX vs. Authentication RX race condition

Bug: 10513949

Change-Id: Ic4d77c94a5b6e4729cd798f7b033e3ea5b2481cc
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index b694bde..3e5d412 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -10,6 +10,7 @@
 
 #include "common.h"
 #include "common/wpa_ctrl.h"
+#include "utils/eloop.h"
 #include "l2_packet/l2_packet.h"
 #include "rsn_supp/wpa.h"
 #include "rsn_supp/wpa_ie.h"
@@ -20,6 +21,9 @@
 #include "ibss_rsn.h"
 
 
+static void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx);
+
+
 static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn,
 						const u8 *addr)
 {
@@ -34,6 +38,7 @@
 
 static void ibss_rsn_free(struct ibss_rsn_peer *peer)
 {
+	eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL);
 	wpa_auth_sta_deinit(peer->auth);
 	wpa_sm_deinit(peer->supp);
 	os_free(peer);
@@ -543,6 +548,23 @@
 }
 
 
+static void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct ibss_rsn_peer *peer = eloop_ctx;
+
+	/*
+	 * Assume peer does not support Authentication exchange or the frame was
+	 * lost somewhere - start EAPOL Authenticator.
+	 */
+	wpa_printf(MSG_DEBUG,
+		   "RSN: Timeout on waiting Authentication frame response from "
+		   MACSTR " - start authenticator", MAC2STR(peer->addr));
+
+	peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
+	ibss_rsn_auth_init(peer->ibss_rsn, peer);
+}
+
+
 int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr)
 {
 	struct ibss_rsn_peer *peer;
@@ -566,6 +588,9 @@
 		 */
 		peer->authentication_status |= IBSS_RSN_AUTH_BY_US;
 		return ibss_rsn_auth_init(ibss_rsn, peer);
+	} else {
+		os_get_time(&peer->own_auth_tx);
+		eloop_register_timeout(1, 0, ibss_rsn_auth_timeout, peer, NULL);
 	}
 
 	return 0;
@@ -807,6 +832,16 @@
 
 	if (peer &&
 	    peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) {
+		if (peer->own_auth_tx.sec) {
+			struct os_time now, diff;
+			os_get_time(&now);
+			os_time_sub(&now, &peer->own_auth_tx, &diff);
+			if (diff.sec == 0 && diff.usec < 500000) {
+				wpa_printf(MSG_DEBUG, "RSN: Skip IBSS reinit since only %u usec from own Auth frame TX",
+					   (int) diff.usec);
+				goto skip_reinit;
+			}
+		}
 		/*
 		 * A peer sent us an Authentication frame even though it already
 		 * started an EAPOL session. We should reinit state machines
@@ -829,6 +864,7 @@
 			   MAC2STR(addr));
 	}
 
+skip_reinit:
 	/* reply with an Authentication frame now, before sending an EAPOL */
 	ibss_rsn_send_auth(ibss_rsn, addr, 2);
 	/* no need to start another AUTH challenge in the other way.. */
@@ -869,7 +905,8 @@
 		}
 
 		/* authentication has been completed */
-		wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with "MACSTR,
+		eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL);
+		wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with " MACSTR,
 			   MAC2STR(header->sa));
 		ibss_rsn_peer_authenticated(ibss_rsn, peer,
 					    IBSS_RSN_AUTH_BY_US);
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 6b89f7a..3089283 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -39,6 +39,8 @@
 
 	struct wpa_state_machine *auth;
 	int authentication_status;
+
+	struct os_time own_auth_tx;
 };
 
 struct ibss_rsn {
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 0827f35..239e608 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -61,6 +61,16 @@
 #define P2P_MAX_INITIAL_CONN_WAIT 10
 #endif /* P2P_MAX_INITIAL_CONN_WAIT */
 
+#ifndef P2P_MAX_INITIAL_CONN_WAIT_GO
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * WPS provisioning step on the GO. This controls the extra time the P2P
+ * operation is considered to be in progress (e.g., to delay other scans) after
+ * WPS provisioning has been completed on the GO during group formation.
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT_GO 10
+#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO */
+
 #ifndef P2P_CONCURRENT_SEARCH_DELAY
 #define P2P_CONCURRENT_SEARCH_DELAY 500
 #endif /* P2P_CONCURRENT_SEARCH_DELAY */
@@ -792,8 +802,10 @@
 							     ssid, go_dev_addr);
 	if (network_id < 0 && ssid)
 		network_id = ssid->id;
-	if (!client)
+	if (!client) {
 		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
+		os_get_time(&wpa_s->global->p2p_go_wait_client);
+	}
 }
 
 
@@ -5823,6 +5835,19 @@
 		}
 	}
 
+	if (!ret && wpa_s->global->p2p_go_wait_client.sec) {
+		struct os_time now;
+		os_get_time(&now);
+		if (now.sec > wpa_s->global->p2p_go_wait_client.sec +
+		    P2P_MAX_INITIAL_CONN_WAIT_GO) {
+			/* Wait for the first client has expired */
+			wpa_s->global->p2p_go_wait_client.sec = 0;
+		} else {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Waiting for initial client connection during group formation");
+			ret = 1;
+		}
+	}
+
 	return ret;
 }
 
@@ -5882,6 +5907,7 @@
 void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
 				       const u8 *addr)
 {
+	wpa_s->global->p2p_go_wait_client.sec = 0;
 	if (addr == NULL)
 		return;
 	wpas_p2p_add_persistent_group_client(wpa_s, addr);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 0858bbc..604997e 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -252,6 +252,7 @@
 	struct wpa_supplicant *p2p_group_formation;
 	struct wpa_supplicant *p2p_invite_group;
 	u8 p2p_dev_addr[ETH_ALEN];
+	struct os_time p2p_go_wait_client;
 	struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
 	struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
 	int p2p_disabled;