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);