[RFC PATCH 22/23] nl80211: Add dedicated ranging handle for peer measurements

Peddolla Harshavardhan Reddy peddolla.reddy at oss.qualcomm.com
Tue Mar 31 22:27:12 PDT 2026


From: Veerendranath Jakkam <vjakkam at qti.qualcomm.com>

Introduce a driver-agnostic ranging handle for PR/PD peer measurements and
plumb it through the nl80211 driver and wpa_supplicant:

- Extend wpa_driver_ops::start_peer_measurement() to take a driver-specific
  ranging handle (socket) and update the nl80211 implementation to use it
  when issuing NL80211_CMD_PEER_MEASUREMENT_START.
- Add new driver ops:
    - create_ranging_handle()
    - destroy_ranging_handle()
    - register_ranging_eloop()
  and implement them for nl80211 using a dedicated nl_sock.
- Use nl80211_cmd_msg() instead of nl80211_bss_msg() for
  NL80211_CMD_PEER_MEASUREMENT_START to support PD interfaces which are
  non-netdev (ifindex = 0, use wdev-based addressing).
- Register the ranging socket with eloop so that
  NL80211_CMD_PEER_MEASUREMENT_RESULT events are delivered to the existing
  nl80211 event handler, and ensure proper unregister/free on destroy.

This separates ranging traffic from the main nl80211 control socket, ensures
correct handling for PD interfaces, and provides a clean lifecycle for the
ranging socket via the new driver callbacks.

Signed-off-by: Veerendranath Jakkam <vjakkam at qti.qualcomm.com>
---
 src/drivers/driver.h           | 37 +++++++++++++++++-
 src/drivers/driver_nl80211.c   | 70 +++++++++++++++++++++++++++++++++-
 src/drivers/driver_nl80211.h   |  6 +++
 wpa_supplicant/driver_i.h      | 29 +++++++++++++-
 wpa_supplicant/pr_supplicant.c |  2 +-
 5 files changed, 138 insertions(+), 6 deletions(-)

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 8ccc0d6f0..786f52fa8 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -5677,7 +5677,42 @@ struct wpa_driver_ops {
 	 */
 	int (*start_peer_measurement)(void *priv, const u8 *peer_addr,
 				      int freq, u8 channel, int bw,
-				      struct pr_pasn_ranging_params *params);
+				      struct pr_pasn_ranging_params *params,
+				      void *ranging_sock);
+
+	/**
+	 * create_ranging_handle - Create a driver-specific ranging socket handle
+	 * @priv: Private driver interface data
+	 * Returns: Opaque pointer to the ranging handle, or %NULL on failure
+	 *
+	 * Allocates and initialises a driver-specific socket/handle that will
+	 * be used to send NL80211_CMD_PEER_MEASUREMENT_START and to receive
+	 * NL80211_CMD_PEER_MEASUREMENT_RESULT events.  The returned pointer is
+	 * treated as opaque by the core; it must be freed with
+	 * destroy_ranging_handle().
+	 */
+	void * (*create_ranging_handle)(void *priv);
+
+	/**
+	 * destroy_ranging_handle - Destroy a ranging socket handle
+	 * @priv: Private driver interface data
+	 * @handle: Pointer to the ranging handle pointer (set to %NULL on return)
+	 *
+	 * Unregisters the handle from eloop (if registered) and frees all
+	 * resources associated with it.
+	 */
+	void (*destroy_ranging_handle)(void *priv, void **handle);
+
+	/**
+	 * register_ranging_eloop - Register ranging handle with eloop
+	 * @priv: Private driver interface data
+	 * @handle: Pointer to the ranging handle pointer
+	 *
+	 * Registers the ranging socket with the event loop so that
+	 * NL80211_CMD_PEER_MEASUREMENT_RESULT events are delivered to the
+	 * driver event handler.
+	 */
+	void (*register_ranging_eloop)(void *priv, void **handle);
 #endif /* CONFIG_PR */
 
 #ifdef CONFIG_NAN
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 370701aa5..19ce3d007 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -9113,6 +9113,68 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
 
 #ifdef CONFIG_PR
 
+struct nl_sock * nl80211_create_pr_ranging_handle(struct nl80211_global *global)
+{
+	return nl_create_handle(global->nl_cb, "pr_ranging");
+}
+
+
+void nl80211_destroy_pr_ranging_handle(void **handle)
+{
+	if (!handle || !*handle)
+		return;
+	/*
+	 * Unregister from eloop before destroying the socket.  If the socket
+	 * was never registered this is a safe no-op.
+	 */
+	eloop_unregister_read_sock(nl_socket_get_fd((struct nl_sock *)*handle));
+	nl_destroy_handles((struct nl_sock **) handle);
+}
+
+
+/**
+ * nl80211_register_pr_ranging_eloop - Register ranging socket with eloop
+ * @global: nl80211 global state
+ * @ranging_sock: Pointer to the ranging socket handle (void **)
+ *
+ * After NL80211_CMD_PEER_MEASUREMENT_START is sent on the ranging socket,
+ * the kernel delivers NL80211_CMD_PEER_MEASUREMENT_RESULT as an event on
+ * that same socket.  Register it with eloop (persist=1 so the handle
+ * remains valid for potential abort commands) so those events are received.
+ */
+void nl80211_register_pr_ranging_eloop(struct nl80211_global *global,
+				       void **ranging_sock)
+{
+	nl80211_register_eloop_read((struct nl_sock **)ranging_sock,
+				    wpa_driver_nl80211_event_receive,
+				    global->nl_cb, 1);
+}
+
+
+/* Driver ops wrappers for ranging handle management */
+
+static void * nl80211_drv_create_ranging_handle(void *priv)
+{
+	struct i802_bss *bss = priv;
+
+	return nl80211_create_pr_ranging_handle(bss->drv->global);
+}
+
+
+static void nl80211_drv_destroy_ranging_handle(void *priv, void **handle)
+{
+	nl80211_destroy_pr_ranging_handle(handle);
+}
+
+
+static void nl80211_drv_register_ranging_eloop(void *priv, void **handle)
+{
+	struct i802_bss *bss = priv;
+
+	nl80211_register_pr_ranging_eloop(bss->drv->global, handle);
+}
+
+
 static u8 get_pr_preamble(u8 ranging_type, u8 format_bw)
 {
 	/* Determine preamble based on ranging type and format_bw */
@@ -9156,7 +9218,8 @@ static u8 get_pr_preamble(u8 ranging_type, u8 format_bw)
  */
 static int nl80211_start_peer_measurement(void *priv, const u8 *peer_addr,
 					  int freq, u8 channel, int bw,
-					  struct pr_pasn_ranging_params *params)
+					  struct pr_pasn_ranging_params *params,
+					  void *ranging_sock)
 {
 	struct i802_bss *bss = priv;
 	struct i802_bss *pd_bss;
@@ -9387,7 +9450,7 @@ static int nl80211_start_peer_measurement(void *priv, const u8 *peer_addr,
 	cookie = 0;
 	os_memset(&ack_arg, 0, sizeof(struct nl80211_ack_ext_arg));
 	ack_arg.ext_data = &cookie;
-	ret = send_and_recv(drv, drv->global->nl, msg, NULL, NULL,
+	ret = send_and_recv(drv, ranging_sock, msg, NULL, NULL,
 			    ack_handler_cookie, &ack_arg, NULL);
 
 	if (ret < 0) {
@@ -16185,5 +16248,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.pd_stop = nl80211_pd_stop,
 	.get_pd_addr = nl80211_get_pd_addr,
 	.start_peer_measurement = nl80211_start_peer_measurement,
+	.create_ranging_handle = nl80211_drv_create_ranging_handle,
+	.destroy_ranging_handle = nl80211_drv_destroy_ranging_handle,
+	.register_ranging_eloop = nl80211_drv_register_ranging_eloop,
 #endif /* CONFIG_PR */
 };
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 1d1187f62..6136b0b45 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -485,4 +485,10 @@ u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv);
 
 int get_sta_mlo_interface_info(struct i802_bss *bss);
 
+/* PR/PD ranging socket management */
+struct nl_sock * nl80211_create_pr_ranging_handle(struct nl80211_global *global);
+void nl80211_register_pr_ranging_eloop(struct nl80211_global *global,
+				       void **ranging_sock);
+void nl80211_destroy_pr_ranging_handle(void **handle);
+
 #endif /* DRIVER_NL80211_H */
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 3d1988fd3..f2e3ddfbf 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -763,13 +763,38 @@ wpa_drv_pd_stop(struct wpa_supplicant *wpa_s)
 static inline int
 wpa_drv_start_peer_measurement(struct wpa_supplicant *wpa_s, const u8 *peer,
 			       int freq, u8 channel, int bw,
-			       struct pr_pasn_ranging_params *params)
+			       struct pr_pasn_ranging_params *params,
+			       void *ranging_sock)
 {
 	if (!wpa_s->driver->start_peer_measurement)
 		return -1;
 	return wpa_s->driver->start_peer_measurement(wpa_s->drv_priv, peer,
 						      freq, channel, bw,
-						      params);
+						      params, ranging_sock);
+}
+
+static inline void *
+wpa_drv_create_ranging_handle(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->driver->create_ranging_handle)
+		return NULL;
+	return wpa_s->driver->create_ranging_handle(wpa_s->drv_priv);
+}
+
+static inline void
+wpa_drv_destroy_ranging_handle(struct wpa_supplicant *wpa_s, void **handle)
+{
+	if (!wpa_s->driver->destroy_ranging_handle)
+		return;
+	wpa_s->driver->destroy_ranging_handle(wpa_s->drv_priv, handle);
+}
+
+static inline void
+wpa_drv_register_ranging_eloop(struct wpa_supplicant *wpa_s, void **handle)
+{
+	if (!wpa_s->driver->register_ranging_eloop)
+		return;
+	wpa_s->driver->register_ranging_eloop(wpa_s->drv_priv, handle);
 }
 
 #endif /* CONFIG_PR */
diff --git a/wpa_supplicant/pr_supplicant.c b/wpa_supplicant/pr_supplicant.c
index 4ac092835..787fbc354 100644
--- a/wpa_supplicant/pr_supplicant.c
+++ b/wpa_supplicant/pr_supplicant.c
@@ -465,7 +465,7 @@ static int wpas_pr_trigger_ranging(struct wpa_supplicant *wpa_s,
 
 	/* Call driver operation to start peer measurement */
 	if (wpa_drv_start_peer_measurement(wpa_s, peer_addr, freq, op_channel,
-					   channel_width, params) < 0) {
+					   channel_width, params, NULL) < 0) {
 		wpa_printf(MSG_ERROR, "PR: Failed to start peer measurement");
 		goto fail;
 	}
-- 
2.34.1




More information about the Hostap mailing list