From 2f8529ec491389bdb41911edcf084bc643d7c9ee Mon Sep 17 00:00:00 2001
From: Chung-Hsien Hsu <stanley.hsu@cypress.com>
Date: Tue, 10 Dec 2019 14:03:57 -0600
Subject: [PATCH 09/49] AP: Support 4-way handshake offload for WPA/WPA2-PSK

Add support for WPA/WPA2-PSK 4-way handshake offload in AP mode. In this
case, the 4-way handshake is handled by driver instead of user space.

Signed-off-by: Chung-Hsien Hsu <chung-hsien.hsu@infineon.com>
---
 src/ap/beacon.c        | 10 ++++++++++
 src/ap/hostapd.c       |  8 +++++++-
 src/ap/wpa_auth.c      | 16 ++++++++++++++++
 src/ap/wpa_auth.h      |  2 ++
 src/ap/wpa_auth_glue.c |  4 ++++
 5 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 8cd1c4170..583b6836e 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -1753,6 +1753,16 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 		}
 	}
 
+	if ((hapd->iface->drv_flags2 &
+	     WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK) &&
+	    (params->key_mgmt_suites &
+	     (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_PSK_SHA256))) {
+		if (hapd->conf->ssid.wpa_passphrase)
+			params->passphrase = hapd->conf->ssid.wpa_passphrase;
+		if (hapd->conf->ssid.wpa_psk->psk)
+			params->psk = hapd->conf->ssid.wpa_psk->psk;
+	}
+
 	return 0;
 }
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 4b88641a2..464d8fa95 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -3203,6 +3203,8 @@ int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
 void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
 			   int reassoc)
 {
+	int key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
+
 	if (hapd->tkip_countermeasures) {
 		hostapd_drv_sta_deauth(hapd, sta->addr,
 				       WLAN_REASON_MICHAEL_MIC_FAILURE);
@@ -3236,7 +3238,11 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
 	/* Start IEEE 802.1X authentication process for new stations */
 	ieee802_1x_new_station(hapd, sta);
 	if (reassoc) {
-		if (sta->auth_alg != WLAN_AUTH_FT &&
+		if ((hapd->iface->drv_flags2 &
+		     WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK) &&
+		    wpa_key_mgmt_wpa_psk(key_mgmt))
+			wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
+		else if (sta->auth_alg != WLAN_AUTH_FT &&
 		    sta->auth_alg != WLAN_AUTH_FILS_SK &&
 		    sta->auth_alg != WLAN_AUTH_FILS_SK_PFS &&
 		    sta->auth_alg != WLAN_AUTH_FILS_PK &&
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 6d60f2629..4b506c1db 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -696,6 +696,22 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
 	}
 #endif /* CONFIG_FILS */
 
+	if (wpa_auth->conf.psk_4way_hs_offload) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+				"4-way handshake offloading for WPA/WPA2-PSK");
+		sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
+		sm->Pair = true;
+		wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+				   WPA_EAPOL_authorized, 1);
+		wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+				   WPA_EAPOL_portValid, 1);
+		wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+				   WPA_EAPOL_keyAvailable, 0);
+		wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+				   WPA_EAPOL_keyDone, 1);
+		return 0;
+	}
+
 	if (sm->started) {
 		os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
 		sm->ReAuthenticationRequest = true;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index fe47723b9..2f807893f 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -273,6 +273,8 @@ struct wpa_auth_config {
 	 * PTK derivation regardless of advertised capabilities.
 	 */
 	bool force_kdk_derivation;
+
+	int psk_4way_hs_offload;
 };
 
 typedef enum {
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 3e9921553..26de12b5b 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -1528,6 +1528,10 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
 	_conf.prot_range_neg =
 		!!(hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG);
 
+	if (!hapd->conf->p2p &&
+	    (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK))
+		_conf.psk_4way_hs_offload = 1;
+
 	hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd);
 	if (hapd->wpa_auth == NULL) {
 		wpa_printf(MSG_ERROR, "WPA initialization failed.");
-- 
2.17.1

