]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd: Support 4-way handshake offload for AP/P2P GO
authorVinayak Yadawad <vinayak.yadawad@broadcom.com>
Wed, 8 Nov 2023 12:56:09 +0000 (18:26 +0530)
committerJouni Malinen <j@w1.fi>
Sat, 11 Nov 2023 20:34:06 +0000 (22:34 +0200)
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>
src/ap/beacon.c
src/ap/drv_callbacks.c
src/ap/hostapd.c
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211_capa.c
src/drivers/driver_nl80211_event.c
wpa_supplicant/ap.c
wpa_supplicant/events.c

index b88aeb03caf90ce6645c4af3be6d88f919b679e3..2101d4847b7e64e0d791f43b6489aee20a05ff20 100644 (file)
@@ -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;
index bc575e2603b19734f177e1faf6d611b21842de0d..be76ec2b158c73a16776c82730920d3533adb16e 100644 (file)
@@ -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)
index 966030d57213958e7da9a65aa0ea6a71ae1187c4..236381fe87ef55d841cf8013a6ecd83794a64bee 100644 (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->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) {
index b5651279646a86a0d783896f3c8c9d7f01a843a4..f0e690d0185bc4131b06a5e09c25f26e7d91e6e0 100644 (file)
@@ -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;
 
        /**
index 8b72d74c567c82ad5fa481ee05fbeac6482e5040..94273bfe2376c88a7682d0cef6db2ab9920038c2 100644 (file)
@@ -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)) &&
index b7d914140c660ef913939e93e56111380e4da0b7..2e7ce5dc8812224434bdef48b834a877bb23820c 100644 (file)
@@ -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;
 }
 
 
index 0297bffeb37370c914263464f116dd09188400ae..0091032e5501ac8979f54e0a12063ac8f783366e 100644 (file)
@@ -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 ")",
index 2fc9f453bbe14062439a066898e7ab30c665dcc1..b6e666a7d25c60c2e077647e5a4d931128ab2aae 100644 (file)
@@ -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;
index aa5c9b058179f20a9118caae8cfacedd5e1f7ecd..2e0570f32dd3e55a34fd7981ecaf53f4bfd20431 100644 (file)
@@ -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,