From da364180fba69a56e65f6554697989171cc9d0c0 Mon Sep 17 00:00:00 2001 From: Vinayak Yadawad Date: Wed, 8 Nov 2023 18:26:09 +0530 Subject: [PATCH] hostapd: Support 4-way handshake offload for AP/P2P GO Add support for offloaded 4-way handshake in AP/P2P GO mode. For drivers supporting the AP PSK offload, wpa_supplicant/hostapd passes down the PSK for the driver to handle the 4-way handshake. The driver is expected to indicate port authorized event to indicate that the 4-way handshake is completed successfully. Signed-off-by: Vinayak Yadawad --- src/ap/beacon.c | 18 ++++++++++++++++++ src/ap/drv_callbacks.c | 10 ++++++++++ src/ap/hostapd.c | 6 +++++- src/drivers/driver.h | 21 +++++++++++++++++++++ src/drivers/driver_nl80211.c | 6 ++++++ src/drivers/driver_nl80211_capa.c | 4 ++++ src/drivers/driver_nl80211_event.c | 8 +++++++- wpa_supplicant/ap.c | 1 + wpa_supplicant/events.c | 16 ++++++++++++++++ 9 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/ap/beacon.c b/src/ap/beacon.c index b88aeb03c..2101d4847 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -17,6 +17,7 @@ #include "common/ieee802_11_common.h" #include "common/hw_features_common.h" #include "common/wpa_ctrl.h" +#include "crypto/sha1.h" #include "wps/wps_defs.h" #include "p2p/p2p.h" #include "hostapd.h" @@ -2026,6 +2027,23 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, resp = hostapd_probe_resp_offloads(hapd, &resp_len); #endif /* NEED_AP_MLME */ + /* If key management offload is enabled, configure PSK to the driver. */ + if (wpa_key_mgmt_wpa_psk_no_sae(hapd->conf->wpa_key_mgmt) && + (hapd->iface->drv_flags2 & + WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK)) { + if (hapd->conf->ssid.wpa_psk && hapd->conf->ssid.wpa_psk_set) { + os_memcpy(params->psk, hapd->conf->ssid.wpa_psk->psk, + PMK_LEN); + params->psk_len = PMK_LEN; + } else if (hapd->conf->ssid.wpa_passphrase && + pbkdf2_sha1(hapd->conf->ssid.wpa_passphrase, + hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len, 4096, + params->psk, PMK_LEN) == 0) { + params->psk_len = PMK_LEN; + } + } + params->head = (u8 *) head; params->head_len = head_len; params->tail = tail; diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index bc575e260..be76ec2b1 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -2186,6 +2186,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { struct hostapd_data *hapd = ctx; + struct sta_info *sta; #ifndef CONFIG_NO_STDOUT_DEBUG int level = MSG_DEBUG; @@ -2305,6 +2306,15 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->assoc_info.link_addr, data->assoc_info.reassoc); break; + case EVENT_PORT_AUTHORIZED: + /* Port authorized event for an associated STA */ + sta = ap_get_sta(hapd, data->port_authorized.sta_addr); + if (sta) + ap_sta_set_authorized(hapd, sta, 1); + else + wpa_printf(MSG_DEBUG, + "No STA info matching port authorized event found"); + break; #ifdef CONFIG_OWE case EVENT_UPDATE_DH: if (!data) diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 966030d57..236381fe8 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -3573,8 +3573,12 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, sta->auth_alg != WLAN_AUTH_FILS_PK && !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH); - } else + } else if (!(hapd->iface->drv_flags2 & + WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK)) { + /* The 4-way handshake offloaded case will have this handled + * based on the port authorized event. */ wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm); + } if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) { if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) { diff --git a/src/drivers/driver.h b/src/drivers/driver.h index b56512796..f0e690d01 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1812,6 +1812,16 @@ struct wpa_driver_ap_params { * mld_link_id - Link id for MLD BSS's */ u8 mld_link_id; + + /** + * psk - PSK passed to the driver for 4-way handshake offload + */ + u8 psk[PMK_LEN]; + + /** + * psk_len - PSK length in bytes (0 = not set) + */ + size_t psk_len; }; struct wpa_driver_mesh_bss_params { @@ -2284,6 +2294,8 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS2_SCAN_MIN_PREQ 0x0000000000008000ULL /** Driver supports SAE authentication offload in STA mode */ #define WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA 0x0000000000010000ULL +/** Driver support AP_PSK authentication offload */ +#define WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK 0x0000000000020000ULL u64 flags2; #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \ @@ -6672,10 +6684,19 @@ union wpa_event_data { /** * struct port_authorized - Data for EVENT_PORT_AUTHORIZED + * @td_bitmap: For STA mode, transition disable bitmap, if received in + * EAPOL-Key msg 3/4 + * @td_bitmap_len: For STA mode, length of td_bitmap + * @sta_addr: For AP mode, the MAC address of the associated STA + * + * This event is used to indicate that the port is authorized and + * open for normal data in STA and AP modes when 4-way handshake is + * offloaded to the driver. */ struct port_authorized { const u8 *td_bitmap; size_t td_bitmap_len; + const u8 *sta_addr; } port_authorized; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 8b72d74c5..94273bfe2 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -5110,6 +5110,12 @@ static int wpa_driver_nl80211_set_ap(void *priv, suites)) goto fail; + if ((params->key_mgmt_suites & WPA_KEY_MGMT_PSK) && + (drv->capa.flags & WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK) && + params->psk_len && + nla_put(msg, NL80211_ATTR_PMK, params->psk_len, params->psk)) + 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)) && diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index b7d914140..2e7ce5dc8 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -705,6 +705,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info, if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT)) capa->flags2 |= WPA_DRIVER_FLAGS2_SCAN_MIN_PREQ; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK)) + capa->flags2 |= WPA_DRIVER_FLAGS2_4WAY_HANDSHAKE_AP_PSK; } diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 0297bffeb..0091032e5 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -3506,7 +3506,13 @@ static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv, } addr = nla_data(tb[NL80211_ATTR_MAC]); - if (os_memcmp(addr, drv->bssid, ETH_ALEN) != 0) { + if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) { + event.port_authorized.sta_addr = addr; + wpa_printf(MSG_DEBUG, + "nl80211: Port authorized for STA addr " MACSTR, + MAC2STR(addr)); + } else if (is_sta_interface(drv->nlmode) && + os_memcmp(addr, drv->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "nl80211: Ignore port authorized event for " MACSTR " (not the currently connected BSSID " MACSTR ")", diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 2fc9f453b..b6e666a7d 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -1058,6 +1058,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, return -1; hapd_iface->owner = wpa_s; hapd_iface->drv_flags = wpa_s->drv_flags; + hapd_iface->drv_flags2 = wpa_s->drv_flags2; hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads; hapd_iface->extended_capa = wpa_s->extended_capa; hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index aa5c9b058..2e0570f32 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -22,6 +22,7 @@ #include "common/wpa_ctrl.h" #include "eap_peer/eap.h" #include "ap/hostapd.h" +#include "ap/sta_info.h" #include "p2p/p2p.h" #include "fst/fst.h" #include "wnm_sta.h" @@ -6411,6 +6412,21 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; #endif /* CONFIG_PASN */ case EVENT_PORT_AUTHORIZED: +#ifdef CONFIG_AP + if (wpa_s->ap_iface && wpa_s->ap_iface->bss[0]) { + struct sta_info *sta; + + sta = ap_get_sta(wpa_s->ap_iface->bss[0], + data->port_authorized.sta_addr); + if (sta) + ap_sta_set_authorized(wpa_s->ap_iface->bss[0], + sta, 1); + else + wpa_printf(MSG_DEBUG, + "No STA info matching port authorized event found"); + break; + } +#endif /* CONFIG_AP */ #ifndef CONFIG_NO_WPA if (data->port_authorized.td_bitmap_len) { wpa_printf(MSG_DEBUG,