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 <vinayak.yadawad@broadcom.com>
This commit is contained in:
Vinayak Yadawad 2023-11-08 18:26:09 +05:30 committed by Jouni Malinen
parent 77386f51ac
commit da364180fb
9 changed files with 88 additions and 2 deletions

View file

@ -17,6 +17,7 @@
#include "common/ieee802_11_common.h" #include "common/ieee802_11_common.h"
#include "common/hw_features_common.h" #include "common/hw_features_common.h"
#include "common/wpa_ctrl.h" #include "common/wpa_ctrl.h"
#include "crypto/sha1.h"
#include "wps/wps_defs.h" #include "wps/wps_defs.h"
#include "p2p/p2p.h" #include "p2p/p2p.h"
#include "hostapd.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); resp = hostapd_probe_resp_offloads(hapd, &resp_len);
#endif /* NEED_AP_MLME */ #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 = (u8 *) head;
params->head_len = head_len; params->head_len = head_len;
params->tail = tail; params->tail = tail;

View file

@ -2186,6 +2186,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data) union wpa_event_data *data)
{ {
struct hostapd_data *hapd = ctx; struct hostapd_data *hapd = ctx;
struct sta_info *sta;
#ifndef CONFIG_NO_STDOUT_DEBUG #ifndef CONFIG_NO_STDOUT_DEBUG
int level = MSG_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.link_addr,
data->assoc_info.reassoc); data->assoc_info.reassoc);
break; 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 #ifdef CONFIG_OWE
case EVENT_UPDATE_DH: case EVENT_UPDATE_DH:
if (!data) if (!data)

View file

@ -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->auth_alg != WLAN_AUTH_FILS_PK &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH); 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); wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
}
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) { if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) {
if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) { if (eloop_cancel_timeout(ap_handle_timer, hapd, sta) > 0) {

View file

@ -1812,6 +1812,16 @@ struct wpa_driver_ap_params {
* mld_link_id - Link id for MLD BSS's * mld_link_id - Link id for MLD BSS's
*/ */
u8 mld_link_id; 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 { struct wpa_driver_mesh_bss_params {
@ -2284,6 +2294,8 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS2_SCAN_MIN_PREQ 0x0000000000008000ULL #define WPA_DRIVER_FLAGS2_SCAN_MIN_PREQ 0x0000000000008000ULL
/** Driver supports SAE authentication offload in STA mode */ /** Driver supports SAE authentication offload in STA mode */
#define WPA_DRIVER_FLAGS2_SAE_OFFLOAD_STA 0x0000000000010000ULL #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; u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \ #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@ -6672,10 +6684,19 @@ union wpa_event_data {
/** /**
* struct port_authorized - Data for EVENT_PORT_AUTHORIZED * 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 { struct port_authorized {
const u8 *td_bitmap; const u8 *td_bitmap;
size_t td_bitmap_len; size_t td_bitmap_len;
const u8 *sta_addr;
} port_authorized; } port_authorized;
/** /**

View file

@ -5110,6 +5110,12 @@ static int wpa_driver_nl80211_set_ap(void *priv,
suites)) suites))
goto fail; 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 && if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
(!params->pairwise_ciphers || (!params->pairwise_ciphers ||
params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) && params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) &&

View file

@ -705,6 +705,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
if (ext_feature_isset(ext_features, len, if (ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT)) NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT))
capa->flags2 |= WPA_DRIVER_FLAGS2_SCAN_MIN_PREQ; 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;
} }

View file

@ -3506,7 +3506,13 @@ static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv,
} }
addr = nla_data(tb[NL80211_ATTR_MAC]); 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, wpa_printf(MSG_DEBUG,
"nl80211: Ignore port authorized event for " MACSTR "nl80211: Ignore port authorized event for " MACSTR
" (not the currently connected BSSID " MACSTR ")", " (not the currently connected BSSID " MACSTR ")",

View file

@ -1058,6 +1058,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
return -1; return -1;
hapd_iface->owner = wpa_s; hapd_iface->owner = wpa_s;
hapd_iface->drv_flags = wpa_s->drv_flags; 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->probe_resp_offloads = wpa_s->probe_resp_offloads;
hapd_iface->extended_capa = wpa_s->extended_capa; hapd_iface->extended_capa = wpa_s->extended_capa;
hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask; hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;

View file

@ -22,6 +22,7 @@
#include "common/wpa_ctrl.h" #include "common/wpa_ctrl.h"
#include "eap_peer/eap.h" #include "eap_peer/eap.h"
#include "ap/hostapd.h" #include "ap/hostapd.h"
#include "ap/sta_info.h"
#include "p2p/p2p.h" #include "p2p/p2p.h"
#include "fst/fst.h" #include "fst/fst.h"
#include "wnm_sta.h" #include "wnm_sta.h"
@ -6411,6 +6412,21 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break; break;
#endif /* CONFIG_PASN */ #endif /* CONFIG_PASN */
case EVENT_PORT_AUTHORIZED: 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 #ifndef CONFIG_NO_WPA
if (data->port_authorized.td_bitmap_len) { if (data->port_authorized.td_bitmap_len) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,