Update to new version 0.8.16 from BRCM

Sync with main tree commit b8349523e460493fa0b4de36c689595109e45e91
Author: Neeraj Kumar Garg <neerajkg@broadcom.com>
Date:   Tue Dec 27 23:21:45 2011 +0200
    P2P: Reject p2p_group_add if forced frequency is not acceptable

Change-Id: Icb4541a371b05c270e80440d7a7fdea7f33ff61e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 0836887..adc69e2 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
 /*
- * hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * IEEE 802.11 RSN / WPA Authenticator
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -52,6 +52,7 @@
 static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
 static const u32 eapol_key_timeout_first = 100; /* ms */
 static const u32 eapol_key_timeout_subseq = 1000; /* ms */
+static const u32 eapol_key_timeout_first_group = 500; /* ms */
 
 /* TODO: make these configurable */
 static const int dot11RSNAConfigPMKLifetime = 43200;
@@ -194,6 +195,7 @@
 {
 	if (wpa_auth->cb.disconnect == NULL)
 		return;
+	wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr));
 	wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
 				WLAN_REASON_PREV_AUTH_NOT_VALID);
 }
@@ -332,7 +334,7 @@
 
 
 static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
-					 int vlan_id)
+					 int vlan_id, int delay_init)
 {
 	struct wpa_group *group;
 
@@ -349,10 +351,6 @@
 		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
 			   "for secure operations - update keys later when "
 			   "the first station connects");
-#ifdef ANDROID_BRCM_P2P_PATCH
-		os_free(group);
-		return NULL;
-#endif
 	}
 
 	/*
@@ -369,9 +367,15 @@
 	}
 
 	group->GInit = TRUE;
-	wpa_group_sm_step(wpa_auth, group);
-	group->GInit = FALSE;
-	wpa_group_sm_step(wpa_auth, group);
+	if (delay_init) {
+		wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
+			   "until Beacon frames have been configured");
+		/* Initialization is completed in wpa_init_keys(). */
+	} else {
+		wpa_group_sm_step(wpa_auth, group);
+		group->GInit = FALSE;
+		wpa_group_sm_step(wpa_auth, group);
+	}
 
 	return group;
 }
@@ -403,7 +407,7 @@
 		return NULL;
 	}
 
-	wpa_auth->group = wpa_group_init(wpa_auth, 0);
+	wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
 	if (wpa_auth->group == NULL) {
 		os_free(wpa_auth->wpa_ie);
 		os_free(wpa_auth);
@@ -444,6 +448,19 @@
 }
 
 
+int wpa_init_keys(struct wpa_authenticator *wpa_auth)
+{
+	struct wpa_group *group = wpa_auth->group;
+
+	wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
+		   "keys");
+	wpa_group_sm_step(wpa_auth, group);
+	group->GInit = FALSE;
+	wpa_group_sm_step(wpa_auth, group);
+	return 0;
+}
+
+
 /**
  * wpa_deinit - Deinitialize WPA authenticator
  * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
@@ -695,6 +712,37 @@
 #endif /* CONFIG_IEEE80211R */
 
 
+static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+				     struct wpa_state_machine *sm, int group)
+{
+	/* Supplicant reported a Michael MIC error */
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+			 "received EAPOL-Key Error Request "
+			 "(STA detected Michael MIC failure (group=%d))",
+			 group);
+
+	if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"ignore Michael MIC failure report since "
+				"group cipher is not TKIP");
+	} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"ignore Michael MIC failure report since "
+				"pairwise cipher is not TKIP");
+	} else {
+		wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+		sm->dot11RSNAStatsTKIPRemoteMICFailures++;
+		wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
+	}
+
+	/*
+	 * Error report is not a request for a new key handshake, but since
+	 * Authenticator may do it, let's change the keys now anyway.
+	 */
+	wpa_request_new_ptk(sm);
+}
+
+
 void wpa_receive(struct wpa_authenticator *wpa_auth,
 		 struct wpa_state_machine *sm,
 		 u8 *data, size_t data_len)
@@ -720,6 +768,9 @@
 	key = (struct wpa_eapol_key *) (hdr + 1);
 	key_info = WPA_GET_BE16(key->key_info);
 	key_data_length = WPA_GET_BE16(key->key_data_length);
+	wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
+		   " key_info=0x%x type=%u key_data_length=%u",
+		   MAC2STR(sm->addr), key_info, key->type, key_data_length);
 	if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
 		wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
 			   "key_data overflow (%d > %lu)",
@@ -819,7 +870,7 @@
 	if (!(key_info & WPA_KEY_INFO_REQUEST) &&
 	    !wpa_replay_counter_valid(sm, key->replay_counter)) {
 		int i;
-		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
 				 "received EAPOL-Key %s with unexpected "
 				 "replay counter", msgtxt);
 		for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
@@ -1000,17 +1051,9 @@
 #endif /* CONFIG_PEERKEY */
 			return;
 		} else if (key_info & WPA_KEY_INFO_ERROR) {
-			/* Supplicant reported a Michael MIC error */
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key Error Request "
-					"(STA detected Michael MIC failure)");
-			wpa_auth_mic_failure_report(wpa_auth, sm->addr);
-			sm->dot11RSNAStatsTKIPRemoteMICFailures++;
-			wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
-			/* Error report is not a request for a new key
-			 * handshake, but since Authenticator may do it, let's
-			 * change the keys now anyway. */
-			wpa_request_new_ptk(sm);
+			wpa_receive_error_report(
+				wpa_auth, sm,
+				!(key_info & WPA_KEY_INFO_KEY_TYPE));
 		} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"received EAPOL-Key Request for new "
@@ -1028,9 +1071,6 @@
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"received EAPOL-Key Request for GTK "
 					"rekeying");
-			/* FIX: why was this triggering PTK rekeying for the
-			 * STA that requested Group Key rekeying?? */
-			/* wpa_request_new_ptk(sta->wpa_sm); */
 			eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
 			wpa_rekey_gtk(wpa_auth, NULL);
 		}
@@ -1057,6 +1097,7 @@
 	os_memcpy(sm->last_rx_eapol_key, data, data_len);
 	sm->last_rx_eapol_key_len = data_len;
 
+	sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
 	sm->EAPOLKeyReceived = TRUE;
 	sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
 	sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
@@ -1293,7 +1334,8 @@
 
 	ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
 	if (ctr == 1 && wpa_auth->conf.tx_status)
-		timeout_ms = eapol_key_timeout_first;
+		timeout_ms = pairwise ? eapol_key_timeout_first :
+			eapol_key_timeout_first_group;
 	else
 		timeout_ms = eapol_key_timeout_subseq;
 	if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
@@ -1844,6 +1886,20 @@
 		gtk_len = 0;
 		keyidx = 0;
 		_rsc = NULL;
+		if (sm->rx_eapol_key_secure) {
+			/*
+			 * It looks like Windows 7 supplicant tries to use
+			 * Secure bit in msg 2/4 after having reported Michael
+			 * MIC failure and it then rejects the 4-way handshake
+			 * if msg 3/4 does not set Secure bit. Work around this
+			 * by setting the Secure bit here even in the case of
+			 * WPA if the supplicant used it first.
+			 */
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					"STA used Secure bit in WPA msg 2/4 - "
+					"set Secure for 3/4 as workaround");
+			secure = 1;
+		}
 	}
 
 	kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
@@ -2469,6 +2525,7 @@
 		group->GN_igtk = tmp;
 #endif /* CONFIG_IEEE80211W */
 		wpa_gtk_update(wpa_auth, group);
+		wpa_group_config_group_keys(wpa_auth, group);
 	}
 }
 
@@ -2771,7 +2828,7 @@
 
 	wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
 		   vlan_id);
-	group = wpa_group_init(wpa_auth, vlan_id);
+	group = wpa_group_init(wpa_auth, vlan_id, 0);
 	if (group == NULL)
 		return NULL;