[PATCH v4 19/20] PR: Allow PMK and password configuration in PR_PASN_START

Kavita Kavita kavita.kavita at oss.qualcomm.com
Fri May 22 18:23:51 PDT 2026


Add optional pmk and password parameters to the PR_PASN_START
ctrl_iface command to allow per-peer credentials to be configured
directly at session initiation time.

When provided, the credentials are stored in the peer's pr_device
entry and used for the PASN exchange. This works for both
USD-discovered peers (overriding DIRA-resolved credentials) and OOB
peers (where DIRA resolution never occurs). The credentials persist
for future sessions with the same peer.

The peer device entry is ensured to exist before applying credentials
so that PR_PASN_START with pmk or password works even when no prior
NAN USD discovery has taken place.

Passing pmk or password with auth=0 (unauthenticated PASN) is
rejected since credentials are not applicable in that mode.

Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy at oss.qualcomm.com>
Signed-off-by: Kavita Kavita <kavita.kavita at oss.qualcomm.com>
---
 src/common/proximity_ranging.c | 32 +++++++++++++++++++++++++++++++
 src/common/proximity_ranging.h |  9 +++++++++
 wpa_supplicant/ctrl_iface.c    | 35 ++++++++++++++++++++++++++++++++++
 wpa_supplicant/pr_supplicant.c | 13 +++++++++++++
 4 files changed, 89 insertions(+)

diff --git a/src/common/proximity_ranging.c b/src/common/proximity_ranging.c
index 6636f539f..a9fc9c0c1 100644
--- a/src/common/proximity_ranging.c
+++ b/src/common/proximity_ranging.c
@@ -240,6 +240,38 @@ void pr_add_dev_ik(struct pr_data *pr, const u8 *dik, const char *password,
 }
 
 
+void pr_set_peer_credentials(struct pr_data *pr, const u8 *addr,
+			     const u8 *pmk, size_t pmk_len,
+			     const char *password)
+{
+	struct pr_device *dev;
+
+	if (!pr || !addr)
+		return;
+
+	dev = pr_get_device(pr, addr);
+	if (!dev) {
+		wpa_printf(MSG_DEBUG, "PR: set_peer_credentials: " MACSTR
+			   " not found", MAC2STR(addr));
+		return;
+	}
+
+	if (pmk && pmk_len) {
+		os_memcpy(dev->pmk, pmk, pmk_len);
+		dev->pmk_len = pmk_len;
+		dev->pmk_valid = true;
+		wpa_printf(MSG_DEBUG, "PR: PMK set for " MACSTR, MAC2STR(addr));
+	}
+
+	if (password) {
+		os_strlcpy(dev->password, password, sizeof(dev->password));
+		dev->password_valid = true;
+		wpa_printf(MSG_DEBUG, "PR: password set for " MACSTR,
+			   MAC2STR(addr));
+	}
+}
+
+
 static struct wpabuf * pr_encaps_elem(const struct wpabuf *subelems,
 				      u32 ie_type)
 {
diff --git a/src/common/proximity_ranging.h b/src/common/proximity_ranging.h
index 8c0507199..e06c327a1 100644
--- a/src/common/proximity_ranging.h
+++ b/src/common/proximity_ranging.h
@@ -358,6 +358,12 @@ struct pr_pasn_ranging_params {
 	u32 center_freq1;
 	u32 center_freq2;
 	u64 cookie;
+
+	/* Per-session credentials — if set, used instead of stored ones */
+	char password[100];
+	bool password_valid;
+	u8 pmk[PMK_LEN_MAX];
+	size_t pmk_len;
 };
 
 struct pr_dev_ik {
@@ -644,6 +650,9 @@ void pr_set_dev_addr(struct pr_data *pr, const u8 *addr);
 void pr_clear_dev_iks(struct pr_data *pr);
 void pr_add_dev_ik(struct pr_data *pr, const u8 *dik, const char *password,
 		   const u8 *pmk, size_t pmk_len, bool own);
+void pr_set_peer_credentials(struct pr_data *pr, const u8 *addr,
+			     const u8 *pmk, size_t pmk_len,
+			     const char *password);
 struct wpabuf * pr_prepare_usd_elems(struct pr_data *pr);
 void pr_process_usd_elems(struct pr_data *pr, const u8 *ies, u16 ies_len,
 			  const u8 *peer_addr, unsigned int freq);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 8cf87ced7..adba94901 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -11625,6 +11625,33 @@ static int wpas_ctrl_iface_pr_pasn_start(struct wpa_supplicant *wpa_s,
 			params.egress_threshold = atoll(token + 17);
 		} else if (os_strcmp(token, "pd_suppress_results=1") == 0) {
 			params.pr_suppress_results = true;
+		} else if (os_strncmp(token, "password=", 9) == 0) {
+			size_t pwd_len = os_strlen(token + 9);
+
+			if (pwd_len == 0 || pwd_len >= sizeof(params.password)) {
+				wpa_printf(MSG_DEBUG,
+					   "CTRL: PR_PASN_START invalid password length %zu",
+					   pwd_len);
+				return -1;
+			}
+			os_strlcpy(params.password, token + 9,
+				   sizeof(params.password));
+			params.password_valid = true;
+		} else if (os_strncmp(token, "pmk=", 4) == 0) {
+			size_t pmk_len = os_strlen(token + 4) / 2;
+
+			if (pmk_len != 32 && pmk_len != 48 && pmk_len != 64) {
+				wpa_printf(MSG_DEBUG,
+					   "CTRL: PR_PASN_START invalid PMK length %zu",
+					   pmk_len);
+				return -1;
+			}
+			if (hexstr2bin(token + 4, params.pmk, pmk_len)) {
+				wpa_printf(MSG_DEBUG,
+					   "CTRL: PR_PASN_START invalid PMK");
+				return -1;
+			}
+			params.pmk_len = pmk_len;
 		} else {
 			wpa_printf(MSG_DEBUG,
 				   "CTRL: PR_PASN_START invalid parameter: '%s'",
@@ -11653,6 +11680,14 @@ static int wpas_ctrl_iface_pr_pasn_start(struct wpa_supplicant *wpa_s,
 		return -1;
 	}
 
+	/* pmk and password are only valid for authenticated modes */
+	if (params.auth_mode == PR_PASN_AUTH_MODE_PASN &&
+	    (params.pmk_len > 0 || params.password_valid)) {
+		wpa_printf(MSG_DEBUG,
+			   "CTRL: PR_PASN_START pmk/password not applicable for unauthenticated mode");
+		return -1;
+	}
+
 	wpa_printf(MSG_DEBUG,
 		   "CTRL: PR_PASN_START params: ranging type=0x%x, role=0x%x,"
 		   " auth_mode=%d, freq=%d, addr=" MACSTR " src_addr=" MACSTR " pasn_role=%d",
diff --git a/wpa_supplicant/pr_supplicant.c b/wpa_supplicant/pr_supplicant.c
index 038f120aa..ed265fb09 100644
--- a/wpa_supplicant/pr_supplicant.c
+++ b/wpa_supplicant/pr_supplicant.c
@@ -1538,6 +1538,19 @@ void wpas_pr_pasn_trigger(struct wpa_supplicant *wpa_s,
 		os_memcpy(pr->pr_pasn_params, pr_pasn_params,
 			  sizeof(*pr->pr_pasn_params));
 
+		/* Ensure peer device entry exists before setting credentials */
+		if (pr_pasn_params->pmk_len > 0 || pr_pasn_params->password_valid) {
+			pr_ensure_oob_peer(pr, pr_pasn_params->peer_addr,
+					   pr_pasn_params->freq);
+			pr_set_peer_credentials(pr,
+						pr_pasn_params->peer_addr,
+						pr_pasn_params->pmk_len > 0 ?
+						pr_pasn_params->pmk : NULL,
+						pr_pasn_params->pmk_len,
+						pr_pasn_params->password_valid ?
+						pr_pasn_params->password : NULL);
+		}
+
 		/* Log EDCA parameters if applicable */
 		if (pr_pasn_params->ranging_type & PR_EDCA_BASED_RANGING) {
 			wpa_printf(MSG_DEBUG,
-- 
2.34.1




More information about the Hostap mailing list