[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