}
}
+#ifdef CONFIG_SAE
+ /* If SAE offload is enabled, provide password to lower layer for
+ * SAE authentication and PMK generation.
+ */
+ if (wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+ (hapd->iface->drv_flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP)) {
+ if (hostapd_sae_pk_in_use(hapd->conf)) {
+ wpa_printf(MSG_ERROR,
+ "SAE PK not supported with SAE offload");
+ return -1;
+ }
+
+ if (hostapd_sae_pw_id_in_use(hapd->conf)) {
+ wpa_printf(MSG_ERROR,
+ "SAE Password Identifiers not supported with SAE offload");
+ return -1;
+ }
+
+ params->sae_password = sae_get_password(hapd, NULL, NULL, NULL,
+ NULL, NULL);
+ if (!params->sae_password) {
+ wpa_printf(MSG_ERROR, "SAE password not configured for offload");
+ return -1;
+ }
+ }
+#endif /* CONFIG_SAE */
+
params->head = (u8 *) head;
params->head_len = head_len;
params->tail = tail;
}
-static const char * sae_get_password(struct hostapd_data *hapd,
- struct sta_info *sta,
- const char *rx_id,
- struct sae_password_entry **pw_entry,
- struct sae_pt **s_pt,
- const struct sae_pk **s_pk)
+const char * sae_get_password(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const char *rx_id,
+ struct sae_password_entry **pw_entry,
+ struct sae_pt **s_pt,
+ const struct sae_pk **s_pk)
{
const char *password = NULL;
struct sae_password_entry *pw;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
if (!is_broadcast_ether_addr(pw->peer_addr) &&
- os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0)
+ (!sta ||
+ os_memcmp(pw->peer_addr, sta->addr, ETH_ALEN) != 0))
continue;
if ((rx_id && !pw->identifier) || (!rx_id && pw->identifier))
continue;
pt = hapd->conf->ssid.pt;
}
- if (!password) {
+ if (!password && sta) {
for (psk = sta->psk; psk; psk = psk->next) {
if (psk->is_passphrase) {
password = psk->passphrase;
enum ieee80211_op_mode;
enum oper_chan_width;
struct ieee802_11_elems;
+struct sae_pk;
+struct sae_pt;
+struct sae_password_entry;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
void punct_update_legacy_bw(u16 bitmap, u8 pri_chan,
enum oper_chan_width *width, u8 *seg0, u8 *seg1);
bool hostapd_is_mld_ap(struct hostapd_data *hapd);
+const char * sae_get_password(struct hostapd_data *hapd,
+ struct sta_info *sta, const char *rx_id,
+ struct sae_password_entry **pw_entry,
+ struct sae_pt **s_pt, const struct sae_pk **s_pk);
#endif /* IEEE802_11_H */
int (*get_ml_rsn_info)(void *ctx, struct wpa_auth_ml_rsn_info *info);
int (*get_ml_key_info)(void *ctx, struct wpa_auth_ml_key_info *info);
#endif /* CONFIG_IEEE80211BE */
+ int (*get_drv_flags)(void *ctx, u64 *drv_flags, u64 *drv_flags2);
};
struct wpa_authenticator * wpa_init(const u8 *addr,
#endif /* CONFIG_IEEE80211BE */
+static int hostapd_wpa_auth_get_drv_flags(void *ctx,
+ u64 *drv_flags, u64 *drv_flags2)
+{
+ struct hostapd_data *hapd = ctx;
+
+ if (drv_flags)
+ *drv_flags = hapd->iface->drv_flags;
+ if (drv_flags2)
+ *drv_flags2 = hapd->iface->drv_flags2;
+
+ return 0;
+}
+
+
int hostapd_setup_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config _conf;
.get_ml_rsn_info = hostapd_wpa_auth_get_ml_rsn_info,
.get_ml_key_info = hostapd_wpa_auth_get_ml_key_info,
#endif /* CONFIG_IEEE80211BE */
+ .get_drv_flags = hostapd_wpa_auth_get_drv_flags,
};
const u8 *wpa_ie;
size_t wpa_ie_len;
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "ap_config.h"
#include "ieee802_11.h"
}
#ifdef CONFIG_SAE
- if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE && data.num_pmkid &&
- !sm->pmksa) {
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "No PMKSA cache entry found for SAE");
- return WPA_INVALID_PMKID;
+ if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE) {
+ u64 drv_flags = 0;
+ u64 drv_flags2 = 0;
+ bool ap_sae_offload = false;
+
+ if (wpa_auth->cb->get_drv_flags &&
+ wpa_auth->cb->get_drv_flags(wpa_auth->cb_ctx, &drv_flags,
+ &drv_flags2) == 0)
+ ap_sae_offload =
+ !!(drv_flags2 &
+ WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP);
+
+ if (!ap_sae_offload && data.num_pmkid && !sm->pmksa) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "No PMKSA cache entry found for SAE");
+ return WPA_INVALID_PMKID;
+ }
}
#endif /* CONFIG_SAE */
* psk_len - PSK length in bytes (0 = not set)
*/
size_t psk_len;
+
+ /**
+ * sae_password - SAE password for SAE offload
+ */
+ const char *sae_password;
};
struct wpa_driver_mesh_bss_params {
#define WPA_DRIVER_FLAGS2_OWE_OFFLOAD_STA 0x0000000000040000ULL
/** Driver supports OWE AP offload */
#define WPA_DRIVER_FLAGS2_OWE_OFFLOAD_AP 0x0000000000080000ULL
+/** Driver support AP SAE authentication offload */
+#define WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP 0x0000000000100000ULL
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
nla_put(msg, NL80211_ATTR_PMK, params->psk_len, params->psk))
goto fail;
+ if (wpa_key_mgmt_sae(params->key_mgmt_suites) &&
+ (drv->capa.flags2 & WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP) &&
+ params->sae_password &&
+ nla_put(msg, NL80211_ATTR_SAE_PASSWORD,
+ os_strlen(params->sae_password), params->sae_password))
+ goto fail;
+
if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
(!params->pairwise_ciphers ||
params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&
if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_OWE_OFFLOAD_AP))
capa->flags2 |= WPA_DRIVER_FLAGS2_OWE_OFFLOAD_AP;
+
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SAE_OFFLOAD_AP))
+ capa->flags2 |= WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP;
}