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.h b/src/drivers/driver.h
index 3c4de7a..5cbf88c 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1116,6 +1116,15 @@
*/
const u8 *psk;
+#ifdef CONFIG_BRCM_SAE
+ /**
+ * sae_password - Password for SAE authentication
+ *
+ * This value is made available only for WPA3-Personal (SAE)
+ */
+ const char *sae_password;
+#endif
+
/**
* drop_unencrypted - Enable/disable unencrypted frame filtering
*
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 1acc43b..79d1261 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
@@ -3397,6 +3397,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,
@@ -6935,6 +6961,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 16d6f5b..cc1ffda 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,
@@ -3139,6 +3144,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)
@@ -3153,6 +3185,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",
@@ -3214,11 +3251,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 474873a..9efa54a 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
@@ -75,6 +79,11 @@
L_CFLAGS += -DENABLE_PRIV_CMD_UPDATE_MBO_CELL_STATUS
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 a3645d1..32e14da 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -4291,6 +4291,19 @@
params.psk = psk;
}
+#ifdef CONFIG_BRCM_SAE
+ if (wpa_key_mgmt_sae(params.key_mgmt_suite)) {
+ params.auth_alg = WPA_AUTH_ALG_SAE;
+ if (ssid->sae_password)
+ params.sae_password = ssid->sae_password;
+ else if (ssid->passphrase)
+ params.passphrase = ssid->passphrase;
+
+ if (ssid->psk_set)
+ params.psk = ssid->psk;
+ }
+#endif
+
params.drop_unencrypted = use_crypt;
params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);