wpa_supplicant: add support for bcmdhd SAE authentication offload

* Required to get WPA3 to work at all on bcmdhd devices

Change-Id: Ie96550256afd1596f26a377b4af104a8bd104c10
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ac2f457..dd476ff 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -40,9 +40,9 @@
 #include "radiotap_iter.h"
 #include "rfkill.h"
 #include "driver_nl80211.h"
-#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA) || defined(CONFIG_BRCM_SAE)
 #include "common/brcm_vendor.h"
-#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA || CONFIG_BRCM_SAE */
 
 #ifndef NETLINK_CAP_ACK
 #define NETLINK_CAP_ACK 10
@@ -3398,6 +3398,32 @@
 }
 #endif /* CONFIG_DRIVER_NL80211_QCA */
 
+#ifdef CONFIG_BRCM_SAE
+static int bcmdhd_set_sae_password(struct wpa_driver_nl80211_data *drv,
+				   const void *data, int len)
+{
+	struct nl_msg *msg;
+	int ret;
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			BRCM_VENDOR_SCMD_BCM_PSK) ||
+	    nla_put(msg, NL80211_ATTR_VENDOR_DATA, len, data)) {
+		nl80211_nlmsg_clear(msg);
+		nlmsg_free(msg);
+		return -1;
+	}
+	ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1, NULL, NULL);
+	if (ret) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Set SAE password failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+	}
+
+	return ret;
+}
+#endif /* CONFIG_BRCM_SAE */
 
 #if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
 static int key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
@@ -7086,6 +7112,23 @@
 			return -1;
 	}
 
+#ifdef CONFIG_BRCM_SAE
+	/* add SAE password in case of SAE authentication offload */
+	if ((params->sae_password || params->passphrase)) {
+		const char *password;
+		size_t pwd_len;
+
+		password = params->sae_password;
+		if (!password)
+			password = params->passphrase;
+		pwd_len = os_strlen(password);
+		wpa_hexdump_ascii_key(MSG_DEBUG, "  * SAE password",
+				      (u8 *) password, pwd_len);
+		if (bcmdhd_set_sae_password(drv, password, pwd_len))
+			return -1;
+	}
+#endif
+
 	if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
 		return -1;
 
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index fdaf07b..32786cb 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -19,6 +19,11 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "driver_nl80211.h"
+#ifdef CONFIG_BRCM_SAE
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/wpa_i.h"
+#include "wpa_supplicant_i.h"
+#endif
 
 static void
 nl80211_control_port_frame_tx_status(struct wpa_driver_nl80211_data *drv,
@@ -3236,6 +3241,33 @@
 	wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
 }
 
+#ifdef CONFIG_BRCM_SAE
+static void brcm_nl80211_sae_key_event(struct wpa_driver_nl80211_data *drv,
+                                       const u8 *data, size_t len)
+{
+	struct nlattr *tb[BRCM_SAE_KEY_ATTR_PMKID + 1];
+	struct wpa_pmkid_params params;
+	struct wpa_supplicant *wpa_s = drv->ctx;
+	struct wpa_sm *sm = wpa_s->wpa;
+
+	wpa_printf(MSG_DEBUG, "nl80211: BRCM SAE key vendor event received");
+
+	if (nla_parse(tb, BRCM_SAE_KEY_ATTR_PMKID, (struct nlattr *) data,
+			len, NULL))
+		return;
+
+	params.bssid = (u8*) nla_data(tb[BRCM_SAE_KEY_ATTR_BSSID]);
+	params.pmk = (u8*) nla_data(tb[BRCM_SAE_KEY_ATTR_PMK]);
+	params.pmk_len = nla_len(tb[BRCM_SAE_KEY_ATTR_PMK]);
+	params.pmkid = (u8*) nla_data(tb[BRCM_SAE_KEY_ATTR_PMKID]);
+
+	wpa_hexdump(MSG_DEBUG, "nl80211: Received BRCM SAE key for", params.bssid,
+			nla_len(tb[BRCM_SAE_KEY_ATTR_BSSID]));
+	wpa_printf(MSG_DEBUG, "nl80211: BRCM SAE key len=%zu", params.pmk_len);
+
+	wpa_sm_set_pmk(sm, params.pmk, params.pmk_len, params.pmkid, params.bssid);
+}
+#endif
 
 static void nl80211_vendor_event_brcm(struct wpa_driver_nl80211_data *drv,
 				      u32 subcmd, u8 *data, size_t len)
@@ -3250,6 +3282,11 @@
 	case BRCM_VENDOR_EVENT_ACS:
 		brcm_nl80211_acs_select_ch(drv, data, len);
 		break;
+#ifdef CONFIG_BRCM_SAE
+	case BRCM_VENDOR_EVENT_SAE_KEY:
+		brcm_nl80211_sae_key_event(drv, data, len);
+		break;
+#endif
 	default:
 		wpa_printf(MSG_DEBUG,
 			   "%s: Ignore unsupported BRCM vendor event %u",
@@ -3311,11 +3348,11 @@
 	case OUI_QCA:
 		nl80211_vendor_event_qca(drv, subcmd, data, len);
 		break;
-#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA)
+#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA) || defined(CONFIG_BRCM_SAE)
 	case OUI_BRCM:
 		nl80211_vendor_event_brcm(drv, subcmd, data, len);
 		break;
-#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */
+#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA || CONFIG_BRCM_SAE */
 	default:
 		wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
 		break;
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 98152be..b614b83 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -18,6 +18,10 @@
   CONFIG_DRIVER_NL80211_QCA=y
 endif
 
+ifneq ($(BOARD_WLAN_BCMDHD_SAE),)
+  CONFIG_BRCM_SAE=y
+endif
+
 include $(LOCAL_PATH)/android.config
 
 # To ignore possible wrong network configurations
@@ -81,6 +85,11 @@
 L_CFLAGS += -DWIFI_BRCM_OPEN_SOURCE_MULTI_AKM
 endif
 
+# BCMDHD SAE authentication offload
+ifdef CONFIG_BRCM_SAE
+L_CFLAGS += -DCONFIG_BRCM_SAE
+endif
+
 # Use Android specific directory for control interface sockets
 L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/vendor/wifi/wpa/sockets\"
 L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/vendor/wifi/wpa/sockets\"
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index d4401ff..1bafed0 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -4364,7 +4364,10 @@
 			params.psk = psk;
 	}
 
-	if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA) &&
+	if (
+#ifndef CONFIG_BRCM_SAE
+	(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA) &&
+#endif
 	    wpa_key_mgmt_sae(params.key_mgmt_suite)) {
 		params.auth_alg = WPA_AUTH_ALG_SAE;
 		if (ssid->sae_password) {
@@ -4373,6 +4376,11 @@
 		} else if (ssid->passphrase) {
 			params.passphrase = ssid->passphrase;
 		}
+
+#ifdef CONFIG_BRCM_SAE
+		if (ssid->psk_set)
+			params.psk = ssid->psk;
+#endif
 	}
 
 	params.drop_unencrypted = use_crypt;