Cumulative patch from commit 3e7f1c7980c6e9fc7173f78aa72b2761fcd8924d (DO NOT MERGE)

3e7f1c7 GnuTLS: Add TLS event callbacks for chain success/failure and peer cert
0eb2ed0 GnuTLS: Add support for OCSP stapling as a client
cf08e9b Add MESH to modes capabilities
db5adfe Add SAE to auth_alg capabilities
0e1bb94 GnuTLS: Verify that server certificate EKU is valid for a server
d4d1f5c GnuTLS: Fix tls_disable_time_checks=1 processing
594d1fc GnuTLS: Add support for private_key and client_cert as blobs
79b1dd9 GnuTLS: Fix DER encoding certificate parsing
a165145 Add "GET tls_library" to provide information on TLS library and version
c3bb84b GnuTLS: Add event callbacks
8ddcd6b GnuTLS: Add support for domain_suffix_match
4bc13bf GnuTLS: Check for any unknown verification failure
e0d431a GnuTLS: Add more debug prints for version and session status
65ec7f4 GnuTLS: Move peer certificate validation into callback function
7c82457 GnuTLS: Remove support for versions older than 2.12.x
e1d63f6 GnuTLS: Remove old version number checks for 1.3.2
ae0a23a GnuTLS: Remove GNUTLS_INTERNAL_STRUCTURE_HACK
db4cf40 GnuTLS: Add support for ca_cert as a blob
224104d TLS: Reject openssl_ciphers parameter in non-OpenSSL cases
b09baf3 Work around Windows build issues
6dbbef9 Define host_to_le32() for Windows builds
7d28e46 Fix os_win32 build
0b40247 Remove Network Security Service (NSS) support
d166947 schannel: Reject subject_match, altsubject_match, suffix_match
59051f8 TLS: Reject subject_match, altsubject_match, suffix_match
f8717ac GnuTLS: Reject subject_match, altsubject_match, suffix_match
e24aef1 Fix a typo in domain_suffix_match documentation
394b547 Improve subject_match and domain_suffix_match documentation
8a42a07 trace: Fix out-of-memory testing logic
79cd993 Add address masks to BSSID lists
b83e455 Add network specific BSSID black and white lists
b3d6a0a Add generic parser for MAC address lists
21c74e8 nl80211: Use a helper function to put mesh_id
85e1fad nl80211: Use a helper function for putting beacon interval
6dfc557 Remove mesh_ht_mode network block parameter
54fe48b mesh: Use the shared function with IBSS to determine channel parameters
f7e889f mesh: Convert channel configuration to use common routines
6334330 mesh: Use a separate variable to track whether HT is enabled
1fc4ab2 nl80211: Move debug prints into nl80211_put_freq_params()
cae87ab nl80211: Add a helper function for putting basic rates
6b8b077 ibss/mesh: Enable HT40 if supported
a828f62 Make check_40mhz_2g4 common
fdd989d Make check_20mhz_bss common
0e550fe Make check_40mhz_5g common
6d5d098 Make get_pri_sec_chan() common
5144274 Introduce common allowed_ht40_channel_pair()
5f10b7f Use common hw_get_freq/hw_get_chan helpers in hostapd
269dfe2 Introduce common hw features
1830817 IBSS: Add WPA_DRIVER_FLAGS_HT_IBSS
f3b8ad4 SAE: Implement retransmission timer
a206e2a SAE: Centralize function for sending initial COMMIT
28c91ee bsd: Fix parsing of ieee80211req_scan_result on FreeBSD and DragonFly
96d1d97 Android: Remove hardcoded ICU include paths from hs20-osu-client
a354bcc D-Bus: Use NoMemory error message from CreateInterface
635874b Handle interface disabled/enabled more consistently
8f2cf37 P2P: Indicate reason=UNAVAILABLE for group netdev going down
86a7fbb Verify that eloop_register_read_sock() succeeds for ctrl_iface setup
27d9701 Fix a memory leak on WPA authenticator error path
c1c07dc Fix hostapd interface addition error path
a156ffd Add support for testing memory allocation failures
52b3943 D-Bus: Fix interface unregistration on error path
96dc9a6 D-Bus (old): Fix interface unregistration on error path
ef03557 Fix memory leak on wpa_supplicant_init_wpa() error path
52a8058 TDLS: Fix an interface addition error path
f2d5728 D-Bus: Fix string array dict entry parser in out-of-memory case
c61bc23 D-Bus: Fix byte array dict entry parser in out-of-memory case
dacf605 D-Bus: Fix Introspect() in case of os_strdup() failure
68a8669 D-Bus (old): Fix wpsReg error message
f0614bc D-Bus (old): Fix message handler error paths
a2af1c7 D-Bus (old): Fix memory leak on error path
3d2e2d5 trace: Fix compiler warning on 32-bit builds with bfd support
b9f6560 eloop: Fix WPA_TRACE tracking in case of realloc failure
e10422c Fix memory leak on hostapd BSS addition error path
2801659 Fix hostapd initialization error path on allocation failure
d58ade2 nl80211: Fix compilation with libnl 1.1 and 2.0
51f3427 crypto: Clear temporary stack buffers after use
77a2c39 crypto: Clear temporary heap allocations before freeing
a15a7fc DH: Clear memory explicitly on private key deinit
77c45e2 Add wpabuf_clear_free() to allow clearing of freed memory
a90c7d9 OpenSSL: Fix pbkdf2_sha1() wrapper
f6ebbcf AES-SIV: Make aes_s2v() static
dcf8fbc nl80211: Simplify event processing error paths
38751d8 nl80211: Remove cfg80211 state mismatch workaround for authentication
64ae244 nl80211: Check support for rekey offload on first use

Change-Id: Ice94c3cf8e39a6d2cac993aacd0f6d45b31c7c15
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 97f98f2..3d4488a 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -328,6 +328,10 @@
 
 #ifdef CONFIG_SAE
 
+#define dot11RSNASAERetransPeriod 40	/* msec */
+#define dot11RSNASAESync 5		/* attempts */
+
+
 static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
 					     struct sta_info *sta, int update)
 {
@@ -483,6 +487,66 @@
 }
 
 
+static int sae_check_big_sync(struct sta_info *sta)
+{
+	if (sta->sae->sync > dot11RSNASAESync) {
+		sta->sae->state = SAE_NOTHING;
+		sta->sae->sync = 0;
+		return -1;
+	}
+	return 0;
+}
+
+
+static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = eloop_data;
+	int ret;
+
+	if (sae_check_big_sync(sta))
+		return;
+	sta->sae->sync++;
+
+	switch (sta->sae->state) {
+	case SAE_COMMITTED:
+		ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+		eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+				       auth_sae_retransmit_timer, hapd, sta);
+		break;
+	case SAE_CONFIRMED:
+		ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
+		eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+				       auth_sae_retransmit_timer, hapd, sta);
+		break;
+	default:
+		ret = -1;
+		break;
+	}
+
+	if (ret != WLAN_STATUS_SUCCESS)
+		wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
+}
+
+
+void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+}
+
+
+static void sae_set_retransmit_timer(struct hostapd_data *hapd,
+				     struct sta_info *sta)
+{
+	if (!(hapd->conf->mesh & MESH_ENABLED))
+		return;
+
+	eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+	eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+			       auth_sae_retransmit_timer, hapd, sta);
+}
+
+
 static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *bssid, u8 auth_transaction)
 {
@@ -530,6 +594,8 @@
 				 * when receiving Confirm from STA.
 				 */
 			}
+			sta->sae->sync = 0;
+			sae_set_retransmit_timer(hapd, sta);
 		} else {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_IEEE80211,
@@ -538,6 +604,7 @@
 		}
 		break;
 	case SAE_COMMITTED:
+		sae_clear_retransmit_timer(hapd, sta);
 		if (auth_transaction == 1) {
 			if (sae_process_commit(sta->sae) < 0)
 				return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -546,14 +613,22 @@
 			if (ret)
 				return ret;
 			sta->sae->state = SAE_CONFIRMED;
+			sta->sae->sync = 0;
+			sae_set_retransmit_timer(hapd, sta);
 		} else if (hapd->conf->mesh & MESH_ENABLED) {
 			/*
 			 * In mesh case, follow SAE finite state machine and
-			 * send Commit now.
+			 * send Commit now, if sync count allows.
 			 */
+			if (sae_check_big_sync(sta))
+				return WLAN_STATUS_SUCCESS;
+			sta->sae->sync++;
+
 			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
 			if (ret)
 				return ret;
+
+			sae_set_retransmit_timer(hapd, sta);
 		} else {
 			/*
 			 * For instructure BSS, send the postponed Confirm from
@@ -575,7 +650,12 @@
 		}
 		break;
 	case SAE_CONFIRMED:
+		sae_clear_retransmit_timer(hapd, sta);
 		if (auth_transaction == 1) {
+			if (sae_check_big_sync(sta))
+				return WLAN_STATUS_SUCCESS;
+			sta->sae->sync++;
+
 			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
 			if (ret)
 				return ret;
@@ -586,6 +666,8 @@
 			ret = auth_sae_send_confirm(hapd, sta, bssid);
 			if (ret)
 				return ret;
+
+			sae_set_retransmit_timer(hapd, sta);
 		} else {
 			sta->flags |= WLAN_STA_AUTH;
 			sta->auth_alg = WLAN_AUTH_SAE;
@@ -603,6 +685,10 @@
 				   MAC2STR(sta->addr));
 			ap_free_sta(hapd, sta);
 		} else {
+			if (sae_check_big_sync(sta))
+				return WLAN_STATUS_SUCCESS;
+			sta->sae->sync++;
+
 			ret = auth_sae_send_confirm(hapd, sta, bssid);
 			sae_clear_temp_data(sta->sae);
 			if (ret)
@@ -632,6 +718,7 @@
 		if (sta->sae == NULL)
 			return;
 		sta->sae->state = SAE_NOTHING;
+		sta->sae->sync = 0;
 	}
 
 	if (auth_transaction == 1) {
@@ -685,6 +772,8 @@
 				return;
 			}
 			sta->sae->state = SAE_COMMITTED;
+			sta->sae->sync = 0;
+			sae_set_retransmit_timer(hapd, sta);
 			return;
 		}
 
@@ -755,6 +844,39 @@
 	}
 	wpabuf_free(data);
 }
+
+
+/**
+ * auth_sae_init_committed - Send COMMIT and start SAE in committed state
+ * @hapd: BSS data for the device initiating the authentication
+ * @sta: the peer to which commit authentication frame is sent
+ *
+ * This function implements Init event handling (IEEE Std 802.11-2012,
+ * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
+ * sta->sae structure should be initialized appropriately via a call to
+ * sae_prepare_commit().
+ */
+int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int ret;
+
+	if (!sta->sae || !sta->sae->tmp)
+		return -1;
+
+	if (sta->sae->state != SAE_NOTHING)
+		return -1;
+
+	ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+	if (ret)
+		return -1;
+
+	sta->sae->state = SAE_COMMITTED;
+	sta->sae->sync = 0;
+	sae_set_retransmit_timer(hapd, sta);
+
+	return 0;
+}
+
 #endif /* CONFIG_SAE */