]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
PASN: Support comeback data
authorPeddolla Harshavardhan Reddy <peddolla@qti.qualcomm.com>
Sat, 14 Jun 2025 08:17:14 +0000 (13:47 +0530)
committerJouni Malinen <j@w1.fi>
Tue, 24 Jun 2025 18:15:01 +0000 (21:15 +0300)
Allow PASN Authentication with a comeback request after the AP's
requested comeback time, as indicated in the status report of the PASN
handshake. Also enable the comeback mechanism by including comeback time
and cookie in the status report to extend PASN Authentication with
comeback.

Signed-off-by: Peddolla Harshavardhan Reddy <peddolla@qti.qualcomm.com>
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211_event.c
wpa_supplicant/pasn_supplicant.c

index f4d6e4289ace47b45aee622eb67a9ffbe37b2051..0a053235320cc64eb4dec19bf18c3c622a5a4bd9 100644 (file)
@@ -3056,6 +3056,11 @@ enum pasn_status {
  * @temporary_network: Indicates if a temporary network was created to perform
  *     PASN authentication.
  * @password: Password of user requested network.
+ * @comeback_len: Length of the comeback cookie data.
+ * @comeback: Comeback cookie data that may be present in case a temporary
+ * rejection is received from the AP.
+ * @comeback_after: The time after which the STA can try for PASN handshake in
+ * case of temporary rejection.
  * @ltf_keyseed_required: Indicates whether LTF keyseed generation is required
  * @status: PASN response status, %PASN_STATUS_SUCCESS for successful
  *     authentication, use %PASN_STATUS_FAILURE if PASN authentication
@@ -3071,6 +3076,9 @@ struct pasn_peer {
        int group;
        bool temporary_network;
        char *password;
+       size_t comeback_len;
+       u8 *comeback;
+       u16 comeback_after;
        bool ltf_keyseed_required;
        enum pasn_status status;
 };
index ce86b72c4640f2ee967fc22bb8f1c8e360e89aa6..0cc5b4b0e110229877429fd6227edf57cecb7301 100644 (file)
@@ -13673,6 +13673,17 @@ static int nl80211_send_pasn_resp(void *priv, struct pasn_auth *params)
                                wpa_cipher_to_cipher_suite(cipher)))
                        goto fail;
 
+               if (params->peer[i].comeback_after &&
+                   params->peer[i].comeback_len &&
+                   params->peer[i].comeback &&
+                   (nla_put_u16(msg,
+                                QCA_WLAN_VENDOR_ATTR_PASN_PEER_COMEBACK_AFTER,
+                                params->peer[i].comeback_after) ||
+                    nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_COOKIE,
+                            params->peer[i].comeback_len,
+                            params->peer[i].comeback)))
+                       goto fail;
+
                wpa_printf(MSG_DEBUG,
                           "nl80211: Own address[%u]: " MACSTR
                           " Peer address[%u]: " MACSTR
index 3bba2af8c90117a54f2dc7f457431465a18bfd50..bcf6ff89556535457af75ba61769a60ab2516600 100644 (file)
@@ -3415,6 +3415,12 @@ static void qca_nl80211_pasn_auth(struct i802_bss *bss, u8 *data, size_t len)
                        os_memcpy(pw[idx], password, password_len);
                        event.pasn_auth.peer[idx].password = pw[idx];
                }
+               if (cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_COOKIE]) {
+                       event.pasn_auth.peer[idx].comeback_len =
+                               nla_len(cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_COOKIE]);
+                       event.pasn_auth.peer[idx].comeback =
+                               nla_data(cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_COOKIE]);
+               }
 
                wpa_printf(MSG_DEBUG, "nl80211: PASN auth action: peer addr "
                           MACSTR " AKMP 0x%x cipher 0x%x",
index 89a8f17e7591f77c5c7d1835841a3fcf5f06b127..0158aadf1b68f7e2dbb21e7bc850ac5e2434b8a9 100644 (file)
@@ -390,8 +390,6 @@ static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
                                          struct pasn_auth *pasn_params)
 {
        struct pasn_peer *peer;
-       u8 comeback_len = 0;
-       const u8 *comeback = NULL;
        struct wpa_ssid *ssid;
 
        if (!pasn_params)
@@ -456,7 +454,7 @@ static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
                                         peer->peer_addr, peer->akmp,
                                         peer->cipher, peer->group,
                                         peer->network_id,
-                                        comeback, comeback_len)) {
+                                        peer->comeback, peer->comeback_len)) {
                        peer->status = PASN_STATUS_FAILURE;
                        wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
                                " akmp=%s, status=%u",
@@ -465,7 +463,9 @@ static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
                                peer->status);
                        wpa_s->pasn_count++;
                        str_clear_free(peer->password);
+                       os_free(peer->comeback);
                        peer->password = NULL;
+                       peer->comeback = NULL;
                        continue;
                }
                wpa_printf(MSG_DEBUG, "PASN: Sent PASN auth start for " MACSTR,
@@ -481,6 +481,7 @@ static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
                for (i = 0; i < pasn_params->num_peers; i++) {
                        peer = &pasn_params->peer[i];
                        str_clear_free(peer->password);
+                       os_free(peer->comeback);
 
                        if (peer->temporary_network) {
                                ssid = wpa_config_get_network(wpa_s->conf,
@@ -910,6 +911,33 @@ static void wpas_pasn_deauth_cb(struct ptksa_cache_entry *entry)
 }
 
 
+static void wpas_pasn_store_comeback_data(struct wpa_supplicant *wpa_s,
+                                         const struct wpabuf *comeback,
+                                         u16 comeback_after)
+{
+       struct pasn_peer *peer;
+
+       if (!wpa_s->pasn_params)
+               return;
+
+       peer = &wpa_s->pasn_params->peer[wpa_s->pasn_count];
+       if (!peer)
+               return;
+
+       os_free(peer->comeback);
+       peer->comeback = os_zalloc(wpabuf_len(comeback));
+       if (!peer->comeback) {
+               wpa_printf(MSG_ERROR,
+                          "PASN: Mem alloc failed for comeback data");
+               return;
+       }
+
+       peer->comeback_len = wpabuf_len(comeback);
+       os_memcpy(peer->comeback, wpabuf_head_u8(comeback), peer->comeback_len);
+       peer->comeback_after = comeback_after;
+}
+
+
 int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
                      const struct ieee80211_mgmt *mgmt, size_t len)
 {
@@ -941,6 +969,10 @@ int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
        forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
 
        if (ret == -1) {
+               if (pasn->status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
+                   pasn->comeback && wpabuf_len(pasn->comeback))
+                       wpas_pasn_store_comeback_data(wpa_s, pasn->comeback,
+                                                     pasn->comeback_after);
                wpas_pasn_auth_stop(wpa_s);
                wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE);
        }
@@ -997,6 +1029,16 @@ void wpas_pasn_auth_trigger(struct wpa_supplicant *wpa_s,
                                return;
                        }
                }
+               if (src->comeback_len && src->comeback) {
+                       dst->comeback = os_memdup(src->comeback,
+                                                 src->comeback_len);
+                       if (!dst->comeback) {
+                               wpa_printf(MSG_DEBUG,
+                                          "PASN: Mem alloc failed for comeback cookie");
+                               return;
+                       }
+                       dst->comeback_len = src->comeback_len;
+               }
 
                if (!is_zero_ether_addr(src->own_addr)) {
                        os_memcpy(dst->own_addr, src->own_addr, ETH_ALEN);