[RFC PATCH 16/34] Add support to initiate PASN authentication for Proximity Ranging
Peddolla Harshavardhan Reddy
peddolla at qti.qualcomm.com
Thu May 15 00:17:39 PDT 2025
Signed-off-by: Peddolla Harshavardhan Reddy <peddolla at qti.qualcomm.com>
---
src/common/proximity_ranging.c | 125 +++++++++++++++++++++++++++
src/common/proximity_ranging.h | 38 +++++++++
wpa_supplicant/pr_supplicant.c | 135 ++++++++++++++++++++++++++++++
wpa_supplicant/pr_supplicant.h | 13 +++
wpa_supplicant/wpa_supplicant_i.h | 1 +
5 files changed, 312 insertions(+)
diff --git a/src/common/proximity_ranging.c b/src/common/proximity_ranging.c
index b2eb42d6b..2bd7ee9fe 100644
--- a/src/common/proximity_ranging.c
+++ b/src/common/proximity_ranging.c
@@ -13,14 +13,22 @@
#include "common/ieee802_11_common.h"
#include "common/qca-vendor.h"
#include "wps/wps_i.h"
+#include "common/sae.h"
#include "proximity_ranging.h"
#include "crypto/sha256.h"
#include "crypto/sha384.h"
#include "crypto/crypto.h"
+#include "pasn/pasn_common.h"
static void pr_device_free(struct pr_data *pr, struct pr_device *dev)
{
+#ifdef CONFIG_PASN
+ if (dev->pasn) {
+ wpa_pasn_reset(dev->pasn);
+ pasn_data_deinit(dev->pasn);
+ }
+#endif /* CONFIG_PASN */
os_free(dev);
}
@@ -973,3 +981,120 @@ void pr_process_usd_elems(struct pr_data *pr, const u8 *ies, u16 ies_len,
pr_parse_free(&msg);
}
+
+
+#ifdef CONFIG_PASN
+
+static int pr_pasn_initialize(struct pr_data *pr, struct pr_device *dev,
+ const u8 *addr, u8 auth_mode, int freq)
+{
+ struct pasn_data *pasn;
+
+ if (!pr || !dev)
+ return -1;
+
+ if (dev->pasn) {
+ wpa_pasn_reset(dev->pasn);
+ } else {
+ dev->pasn = pasn_data_init();
+ if (!dev->pasn)
+ return -1;
+ }
+
+ pasn = dev->pasn;
+ os_memcpy(pasn->own_addr, pr->cfg->dev_addr, ETH_ALEN);
+ os_memcpy(pasn->peer_addr, addr, ETH_ALEN);
+
+ if (dev->pasn_role == PR_ROLE_PASN_INITIATOR) {
+ os_memcpy(pasn->bssid, pasn->peer_addr, ETH_ALEN);
+ } else {
+ os_memcpy(pasn->bssid, pasn->own_addr, ETH_ALEN);
+ }
+
+ pasn->noauth = 1;
+
+ if ((pr->cfg->pasn_type & 0xc) &&
+ (dev->pr_caps.pasn_type & 0xc)) {
+ pasn->group = 20;
+ pasn->cipher = WPA_CIPHER_GCMP_256;
+ } else {
+ pasn->group = 19;
+ pasn->cipher = WPA_CIPHER_CCMP;
+ }
+
+ if (pr->cfg->secure_he_ltf)
+ pasn_enable_kdk_derivation(pasn);
+ else
+ pasn_disable_kdk_derivation(pasn);
+
+ wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
+
+ if (pr->cfg->secure_he_ltf)
+ pasn->secure_ltf = true;
+
+ if (auth_mode == PR_PASN_AUTH_MODE_SAE) {
+ pasn->akmp = WPA_KEY_MGMT_SAE;
+ } else if (auth_mode == PR_PASN_AUTH_MODE_PMK) {
+ pasn->akmp = WPA_KEY_MGMT_SAE;
+ } else {
+ pasn->akmp = WPA_KEY_MGMT_PASN;
+ }
+
+ pasn->rsn_pairwise = pasn->cipher;
+ pasn->wpa_key_mgmt = pasn->akmp;
+
+ pasn->cb_ctx = pr->cfg->cb_ctx;
+ pasn->send_mgmt = pr->cfg->pasn_send_mgmt;
+ pasn->freq = freq;
+ return 0;
+}
+
+
+int pr_initiate_pasn_auth(struct pr_data *pr, const u8 *addr, int freq,
+ u8 auth_mode, u8 ranging_role, u8 ranging_type,
+ int forced_pr_freq)
+{
+ int ret = 0;
+ struct pasn_data *pasn;
+ struct pr_device *dev;
+
+ if (!addr) {
+ wpa_printf(MSG_DEBUG, "Peer address NULL");
+ return -1;
+ }
+
+ dev = pr_get_device(pr, addr);
+ if (!dev) {
+ wpa_printf(MSG_DEBUG, "Peer not known");
+ return -1;
+ }
+
+ if (freq == 0)
+ freq = dev->listen_freq;
+
+ dev->pasn_role = PR_ROLE_PASN_INITIATOR;
+
+ if (pr_pasn_initialize(pr, dev, addr, auth_mode, freq)) {
+ wpa_printf(MSG_ERROR, "PR PASN: Initialize failed");
+ return -1;
+ }
+ pasn = dev->pasn;
+
+ if (auth_mode == PR_PASN_AUTH_MODE_PMK) {
+ ret = wpa_pasn_verify(pasn, pasn->own_addr, pasn->peer_addr,
+ pasn->bssid, pasn->akmp, pasn->cipher,
+ pasn->group, pasn->freq, NULL, 0, NULL, 0,
+ NULL);
+ } else {
+ ret = wpas_pasn_start(pasn, pasn->own_addr, pasn->peer_addr,
+ pasn->bssid, pasn->akmp, pasn->cipher,
+ pasn->group, pasn->freq, NULL, 0, NULL, 0,
+ NULL);
+ }
+ if (ret)
+ wpa_printf(MSG_ERROR, "PR: Failed to start PASN");
+
+ return ret;
+}
+
+#endif /* CONFIG_PASN */
diff --git a/src/common/proximity_ranging.h b/src/common/proximity_ranging.h
index 5d5ec0dc3..16ebaabd7 100644
--- a/src/common/proximity_ranging.h
+++ b/src/common/proximity_ranging.h
@@ -38,6 +38,12 @@
#define PR_MAX_PEER 100
+enum pr_pasn_role {
+ PR_ROLE_IDLE = 0,
+ PR_ROLE_PASN_INITIATOR,
+ PR_ROLE_PASN_RESPONDER,
+};
+
/**
* struct pr_channels - List of supported channels
*/
@@ -171,6 +177,17 @@ enum pr_attr_id {
#define PR_ISTA_SUPPORT BIT(0)
#define PR_RSTA_SUPPORT BIT(1)
+/* PASN capabilities*/
+#define PR_PASN_DH19_AUTH BIT(0)
+#define PR_PASN_DH19_UNAUTH BIT(1)
+#define PR_PASN_DH20_AUTH BIT(2)
+#define PR_PASN_DH20_UNAUTH BIT(3)
+
+/* Authentication Mode */
+#define PR_PASN_AUTH_MODE_PASN 0
+#define PR_PASN_AUTH_MODE_SAE 1
+#define PR_PASN_AUTH_MODE_PMK 2
+
struct pr_dev_ik {
struct dl_list list;
u8 dik[DEVICE_IDENTITY_KEY_LEN];
@@ -208,6 +225,10 @@ struct pr_device {
*/
u8 pmk[PMK_LEN_MAX];
bool pmk_valid;
+
+ /* PASN data structure */
+ struct pasn_data *pasn;
+ enum pr_pasn_role pasn_role;
};
@@ -312,6 +333,20 @@ struct pr_config {
* cb_ctx - Context to use with callback functions
*/
void *cb_ctx;
+
+ /**
+ * pasn_send_mgmt - Function handler to transmit a Management frame
+ * @ctx: Callback context from cb_ctx
+ * @data: Frame to transmit
+ * @data_len: Length of frame to transmit
+ * @noack: No ack flag
+ * @freq: Frequency in MHz for the channel on which to transmit
+ * @wait: How many milliseconds to wait for a response frame
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*pasn_send_mgmt)(void *ctx, const u8 *data, size_t data_len,
+ int noack, unsigned int freq, unsigned int wait);
+
};
struct pr_data {
@@ -351,5 +386,8 @@ void pr_add_dev_ik(struct pr_data *pr, const u8 *dik, const char *password,
struct wpabuf * pr_prepare_usd_elems(struct pr_data *pr, const char *country);
void pr_process_usd_elems(struct pr_data *pr, const u8 *ies, u16 ies_len,
const u8 *peer_addr, unsigned int freq);
+int pr_initiate_pasn_auth(struct pr_data *pr, const u8 *addr, int freq,
+ u8 auth_mode, u8 ranging_role, u8 ranging_type,
+ int forced_pr_freq);
#endif /* PROXIMITY_RANGING_H */
diff --git a/wpa_supplicant/pr_supplicant.c b/wpa_supplicant/pr_supplicant.c
index 18eebea73..0ec4ca828 100644
--- a/wpa_supplicant/pr_supplicant.c
+++ b/wpa_supplicant/pr_supplicant.c
@@ -74,6 +74,17 @@ static int wpas_pr_setup_channels(struct wpa_supplicant *wpa_s,
return 0;
}
+
+static int wpas_pr_pasn_send_mgmt(void *ctx, const u8 *data, size_t data_len,
+ int noack, unsigned int freq,
+ unsigned int wait)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait);
+}
+
+
struct wpabuf * wpas_pr_usd_elems(struct wpa_supplicant *wpa_s)
{
return pr_prepare_usd_elems(wpa_s->global->pr, wpa_s->conf->country);
@@ -132,6 +143,8 @@ int wpas_pr_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
pr.support_6ghz = false;
+ pr.pasn_send_mgmt = wpas_pr_pasn_send_mgmt;
+
pr.secure_he_ltf = wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA;
wpas_pr_setup_channels(wpa_s, &pr.ntb_channels);
@@ -213,3 +226,125 @@ void wpas_pr_set_dev_ik(struct wpa_supplicant *wpa_s, const u8 *dik,
pr_add_dev_ik(pr, dik, password, pmk, own);
}
+
+#ifdef CONFIG_PASN
+
+struct wpa_pr_pasn_auth_work {
+ u8 peer_addr[ETH_ALEN];
+ u8 auth_mode;
+ int freq;
+ enum pr_pasn_role role;
+ u8 ranging_role;
+ u8 ranging_type;
+ u8 *ssid;
+ size_t ssid_len;
+ u8 bssid[ETH_ALEN];
+ int forced_pr_freq;
+};
+
+
+static void wpas_pr_pasn_free_auth_work(struct wpa_pr_pasn_auth_work *awork)
+{
+ if (!awork)
+ return;
+ os_free(awork->ssid);
+ os_free(awork);
+}
+
+
+static void wpas_pr_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "PR PASN: Cancel pr-pasn-start-auth work");
+
+ /* Remove pending/started work */
+ radio_remove_works(wpa_s, "pr-pasn-start-auth", 0);
+}
+
+
+static void wpas_pr_pasn_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->pr_pasn_auth_work) {
+ wpas_pr_pasn_cancel_auth_work(wpa_s);
+ wpa_s->pr_pasn_auth_work = NULL;
+ }
+ wpa_printf(MSG_DEBUG, "PR: PASN timed out");
+}
+
+
+static void wpas_pr_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
+{
+ int ret;
+ struct wpa_supplicant *wpa_s = work->wpa_s;
+ struct wpa_pr_pasn_auth_work *awork = work->ctx;
+ struct pr_data *pr = wpa_s->global->pr;
+ const u8 *peer_addr = NULL;
+
+ if (deinit) {
+ if (!work->started)
+ eloop_cancel_timeout(wpas_pr_pasn_timeout, wpa_s, NULL);
+
+ wpas_pr_pasn_free_auth_work(awork);
+ return;
+ }
+
+ if (!is_zero_ether_addr(awork->peer_addr))
+ peer_addr = awork->peer_addr;
+
+ ret = pr_initiate_pasn_auth(pr, peer_addr, awork->freq,
+ awork->auth_mode, awork->ranging_role,
+ awork->ranging_type, awork->forced_pr_freq);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "PR PASN: Failed to start PASN authentication");
+ goto fail;
+ }
+ eloop_cancel_timeout(wpas_pr_pasn_timeout,
+ wpa_s, NULL);
+ eloop_register_timeout(2, 0,
+ wpas_pr_pasn_timeout,
+ wpa_s, NULL);
+ wpa_s->pr_pasn_auth_work = work;
+ return;
+
+fail:
+ wpas_pr_pasn_free_auth_work(awork);
+ work->ctx = NULL;
+ radio_work_done(work);
+}
+
+
+int wpas_pr_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int freq, u8 auth_mode,
+ u8 ranging_role, u8 ranging_type,
+ int forced_pr_freq)
+{
+ struct wpa_pr_pasn_auth_work *awork;
+
+ wpas_pr_pasn_cancel_auth_work(wpa_s);
+ wpa_s->pr_pasn_auth_work = NULL;
+
+ awork = os_zalloc(sizeof(*awork));
+ if (!awork)
+ return -1;
+
+ awork->freq = freq;
+ os_memcpy(awork->peer_addr, peer_addr, ETH_ALEN);
+ awork->ranging_role = ranging_role;
+ awork->ranging_type = ranging_type;
+ awork->auth_mode = auth_mode;
+ awork->forced_pr_freq = forced_pr_freq;
+
+ if (radio_add_work(wpa_s, freq, "pr-pasn-start-auth", 1,
+ wpas_pr_pasn_auth_start_cb, awork) < 0) {
+ wpas_pr_pasn_free_auth_work(awork);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "PR PASN: Authentication work successfully added");
+ return 0;
+}
+
+#endif /* CONFIG_PASN */
diff --git a/wpa_supplicant/pr_supplicant.h b/wpa_supplicant/pr_supplicant.h
index ff4478ef9..4f082fb5d 100644
--- a/wpa_supplicant/pr_supplicant.h
+++ b/wpa_supplicant/pr_supplicant.h
@@ -22,6 +22,10 @@ struct wpabuf * wpas_pr_usd_elems(struct wpa_supplicant *wpa_s);
void wpas_pr_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
u16 buf_len, const u8 *peer_addr,
unsigned int freq);
+int wpas_pr_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int freq, u8 auth_mode,
+ u8 ranging_role, u8 ranging_type,
+ int forced_pr_freq);
#else /* CONFIG_PR */
static inline int wpas_pr_init(struct wpa_global *global,
struct wpa_supplicant *wpa_s)
@@ -49,6 +53,15 @@ static inline struct wpabuf * wpas_pr_usd_elems(struct wpa_supplicant *wpa_s)
return NULL;
}
+static inline int wpas_pr_initiate_pasn_auth(struct wpa_supplicant *wpa_s,
+ const u8 *peer_addr, int freq,
+ u8 auth_mode, u8 ranging_role,
+ u8 ranging_type,
+ int forced_pr_freq)
+{
+ return 0;
+}
+
#endif /* CONFIG_PR */
#endif /*PR_SUPPLICANT_H */
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 85515f6fb..d648e6ccc 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1614,6 +1614,7 @@ struct wpa_supplicant {
#ifdef CONFIG_P2P
struct wpa_radio_work *p2p_pasn_auth_work;
#endif /* CONFIG_P2P */
+ struct wpa_radio_work *pr_pasn_auth_work;
#endif /* CONFIG_PASN */
bool is_6ghz_enabled;
--
2.34.1
More information about the Hostap
mailing list