[RFC PATCH 04/23] nl80211: Parse Peer Measurement (PMSR) capabilities
Peddolla Harshavardhan Reddy
peddolla.reddy at oss.qualcomm.com
Tue Mar 31 22:48:42 PDT 2026
From: Peddolla Harshavardhan Reddy <peddolla at qti.qualcomm.com>
This commit adds support for parsing the NL80211_ATTR_PEER_MEASUREMENTS
attribute to determine the driver's capabilities for Proximity Ranging
(PR) using Fine Timing Measurement (FTM).
The new functionality includes:
- A handler to parse the main PMSR capabilities attribute.
- A specific parser for FTM capabilities (pmsr_capa_handler) that
extracts details such as ASAP support, trigger-based options,
antenna configurations, and supported ranging intervals.
- Updates the driver capability flags (drv->capa) with the parsed
Proximity Ranging features.
Signed-off-by: Peddolla Harshavardhan Reddy <peddolla at qti.qualcomm.com>
---
src/common/proximity_ranging.h | 12 +++
src/drivers/driver.h | 12 +++
src/drivers/driver_nl80211_capa.c | 128 ++++++++++++++++++++++++++++++
wpa_supplicant/pr_supplicant.c | 8 ++
wpa_supplicant/wpa_supplicant.c | 3 +-
5 files changed, 162 insertions(+), 1 deletion(-)
diff --git a/src/common/proximity_ranging.h b/src/common/proximity_ranging.h
index 14106d2fb..536d51375 100644
--- a/src/common/proximity_ranging.h
+++ b/src/common/proximity_ranging.h
@@ -358,6 +358,8 @@ struct pr_config {
u8 edca_format_and_bw;
+ u32 edca_min_ranging_interval;
+
u8 max_tx_antenna;
u8 max_rx_antenna;
@@ -368,6 +370,14 @@ struct pr_config {
bool ntb_rsta_support;
+ bool concurrent_ista_rsta;
+
+ u32 pmsr_max_peers;
+
+ u32 pr_max_peer_ista_role;
+
+ u32 pr_max_peer_rsta_role;
+
bool secure_he_ltf;
u8 max_tx_ltf_repetations;
@@ -388,6 +398,8 @@ struct pr_config {
u8 ntb_format_and_bw;
+ u32 ntb_min_ranging_interval;
+
struct pr_channels ntb_channels;
bool support_6ghz;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 268229edd..5f05550be 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2446,6 +2446,11 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS2_802_1X_AUTH 0x0000000800000000ULL
/** Driver supports MAC address filter for remain-on-channel */
#define WPA_DRIVER_FLAGS2_ROC_ADDR_FILTER 0x0000001000000000ULL
+/** Driver supports Proximity Ranging (PR) */
+#define WPA_DRIVER_FLAGS2_PR_SUPPORT 0x000000200000000ULL
+/** Driver supports concurrent ISTA and RSTA roles for PR */
+#define WPA_DRIVER_FLAGS2_PR_CONCURRENT_ISTA_RSTA 0x0000004000000000ULL
+
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -2575,6 +2580,7 @@ struct wpa_driver_capa {
u8 edca_format_and_bw;
u8 max_tx_antenna;
u8 max_rx_antenna;
+ u32 edca_min_ranging_interval;
/* NTB based ranging capabilities */
u8 ntb_format_and_bw;
@@ -2586,6 +2592,12 @@ struct wpa_driver_capa {
u8 max_rx_sts_gt_80;
u8 max_tx_sts_le_80;
u8 max_tx_sts_gt_80;
+ u32 ntb_min_ranging_interval;
+
+ /* Peer measurement capabilities */
+ u32 pmsr_max_peers;
+ u32 pr_max_peer_ista_role;
+ u32 pr_max_peer_rsta_role;
#ifdef CONFIG_NAN
/* Driver supports dual band NAN operation */
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index b8bfb6613..c9308812d 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -18,6 +18,7 @@
#include "common/qca-vendor-attr.h"
#include "common/brcm_vendor.h"
#include "driver_nl80211.h"
+#include "common/proximity_ranging.h"
static int protocol_feature_handler(struct nl_msg *msg, void *arg)
@@ -964,6 +965,128 @@ static void wiphy_info_mbssid(struct wpa_driver_capa *cap, struct nlattr *attr)
}
+#ifdef CONFIG_PR
+
+static void pmsr_type_ftm_handler(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *capa)
+{
+ u32 max_rx_sts, max_tx_sts;
+ struct nlattr *tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX + 1];
+
+ if (nla_parse_nested(tb, NL80211_PMSR_FTM_CAPA_ATTR_MAX, capa, NULL))
+ return;
+
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_ASAP])
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_FTM_INITIATOR;
+
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED])
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_NON_TRIGGER_BASED_INITIATOR;
+
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_PD_SUPPORT])
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_PR_SUPPORT;
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_PD_CONCURRENT_ISTA_RSTA_SUPPORT])
+ drv->capa.flags2 |=
+ WPA_DRIVER_FLAGS2_PR_CONCURRENT_ISTA_RSTA;
+
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_TX_LTF_REP])
+ drv->capa.max_tx_ltf_repetations =
+ nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_TX_LTF_REP]);
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_RX_LTF_REP])
+ drv->capa.max_rx_ltf_repetations =
+ nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_RX_LTF_REP]);
+
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_RX_STS]) {
+ max_rx_sts = nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_RX_STS]);
+ drv->capa.max_rx_sts_le_80 = max_rx_sts;
+ drv->capa.max_rx_sts_gt_80 = max_rx_sts;
+ }
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_TX_STS]) {
+ max_tx_sts = nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_TX_STS]);
+ drv->capa.max_tx_sts_le_80 = max_tx_sts;
+ drv->capa.max_tx_sts_gt_80 = max_tx_sts;
+ }
+
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_TOTAL_LTF_TX])
+ drv->capa.max_tx_ltf_total =
+ nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_TOTAL_LTF_TX]);
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_TOTAL_LTF_RX])
+ drv->capa.max_rx_ltf_total =
+ nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_TOTAL_LTF_RX]);
+
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_RSTA_SUPPORT] &&
+ tb[NL80211_PMSR_FTM_CAPA_ATTR_RSTA_SUPPORT_NTB])
+ drv->capa.flags2 |= WPA_DRIVER_FLAGS2_NON_TRIGGER_BASED_RESPONDER;
+
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_NUM_TX_ANTENNAS])
+ drv->capa.max_tx_antenna =
+ nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_NUM_TX_ANTENNAS]);
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_NUM_RX_ANTENNAS])
+ drv->capa.max_rx_antenna =
+ nla_get_u8(tb[NL80211_PMSR_FTM_CAPA_ATTR_MAX_NUM_RX_ANTENNAS]);
+
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MIN_INTERVAL_EDCA])
+ drv->capa.edca_min_ranging_interval =
+ nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_MIN_INTERVAL_EDCA]);
+ if (tb[NL80211_PMSR_FTM_CAPA_ATTR_MIN_INTERVAL_NTB])
+ drv->capa.ntb_min_ranging_interval =
+ nla_get_u32(tb[NL80211_PMSR_FTM_CAPA_ATTR_MIN_INTERVAL_NTB]);
+}
+
+
+static void wiphy_info_pmsr_type_capa(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *attr)
+{
+ struct nlattr *pos;
+ int rem;
+
+ nla_for_each_nested(pos, attr, rem) {
+ if (nla_type(pos) == NL80211_PMSR_TYPE_FTM)
+ pmsr_type_ftm_handler(drv, pos);
+ }
+}
+
+
+static void wiphy_info_pmsr_capa(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ struct nlattr *pmsr_capa[NL80211_PMSR_ATTR_MAX + 1];
+ static struct nla_policy
+ pmsr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
+ [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_U32 },
+ [NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_NESTED },
+ [NL80211_PMSR_ATTR_PD_MAX_PEER_ISTA_ROLE] = {
+ .type = NLA_U32
+ },
+ [NL80211_PMSR_ATTR_PD_MAX_PEER_RSTA_ROLE] = {
+ .type = NLA_U32
+ },
+ };
+
+ if (nla_parse_nested(pmsr_capa, NL80211_PMSR_ATTR_MAX,
+ tb[NL80211_ATTR_PEER_MEASUREMENTS],
+ pmsr_policy)) {
+ wpa_printf(MSG_DEBUG, "nl80211: Failed To parse PMSR capabilities");
+ return;
+ }
+
+ /* Parse PMSR capablities */
+ if (pmsr_capa[NL80211_PMSR_ATTR_MAX_PEERS])
+ drv->capa.pmsr_max_peers =
+ nla_get_u32(pmsr_capa[NL80211_PMSR_ATTR_MAX_PEERS]);
+ if (pmsr_capa[NL80211_PMSR_ATTR_PD_MAX_PEER_ISTA_ROLE])
+ drv->capa.pr_max_peer_ista_role =
+ nla_get_u32(pmsr_capa[NL80211_PMSR_ATTR_PD_MAX_PEER_ISTA_ROLE]);
+ if (pmsr_capa[NL80211_PMSR_ATTR_PD_MAX_PEER_RSTA_ROLE])
+ drv->capa.pr_max_peer_rsta_role =
+ nla_get_u32(pmsr_capa[NL80211_PMSR_ATTR_PD_MAX_PEER_RSTA_ROLE]);
+
+ if (pmsr_capa[NL80211_PMSR_ATTR_TYPE_CAPA])
+ wiphy_info_pmsr_type_capa(drv,
+ pmsr_capa[NL80211_PMSR_ATTR_TYPE_CAPA]);
+}
+
+#endif /* CONFIG_PR */
+
static int wiphy_info_handler(struct nl_msg *msg, void *arg)
{
struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -1090,6 +1213,11 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
wiphy_info_extended_capab(drv, tb[NL80211_ATTR_IFTYPE_EXT_CAPA]);
+#ifdef CONFIG_PR
+ if (tb[NL80211_ATTR_PEER_MEASUREMENTS])
+ wiphy_info_pmsr_capa(drv, tb);
+#endif /* CONFIG_PR */
+
if (tb[NL80211_ATTR_VENDOR_DATA]) {
struct nlattr *nl;
int rem;
diff --git a/wpa_supplicant/pr_supplicant.c b/wpa_supplicant/pr_supplicant.c
index c50d4bd92..a218d78cf 100644
--- a/wpa_supplicant/pr_supplicant.c
+++ b/wpa_supplicant/pr_supplicant.c
@@ -372,6 +372,14 @@ int wpas_pr_init(struct wpa_global *global, struct wpa_supplicant *wpa_s,
pr.max_tx_sts_le_80 = capa->max_tx_sts_le_80;
pr.max_tx_sts_gt_80 = capa->max_tx_sts_gt_80;
+ pr.edca_min_ranging_interval = capa->edca_min_ranging_interval;
+ pr.ntb_min_ranging_interval = capa->ntb_min_ranging_interval;
+ pr.concurrent_ista_rsta = !!(wpa_s->drv_flags2 &
+ WPA_DRIVER_FLAGS2_PR_CONCURRENT_ISTA_RSTA);
+ pr.pmsr_max_peers = capa->pmsr_max_peers;
+ pr.pr_max_peer_ista_role = capa->pr_max_peer_ista_role;
+ pr.pr_max_peer_rsta_role = capa->pr_max_peer_rsta_role;
+
pr.support_6ghz = wpas_is_6ghz_supported(wpa_s, true);
pr.pasn_send_mgmt = wpas_pr_pasn_send_mgmt;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 72079bccf..bd7910ea9 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -8052,7 +8052,8 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
return -1;
}
- if (wpas_pr_init(wpa_s->global, wpa_s, &capa) < 0)
+ if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PR_SUPPORT) &&
+ wpas_pr_init(wpa_s->global, wpa_s, &capa) < 0)
return -1;
if (wpa_bss_init(wpa_s) < 0)
--
2.34.1
More information about the Hostap
mailing list