[PATCH v4 03/20] nl80211: Add Proximity Detection (PD) support
Kavita Kavita
kavita.kavita at oss.qualcomm.com
Fri May 22 18:23:35 PDT 2026
From: Veerendranath Jakkam <vjakkam at qti.qualcomm.com>
Introduce driver and nl80211 support for a Proximity Detection (PD)
virtual interface, enabled under CONFIG_PR.
Two new driver ops are added:
- pd_start(): create interface for Proximity Detection and return the
assigned MAC address
- pd_stop(): stop interface for Proximity Detection
On the nl80211 side, nl80211_pd_start() allocates a dedicated i802_bss
(drv->pd_bss) outside the regular BSS list, creates the PD wdev via
nl80211_create_iface(), and activates it. nl80211_pd_stop() tears it
down in the correct order: deactivate first, then destroy BSS resources,
then delete the wdev. The driver deinit path calls nl80211_pd_stop() if
a PD wdev is still active.
The wdev_info struct and its netlink callback are generalized and
renamed to nl80211_wdev_handler_info to capture both wdev_id and MAC
address, replacing the previous nl80211_wdev_handler. This handler is
shared between PD wdev creation and the existing non-netdev interface
path in wpa_driver_nl80211_if_add().
wpa_supplicant is updated with wpa_drv_pd_start() and wpa_drv_pd_stop()
wrappers that call into the driver if CONFIG_PR is enabled.
Signed-off-by: Veerendranath Jakkam <vjakkam at qti.qualcomm.com>
---
src/drivers/driver.h | 19 ++++
src/drivers/driver_nl80211.c | 173 +++++++++++++++++++++++++++++------
src/drivers/driver_nl80211.h | 3 +
wpa_supplicant/driver_i.h | 20 ++++
4 files changed, 188 insertions(+), 27 deletions(-)
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 0e7b26a03..e7ce48c80 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -5903,6 +5903,25 @@ struct wpa_driver_ops {
const struct wpabuf *ulw,
struct nan_peer_schedule_config *sched);
#endif /* CONFIG_NAN */
+
+#ifdef CONFIG_PR
+ /**
+ * pd_start - Create interface for Proximity Detection
+ * @priv: Private driver interface data
+ * @addr: Requested MAC address
+ * @pd_addr: MAC address of the interface
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*pd_start)(void *priv, const u8 *addr, u8 *pd_addr);
+
+ /**
+ * pd_stop - Stop interface for Proximity Detection
+ * @priv: Private driver interface data
+ */
+ void (*pd_stop)(void *priv);
+
+#endif /* CONFIG_PR */
+
};
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index d87b39969..45086428e 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -199,6 +199,9 @@ static int nl80211_put_mesh_config(struct nl_msg *msg,
#endif /* CONFIG_MESH */
static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
u16 reason, int link_id);
+#ifdef CONFIG_PR
+static void nl80211_pd_stop(void *priv);
+#endif /* CONFIG_PR */
/* Converts nl80211_chan_width to a common format */
@@ -3253,6 +3256,31 @@ static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
}
+struct wdev_info {
+ u64 wdev_id;
+ int wdev_id_set;
+ u8 macaddr[ETH_ALEN];
+};
+
+static int nl80211_wdev_handler_info(struct nl_msg *msg, void *arg)
+{
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct wdev_info *wi = arg;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (tb[NL80211_ATTR_WDEV]) {
+ wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
+ wi->wdev_id_set = 1;
+ }
+ if (tb[NL80211_ATTR_MAC])
+ os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
+ ETH_ALEN);
+ return NL_SKIP;
+}
+
+
static int nl80211_set_pr_dev(struct i802_bss *bss, bool start)
{
struct nl_msg *msg;
@@ -3270,6 +3298,115 @@ static int nl80211_set_pr_dev(struct i802_bss *bss, bool start)
}
+#ifdef CONFIG_PR
+/**
+ * nl80211_pd_start - Create interface for Proximity Detection
+ */
+static int nl80211_pd_start(void *priv, const u8 *addr, u8 *pd_addr)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct i802_bss *pd_bss;
+ struct wdev_info info;
+ int ret;
+
+ if (drv->pd_bss) {
+ wpa_printf(MSG_DEBUG, "nl80211: PD wdev already active");
+ if (pd_addr)
+ os_memcpy(pd_addr, drv->pd_bss->addr, ETH_ALEN);
+ return 0;
+ }
+
+ pd_bss = os_zalloc(sizeof(*pd_bss));
+ if (!pd_bss)
+ return -1;
+
+ pd_bss->drv = drv;
+ pd_bss->ctx = bss->ctx; /* parent wpa_s */
+ pd_bss->flink = &pd_bss->links[0];
+ os_strlcpy(pd_bss->ifname, "pd-wdev", sizeof(pd_bss->ifname));
+
+ os_memset(&info, 0, sizeof(info));
+ ret = nl80211_create_iface(drv, "pd-wdev", NL80211_IFTYPE_PD, addr,
+ 0, nl80211_wdev_handler_info, &info, 0);
+ if (ret || !info.wdev_id_set) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to create PD wdev (ret=%d)", ret);
+ os_free(pd_bss);
+ return -1;
+ }
+
+ pd_bss->wdev_id = info.wdev_id;
+ pd_bss->wdev_id_set = 1;
+ if (!is_zero_ether_addr(info.macaddr))
+ os_memcpy(pd_bss->addr, info.macaddr, ETH_ALEN);
+ else if (addr)
+ os_memcpy(pd_bss->addr, addr, ETH_ALEN);
+ os_memcpy(pd_bss->flink->addr, pd_bss->addr, ETH_ALEN);
+
+ /* Activate the PD device */
+ ret = nl80211_set_pr_dev(pd_bss, 1);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to start PD device (ret=%d)", ret);
+ goto failed;
+ }
+
+ if (nl80211_init_bss(pd_bss)) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: Failed to init PD BSS");
+ goto failed_stop;
+ }
+
+ if (nl80211_mgmt_subscribe_non_ap(pd_bss))
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Failed to register frame processing for PD interface - ignore for now");
+
+ drv->pd_bss = pd_bss;
+
+ if (pd_addr)
+ os_memcpy(pd_addr, pd_bss->addr, ETH_ALEN);
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: PD wdev created wdev_id=0x%llx addr=" MACSTR,
+ (unsigned long long) pd_bss->wdev_id,
+ MAC2STR(pd_bss->addr));
+ return 0;
+
+failed_stop:
+ nl80211_set_pr_dev(pd_bss, 0);
+failed:
+ nl80211_del_non_netdev(pd_bss);
+ os_free(pd_bss);
+ return -1;
+}
+
+
+/**
+ * nl80211_pd_stop - Stop interface for Proximity Detection
+ */
+static void nl80211_pd_stop(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+
+ if (!drv->pd_bss)
+ return;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Stopping PD wdev wdev_id=0x%llx addr=" MACSTR,
+ (unsigned long long) drv->pd_bss->wdev_id,
+ MAC2STR(drv->pd_bss->addr));
+
+ nl80211_set_pr_dev(drv->pd_bss, 0);
+ nl80211_destroy_bss(drv->pd_bss);
+ nl80211_del_non_netdev(drv->pd_bss);
+ os_free(drv->pd_bss);
+ drv->pd_bss = NULL;
+}
+#endif /* CONFIG_PR */
+
+
#ifdef CONFIG_NAN
static void nl80211_nan_stop(struct i802_bss *bss)
{
@@ -3634,6 +3771,10 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss)
eloop_unregister_read_sock(drv->eapol_tx_sock);
if (drv->eapol_tx_sock >= 0)
close(drv->eapol_tx_sock);
+#ifdef CONFIG_PR
+ if (drv->pd_bss)
+ nl80211_pd_stop(bss);
+#endif /* CONFIG_PR */
if (bss->nl_preq)
wpa_driver_nl80211_probe_req_report(bss, 0);
@@ -9552,32 +9693,6 @@ static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
}
-struct wdev_info {
- u64 wdev_id;
- int wdev_id_set;
- u8 macaddr[ETH_ALEN];
-};
-
-static int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
-{
- struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
- struct nlattr *tb[NL80211_ATTR_MAX + 1];
- struct wdev_info *wi = arg;
-
- nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
- genlmsg_attrlen(gnlh, 0), NULL);
- if (tb[NL80211_ATTR_WDEV]) {
- wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
- wi->wdev_id_set = 1;
- }
-
- if (tb[NL80211_ATTR_MAC])
- os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
- ETH_ALEN);
-
- return NL_SKIP;
-}
-
static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr,
@@ -9600,7 +9715,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
os_memset(&nonnetdev_info, 0, sizeof(nonnetdev_info));
ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
- 0, nl80211_wdev_handler,
+ 0, nl80211_wdev_handler_info,
&nonnetdev_info, use_existing);
if (!nonnetdev_info.wdev_id_set || ifidx != 0) {
wpa_printf(MSG_ERROR,
@@ -16253,4 +16368,8 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.nan_config_schedule = wpa_driver_nl80211_nan_config_schedule,
.nan_config_peer_schedule = wpa_driver_nl80211_nan_config_peer_schedule,
#endif /* CONFIG_NAN */
+#ifdef CONFIG_PR
+ .pd_start = nl80211_pd_start,
+ .pd_stop = nl80211_pd_stop,
+#endif /* CONFIG_PR */
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 0f03da642..d1133a1fe 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -287,6 +287,9 @@ struct wpa_driver_nl80211_data {
#ifdef CONFIG_NAN
unsigned int nan_started:1;
#endif /* CONFIG_NAN */
+#ifdef CONFIG_PR
+ struct i802_bss *pd_bss; /* PD wdev; not in the BSS list */
+#endif /* CONFIG_PR */
};
struct nl80211_err_info {
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 034827488..c19c834b5 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -738,6 +738,26 @@ static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s,
return wpa_s->driver->set_wowlan(wpa_s->drv_priv, triggers);
}
+#ifdef CONFIG_PR
+
+static inline int
+wpa_drv_pd_start(struct wpa_supplicant *wpa_s, const u8 *addr, u8 *pd_addr)
+{
+ if (!wpa_s->driver->pd_start)
+ return -1;
+ return wpa_s->driver->pd_start(wpa_s->drv_priv, addr, pd_addr);
+}
+
+static inline void
+wpa_drv_pd_stop(struct wpa_supplicant *wpa_s)
+{
+ if (!wpa_s->driver->pd_stop)
+ return;
+ wpa_s->driver->pd_stop(wpa_s->drv_priv);
+}
+
+#endif /* CONFIG_PR */
+
static inline int wpa_drv_vendor_cmd(struct wpa_supplicant *wpa_s,
int vendor_id, int subcmd, const u8 *data,
size_t data_len,
--
2.34.1
More information about the Hostap
mailing list